-
Notifications
You must be signed in to change notification settings - Fork 39
/
walletextension_container.go
186 lines (159 loc) · 5.42 KB
/
walletextension_container.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package walletextension
import (
"crypto/tls"
"net/http"
"os"
"time"
"github.com/ten-protocol/go-ten/tools/walletextension/services"
"github.com/ten-protocol/go-ten/go/common/subscription"
"github.com/ten-protocol/go-ten/tools/walletextension/httpapi"
"github.com/ten-protocol/go-ten/tools/walletextension/rpcapi"
"github.com/ten-protocol/go-ten/lib/gethfork/node"
gethlog "github.com/ethereum/go-ethereum/log"
"github.com/ten-protocol/go-ten/go/common/log"
"github.com/ten-protocol/go-ten/go/common/stopcontrol"
gethrpc "github.com/ten-protocol/go-ten/lib/gethfork/rpc"
wecommon "github.com/ten-protocol/go-ten/tools/walletextension/common"
"github.com/ten-protocol/go-ten/tools/walletextension/keymanager"
"github.com/ten-protocol/go-ten/tools/walletextension/storage"
"golang.org/x/crypto/acme/autocert"
)
type Container struct {
stopControl *stopcontrol.StopControl
logger gethlog.Logger
rpcServer node.Server
services *services.Services
newHeadsService *subscription.NewHeadsService
}
func NewContainerFromConfig(config wecommon.Config, logger gethlog.Logger) *Container {
// create the account manager with a single unauthenticated connection
hostRPCBindAddrWS := wecommon.WSProtocol + config.NodeRPCWebsocketAddress
hostRPCBindAddrHTTP := wecommon.HTTPProtocol + config.NodeRPCHTTPAddress
// get the encryption key (method is determined by the config)
encryptionKey, err := keymanager.GetEncryptionKey(config, logger)
if err != nil {
logger.Crit("unable to get encryption key", log.ErrKey, err)
os.Exit(1)
}
// start the database with the encryption key
userStorage, err := storage.New(config.DBType, config.DBConnectionURL, config.DBPathOverride, encryptionKey, logger)
if err != nil {
logger.Crit("unable to create database to store viewing keys ", log.ErrKey, err)
os.Exit(1)
}
// captures version in the env vars
version := os.Getenv("OBSCURO_GATEWAY_VERSION")
if version == "" {
version = "dev"
}
stopControl := stopcontrol.New()
walletExt := services.NewServices(hostRPCBindAddrHTTP, hostRPCBindAddrWS, userStorage, stopControl, version, logger, &config)
cfg := &node.RPCConfig{
EnableHTTP: true,
HTTPPort: config.WalletExtensionPortHTTP,
EnableWs: true,
WsPort: config.WalletExtensionPortWS,
WsPath: wecommon.APIVersion1 + "/",
HTTPPath: wecommon.APIVersion1 + "/",
Host: config.WalletExtensionHost,
}
// check if TLS is enabled
if config.EnableTLS {
// Create autocert manager for automatic certificate management
// Generating a certificate consists of the following steps:
// generating a new private key
// domain ownership verification (HTTP-01 challenge since certManager.HTTPHandler(nil) is set)
// Certificate Signing Request (CRS) is generated
// CRS is sent to CA (Let's Encrypt) via ACME (automated certificate management environment) client
// CA verifies CRS and issues a certificate
// Store certificate and private key in certificate storage based on the database type
certStorage, err := storage.NewCertStorage(config.DBType, config.DBConnectionURL, encryptionKey, logger)
if err != nil {
logger.Crit("unable to create certificate storage", log.ErrKey, err)
os.Exit(1)
}
certManager := &autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist(config.TLSDomain),
Cache: certStorage,
}
// Create HTTP-01 challenge handler
httpServer := &http.Server{
Addr: ":http", // Port 80
Handler: certManager.HTTPHandler(nil),
}
go httpServer.ListenAndServe() // Start HTTP server for ACME challenges
tlsConfig := &tls.Config{
GetCertificate: certManager.GetCertificate,
MinVersion: tls.VersionTLS12,
}
// Update RPC server config to use TLS
cfg.TLSConfig = tlsConfig
}
rpcServer := node.NewServer(cfg, logger)
rpcServer.RegisterRoutes(httpapi.NewHTTPRoutes(walletExt))
// register all RPC endpoints exposed by a typical Geth node
rpcServer.RegisterAPIs([]gethrpc.API{
{
Namespace: "eth",
Service: rpcapi.NewEthereumAPI(walletExt),
}, {
Namespace: "eth",
Service: rpcapi.NewBlockChainAPI(walletExt),
}, {
Namespace: "eth",
Service: rpcapi.NewTransactionAPI(walletExt),
}, {
Namespace: "txpool",
Service: rpcapi.NewTxPoolAPI(walletExt),
}, {
Namespace: "debug",
Service: rpcapi.NewDebugAPI(walletExt),
}, {
Namespace: "sessionkeys",
Service: rpcapi.NewSessionKeyAPI(walletExt),
}, {
Namespace: "eth",
Service: rpcapi.NewFilterAPI(walletExt),
}, {
Namespace: "net",
Service: rpcapi.NewNetAPI(walletExt),
}, {
Namespace: "web3",
Service: rpcapi.NewWeb3API(walletExt),
},
})
return &Container{
stopControl: stopControl,
rpcServer: rpcServer,
newHeadsService: walletExt.NewHeadsService,
services: walletExt,
logger: logger,
}
}
// Start starts the wallet extension container
func (w *Container) Start() error {
err := w.newHeadsService.Start()
if err != nil {
return err
}
err = w.rpcServer.Start()
if err != nil {
return err
}
return nil
}
func (w *Container) Stop() error {
w.stopControl.Stop()
_ = w.newHeadsService.Stop()
if w.rpcServer != nil {
// rpc server cannot be stopped synchronously as it will kill current request
go func() {
// make sure it's not killing the connection before returning the response
time.Sleep(time.Second) // todo review this sleep
w.rpcServer.Stop()
}()
}
w.services.Stop()
return nil
}