@@ -39,23 +39,31 @@ function getEncryptedAttester(keystore: KeyStore) {
3939describe ( 'validator keys utilities' , ( ) => {
4040 let tmp : string ;
4141 let feeRecipient : AztecAddress ;
42- let originalKeystorePassword : string | undefined ;
42+ let originalKeystorePasswords : Record < string , string | undefined > ;
4343
4444 beforeAll ( async ( ) => {
4545 feeRecipient = await AztecAddress . random ( ) ;
4646 tmp = mkdtempSync ( join ( tmpdir ( ) , 'aztec-valkeys-' ) ) ;
4747 } ) ;
4848
4949 beforeEach ( ( ) => {
50- originalKeystorePassword = process . env . AZTEC_KEYSTORE_PASSWORD ;
50+ originalKeystorePasswords = {
51+ AZTEC_KEYSTORE_PASSWORD : process . env . AZTEC_KEYSTORE_PASSWORD ,
52+ AZTEC_ETH_KEYSTORE_PASSWORD : process . env . AZTEC_ETH_KEYSTORE_PASSWORD ,
53+ AZTEC_BLS_KEYSTORE_PASSWORD : process . env . AZTEC_BLS_KEYSTORE_PASSWORD ,
54+ } ;
5155 delete process . env . AZTEC_KEYSTORE_PASSWORD ;
56+ delete process . env . AZTEC_ETH_KEYSTORE_PASSWORD ;
57+ delete process . env . AZTEC_BLS_KEYSTORE_PASSWORD ;
5258 } ) ;
5359
5460 afterEach ( ( ) => {
55- if ( originalKeystorePassword === undefined ) {
56- delete process . env . AZTEC_KEYSTORE_PASSWORD ;
57- } else {
58- process . env . AZTEC_KEYSTORE_PASSWORD = originalKeystorePassword ;
61+ for ( const [ key , value ] of Object . entries ( originalKeystorePasswords ) ) {
62+ if ( value === undefined ) {
63+ delete process . env [ key ] ;
64+ } else {
65+ process . env [ key ] = value ;
66+ }
5967 }
6068 } ) ;
6169
@@ -593,6 +601,142 @@ describe('validator keys utilities', () => {
593601 ) . rejects . toThrow ( / - - p a s s w o r d a n d - - p a s s w o r d - f i l e c a n n o t b e u s e d t o g e t h e r / ) ;
594602 } ) ;
595603
604+ it ( 'writes ETH and BLS keystores with different passwords' , async ( ) => {
605+ const path = join ( tmp , 'separate-passwords.json' ) ;
606+ const ethPassword = 'eth-password-123' ;
607+ const blsPassword = 'bls-password-123' ;
608+ const logs : string [ ] = [ ] ;
609+ const log = ( s : string ) => logs . push ( s ) ;
610+
611+ await newValidatorKeystore (
612+ {
613+ dataDir : tmp ,
614+ file : 'separate-passwords.json' ,
615+ count : 1 ,
616+ mnemonic : TEST_MNEMONIC ,
617+ ethPassword,
618+ blsPassword,
619+ encryptedKeystoreDir : tmp ,
620+ feeRecipient : ( '0x' + '07' . repeat ( 32 ) ) as unknown as AztecAddress ,
621+ } ,
622+ log ,
623+ ) ;
624+
625+ const att = getEncryptedAttester ( loadKeystoreFile ( path ) ) ;
626+ expect ( att . eth . password ) . toBe ( ethPassword ) ;
627+ expect ( att . bls . password ) . toBe ( blsPassword ) ;
628+ } ) ;
629+
630+ it ( 'uses role-specific passwords over the shared password' , async ( ) => {
631+ const path = join ( tmp , 'shared-with-bls-override.json' ) ;
632+ const sharedPassword = 'shared-password-123' ;
633+ const blsPassword = 'bls-password-override' ;
634+ const logs : string [ ] = [ ] ;
635+ const log = ( s : string ) => logs . push ( s ) ;
636+
637+ await newValidatorKeystore (
638+ {
639+ dataDir : tmp ,
640+ file : 'shared-with-bls-override.json' ,
641+ count : 1 ,
642+ mnemonic : TEST_MNEMONIC ,
643+ password : sharedPassword ,
644+ blsPassword,
645+ encryptedKeystoreDir : tmp ,
646+ feeRecipient : ( '0x' + '07' . repeat ( 32 ) ) as unknown as AztecAddress ,
647+ } ,
648+ log ,
649+ ) ;
650+
651+ const att = getEncryptedAttester ( loadKeystoreFile ( path ) ) ;
652+ expect ( att . eth . password ) . toBe ( sharedPassword ) ;
653+ expect ( att . bls . password ) . toBe ( blsPassword ) ;
654+ } ) ;
655+
656+ it ( 'reads ETH and BLS passwords from role-specific environment variables through command options' , async ( ) => {
657+ const path = join ( tmp , 'role-env-passwords.json' ) ;
658+ const ethPassword = 'eth-env-password-123' ;
659+ const blsPassword = 'bls-env-password-123' ;
660+ process . env . AZTEC_ETH_KEYSTORE_PASSWORD = ethPassword ;
661+ process . env . AZTEC_BLS_KEYSTORE_PASSWORD = blsPassword ;
662+ const logs : string [ ] = [ ] ;
663+ const log = ( s : string ) => logs . push ( s ) ;
664+ const program = new Command ( ) ;
665+ program . exitOverride ( ) ;
666+ program
667+ . command ( 'new' )
668+ . addOption ( new Option ( '--eth-password <str>' ) . env ( 'AZTEC_ETH_KEYSTORE_PASSWORD' ) )
669+ . addOption ( new Option ( '--bls-password <str>' ) . env ( 'AZTEC_BLS_KEYSTORE_PASSWORD' ) )
670+ . option ( '--data-dir <path>' )
671+ . option ( '--file <name>' )
672+ . option ( '--mnemonic <mnemonic>' )
673+ . option ( '--encrypted-keystore-dir <dir>' )
674+ . action ( async options => {
675+ await newValidatorKeystore ( { ...options , feeRecipient } , log ) ;
676+ } ) ;
677+
678+ await program . parseAsync (
679+ [
680+ 'new' ,
681+ '--data-dir' ,
682+ tmp ,
683+ '--file' ,
684+ 'role-env-passwords.json' ,
685+ '--mnemonic' ,
686+ TEST_MNEMONIC ,
687+ '--encrypted-keystore-dir' ,
688+ tmp ,
689+ ] ,
690+ { from : 'user' } ,
691+ ) ;
692+
693+ const att = getEncryptedAttester ( loadKeystoreFile ( path ) ) ;
694+ expect ( att . eth . password ) . toBe ( ethPassword ) ;
695+ expect ( att . bls . password ) . toBe ( blsPassword ) ;
696+ } ) ;
697+
698+ it ( 'rejects role-specific password sources without a password for the other role' , async ( ) => {
699+ const logs : string [ ] = [ ] ;
700+ const log = ( s : string ) => logs . push ( s ) ;
701+
702+ await expect (
703+ newValidatorKeystore (
704+ {
705+ dataDir : tmp ,
706+ file : 'only-eth-password.json' ,
707+ count : 1 ,
708+ mnemonic : TEST_MNEMONIC ,
709+ ethPassword : 'eth-password-123' ,
710+ feeRecipient : ( '0x' + '07' . repeat ( 32 ) ) as unknown as AztecAddress ,
711+ } ,
712+ log ,
713+ ) ,
714+ ) . rejects . toThrow ( / B o t h E T H a n d B L S p a s s w o r d s a r e r e q u i r e d / ) ;
715+ } ) ;
716+
717+ it ( 'rejects conflicting role-specific password sources' , async ( ) => {
718+ const ethPasswordFile = join ( tmp , 'conflicting-eth-password.txt' ) ;
719+ writeFileSync ( ethPasswordFile , 'eth-file-password' , 'utf-8' ) ;
720+ const logs : string [ ] = [ ] ;
721+ const log = ( s : string ) => logs . push ( s ) ;
722+
723+ await expect (
724+ newValidatorKeystore (
725+ {
726+ dataDir : tmp ,
727+ file : 'conflicting-eth-password-source.json' ,
728+ count : 1 ,
729+ mnemonic : TEST_MNEMONIC ,
730+ ethPassword : 'eth-password-123' ,
731+ ethPasswordFile,
732+ blsPassword : 'bls-password-123' ,
733+ feeRecipient : ( '0x' + '07' . repeat ( 32 ) ) as unknown as AztecAddress ,
734+ } ,
735+ log ,
736+ ) ,
737+ ) . rejects . toThrow ( / - - e t h - p a s s w o r d a n d - - e t h - p a s s w o r d - f i l e c a n n o t b e u s e d t o g e t h e r / ) ;
738+ } ) ;
739+
596740 it ( 'does not output a generated mnemonic when writing encrypted keystores' , async ( ) => {
597741 const logs : string [ ] = [ ] ;
598742 const log = ( s : string ) => logs . push ( s ) ;
0 commit comments