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  }