@@ -23,73 +23,104 @@ type enclaveServiceLocator interface {
23
23
type Service struct {
24
24
hostData host.Identity
25
25
sl enclaveServiceLocator
26
- // eventually this service will support multiple enclaves for HA, but currently there's only one
27
- // The service goes via the Guardian to talk to the enclave (because guardian knows if the enclave is healthy etc.)
28
- enclaveGuardian * Guardian
26
+
27
+ // The service goes via the Guardians to talk to the enclave (because guardian knows if the enclave is healthy etc.)
28
+ enclaveGuardians [] * Guardian
29
29
30
30
running atomic.Bool
31
31
logger gethlog.Logger
32
32
}
33
33
34
- func NewService (hostData host.Identity , serviceLocator enclaveServiceLocator , enclaveGuardian * Guardian , logger gethlog.Logger ) * Service {
34
+ func NewService (hostData host.Identity , serviceLocator enclaveServiceLocator , enclaveGuardians [] * Guardian , logger gethlog.Logger ) * Service {
35
35
return & Service {
36
- hostData : hostData ,
37
- sl : serviceLocator ,
38
- enclaveGuardian : enclaveGuardian ,
39
- logger : logger ,
36
+ hostData : hostData ,
37
+ sl : serviceLocator ,
38
+ enclaveGuardians : enclaveGuardians ,
39
+ logger : logger ,
40
40
}
41
41
}
42
42
43
43
func (e * Service ) Start () error {
44
44
e .running .Store (true )
45
- return e .enclaveGuardian .Start ()
45
+ for _ , guardian := range e .enclaveGuardians {
46
+ if err := guardian .Start (); err != nil {
47
+ // abandon starting the rest of the guardians if one fails
48
+ return err
49
+ }
50
+ }
51
+ return nil
46
52
}
47
53
48
54
func (e * Service ) Stop () error {
49
55
e .running .Store (false )
50
- return e .enclaveGuardian .Stop ()
56
+ var errors []error
57
+ for i , guardian := range e .enclaveGuardians {
58
+ if err := guardian .Stop (); err != nil {
59
+ errors = append (errors , fmt .Errorf ("error stopping enclave guardian [%d]: %w" , i , err ))
60
+ }
61
+ }
62
+ if len (errors ) > 0 {
63
+ return fmt .Errorf ("errors stopping enclave guardians: %v" , errors )
64
+ }
65
+ return nil
51
66
}
52
67
53
68
func (e * Service ) HealthStatus () host.HealthStatus {
54
69
if ! e .running .Load () {
55
70
return & host.BasicErrHealthStatus {ErrMsg : "not running" }
56
71
}
57
72
58
- // check the enclave health, which in turn checks the DB health
59
- enclaveHealthy , err := e .enclaveGuardian .enclaveClient .HealthCheck ()
60
- if err != nil {
61
- return & host.BasicErrHealthStatus {ErrMsg : fmt .Sprintf ("unable to HealthCheck enclave - %s" , err .Error ())}
62
- } else if ! enclaveHealthy {
63
- return & host.BasicErrHealthStatus {ErrMsg : "enclave reported itself as not healthy" }
64
- }
73
+ errors := make ([]error , 0 , len (e .enclaveGuardians ))
65
74
66
- if ! e .enclaveGuardian .GetEnclaveState ().InSyncWithL1 () {
67
- return & host.BasicErrHealthStatus {ErrMsg : "enclave not in sync with L1" }
75
+ for i , guardian := range e .enclaveGuardians {
76
+ // check the enclave health, which in turn checks the DB health
77
+ enclaveHealthy , err := guardian .enclaveClient .HealthCheck ()
78
+ if err != nil {
79
+ errors = append (errors , fmt .Errorf ("unable to HealthCheck enclave[%d] - %w" , i , err ))
80
+ } else if ! enclaveHealthy {
81
+ errors = append (errors , fmt .Errorf ("enclave[%d] reported itself not healthy" , i ))
82
+ }
83
+
84
+ if ! guardian .GetEnclaveState ().InSyncWithL1 () {
85
+ errors = append (errors , fmt .Errorf ("enclave[%d] not in sync with L1" , i ))
86
+ }
68
87
}
69
88
70
89
// empty error msg means healthy
71
- return & host.BasicErrHealthStatus {ErrMsg : "" }
90
+ return & host.GroupErrsHealthStatus {Errors : errors }
91
+ }
92
+
93
+ func (e * Service ) HealthyGuardian () * Guardian {
94
+ for _ , guardian := range e .enclaveGuardians {
95
+ if guardian .HealthStatus ().OK () {
96
+ return guardian
97
+ }
98
+ }
99
+ return nil
72
100
}
73
101
74
102
// LookupBatchBySeqNo is used to fetch batch data from the enclave - it is only used as a fallback for the sequencer
75
103
// host if it's missing a batch (other host services should use L2Repo to fetch batch data)
76
104
func (e * Service ) LookupBatchBySeqNo (seqNo * big.Int ) (* common.ExtBatch , error ) {
77
- state := e .enclaveGuardian .GetEnclaveState ()
105
+ hg := e .HealthyGuardian ()
106
+ state := hg .GetEnclaveState ()
78
107
if state .GetEnclaveL2Head ().Cmp (seqNo ) < 0 {
79
108
return nil , errutil .ErrNotFound
80
109
}
81
- client := e . enclaveGuardian .GetEnclaveClient ()
110
+ client := hg .GetEnclaveClient ()
82
111
return client .GetBatchBySeqNo (seqNo .Uint64 ())
83
112
}
84
113
85
114
func (e * Service ) GetEnclaveClient () common.Enclave {
86
- return e .enclaveGuardian .GetEnclaveClient ()
115
+ // for now we always return first guardian's enclave client
116
+ // in future be good to load balance and failover but need to improve subscribe/unsubscribe (unsubscribe from same enclave)
117
+ return e .enclaveGuardians [0 ].GetEnclaveClient ()
87
118
}
88
119
89
120
func (e * Service ) SubmitAndBroadcastTx (encryptedParams common.EncryptedParamsSendRawTx ) (* responses.RawTx , error ) {
90
121
encryptedTx := common .EncryptedTx (encryptedParams )
91
122
92
- enclaveResponse , sysError := e .enclaveGuardian . GetEnclaveClient ().SubmitTx (encryptedTx )
123
+ enclaveResponse , sysError := e .GetEnclaveClient ().SubmitTx (encryptedTx )
93
124
if sysError != nil {
94
125
e .logger .Warn ("Could not submit transaction due to sysError." , log .ErrKey , sysError )
95
126
return nil , sysError
@@ -110,9 +141,9 @@ func (e *Service) SubmitAndBroadcastTx(encryptedParams common.EncryptedParamsSen
110
141
}
111
142
112
143
func (e * Service ) Subscribe (id rpc.ID , encryptedParams common.EncryptedParamsLogSubscription ) error {
113
- return e .enclaveGuardian . GetEnclaveClient ().Subscribe (id , encryptedParams )
144
+ return e .GetEnclaveClient ().Subscribe (id , encryptedParams )
114
145
}
115
146
116
147
func (e * Service ) Unsubscribe (id rpc.ID ) error {
117
- return e .enclaveGuardian . GetEnclaveClient ().Unsubscribe (id )
148
+ return e .GetEnclaveClient ().Unsubscribe (id )
118
149
}
0 commit comments