-
Notifications
You must be signed in to change notification settings - Fork 31
/
service.go
118 lines (98 loc) · 3.9 KB
/
service.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package enclave
import (
"fmt"
"math/big"
"sync/atomic"
gethlog "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/obscuronet/go-obscuro/go/common"
"github.com/obscuronet/go-obscuro/go/common/errutil"
"github.com/obscuronet/go-obscuro/go/common/host"
"github.com/obscuronet/go-obscuro/go/common/log"
"github.com/obscuronet/go-obscuro/go/responses"
)
// This private interface enforces the services that the enclaves service depends on
type enclaveServiceLocator interface {
P2P() host.P2P
}
// Service is a host service that provides access to the enclave(s) - it handles failover, load balancing, circuit breaking when a host has multiple enclaves
type Service struct {
hostData host.Identity
sl enclaveServiceLocator
// eventually this service will support multiple enclaves for HA, but currently there's only one
// The service goes via the Guardian to talk to the enclave (because guardian knows if the enclave is healthy etc.)
enclaveGuardian *Guardian
running atomic.Bool
logger gethlog.Logger
}
func NewService(hostData host.Identity, serviceLocator enclaveServiceLocator, enclaveGuardian *Guardian, logger gethlog.Logger) *Service {
return &Service{
hostData: hostData,
sl: serviceLocator,
enclaveGuardian: enclaveGuardian,
logger: logger,
}
}
func (e *Service) Start() error {
e.running.Store(true)
return e.enclaveGuardian.Start()
}
func (e *Service) Stop() error {
e.running.Store(false)
return e.enclaveGuardian.Stop()
}
func (e *Service) HealthStatus() host.HealthStatus {
if !e.running.Load() {
return &host.BasicErrHealthStatus{ErrMsg: "not running"}
}
// check the enclave health, which in turn checks the DB health
enclaveHealthy, err := e.enclaveGuardian.enclaveClient.HealthCheck()
if err != nil {
return &host.BasicErrHealthStatus{ErrMsg: fmt.Sprintf("unable to HealthCheck enclave - %s", err.Error())}
} else if !enclaveHealthy {
return &host.BasicErrHealthStatus{ErrMsg: "enclave reported itself as not healthy"}
}
if !e.enclaveGuardian.GetEnclaveState().InSyncWithL1() {
return &host.BasicErrHealthStatus{ErrMsg: "enclave not in sync with L1"}
}
// empty error msg means healthy
return &host.BasicErrHealthStatus{ErrMsg: ""}
}
// LookupBatchBySeqNo is used to fetch batch data from the enclave - it is only used as a fallback for the sequencer
// host if it's missing a batch (other host services should use L2Repo to fetch batch data)
func (e *Service) LookupBatchBySeqNo(seqNo *big.Int) (*common.ExtBatch, error) {
state := e.enclaveGuardian.GetEnclaveState()
if state.GetEnclaveL2Head().Cmp(seqNo) < 0 {
return nil, errutil.ErrNotFound
}
client := e.enclaveGuardian.GetEnclaveClient()
return client.GetBatchBySeqNo(seqNo.Uint64())
}
func (e *Service) GetEnclaveClient() common.Enclave {
return e.enclaveGuardian.GetEnclaveClient()
}
func (e *Service) SubmitAndBroadcastTx(encryptedParams common.EncryptedParamsSendRawTx) (*responses.RawTx, error) {
encryptedTx := common.EncryptedTx(encryptedParams)
enclaveResponse, sysError := e.enclaveGuardian.GetEnclaveClient().SubmitTx(encryptedTx)
if sysError != nil {
e.logger.Warn("Could not submit transaction due to sysError.", log.ErrKey, sysError)
return nil, sysError
}
if enclaveResponse.Error() != nil {
e.logger.Trace("Could not submit transaction.", log.ErrKey, enclaveResponse.Error())
return enclaveResponse, nil //nolint: nilerr
}
if !e.hostData.IsSequencer {
err := e.sl.P2P().SendTxToSequencer(encryptedTx)
if err != nil {
return nil, fmt.Errorf("could not broadcast transaction to sequencer. Cause: %w", err)
}
}
return enclaveResponse, nil
}
func (e *Service) Subscribe(id rpc.ID, encryptedParams common.EncryptedParamsLogSubscription) error {
return e.enclaveGuardian.GetEnclaveClient().Subscribe(id, encryptedParams)
}
func (e *Service) Unsubscribe(id rpc.ID) error {
return e.enclaveGuardian.GetEnclaveClient().Unsubscribe(id)
}