github.com/eris-ltd/erisdb@v0.25.0/core/processes.go (about) 1 package core 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "time" 8 9 "github.com/hyperledger/burrow/bcm" 10 11 "github.com/hyperledger/burrow/execution" 12 13 "github.com/hyperledger/burrow/consensus/abci" 14 15 "github.com/hyperledger/burrow/keys" 16 "github.com/hyperledger/burrow/logging/structure" 17 "github.com/hyperledger/burrow/process" 18 "github.com/hyperledger/burrow/project" 19 "github.com/hyperledger/burrow/rpc" 20 "github.com/hyperledger/burrow/rpc/metrics" 21 "github.com/hyperledger/burrow/rpc/rpcdump" 22 "github.com/hyperledger/burrow/rpc/rpcevents" 23 "github.com/hyperledger/burrow/rpc/rpcinfo" 24 "github.com/hyperledger/burrow/rpc/rpcquery" 25 "github.com/hyperledger/burrow/rpc/rpctransact" 26 "github.com/hyperledger/burrow/txs" 27 "github.com/tendermint/tendermint/version" 28 "github.com/tmthrgd/go-hex" 29 ) 30 31 const ( 32 ProfilingProcessName = "Profiling" 33 DatabaseProcessName = "Database" 34 NoConsensusProcessName = "NoConsensusExecution" 35 TendermintProcessName = "Tendermint" 36 StartupProcessName = "StartupAnnouncer" 37 InfoProcessName = "rpcConfig/info" 38 GRPCProcessName = "rpcConfig/GRPC" 39 MetricsProcessName = "rpcConfig/metrics" 40 ) 41 42 func DefaultProcessLaunchers(kern *Kernel, rpcConfig *rpc.RPCConfig, keysConfig *keys.KeysConfig) []process.Launcher { 43 // Run announcer after Tendermint so it can get some details 44 return []process.Launcher{ 45 ProfileLauncher(kern, rpcConfig.Profiler), 46 DatabaseLauncher(kern), 47 NoConsensusLauncher(kern), 48 TendermintLauncher(kern), 49 StartupLauncher(kern), 50 InfoLauncher(kern, rpcConfig.Info), 51 MetricsLauncher(kern, rpcConfig.Metrics), 52 GRPCLauncher(kern, rpcConfig.GRPC, keysConfig), 53 } 54 } 55 56 func ProfileLauncher(kern *Kernel, conf *rpc.ServerConfig) process.Launcher { 57 return process.Launcher{ 58 Name: ProfilingProcessName, 59 Enabled: conf.Enabled, 60 Launch: func() (process.Process, error) { 61 debugServer := &http.Server{ 62 Addr: conf.ListenAddress, 63 } 64 go func() { 65 err := debugServer.ListenAndServe() 66 if err != nil { 67 kern.Logger.InfoMsg("Error from pprof debug server", structure.ErrorKey, err) 68 } 69 }() 70 return debugServer, nil 71 }, 72 } 73 } 74 75 func DatabaseLauncher(kern *Kernel) process.Launcher { 76 return process.Launcher{ 77 Name: DatabaseProcessName, 78 Enabled: true, 79 Launch: func() (process.Process, error) { 80 // Just close database 81 return process.ShutdownFunc(func(ctx context.Context) error { 82 kern.database.Close() 83 return nil 84 }), nil 85 }, 86 } 87 } 88 89 // Run a single uncoordinated local state 90 func NoConsensusLauncher(kern *Kernel) process.Launcher { 91 return process.Launcher{ 92 Name: NoConsensusProcessName, 93 Enabled: kern.Node == nil, 94 Launch: func() (process.Process, error) { 95 accountState := kern.State 96 nameRegState := kern.State 97 kern.Service = rpc.NewService(accountState, nameRegState, kern.Blockchain, kern.State, nil, kern.Logger) 98 // TimeoutFactor scales in units of seconds 99 blockDuration := time.Duration(kern.timeoutFactor * float64(time.Second)) 100 //proc := abci.NewProcess(kern.checker, kern.committer, kern.Blockchain, kern.txCodec, blockDuration, kern.Panic) 101 proc := abci.NewProcess(kern.committer, kern.Blockchain, kern.txCodec, blockDuration, kern.Panic) 102 // Provide execution accounts against backend state since we will commit immediately 103 accounts := execution.NewAccounts(kern.committer, kern.keyClient, AccountsRingMutexCount) 104 // Elide consensus and use a CheckTx function that immediately commits any valid transaction 105 kern.Transactor = execution.NewTransactor(kern.Blockchain, kern.Emitter, accounts, proc.CheckTx, kern.txCodec, 106 kern.Logger) 107 return proc, nil 108 }, 109 } 110 } 111 112 func TendermintLauncher(kern *Kernel) process.Launcher { 113 return process.Launcher{ 114 Name: TendermintProcessName, 115 Enabled: kern.Node != nil, 116 Launch: func() (process.Process, error) { 117 const errHeader = "TendermintLauncher():" 118 nodeView, err := kern.GetNodeView() 119 if err != nil { 120 return nil, fmt.Errorf("%s cannot get NodeView %v", errHeader, err) 121 } 122 123 accountState := kern.State 124 nameRegState := kern.State 125 kern.Service = rpc.NewService(accountState, nameRegState, kern.Blockchain, kern.State, nodeView, kern.Logger) 126 127 kern.Blockchain.SetBlockStore(bcm.NewBlockStore(nodeView.BlockStore())) 128 // Provide execution accounts against checker state so that we can assign sequence numbers 129 accounts := execution.NewAccounts(kern.checker, kern.keyClient, AccountsRingMutexCount) 130 // Pass transactions to Tendermint's CheckTx function for broadcast and consensus 131 checkTx := kern.Node.MempoolReactor().Mempool.CheckTx 132 kern.Transactor = execution.NewTransactor(kern.Blockchain, kern.Emitter, accounts, checkTx, kern.txCodec, 133 kern.Logger) 134 135 if err := kern.Node.Start(); err != nil { 136 return nil, fmt.Errorf("%s error starting Tendermint node: %v", errHeader, err) 137 } 138 139 return process.ShutdownFunc(func(ctx context.Context) error { 140 err := kern.Node.Stop() 141 // Close tendermint database connections using our wrapper 142 defer kern.Node.Close() 143 if err != nil { 144 return err 145 } 146 select { 147 case <-ctx.Done(): 148 return ctx.Err() 149 case <-kern.Node.Quit(): 150 kern.Logger.InfoMsg("Tendermint Node has quit, closing DB connections...") 151 return nil 152 } 153 }), nil 154 }, 155 } 156 } 157 158 func StartupLauncher(kern *Kernel) process.Launcher { 159 return process.Launcher{ 160 Name: StartupProcessName, 161 Enabled: true, 162 Launch: func() (process.Process, error) { 163 start := time.Now() 164 shutdown := process.ShutdownFunc(func(ctx context.Context) error { 165 stop := time.Now() 166 return kern.Logger.InfoMsg("Burrow is shutting down. Prepare for re-entrancy.", 167 "announce", "shutdown", 168 "shutdown_time", stop, 169 "elapsed_run_time", stop.Sub(start).String()) 170 }) 171 172 if kern.Node == nil { 173 return shutdown, nil 174 } 175 176 nodeView, err := kern.GetNodeView() 177 if err != nil { 178 return nil, err 179 } 180 181 genesisDoc := kern.Blockchain.GenesisDoc() 182 info := kern.Node.NodeInfo() 183 logger := kern.Logger.With( 184 "launch_time", start, 185 "burrow_version", project.FullVersion(), 186 "tendermint_version", version.TMCoreSemVer, 187 "validator_address", nodeView.ValidatorAddress(), 188 "node_id", string(info.ID()), 189 "net_address", info.NetAddress().String(), 190 "genesis_app_hash", genesisDoc.AppHash.String(), 191 "genesis_hash", hex.EncodeUpperToString(genesisDoc.Hash()), 192 ) 193 194 err = logger.InfoMsg("Burrow is launching. We have marmot-off.", "announce", "startup") 195 return shutdown, err 196 }, 197 } 198 } 199 200 func InfoLauncher(kern *Kernel, conf *rpc.ServerConfig) process.Launcher { 201 return process.Launcher{ 202 Name: InfoProcessName, 203 Enabled: conf.Enabled, 204 Launch: func() (process.Process, error) { 205 listener, err := process.ListenerFromAddress(conf.ListenAddress) 206 if err != nil { 207 return nil, err 208 } 209 err = kern.registerListener(InfoProcessName, listener) 210 if err != nil { 211 return nil, err 212 } 213 server, err := rpcinfo.StartServer(kern.Service, "/websocket", listener, kern.Logger) 214 if err != nil { 215 return nil, err 216 } 217 return server, nil 218 }, 219 } 220 } 221 222 func MetricsLauncher(kern *Kernel, conf *rpc.MetricsConfig) process.Launcher { 223 return process.Launcher{ 224 Name: MetricsProcessName, 225 Enabled: conf.Enabled, 226 Launch: func() (process.Process, error) { 227 listener, err := process.ListenerFromAddress(conf.ListenAddress) 228 if err != nil { 229 return nil, err 230 } 231 err = kern.registerListener(MetricsProcessName, listener) 232 if err != nil { 233 return nil, err 234 } 235 server, err := metrics.StartServer(kern.Service, conf.MetricsPath, listener, conf.BlockSampleSize, 236 kern.Logger) 237 if err != nil { 238 return nil, err 239 } 240 return server, nil 241 }, 242 } 243 } 244 245 func GRPCLauncher(kern *Kernel, conf *rpc.ServerConfig, keyConfig *keys.KeysConfig) process.Launcher { 246 return process.Launcher{ 247 Name: GRPCProcessName, 248 Enabled: conf.Enabled, 249 Launch: func() (process.Process, error) { 250 nodeView, err := kern.GetNodeView() 251 if err != nil { 252 return nil, err 253 } 254 255 listener, err := process.ListenerFromAddress(conf.ListenAddress) 256 if err != nil { 257 return nil, err 258 } 259 err = kern.registerListener(GRPCProcessName, listener) 260 if err != nil { 261 return nil, err 262 } 263 264 grpcServer := rpc.NewGRPCServer(kern.Logger) 265 var ks *keys.KeyStore 266 if kern.keyStore != nil { 267 ks = kern.keyStore 268 } 269 grpcServer.GetServiceInfo() 270 271 if keyConfig.GRPCServiceEnabled { 272 if kern.keyStore == nil { 273 ks = keys.NewKeyStore(keyConfig.KeysDirectory, keyConfig.AllowBadFilePermissions) 274 } 275 keys.RegisterKeysServer(grpcServer, ks) 276 } 277 278 nameRegState := kern.State 279 proposalRegState := kern.State 280 rpcquery.RegisterQueryServer(grpcServer, rpcquery.NewQueryServer(kern.State, nameRegState, proposalRegState, 281 kern.Blockchain, kern.State, nodeView, kern.Logger)) 282 283 txCodec := txs.NewAminoCodec() 284 rpctransact.RegisterTransactServer(grpcServer, rpctransact.NewTransactServer(kern.Transactor, txCodec)) 285 286 rpcevents.RegisterExecutionEventsServer(grpcServer, rpcevents.NewExecutionEventsServer(kern.State, 287 kern.Emitter, kern.Blockchain, kern.Logger)) 288 289 rpcdump.RegisterDumpServer(grpcServer, rpcdump.NewDumpServer(kern.State, kern.Blockchain, kern.Logger)) 290 291 // Provides metadata about services registered 292 // reflection.Register(grpcServer) 293 294 go grpcServer.Serve(listener) 295 296 return process.ShutdownFunc(func(ctx context.Context) error { 297 grpcServer.Stop() 298 // listener is closed for us 299 return nil 300 }), nil 301 }, 302 } 303 }