@@ -5,7 +5,7 @@ import type { Signature } from '@aztec/foundation/eth-signature';
55import type { EthRemoteSignerConfig } from '@aztec/node-keystore' ;
66import type { AztecAddress } from '@aztec/stdlib/aztec-address' ;
77import { DutyAlreadySignedError , SlashingProtectionError } from '@aztec/validator-ha-signer/errors' ;
8- import { DutyType , type SigningContext } from '@aztec/validator-ha-signer/types' ;
8+ import { DutyType , type SigningContext , isHAProtectedContext } from '@aztec/validator-ha-signer/types' ;
99import type { ValidatorHASigner } from '@aztec/validator-ha-signer/validator-ha-signer' ;
1010
1111import { beforeEach , describe , expect , it , jest } from '@jest/globals' ;
@@ -89,9 +89,8 @@ describe('HAKeyStore', () => {
8989 mockHASigner . signWithProtection . mockResolvedValue ( mockSignature ) ;
9090 } ) ;
9191
92- describe ( 'ValidatorKeyStore interface delegation (AUTH_REQUEST bypasses HA)' , ( ) => {
92+ describe ( 'ValidatorKeyStore interface delegation (non-HA duties bypass HA)' , ( ) => {
9393 let haKeyStore : HAKeyStore ;
94- const authRequestContext : SigningContext = { dutyType : DutyType . AUTH_REQUEST } ;
9594
9695 beforeEach ( ( ) => {
9796 haKeyStore = new HAKeyStore ( mockBaseKeyStore , mockHASigner ) ;
@@ -109,40 +108,84 @@ describe('HAKeyStore', () => {
109108 expect ( mockBaseKeyStore . getAddresses ) . toHaveBeenCalled ( ) ;
110109 } ) ;
111110
112- it ( 'should delegate signTypedData to base key store for AUTH_REQUEST (bypasses HA)' , async ( ) => {
113- const result = await haKeyStore . signTypedData ( mockTypedData , authRequestContext ) ;
114- expect ( result ) . toEqual ( [ mockSignature ] ) ;
115- expect ( mockBaseKeyStore . signTypedData ) . toHaveBeenCalledWith ( mockTypedData , authRequestContext ) ;
116- expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
117- } ) ;
111+ describe ( 'AUTH_REQUEST duties bypass HA' , ( ) => {
112+ const authRequestContext : SigningContext = { dutyType : DutyType . AUTH_REQUEST } ;
118113
119- it ( 'should delegate signMessage to base key store for AUTH_REQUEST (bypasses HA) ' , async ( ) => {
120- const result = await haKeyStore . signMessage ( SIGNING_ROOT , authRequestContext ) ;
121- expect ( result ) . toEqual ( [ mockSignature ] ) ;
122- expect ( mockBaseKeyStore . signMessage ) . toHaveBeenCalledWith ( SIGNING_ROOT , authRequestContext ) ;
123- expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
124- } ) ;
114+ it ( 'should delegate signTypedData to base key store for AUTH_REQUEST' , async ( ) => {
115+ const result = await haKeyStore . signTypedData ( mockTypedData , authRequestContext ) ;
116+ expect ( result ) . toEqual ( [ mockSignature ] ) ;
117+ expect ( mockBaseKeyStore . signTypedData ) . toHaveBeenCalledWith ( mockTypedData , authRequestContext ) ;
118+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
119+ } ) ;
125120
126- it ( 'should delegate signTypedDataWithAddress without HA for AUTH_REQUEST' , async ( ) => {
127- const result = await haKeyStore . signTypedDataWithAddress ( VALIDATOR_ADDRESS , mockTypedData , authRequestContext ) ;
128- expect ( result ) . toBe ( mockSignature ) ;
129- expect ( mockBaseKeyStore . signTypedDataWithAddress ) . toHaveBeenCalledWith (
130- VALIDATOR_ADDRESS ,
131- mockTypedData ,
132- authRequestContext ,
133- ) ;
134- expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
121+ it ( 'should delegate signMessage to base key store for AUTH_REQUEST' , async ( ) => {
122+ const result = await haKeyStore . signMessage ( SIGNING_ROOT , authRequestContext ) ;
123+ expect ( result ) . toEqual ( [ mockSignature ] ) ;
124+ expect ( mockBaseKeyStore . signMessage ) . toHaveBeenCalledWith ( SIGNING_ROOT , authRequestContext ) ;
125+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
126+ } ) ;
127+
128+ it ( 'should delegate signTypedDataWithAddress without HA for AUTH_REQUEST' , async ( ) => {
129+ const result = await haKeyStore . signTypedDataWithAddress ( VALIDATOR_ADDRESS , mockTypedData , authRequestContext ) ;
130+ expect ( result ) . toBe ( mockSignature ) ;
131+ expect ( mockBaseKeyStore . signTypedDataWithAddress ) . toHaveBeenCalledWith (
132+ VALIDATOR_ADDRESS ,
133+ mockTypedData ,
134+ authRequestContext ,
135+ ) ;
136+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
137+ } ) ;
138+
139+ it ( 'should delegate signMessageWithAddress without HA for AUTH_REQUEST' , async ( ) => {
140+ const result = await haKeyStore . signMessageWithAddress ( VALIDATOR_ADDRESS , SIGNING_ROOT , authRequestContext ) ;
141+ expect ( result ) . toBe ( mockSignature ) ;
142+ expect ( mockBaseKeyStore . signMessageWithAddress ) . toHaveBeenCalledWith (
143+ VALIDATOR_ADDRESS ,
144+ SIGNING_ROOT ,
145+ authRequestContext ,
146+ ) ;
147+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
148+ } ) ;
135149 } ) ;
136150
137- it ( 'should delegate signMessageWithAddress without HA for AUTH_REQUEST' , async ( ) => {
138- const result = await haKeyStore . signMessageWithAddress ( VALIDATOR_ADDRESS , SIGNING_ROOT , authRequestContext ) ;
139- expect ( result ) . toBe ( mockSignature ) ;
140- expect ( mockBaseKeyStore . signMessageWithAddress ) . toHaveBeenCalledWith (
141- VALIDATOR_ADDRESS ,
142- SIGNING_ROOT ,
143- authRequestContext ,
144- ) ;
145- expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
151+ describe ( 'TXS duties bypass HA' , ( ) => {
152+ const txsContext : SigningContext = { dutyType : DutyType . TXS } ;
153+
154+ it ( 'should delegate signTypedData to base key store for TXS' , async ( ) => {
155+ const result = await haKeyStore . signTypedData ( mockTypedData , txsContext ) ;
156+ expect ( result ) . toEqual ( [ mockSignature ] ) ;
157+ expect ( mockBaseKeyStore . signTypedData ) . toHaveBeenCalledWith ( mockTypedData , txsContext ) ;
158+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
159+ } ) ;
160+
161+ it ( 'should delegate signMessage to base key store for TXS' , async ( ) => {
162+ const result = await haKeyStore . signMessage ( SIGNING_ROOT , txsContext ) ;
163+ expect ( result ) . toEqual ( [ mockSignature ] ) ;
164+ expect ( mockBaseKeyStore . signMessage ) . toHaveBeenCalledWith ( SIGNING_ROOT , txsContext ) ;
165+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
166+ } ) ;
167+
168+ it ( 'should delegate signTypedDataWithAddress without HA for TXS' , async ( ) => {
169+ const result = await haKeyStore . signTypedDataWithAddress ( VALIDATOR_ADDRESS , mockTypedData , txsContext ) ;
170+ expect ( result ) . toBe ( mockSignature ) ;
171+ expect ( mockBaseKeyStore . signTypedDataWithAddress ) . toHaveBeenCalledWith (
172+ VALIDATOR_ADDRESS ,
173+ mockTypedData ,
174+ txsContext ,
175+ ) ;
176+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
177+ } ) ;
178+
179+ it ( 'should delegate signMessageWithAddress without HA for TXS' , async ( ) => {
180+ const result = await haKeyStore . signMessageWithAddress ( VALIDATOR_ADDRESS , SIGNING_ROOT , txsContext ) ;
181+ expect ( result ) . toBe ( mockSignature ) ;
182+ expect ( mockBaseKeyStore . signMessageWithAddress ) . toHaveBeenCalledWith (
183+ VALIDATOR_ADDRESS ,
184+ SIGNING_ROOT ,
185+ txsContext ,
186+ ) ;
187+ expect ( mockHASigner . signWithProtection ) . not . toHaveBeenCalled ( ) ;
188+ } ) ;
146189 } ) ;
147190 } ) ;
148191
@@ -331,4 +374,69 @@ describe('HAKeyStore', () => {
331374 expect ( mockHASigner . stop ) . toHaveBeenCalledTimes ( 1 ) ;
332375 } ) ;
333376 } ) ;
377+
378+ describe ( 'isHAProtectedContext type guard' , ( ) => {
379+ it ( 'should return false for AUTH_REQUEST' , ( ) => {
380+ const context : SigningContext = { dutyType : DutyType . AUTH_REQUEST } ;
381+ expect ( isHAProtectedContext ( context ) ) . toBe ( false ) ;
382+ } ) ;
383+
384+ it ( 'should return false for TXS' , ( ) => {
385+ const context : SigningContext = { dutyType : DutyType . TXS } ;
386+ expect ( isHAProtectedContext ( context ) ) . toBe ( false ) ;
387+ } ) ;
388+
389+ it ( 'should return true for BLOCK_PROPOSAL' , ( ) => {
390+ const context : SigningContext = {
391+ slot : SlotNumber ( 100 ) ,
392+ blockNumber : BlockNumber ( 50 ) ,
393+ dutyType : DutyType . BLOCK_PROPOSAL ,
394+ blockIndexWithinCheckpoint : 0 ,
395+ } ;
396+ expect ( isHAProtectedContext ( context ) ) . toBe ( true ) ;
397+ } ) ;
398+
399+ it ( 'should return true for ATTESTATION' , ( ) => {
400+ const context : SigningContext = {
401+ slot : SlotNumber ( 100 ) ,
402+ blockNumber : BlockNumber ( 50 ) ,
403+ dutyType : DutyType . ATTESTATION ,
404+ } ;
405+ expect ( isHAProtectedContext ( context ) ) . toBe ( true ) ;
406+ } ) ;
407+
408+ it ( 'should return true for CHECKPOINT_PROPOSAL' , ( ) => {
409+ const context : SigningContext = {
410+ slot : SlotNumber ( 100 ) ,
411+ blockNumber : BlockNumber ( 50 ) ,
412+ dutyType : DutyType . CHECKPOINT_PROPOSAL ,
413+ } ;
414+ expect ( isHAProtectedContext ( context ) ) . toBe ( true ) ;
415+ } ) ;
416+
417+ it ( 'should return true for ATTESTATIONS_AND_SIGNERS' , ( ) => {
418+ const context : SigningContext = {
419+ slot : SlotNumber ( 100 ) ,
420+ blockNumber : BlockNumber ( 50 ) ,
421+ dutyType : DutyType . ATTESTATIONS_AND_SIGNERS ,
422+ } ;
423+ expect ( isHAProtectedContext ( context ) ) . toBe ( true ) ;
424+ } ) ;
425+
426+ it ( 'should return true for GOVERNANCE_VOTE' , ( ) => {
427+ const context : SigningContext = {
428+ slot : SlotNumber ( 100 ) ,
429+ dutyType : DutyType . GOVERNANCE_VOTE ,
430+ } ;
431+ expect ( isHAProtectedContext ( context ) ) . toBe ( true ) ;
432+ } ) ;
433+
434+ it ( 'should return true for SLASHING_VOTE' , ( ) => {
435+ const context : SigningContext = {
436+ slot : SlotNumber ( 100 ) ,
437+ dutyType : DutyType . SLASHING_VOTE ,
438+ } ;
439+ expect ( isHAProtectedContext ( context ) ) . toBe ( true ) ;
440+ } ) ;
441+ } ) ;
334442} ) ;
0 commit comments