@aztec/sequencer-client 0.1.0-alpha11
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/.eslintrc.cjs +1 -0
- package/.tsbuildinfo +1 -0
- package/README.md +45 -0
- package/dest/block_builder/index.d.ts +19 -0
- package/dest/block_builder/index.d.ts.map +1 -0
- package/dest/block_builder/index.js +2 -0
- package/dest/block_builder/solo_block_builder.d.ts +76 -0
- package/dest/block_builder/solo_block_builder.d.ts.map +1 -0
- package/dest/block_builder/solo_block_builder.js +453 -0
- package/dest/block_builder/solo_block_builder.test.d.ts +3 -0
- package/dest/block_builder/solo_block_builder.test.d.ts.map +1 -0
- package/dest/block_builder/solo_block_builder.test.js +291 -0
- package/dest/block_builder/types.d.ts +12 -0
- package/dest/block_builder/types.d.ts.map +1 -0
- package/dest/block_builder/types.js +2 -0
- package/dest/client/index.d.ts +2 -0
- package/dest/client/index.d.ts.map +1 -0
- package/dest/client/index.js +2 -0
- package/dest/client/sequencer-client.d.ts +32 -0
- package/dest/client/sequencer-client.d.ts.map +1 -0
- package/dest/client/sequencer-client.js +47 -0
- package/dest/config.d.ts +12 -0
- package/dest/config.d.ts.map +1 -0
- package/dest/config.js +25 -0
- package/dest/global_variable_builder/config.d.ts +19 -0
- package/dest/global_variable_builder/config.d.ts.map +1 -0
- package/dest/global_variable_builder/config.js +2 -0
- package/dest/global_variable_builder/global_builder.d.ts +30 -0
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -0
- package/dest/global_variable_builder/global_builder.js +24 -0
- package/dest/global_variable_builder/index.d.ts +11 -0
- package/dest/global_variable_builder/index.d.ts.map +1 -0
- package/dest/global_variable_builder/index.js +12 -0
- package/dest/global_variable_builder/viem-reader.d.ts +26 -0
- package/dest/global_variable_builder/viem-reader.d.ts.map +1 -0
- package/dest/global_variable_builder/viem-reader.js +43 -0
- package/dest/index.d.ts +11 -0
- package/dest/index.d.ts.map +1 -0
- package/dest/index.js +12 -0
- package/dest/mocks/tx.d.ts +10 -0
- package/dest/mocks/tx.d.ts.map +1 -0
- package/dest/mocks/tx.js +18 -0
- package/dest/mocks/verification_keys.d.ts +28 -0
- package/dest/mocks/verification_keys.d.ts.map +1 -0
- package/dest/mocks/verification_keys.js +14 -0
- package/dest/prover/empty.d.ts +41 -0
- package/dest/prover/empty.d.ts.map +1 -0
- package/dest/prover/empty.js +57 -0
- package/dest/prover/index.d.ts +17 -0
- package/dest/prover/index.d.ts.map +1 -0
- package/dest/prover/index.js +2 -0
- package/dest/publisher/config.d.ts +33 -0
- package/dest/publisher/config.d.ts.map +1 -0
- package/dest/publisher/config.js +2 -0
- package/dest/publisher/index.d.ts +10 -0
- package/dest/publisher/index.d.ts.map +1 -0
- package/dest/publisher/index.js +11 -0
- package/dest/publisher/l1-publisher.d.ts +99 -0
- package/dest/publisher/l1-publisher.d.ts.map +1 -0
- package/dest/publisher/l1-publisher.js +154 -0
- package/dest/publisher/l1-publisher.test.d.ts +2 -0
- package/dest/publisher/l1-publisher.test.d.ts.map +1 -0
- package/dest/publisher/l1-publisher.test.js +58 -0
- package/dest/publisher/viem-tx-sender.d.ts +42 -0
- package/dest/publisher/viem-tx-sender.d.ts.map +1 -0
- package/dest/publisher/viem-tx-sender.js +115 -0
- package/dest/receiver.d.ts +13 -0
- package/dest/receiver.d.ts.map +1 -0
- package/dest/receiver.js +2 -0
- package/dest/sequencer/config.d.ts +26 -0
- package/dest/sequencer/config.d.ts.map +1 -0
- package/dest/sequencer/config.js +2 -0
- package/dest/sequencer/index.d.ts +4 -0
- package/dest/sequencer/index.d.ts.map +1 -0
- package/dest/sequencer/index.js +4 -0
- package/dest/sequencer/processed_tx.d.ts +34 -0
- package/dest/sequencer/processed_tx.d.ts.map +1 -0
- package/dest/sequencer/processed_tx.js +39 -0
- package/dest/sequencer/public_processor.d.ts +68 -0
- package/dest/sequencer/public_processor.d.ts.map +1 -0
- package/dest/sequencer/public_processor.js +195 -0
- package/dest/sequencer/public_processor.test.d.ts +2 -0
- package/dest/sequencer/public_processor.test.d.ts.map +1 -0
- package/dest/sequencer/public_processor.test.js +159 -0
- package/dest/sequencer/sequencer.d.ts +133 -0
- package/dest/sequencer/sequencer.d.ts.map +1 -0
- package/dest/sequencer/sequencer.js +293 -0
- package/dest/sequencer/sequencer.test.d.ts +2 -0
- package/dest/sequencer/sequencer.test.d.ts.map +1 -0
- package/dest/sequencer/sequencer.test.js +100 -0
- package/dest/sequencer/utils.d.ts +7 -0
- package/dest/sequencer/utils.d.ts.map +1 -0
- package/dest/sequencer/utils.js +9 -0
- package/dest/simulator/index.d.ts +42 -0
- package/dest/simulator/index.d.ts.map +1 -0
- package/dest/simulator/index.js +2 -0
- package/dest/simulator/public_executor.d.ts +39 -0
- package/dest/simulator/public_executor.d.ts.map +1 -0
- package/dest/simulator/public_executor.js +118 -0
- package/dest/simulator/public_kernel.d.ts +20 -0
- package/dest/simulator/public_kernel.d.ts.map +1 -0
- package/dest/simulator/public_kernel.js +27 -0
- package/dest/simulator/rollup.d.ts +33 -0
- package/dest/simulator/rollup.d.ts.map +1 -0
- package/dest/simulator/rollup.js +41 -0
- package/dest/utils.d.ts +12 -0
- package/dest/utils.d.ts.map +1 -0
- package/dest/utils.js +16 -0
- package/jest.integration.config.json +13 -0
- package/package.json +23 -0
- package/src/block_builder/index.ts +23 -0
- package/src/block_builder/solo_block_builder.test.ts +425 -0
- package/src/block_builder/solo_block_builder.ts +710 -0
- package/src/block_builder/types.ts +16 -0
- package/src/client/index.ts +1 -0
- package/src/client/sequencer-client.ts +79 -0
- package/src/config.ts +48 -0
- package/src/global_variable_builder/config.ts +19 -0
- package/src/global_variable_builder/global_builder.ts +43 -0
- package/src/global_variable_builder/index.ts +15 -0
- package/src/global_variable_builder/viem-reader.ts +63 -0
- package/src/index.ts +12 -0
- package/src/mocks/tx.ts +26 -0
- package/src/mocks/verification_keys.ts +36 -0
- package/src/prover/empty.ts +73 -0
- package/src/prover/index.ts +27 -0
- package/src/publisher/config.ts +36 -0
- package/src/publisher/index.ts +14 -0
- package/src/publisher/l1-publisher.test.ts +77 -0
- package/src/publisher/l1-publisher.ts +236 -0
- package/src/publisher/viem-tx-sender.ts +166 -0
- package/src/receiver.ts +13 -0
- package/src/sequencer/config.ts +27 -0
- package/src/sequencer/index.ts +3 -0
- package/src/sequencer/processed_tx.ts +82 -0
- package/src/sequencer/public_processor.test.ts +225 -0
- package/src/sequencer/public_processor.ts +280 -0
- package/src/sequencer/sequencer.test.ts +158 -0
- package/src/sequencer/sequencer.ts +356 -0
- package/src/sequencer/utils.ts +18 -0
- package/src/simulator/index.ts +51 -0
- package/src/simulator/public_executor.ts +137 -0
- package/src/simulator/public_kernel.ts +27 -0
- package/src/simulator/rollup.ts +54 -0
- package/src/utils.ts +16 -0
- package/tsconfig.json +38 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AppendOnlyTreeSnapshot, BaseOrMergeRollupPublicInputs, RootRollupPublicInputs } from '@aztec/circuits.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type to assert that only the correct trees are checked when validating rollup tree outputs.
|
|
5
|
+
*/
|
|
6
|
+
export type AllowedTreeNames<T extends BaseOrMergeRollupPublicInputs | RootRollupPublicInputs> =
|
|
7
|
+
T extends RootRollupPublicInputs
|
|
8
|
+
? 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message'
|
|
9
|
+
: 'PrivateData' | 'Contract' | 'Nullifier';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Type to assert the correct object field is indexed when validating rollup tree outputs.
|
|
13
|
+
*/
|
|
14
|
+
export type OutputWithTreeSnapshot<T extends BaseOrMergeRollupPublicInputs | RootRollupPublicInputs> = {
|
|
15
|
+
[K in `end${AllowedTreeNames<T>}TreeSnapshot`]: AppendOnlyTreeSnapshot;
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './sequencer-client.js';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { P2P } from '@aztec/p2p';
|
|
2
|
+
import { WorldStateSynchroniser } from '@aztec/world-state';
|
|
3
|
+
|
|
4
|
+
import { ContractDataSource, L1ToL2MessageSource, L2BlockSource } from '@aztec/types';
|
|
5
|
+
import { SoloBlockBuilder } from '../block_builder/solo_block_builder.js';
|
|
6
|
+
import { SequencerClientConfig } from '../config.js';
|
|
7
|
+
import { getL1Publisher, getVerificationKeys, Sequencer } from '../index.js';
|
|
8
|
+
import { EmptyRollupProver } from '../prover/empty.js';
|
|
9
|
+
import { PublicProcessorFactory } from '../sequencer/public_processor.js';
|
|
10
|
+
import { WasmRollupCircuitSimulator } from '../simulator/rollup.js';
|
|
11
|
+
import { getGlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Encapsulates the full sequencer and publisher.
|
|
15
|
+
*/
|
|
16
|
+
export class SequencerClient {
|
|
17
|
+
constructor(private sequencer: Sequencer) {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initializes and starts a new instance.
|
|
21
|
+
* @param config - Configuration for the sequencer, publisher, and L1 tx sender.
|
|
22
|
+
* @param p2pClient - P2P client that provides the txs to be sequenced.
|
|
23
|
+
* @param worldStateSynchroniser - Provides access to world state.
|
|
24
|
+
* @param contractDataSource - Provides access to contract bytecode for public executions.
|
|
25
|
+
* @param l2BlockSource - Provides information about the previously published blocks.
|
|
26
|
+
* @param l1ToL2MessageSource - Provides access to L1 to L2 messages.
|
|
27
|
+
* @returns A new running instance.
|
|
28
|
+
*/
|
|
29
|
+
public static async new(
|
|
30
|
+
config: SequencerClientConfig,
|
|
31
|
+
p2pClient: P2P,
|
|
32
|
+
worldStateSynchroniser: WorldStateSynchroniser,
|
|
33
|
+
contractDataSource: ContractDataSource,
|
|
34
|
+
l2BlockSource: L2BlockSource,
|
|
35
|
+
l1ToL2MessageSource: L1ToL2MessageSource,
|
|
36
|
+
) {
|
|
37
|
+
const publisher = getL1Publisher(config);
|
|
38
|
+
const globalsBuilder = getGlobalVariableBuilder(config);
|
|
39
|
+
const merkleTreeDb = worldStateSynchroniser.getLatest();
|
|
40
|
+
|
|
41
|
+
const blockBuilder = new SoloBlockBuilder(
|
|
42
|
+
merkleTreeDb,
|
|
43
|
+
getVerificationKeys(),
|
|
44
|
+
await WasmRollupCircuitSimulator.new(),
|
|
45
|
+
new EmptyRollupProver(),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const publicProcessorFactory = new PublicProcessorFactory(merkleTreeDb, contractDataSource, l1ToL2MessageSource);
|
|
49
|
+
|
|
50
|
+
const sequencer = new Sequencer(
|
|
51
|
+
publisher,
|
|
52
|
+
globalsBuilder,
|
|
53
|
+
p2pClient,
|
|
54
|
+
worldStateSynchroniser,
|
|
55
|
+
blockBuilder,
|
|
56
|
+
l2BlockSource,
|
|
57
|
+
l1ToL2MessageSource,
|
|
58
|
+
publicProcessorFactory,
|
|
59
|
+
config,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await sequencer.start();
|
|
63
|
+
return new SequencerClient(sequencer);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Stops the sequencer from processing new txs.
|
|
68
|
+
*/
|
|
69
|
+
public async stop() {
|
|
70
|
+
await this.sequencer.stop();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Restarts the sequencer after being stopped.
|
|
75
|
+
*/
|
|
76
|
+
public restart() {
|
|
77
|
+
this.sequencer.restart();
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { SequencerConfig } from './sequencer/config.js';
|
|
2
|
+
import { PublisherConfig, TxSenderConfig } from './publisher/config.js';
|
|
3
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
+
import { GlobalReaderConfig } from './global_variable_builder/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration settings for the SequencerClient.
|
|
8
|
+
*/
|
|
9
|
+
export type SequencerClientConfig = PublisherConfig & TxSenderConfig & SequencerConfig & GlobalReaderConfig;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates an instance of SequencerClientConfig out of environment variables using sensible defaults for integration testing if not set.
|
|
13
|
+
*/
|
|
14
|
+
export function getConfigEnvVars(): SequencerClientConfig {
|
|
15
|
+
const {
|
|
16
|
+
SEQ_PUBLISHER_PRIVATE_KEY,
|
|
17
|
+
ETHEREUM_HOST,
|
|
18
|
+
CHAIN_ID,
|
|
19
|
+
VERSION,
|
|
20
|
+
API_KEY,
|
|
21
|
+
SEQ_REQUIRED_CONFS,
|
|
22
|
+
SEQ_RETRY_INTERVAL,
|
|
23
|
+
SEQ_TX_POLLING_INTERVAL,
|
|
24
|
+
SEQ_MAX_TX_PER_BLOCK,
|
|
25
|
+
SEQ_MIN_TX_PER_BLOCK,
|
|
26
|
+
ROLLUP_CONTRACT_ADDRESS,
|
|
27
|
+
INBOX_CONTRACT_ADDRESS,
|
|
28
|
+
CONTRACT_DEPLOYMENT_EMITTER_ADDRESS,
|
|
29
|
+
} = process.env;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
rpcUrl: ETHEREUM_HOST ? ETHEREUM_HOST : '',
|
|
33
|
+
chainId: CHAIN_ID ? +CHAIN_ID : 31337, // 31337 is the default chain id for anvil
|
|
34
|
+
version: VERSION ? +VERSION : 1, // 1 is our default version
|
|
35
|
+
apiKey: API_KEY,
|
|
36
|
+
requiredConfirmations: SEQ_REQUIRED_CONFS ? +SEQ_REQUIRED_CONFS : 1,
|
|
37
|
+
retryIntervalMs: SEQ_RETRY_INTERVAL ? +SEQ_RETRY_INTERVAL : 1_000,
|
|
38
|
+
transactionPollingInterval: SEQ_TX_POLLING_INTERVAL ? +SEQ_TX_POLLING_INTERVAL : 1_000,
|
|
39
|
+
rollupContract: ROLLUP_CONTRACT_ADDRESS ? EthAddress.fromString(ROLLUP_CONTRACT_ADDRESS) : EthAddress.ZERO,
|
|
40
|
+
inboxContract: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO,
|
|
41
|
+
contractDeploymentEmitterContract: CONTRACT_DEPLOYMENT_EMITTER_ADDRESS
|
|
42
|
+
? EthAddress.fromString(CONTRACT_DEPLOYMENT_EMITTER_ADDRESS)
|
|
43
|
+
: EthAddress.ZERO,
|
|
44
|
+
publisherPrivateKey: Buffer.from(SEQ_PUBLISHER_PRIVATE_KEY || '', 'hex'),
|
|
45
|
+
maxTxsPerBlock: SEQ_MAX_TX_PER_BLOCK ? +SEQ_MAX_TX_PER_BLOCK : 32,
|
|
46
|
+
minTxsPerBlock: SEQ_MIN_TX_PER_BLOCK ? +SEQ_MIN_TX_PER_BLOCK : 1,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EthAddress } from '@aztec/circuits.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configuration of the L1GlobalReader.
|
|
5
|
+
*/
|
|
6
|
+
export interface GlobalReaderConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Rollup contract address.
|
|
9
|
+
*/
|
|
10
|
+
rollupContract: EthAddress;
|
|
11
|
+
/**
|
|
12
|
+
* The RPC Url of the ethereum host.
|
|
13
|
+
*/
|
|
14
|
+
rpcUrl: string;
|
|
15
|
+
/**
|
|
16
|
+
* The API key of the ethereum host.
|
|
17
|
+
*/
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Fr, GlobalVariables } from '@aztec/circuits.js';
|
|
2
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Reads values from L1 state that is used for the global values.
|
|
6
|
+
*/
|
|
7
|
+
export interface L1GlobalReader {
|
|
8
|
+
getLastTimestamp(): Promise<bigint>;
|
|
9
|
+
getVersion(): Promise<bigint>;
|
|
10
|
+
getChainId(): Promise<bigint>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Builds global variables from L1 state.
|
|
15
|
+
*/
|
|
16
|
+
export interface GlobalVariableBuilder {
|
|
17
|
+
buildGlobalVariables(blockNumber: Fr): Promise<GlobalVariables>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Simple implementation of a builder that uses the minimum time possible for the global variables.
|
|
22
|
+
*/
|
|
23
|
+
export class SimpleGlobalVariableBuilder implements GlobalVariableBuilder {
|
|
24
|
+
private log = createDebugLogger('aztec:sequencer:simple_global_variable_builder');
|
|
25
|
+
constructor(private readonly reader: L1GlobalReader) {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Simple builder of global variables that use the minimum time possible.
|
|
29
|
+
* @param blockNumber - The block number to build global variables for.
|
|
30
|
+
* @returns The global variables for the given block number.
|
|
31
|
+
*/
|
|
32
|
+
public async buildGlobalVariables(blockNumber: Fr): Promise<GlobalVariables> {
|
|
33
|
+
const lastTimestamp = new Fr(await this.reader.getLastTimestamp());
|
|
34
|
+
const version = new Fr(await this.reader.getVersion());
|
|
35
|
+
const chainId = new Fr(await this.reader.getChainId());
|
|
36
|
+
|
|
37
|
+
this.log(
|
|
38
|
+
`Built global variables for block ${blockNumber}: (${chainId}, ${version}, ${blockNumber}, ${lastTimestamp})`,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return new GlobalVariables(chainId, version, blockNumber, lastTimestamp);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GlobalReaderConfig } from './config.js';
|
|
2
|
+
import { GlobalVariableBuilder, SimpleGlobalVariableBuilder } from './global_builder.js';
|
|
3
|
+
import { ViemReader } from './viem-reader.js';
|
|
4
|
+
|
|
5
|
+
export { SimpleGlobalVariableBuilder } from './global_builder.js';
|
|
6
|
+
export { GlobalReaderConfig } from './config.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns a new instance of the global variable builder.
|
|
10
|
+
* @param config - Configuration to initialize the builder.
|
|
11
|
+
* @returns A new instance of the global variable builder.
|
|
12
|
+
*/
|
|
13
|
+
export function getGlobalVariableBuilder(config: GlobalReaderConfig): GlobalVariableBuilder {
|
|
14
|
+
return new SimpleGlobalVariableBuilder(new ViemReader(config));
|
|
15
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createEthereumChain } from '@aztec/ethereum';
|
|
2
|
+
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
3
|
+
import {
|
|
4
|
+
GetContractReturnType,
|
|
5
|
+
PublicClient,
|
|
6
|
+
HttpTransport,
|
|
7
|
+
createPublicClient,
|
|
8
|
+
http,
|
|
9
|
+
getContract,
|
|
10
|
+
getAddress,
|
|
11
|
+
} from 'viem';
|
|
12
|
+
import * as chains from 'viem/chains';
|
|
13
|
+
import { GlobalReaderConfig } from './config.js';
|
|
14
|
+
import { L1GlobalReader } from './global_builder.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Reads values from L1 state using viem.
|
|
18
|
+
*/
|
|
19
|
+
export class ViemReader implements L1GlobalReader {
|
|
20
|
+
private rollupContract: GetContractReturnType<typeof RollupAbi, PublicClient<HttpTransport, chains.Chain>>;
|
|
21
|
+
private publicClient: PublicClient<HttpTransport, chains.Chain>;
|
|
22
|
+
|
|
23
|
+
constructor(config: GlobalReaderConfig) {
|
|
24
|
+
const { rpcUrl, apiKey, rollupContract: rollupContractAddress } = config;
|
|
25
|
+
|
|
26
|
+
const chain = createEthereumChain(rpcUrl, apiKey);
|
|
27
|
+
|
|
28
|
+
this.publicClient = createPublicClient({
|
|
29
|
+
chain: chain.chainInfo,
|
|
30
|
+
transport: http(chain.rpcUrl),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
this.rollupContract = getContract({
|
|
34
|
+
address: getAddress(rollupContractAddress.toString()),
|
|
35
|
+
abi: RollupAbi,
|
|
36
|
+
publicClient: this.publicClient,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Fetches the last timestamp that a block was processed by the contract.
|
|
42
|
+
* @returns The last timestamp that a block was processed by the contract.
|
|
43
|
+
*/
|
|
44
|
+
public async getLastTimestamp(): Promise<bigint> {
|
|
45
|
+
return BigInt(await this.rollupContract.read.lastBlockTs());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Fetches the version of the rollup contract.
|
|
50
|
+
* @returns The version of the rollup contract.
|
|
51
|
+
*/
|
|
52
|
+
public async getVersion(): Promise<bigint> {
|
|
53
|
+
return BigInt(await this.rollupContract.read.VERSION());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Gets the chain id.
|
|
58
|
+
* @returns The chain id.
|
|
59
|
+
*/
|
|
60
|
+
public async getChainId(): Promise<bigint> {
|
|
61
|
+
return await Promise.resolve(BigInt(this.publicClient.chain.id));
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './sequencer/index.js';
|
|
2
|
+
export * from './config.js';
|
|
3
|
+
export * from './publisher/index.js';
|
|
4
|
+
export * from './client/index.js';
|
|
5
|
+
export * from './mocks/tx.js';
|
|
6
|
+
export * from './mocks/verification_keys.js';
|
|
7
|
+
|
|
8
|
+
// Used by publisher test in e2e
|
|
9
|
+
export { WasmRollupCircuitSimulator } from './simulator/rollup.js';
|
|
10
|
+
export { EmptyRollupProver } from './prover/empty.js';
|
|
11
|
+
export { SoloBlockBuilder } from './block_builder/solo_block_builder.js';
|
|
12
|
+
export { makeProcessedTx, makeEmptyProcessedTx } from './sequencer/processed_tx.js';
|
package/src/mocks/tx.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { KERNEL_PUBLIC_CALL_STACK_LENGTH, makeEmptyProof } from '@aztec/circuits.js';
|
|
2
|
+
import { makeKernelPublicInputs, makePublicCallRequest } from '@aztec/circuits.js/factories';
|
|
3
|
+
import { FunctionL2Logs, Tx, TxL2Logs } from '@aztec/types';
|
|
4
|
+
import times from 'lodash.times';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Testing utility to create empty logs composed from a single empty log.
|
|
8
|
+
*/
|
|
9
|
+
export function makeEmptyLogs(): TxL2Logs {
|
|
10
|
+
const functionLogs = [new FunctionL2Logs([Buffer.alloc(0)])];
|
|
11
|
+
return new TxL2Logs(functionLogs);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Testing utility to create a tx with gibberish kernel circuit output, random logs, and an empty proof.
|
|
16
|
+
*/
|
|
17
|
+
export function makeTx(seed = 0) {
|
|
18
|
+
return new Tx(
|
|
19
|
+
makeKernelPublicInputs(seed),
|
|
20
|
+
makeEmptyProof(),
|
|
21
|
+
TxL2Logs.random(2, 3),
|
|
22
|
+
TxL2Logs.random(3, 0),
|
|
23
|
+
[],
|
|
24
|
+
times(KERNEL_PUBLIC_CALL_STACK_LENGTH, makePublicCallRequest),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { VerificationKey } from '@aztec/circuits.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Well-known verification keys.
|
|
5
|
+
*/
|
|
6
|
+
export interface VerificationKeys {
|
|
7
|
+
/**
|
|
8
|
+
* Verification key for the default public kernel circuit.
|
|
9
|
+
*/
|
|
10
|
+
publicKernelCircuit: VerificationKey;
|
|
11
|
+
/**
|
|
12
|
+
* Verification key for the default private kernel circuit.
|
|
13
|
+
*/
|
|
14
|
+
privateKernelCircuit: VerificationKey;
|
|
15
|
+
/**
|
|
16
|
+
* Verification key for the default base rollup circuit.
|
|
17
|
+
*/
|
|
18
|
+
baseRollupCircuit: VerificationKey;
|
|
19
|
+
/**
|
|
20
|
+
* Verification key for the default merge rollup circuit.
|
|
21
|
+
*/
|
|
22
|
+
mergeRollupCircuit: VerificationKey;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns mock verification keys for each well known circuit.
|
|
27
|
+
* @returns A VerificationKeys object with fake values.
|
|
28
|
+
*/
|
|
29
|
+
export function getVerificationKeys(): VerificationKeys {
|
|
30
|
+
return {
|
|
31
|
+
privateKernelCircuit: VerificationKey.makeFake(),
|
|
32
|
+
baseRollupCircuit: VerificationKey.makeFake(),
|
|
33
|
+
mergeRollupCircuit: VerificationKey.makeFake(),
|
|
34
|
+
publicKernelCircuit: VerificationKey.makeFake(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* eslint-disable require-await */
|
|
2
|
+
import {
|
|
3
|
+
AggregationObject,
|
|
4
|
+
BaseOrMergeRollupPublicInputs,
|
|
5
|
+
BaseRollupInputs,
|
|
6
|
+
MergeRollupInputs,
|
|
7
|
+
Proof,
|
|
8
|
+
PublicCircuitPublicInputs,
|
|
9
|
+
PublicKernelPublicInputs,
|
|
10
|
+
RootRollupInputs,
|
|
11
|
+
RootRollupPublicInputs,
|
|
12
|
+
} from '@aztec/circuits.js';
|
|
13
|
+
import { PublicProver, RollupProver } from './index.js';
|
|
14
|
+
|
|
15
|
+
const EMPTY_PROOF_SIZE = 42;
|
|
16
|
+
|
|
17
|
+
// TODO: Silently modifying one of the inputs to inject the aggregation object is horrible.
|
|
18
|
+
// We should rethink these interfaces.
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Prover implementation that returns empty proofs and overrides aggregation objects.
|
|
22
|
+
*/
|
|
23
|
+
export class EmptyRollupProver implements RollupProver {
|
|
24
|
+
/**
|
|
25
|
+
* Creates an empty proof for the given input.
|
|
26
|
+
* @param _input - Input to the circuit.
|
|
27
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
28
|
+
*/
|
|
29
|
+
async getBaseRollupProof(_input: BaseRollupInputs, publicInputs: BaseOrMergeRollupPublicInputs): Promise<Proof> {
|
|
30
|
+
publicInputs.endAggregationObject = AggregationObject.makeFake();
|
|
31
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates an empty proof for the given input.
|
|
36
|
+
* @param _input - Input to the circuit.
|
|
37
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
38
|
+
*/
|
|
39
|
+
async getMergeRollupProof(_input: MergeRollupInputs, publicInputs: BaseOrMergeRollupPublicInputs): Promise<Proof> {
|
|
40
|
+
publicInputs.endAggregationObject = AggregationObject.makeFake();
|
|
41
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates an empty proof for the given input.
|
|
45
|
+
* @param _input - Input to the circuit.
|
|
46
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
47
|
+
*/
|
|
48
|
+
async getRootRollupProof(_input: RootRollupInputs, publicInputs: RootRollupPublicInputs): Promise<Proof> {
|
|
49
|
+
publicInputs.endAggregationObject = AggregationObject.makeFake();
|
|
50
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Prover implementation that returns empty proofs.
|
|
56
|
+
*/
|
|
57
|
+
export class EmptyPublicProver implements PublicProver {
|
|
58
|
+
/**
|
|
59
|
+
* Creates an empty proof for the given input.
|
|
60
|
+
* @param _publicInputs - Public inputs obtained via simulation.
|
|
61
|
+
*/
|
|
62
|
+
async getPublicCircuitProof(_publicInputs: PublicCircuitPublicInputs): Promise<Proof> {
|
|
63
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Creates an empty proof for the given input.
|
|
68
|
+
* @param _publicInputs - Public inputs obtained via simulation.
|
|
69
|
+
*/
|
|
70
|
+
async getPublicKernelCircuitProof(_publicInputs: PublicKernelPublicInputs): Promise<Proof> {
|
|
71
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseOrMergeRollupPublicInputs,
|
|
3
|
+
BaseRollupInputs,
|
|
4
|
+
MergeRollupInputs,
|
|
5
|
+
Proof,
|
|
6
|
+
PublicCircuitPublicInputs,
|
|
7
|
+
PublicKernelPublicInputs,
|
|
8
|
+
RootRollupInputs,
|
|
9
|
+
RootRollupPublicInputs,
|
|
10
|
+
} from '@aztec/circuits.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Generates proofs for the base, merge, and root rollup circuits.
|
|
14
|
+
*/
|
|
15
|
+
export interface RollupProver {
|
|
16
|
+
getBaseRollupProof(input: BaseRollupInputs, publicInputs: BaseOrMergeRollupPublicInputs): Promise<Proof>;
|
|
17
|
+
getMergeRollupProof(input: MergeRollupInputs, publicInputs: BaseOrMergeRollupPublicInputs): Promise<Proof>;
|
|
18
|
+
getRootRollupProof(input: RootRollupInputs, publicInputs: RootRollupPublicInputs): Promise<Proof>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Generates proofs for the public and public kernel circuits.
|
|
23
|
+
*/
|
|
24
|
+
export interface PublicProver {
|
|
25
|
+
getPublicCircuitProof(publicInputs: PublicCircuitPublicInputs): Promise<Proof>;
|
|
26
|
+
getPublicKernelCircuitProof(publicInputs: PublicKernelPublicInputs): Promise<Proof>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { L1Addresses } from '@aztec/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The configuration of the rollup transaction publisher.
|
|
5
|
+
*/
|
|
6
|
+
export interface TxSenderConfig extends L1Addresses {
|
|
7
|
+
/**
|
|
8
|
+
* The private key to be used by the publisher.
|
|
9
|
+
*/
|
|
10
|
+
publisherPrivateKey: Buffer;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The RPC Url of the ethereum host.
|
|
14
|
+
*/
|
|
15
|
+
rpcUrl: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The API key of the ethereum host.
|
|
19
|
+
*/
|
|
20
|
+
apiKey?: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The number of confirmations required.
|
|
24
|
+
*/
|
|
25
|
+
requiredConfirmations: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configuration of the L1Publisher.
|
|
30
|
+
*/
|
|
31
|
+
export interface PublisherConfig {
|
|
32
|
+
/**
|
|
33
|
+
* The interval to wait between publish retries.
|
|
34
|
+
*/
|
|
35
|
+
retryIntervalMs: number;
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PublisherConfig, TxSenderConfig } from './config.js';
|
|
2
|
+
import { L1Publisher } from './l1-publisher.js';
|
|
3
|
+
import { ViemTxSender } from './viem-tx-sender.js';
|
|
4
|
+
|
|
5
|
+
export { L1Publisher } from './l1-publisher.js';
|
|
6
|
+
export { PublisherConfig } from './config.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns a new instance of the L1Publisher.
|
|
10
|
+
* @param config - Configuration to initialize the new instance.
|
|
11
|
+
*/
|
|
12
|
+
export function getL1Publisher(config: PublisherConfig & TxSenderConfig): L1Publisher {
|
|
13
|
+
return new L1Publisher(new ViemTxSender(config), config);
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { L2Block } from '@aztec/types';
|
|
2
|
+
import { mock, MockProxy } from 'jest-mock-extended';
|
|
3
|
+
import { sleep } from '../utils.js';
|
|
4
|
+
import { L1Publisher, L1PublisherTxSender, MinimalTransactionReceipt } from './l1-publisher.js';
|
|
5
|
+
|
|
6
|
+
describe('L1Publisher', () => {
|
|
7
|
+
let txSender: MockProxy<L1PublisherTxSender>;
|
|
8
|
+
let txHash: string;
|
|
9
|
+
let txReceipt: MinimalTransactionReceipt;
|
|
10
|
+
let l2Block: L2Block;
|
|
11
|
+
let l2Inputs: Buffer;
|
|
12
|
+
let l2Proof: Buffer;
|
|
13
|
+
let publisher: L1Publisher;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
l2Block = L2Block.random(42);
|
|
17
|
+
l2Inputs = l2Block.encode();
|
|
18
|
+
l2Proof = Buffer.alloc(0);
|
|
19
|
+
|
|
20
|
+
txSender = mock<L1PublisherTxSender>();
|
|
21
|
+
txHash = `0x${Buffer.from('txHash').toString('hex')}`; // random tx hash
|
|
22
|
+
txReceipt = { transactionHash: txHash, status: true };
|
|
23
|
+
txSender.sendProcessTx.mockResolvedValueOnce(txHash);
|
|
24
|
+
txSender.getTransactionReceipt.mockResolvedValueOnce(txReceipt);
|
|
25
|
+
|
|
26
|
+
publisher = new L1Publisher(txSender, { retryIntervalMs: 1 });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('publishes l2 block to l1', async () => {
|
|
30
|
+
const result = await publisher.processL2Block(l2Block);
|
|
31
|
+
|
|
32
|
+
expect(result).toEqual(true);
|
|
33
|
+
expect(txSender.sendProcessTx).toHaveBeenCalledWith({ proof: l2Proof, inputs: l2Inputs });
|
|
34
|
+
expect(txSender.getTransactionReceipt).toHaveBeenCalledWith(txHash);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('does not retry if sending a tx fails', async () => {
|
|
38
|
+
txSender.sendProcessTx.mockReset().mockRejectedValueOnce(new Error()).mockResolvedValueOnce(txHash);
|
|
39
|
+
|
|
40
|
+
const result = await publisher.processL2Block(l2Block);
|
|
41
|
+
|
|
42
|
+
expect(result).toEqual(false);
|
|
43
|
+
expect(txSender.sendProcessTx).toHaveBeenCalledTimes(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('retries if fetching the receipt fails', async () => {
|
|
47
|
+
txSender.getTransactionReceipt.mockReset().mockRejectedValueOnce(new Error()).mockResolvedValueOnce(txReceipt);
|
|
48
|
+
|
|
49
|
+
const result = await publisher.processL2Block(l2Block);
|
|
50
|
+
|
|
51
|
+
expect(result).toEqual(true);
|
|
52
|
+
expect(txSender.getTransactionReceipt).toHaveBeenCalledTimes(2);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('returns false if tx reverts', async () => {
|
|
56
|
+
txSender.getTransactionReceipt.mockReset().mockResolvedValueOnce({ ...txReceipt, status: false });
|
|
57
|
+
|
|
58
|
+
const result = await publisher.processL2Block(l2Block);
|
|
59
|
+
|
|
60
|
+
expect(result).toEqual(false);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('returns false if interrupted', async () => {
|
|
64
|
+
txSender.sendProcessTx.mockReset().mockImplementationOnce(() => sleep(10, txHash));
|
|
65
|
+
|
|
66
|
+
const resultPromise = publisher.processL2Block(l2Block);
|
|
67
|
+
publisher.interrupt();
|
|
68
|
+
const result = await resultPromise;
|
|
69
|
+
|
|
70
|
+
expect(result).toEqual(false);
|
|
71
|
+
expect(txSender.getTransactionReceipt).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it.skip('waits for fee distributor balance', () => {});
|
|
75
|
+
|
|
76
|
+
it.skip('fails if contract is changed underfoot', () => {});
|
|
77
|
+
});
|