@@ -8,10 +8,13 @@ import {
88 GrumpkinScalar ,
99 type SentTx ,
1010 TxStatus ,
11+ createDebugLogger ,
12+ sleep ,
1113} from '@aztec/aztec.js' ;
1214import { type BootNodeConfig , BootstrapNode , createLibP2PPeerId } from '@aztec/p2p' ;
1315import { type PXEService , createPXEService , getPXEServiceConfig as getRpcConfig } from '@aztec/pxe' ;
1416
17+ import fs from 'fs' ;
1518import { mnemonicToAccount } from 'viem/accounts' ;
1619
1720import { MNEMONIC } from './fixtures/fixtures.js' ;
@@ -30,21 +33,36 @@ interface NodeContext {
3033 account : AztecAddress ;
3134}
3235
36+ const PEER_ID_PRIVATE_KEYS = [
37+ '0802122002f651fd8653925529e3baccb8489b3af4d7d9db440cbf5df4a63ff04ea69683' ,
38+ '08021220c3bd886df5fe5b33376096ad0dab3d2dc86ed2a361d5fde70f24d979dc73da41' ,
39+ '080212206b6567ac759db5434e79495ec7458e5e93fe479a5b80713446e0bce5439a5655' ,
40+ '08021220366453668099bdacdf08fab476ee1fced6bf00ddc1223d6c2ee626e7236fb526' ,
41+ ] ;
42+
3343describe ( 'e2e_p2p_network' , ( ) => {
3444 let config : AztecNodeConfig ;
3545 let logger : DebugLogger ;
3646 let teardown : ( ) => Promise < void > ;
47+ let bootstrapNode : BootstrapNode ;
48+ let bootstrapNodeEnr : string ;
3749
3850 beforeEach ( async ( ) => {
39- ( { teardown, config, logger } = await setup ( 1 ) ) ;
51+ ( { teardown, config, logger } = await setup ( 0 ) ) ;
52+ bootstrapNode = await createBootstrapNode ( ) ;
53+ bootstrapNodeEnr = bootstrapNode . getENR ( ) . encodeTxt ( ) ;
4054 } ) ;
4155
4256 afterEach ( ( ) => teardown ( ) ) ;
4357
58+ afterAll ( ( ) => {
59+ for ( let i = 0 ; i < NUM_NODES ; i ++ ) {
60+ fs . rmSync ( `./data-${ i } ` , { recursive : true , force : true } ) ;
61+ }
62+ } ) ;
63+
4464 it ( 'should rollup txs from all peers' , async ( ) => {
4565 // create the bootstrap node for the network
46- const bootstrapNode = await createBootstrapNode ( ) ;
47- const bootstrapNodeEnr = bootstrapNode . getENR ( ) ;
4866 if ( ! bootstrapNodeEnr ) {
4967 throw new Error ( 'Bootstrap node ENR is not available' ) ;
5068 }
@@ -53,14 +71,29 @@ describe('e2e_p2p_network', () => {
5371 // should be set so that the only way for rollups to be built
5472 // is if the txs are successfully gossiped around the nodes.
5573 const contexts : NodeContext [ ] = [ ] ;
74+ const nodes : AztecNodeService [ ] = [ ] ;
5675 for ( let i = 0 ; i < NUM_NODES ; i ++ ) {
57- const node = await createNode ( i + 1 + BOOT_NODE_UDP_PORT , bootstrapNodeEnr ?. encodeTxt ( ) , i ) ;
76+ const node = await createNode ( i + 1 + BOOT_NODE_UDP_PORT , bootstrapNodeEnr , i ) ;
77+ nodes . push ( node ) ;
78+ }
79+
80+ // wait a bit for peers to discover each other
81+ await sleep ( 2000 ) ;
82+
83+ for ( const node of nodes ) {
5884 const context = await createPXEServiceAndSubmitTransactions ( node , NUM_TXS_PER_NODE ) ;
5985 contexts . push ( context ) ;
6086 }
6187
6288 // now ensure that all txs were successfully mined
63- await Promise . all ( contexts . flatMap ( context => context . txs . map ( tx => tx . wait ( ) ) ) ) ;
89+ await Promise . all (
90+ contexts . flatMap ( ( context , i ) =>
91+ context . txs . map ( async ( tx , j ) => {
92+ logger . info ( `Waiting for tx ${ i } -${ j } : ${ await tx . getTxHash ( ) } to be mined` ) ;
93+ return tx . wait ( ) ;
94+ } ) ,
95+ ) ,
96+ ) ;
6497
6598 // shutdown all nodes.
6699 for ( const context of contexts ) {
@@ -70,6 +103,61 @@ describe('e2e_p2p_network', () => {
70103 await bootstrapNode . stop ( ) ;
71104 } ) ;
72105
106+ it ( 'should re-discover stored peers without bootstrap node' , async ( ) => {
107+ const contexts : NodeContext [ ] = [ ] ;
108+ const nodes : AztecNodeService [ ] = [ ] ;
109+ for ( let i = 0 ; i < NUM_NODES ; i ++ ) {
110+ const node = await createNode ( i + 1 + BOOT_NODE_UDP_PORT , bootstrapNodeEnr , i , `./data-${ i } ` ) ;
111+ nodes . push ( node ) ;
112+ }
113+ // wait a bit for peers to discover each other
114+ await sleep ( 3000 ) ;
115+
116+ // stop bootstrap node
117+ await bootstrapNode . stop ( ) ;
118+
119+ // create new nodes from datadir
120+ const newNodes : AztecNodeService [ ] = [ ] ;
121+
122+ // stop all nodes
123+ for ( let i = 0 ; i < NUM_NODES ; i ++ ) {
124+ const node = nodes [ i ] ;
125+ await node . stop ( ) ;
126+ logger . info ( `Node ${ i } stopped` ) ;
127+ await sleep ( 1200 ) ;
128+ const newNode = await createNode ( i + 1 + BOOT_NODE_UDP_PORT , undefined , i , `./data-${ i } ` ) ;
129+ logger . info ( `Node ${ i } restarted` ) ;
130+ newNodes . push ( newNode ) ;
131+ // const context = await createPXEServiceAndSubmitTransactions(node, NUM_TXS_PER_NODE);
132+ // contexts.push(context);
133+ }
134+
135+ // wait a bit for peers to discover each other
136+ await sleep ( 2000 ) ;
137+
138+ for ( const node of newNodes ) {
139+ const context = await createPXEServiceAndSubmitTransactions ( node , NUM_TXS_PER_NODE ) ;
140+ contexts . push ( context ) ;
141+ }
142+
143+ // now ensure that all txs were successfully mined
144+ await Promise . all (
145+ contexts . flatMap ( ( context , i ) =>
146+ context . txs . map ( async ( tx , j ) => {
147+ logger . info ( `Waiting for tx ${ i } -${ j } : ${ await tx . getTxHash ( ) } to be mined` ) ;
148+ return tx . wait ( ) ;
149+ } ) ,
150+ ) ,
151+ ) ;
152+
153+ // shutdown all nodes.
154+ // for (const context of contexts) {
155+ for ( const context of contexts ) {
156+ await context . node . stop ( ) ;
157+ await context . pxeService . stop ( ) ;
158+ }
159+ } ) ;
160+
73161 const createBootstrapNode = async ( ) => {
74162 const peerId = await createLibP2PPeerId ( ) ;
75163 const bootstrapNode = new BootstrapNode ( ) ;
@@ -87,7 +175,12 @@ describe('e2e_p2p_network', () => {
87175 } ;
88176
89177 // creates a P2P enabled instance of Aztec Node Service
90- const createNode = async ( tcpListenPort : number , bootstrapNode : string , publisherAddressIndex : number ) => {
178+ const createNode = async (
179+ tcpListenPort : number ,
180+ bootstrapNode : string | undefined ,
181+ publisherAddressIndex : number ,
182+ dataDirectory ?: string ,
183+ ) => {
91184 // We use different L1 publisher accounts in order to avoid duplicate tx nonces. We start from
92185 // publisherAddressIndex + 1 because index 0 was already used during test environment setup.
93186 const hdAccount = mnemonicToAccount ( MNEMONIC , { addressIndex : publisherAddressIndex + 1 } ) ;
@@ -96,38 +189,21 @@ describe('e2e_p2p_network', () => {
96189
97190 const newConfig : AztecNodeConfig = {
98191 ...config ,
192+ peerIdPrivateKey : PEER_ID_PRIVATE_KEYS [ publisherAddressIndex ] ,
99193 udpListenAddress : `0.0.0.0:${ tcpListenPort } ` ,
100194 tcpListenAddress : `0.0.0.0:${ tcpListenPort } ` ,
101195 tcpAnnounceAddress : `127.0.0.1:${ tcpListenPort } ` ,
102196 udpAnnounceAddress : `127.0.0.1:${ tcpListenPort } ` ,
103- bootstrapNodes : [ bootstrapNode ] ,
104197 minTxsPerBlock : NUM_TXS_PER_BLOCK ,
105198 maxTxsPerBlock : NUM_TXS_PER_BLOCK ,
106199 p2pEnabled : true ,
107200 p2pBlockCheckIntervalMS : 1000 ,
108201 p2pL2QueueSize : 1 ,
109202 transactionProtocol : '' ,
203+ dataDirectory,
204+ bootstrapNodes : bootstrapNode ? [ bootstrapNode ] : [ ] ,
110205 } ;
111- return await AztecNodeService . createAndSync ( newConfig ) ;
112- } ;
113-
114- // submits a set of transactions to the provided Private eXecution Environment (PXE)
115- const submitTxsTo = async ( pxe : PXEService , account : AztecAddress , numTxs : number ) => {
116- const txs : SentTx [ ] = [ ] ;
117- for ( let i = 0 ; i < numTxs ; i ++ ) {
118- const tx = getSchnorrAccount ( pxe , Fr . random ( ) , GrumpkinScalar . random ( ) , Fr . random ( ) ) . deploy ( ) ;
119- logger . info ( `Tx sent with hash ${ await tx . getTxHash ( ) } ` ) ;
120- const receipt = await tx . getReceipt ( ) ;
121- expect ( receipt ) . toEqual (
122- expect . objectContaining ( {
123- status : TxStatus . PENDING ,
124- error : '' ,
125- } ) ,
126- ) ;
127- logger . info ( `Receipt received for ${ await tx . getTxHash ( ) } ` ) ;
128- txs . push ( tx ) ;
129- }
130- return txs ;
206+ return await AztecNodeService . createAndSync ( newConfig , createDebugLogger ( `aztec:node-${ tcpListenPort } ` ) ) ;
131207 } ;
132208
133209 // creates an instance of the PXE and submit a given number of transactions to it.
@@ -142,12 +218,44 @@ describe('e2e_p2p_network', () => {
142218 const completeAddress = CompleteAddress . fromSecretKeyAndPartialAddress ( secretKey , Fr . random ( ) ) ;
143219 await pxeService . registerAccount ( secretKey , completeAddress . partialAddress ) ;
144220
145- const txs = await submitTxsTo ( pxeService , completeAddress . address , numTxs ) ;
221+ const txs = await submitTxsTo ( pxeService , numTxs ) ;
146222 return {
147223 txs,
148224 account : completeAddress . address ,
149225 pxeService,
150226 node,
151227 } ;
152228 } ;
229+
230+ // submits a set of transactions to the provided Private eXecution Environment (PXE)
231+ const submitTxsTo = async ( pxe : PXEService , numTxs : number ) => {
232+ const txs : SentTx [ ] = [ ] ;
233+ for ( let i = 0 ; i < numTxs ; i ++ ) {
234+ // const tx = getSchnorrAccount(pxe, Fr.random(), GrumpkinScalar.random(), Fr.random()).deploy();
235+ const accountManager = getSchnorrAccount ( pxe , Fr . random ( ) , GrumpkinScalar . random ( ) , Fr . random ( ) ) ;
236+ const deployMethod = await accountManager . getDeployMethod ( ) ;
237+ await deployMethod . create ( {
238+ contractAddressSalt : accountManager . salt ,
239+ skipClassRegistration : true ,
240+ skipPublicDeployment : true ,
241+ universalDeploy : true ,
242+ } ) ;
243+ await deployMethod . prove ( { } ) ;
244+ const tx = deployMethod . send ( ) ;
245+
246+ const txHash = await tx . getTxHash ( ) ;
247+
248+ logger . info ( `Tx sent with hash ${ txHash } ` ) ;
249+ const receipt = await tx . getReceipt ( ) ;
250+ expect ( receipt ) . toEqual (
251+ expect . objectContaining ( {
252+ status : TxStatus . PENDING ,
253+ error : '' ,
254+ } ) ,
255+ ) ;
256+ logger . info ( `Receipt received for ${ txHash } ` ) ;
257+ txs . push ( tx ) ;
258+ }
259+ return txs ;
260+ } ;
153261} ) ;
0 commit comments