2018-02-09 16:08:50 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2019-02-19 11:48:48 +00:00
|
|
|
"context"
|
2018-03-14 09:36:59 +00:00
|
|
|
"fmt"
|
2018-03-23 20:36:59 +00:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2018-02-09 16:08:50 +00:00
|
|
|
|
2018-03-25 10:45:54 +00:00
|
|
|
"github.com/CityOfZion/neo-go/config"
|
2018-03-14 09:36:59 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/core"
|
2019-09-10 14:22:21 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
2018-02-09 16:08:50 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/network"
|
2018-03-23 20:36:59 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/rpc"
|
|
|
|
"github.com/pkg/errors"
|
2018-03-17 11:53:21 +00:00
|
|
|
log "github.com/sirupsen/logrus"
|
2018-02-09 16:08:50 +00:00
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
2018-03-02 15:24:09 +00:00
|
|
|
// NewCommand creates a new Node command.
|
2018-02-09 16:08:50 +00:00
|
|
|
func NewCommand() cli.Command {
|
|
|
|
return cli.Command{
|
|
|
|
Name: "node",
|
|
|
|
Usage: "start a NEO node",
|
|
|
|
Action: startServer,
|
|
|
|
Flags: []cli.Flag{
|
2018-03-15 20:45:37 +00:00
|
|
|
cli.StringFlag{Name: "config-path"},
|
2018-02-09 16:08:50 +00:00
|
|
|
cli.BoolFlag{Name: "privnet, p"},
|
|
|
|
cli.BoolFlag{Name: "mainnet, m"},
|
|
|
|
cli.BoolFlag{Name: "testnet, t"},
|
2018-03-17 11:53:21 +00:00
|
|
|
cli.BoolFlag{Name: "debug, d"},
|
2018-02-09 16:08:50 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 11:48:48 +00:00
|
|
|
func newGraceContext() context.Context {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
stop := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(stop, os.Interrupt)
|
|
|
|
go func() {
|
|
|
|
<-stop
|
|
|
|
cancel()
|
|
|
|
}()
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
|
2018-02-09 16:08:50 +00:00
|
|
|
func startServer(ctx *cli.Context) error {
|
2018-03-25 10:45:54 +00:00
|
|
|
net := config.ModePrivNet
|
2018-02-09 16:08:50 +00:00
|
|
|
if ctx.Bool("testnet") {
|
2018-03-25 10:45:54 +00:00
|
|
|
net = config.ModeTestNet
|
2018-02-09 16:08:50 +00:00
|
|
|
}
|
|
|
|
if ctx.Bool("mainnet") {
|
2018-03-25 10:45:54 +00:00
|
|
|
net = config.ModeMainNet
|
2018-02-09 16:08:50 +00:00
|
|
|
}
|
|
|
|
|
2019-02-19 11:48:48 +00:00
|
|
|
grace, cancel := context.WithCancel(newGraceContext())
|
|
|
|
defer cancel()
|
|
|
|
|
2019-08-30 08:22:11 +00:00
|
|
|
configPath := "./config"
|
2018-07-22 06:46:49 +00:00
|
|
|
if argCp := ctx.String("config-path"); argCp != "" {
|
|
|
|
configPath = argCp
|
|
|
|
}
|
2018-03-25 10:45:54 +00:00
|
|
|
cfg, err := config.Load(configPath, net)
|
2018-03-15 20:45:37 +00:00
|
|
|
if err != nil {
|
2018-03-17 11:53:21 +00:00
|
|
|
return cli.NewExitError(err, 1)
|
2018-03-09 15:55:25 +00:00
|
|
|
}
|
|
|
|
|
2018-03-25 10:45:54 +00:00
|
|
|
serverConfig := network.NewServerConfig(cfg)
|
2019-09-10 14:22:21 +00:00
|
|
|
|
|
|
|
chain, err := initBlockChain(grace, cfg)
|
2018-03-14 09:36:59 +00:00
|
|
|
if err != nil {
|
2019-09-10 14:22:21 +00:00
|
|
|
return err
|
2018-03-14 09:36:59 +00:00
|
|
|
}
|
|
|
|
|
2018-03-17 11:53:21 +00:00
|
|
|
if ctx.Bool("debug") {
|
|
|
|
log.SetLevel(log.DebugLevel)
|
|
|
|
}
|
|
|
|
|
2018-03-23 20:36:59 +00:00
|
|
|
server := network.NewServer(serverConfig, chain)
|
2018-03-25 10:45:54 +00:00
|
|
|
rpcServer := rpc.NewServer(chain, cfg.ApplicationConfiguration.RPCPort, server)
|
2018-03-23 20:36:59 +00:00
|
|
|
errChan := make(chan error)
|
|
|
|
|
|
|
|
go server.Start(errChan)
|
|
|
|
go rpcServer.Start(errChan)
|
|
|
|
|
2018-03-25 10:45:54 +00:00
|
|
|
fmt.Println(logo())
|
|
|
|
fmt.Println(server.UserAgent)
|
|
|
|
fmt.Println()
|
|
|
|
|
|
|
|
var shutdownErr error
|
2018-03-23 20:36:59 +00:00
|
|
|
Main:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case err := <-errChan:
|
|
|
|
shutdownErr = errors.Wrap(err, "Error encountered by server")
|
2019-02-19 11:48:48 +00:00
|
|
|
cancel()
|
2018-03-23 20:36:59 +00:00
|
|
|
|
2019-02-19 11:48:48 +00:00
|
|
|
case <-grace.Done():
|
2018-03-23 20:36:59 +00:00
|
|
|
server.Shutdown()
|
|
|
|
if serverErr := rpcServer.Shutdown(); serverErr != nil {
|
|
|
|
shutdownErr = errors.Wrap(serverErr, "Error encountered whilst shutting down server")
|
|
|
|
}
|
|
|
|
break Main
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if shutdownErr != nil {
|
|
|
|
return cli.NewExitError(shutdownErr, 1)
|
|
|
|
}
|
|
|
|
|
2018-02-09 16:08:50 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-09-10 14:22:21 +00:00
|
|
|
// initBlockChain initializes BlockChain with preselected DB.
|
|
|
|
func initBlockChain(context context.Context, cfg config.Config) (*core.Blockchain, error) {
|
2019-09-16 15:52:47 +00:00
|
|
|
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
2019-09-10 14:22:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, cli.NewExitError(fmt.Errorf("could not initialize storage: %s", err), 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
chain, err := core.NewBlockchain(context, store, cfg.ProtocolConfiguration)
|
|
|
|
if err != nil {
|
|
|
|
return nil, cli.NewExitError(fmt.Errorf("could not initialize blockchain: %s", err), 1)
|
|
|
|
}
|
|
|
|
return chain, nil
|
|
|
|
}
|
|
|
|
|
2018-03-17 11:53:21 +00:00
|
|
|
func logo() string {
|
|
|
|
return `
|
|
|
|
_ ____________ __________
|
|
|
|
/ | / / ____/ __ \ / ____/ __ \
|
|
|
|
/ |/ / __/ / / / /_____/ / __/ / / /
|
|
|
|
/ /| / /___/ /_/ /_____/ /_/ / /_/ /
|
|
|
|
/_/ |_/_____/\____/ \____/\____/
|
|
|
|
`
|
2018-03-14 09:36:59 +00:00
|
|
|
}
|