From c3c07dbfd0392b03119c22d26680a5bb52a095e7 Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Wed, 3 Jun 2020 21:00:09 +0200 Subject: [PATCH 1/2] go/consensus/tendermint: Propagate errors during initial replay --- go/consensus/tendermint/tendermint.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/go/consensus/tendermint/tendermint.go b/go/consensus/tendermint/tendermint.go index 1c0b0f23f58..e1040601758 100644 --- a/go/consensus/tendermint/tendermint.go +++ b/go/consensus/tendermint/tendermint.go @@ -1119,7 +1119,20 @@ func (t *tendermintService) lazyInit() error { // // Defer actually initializing the node till after everything // else is setup. - t.startFn = func() error { + t.startFn = func() (err error) { + defer func() { + // The node constructor can panic early in case an error occurrs during block replay as + // the fail monitor is not yet initialized in that case. Propagate the error. + if p := recover(); p != nil { + switch pt := p.(type) { + case error: + err = pt + default: + err = fmt.Errorf("%v", pt) + } + } + }() + t.node, err = tmnode.NewNode(tenderConfig, tendermintPV, &tmp2p.NodeKey{PrivKey: crypto.SignerToTendermint(t.nodeSigner)}, @@ -1134,7 +1147,7 @@ func (t *tendermintService) lazyInit() error { } if t.stateDb == nil { // Sanity check for the above wrapDbProvider hack in case the DB provider changes. - panic("tendermint: state database not set") + return fmt.Errorf("tendermint: internal error: state database not set") } t.client = tmcli.New(t.node) t.failMonitor = newFailMonitor(t.Logger, t.node.ConsensusState().Wait) From a3d28286adba7f41acfe9904578fe872ece50072 Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Wed, 3 Jun 2020 21:03:24 +0200 Subject: [PATCH 2/2] go/oasis-node: Treat shutdown requested during startup as ok --- .changelog/2975.bugfix.md | 1 + go/oasis-node/cmd/node/node.go | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 .changelog/2975.bugfix.md diff --git a/.changelog/2975.bugfix.md b/.changelog/2975.bugfix.md new file mode 100644 index 00000000000..c9d26ba6877 --- /dev/null +++ b/.changelog/2975.bugfix.md @@ -0,0 +1 @@ +go/oasis-node: Properly handle shutdown during startup diff --git a/go/oasis-node/cmd/node/node.go b/go/oasis-node/cmd/node/node.go index 85ccffb37ba..d4c6ea1b963 100644 --- a/go/oasis-node/cmd/node/node.go +++ b/go/oasis-node/cmd/node/node.go @@ -82,7 +82,12 @@ func Run(cmd *cobra.Command, args []string) { cmdCommon.SetIsNodeCmd(true) node, err := NewNode() - if err != nil { + switch { + case err == nil: + case errors.Is(err, context.Canceled): + // Shutdown requested during startup. + return + default: os.Exit(1) } defer node.Cleanup() @@ -482,22 +487,26 @@ func NewTestNode() (*Node, error) { return newNode(true) } -func newNode(testNode bool) (*Node, error) { // nolint: gocyclo +func newNode(testNode bool) (node *Node, err error) { // nolint: gocyclo logger := cmdCommon.Logger() - node := &Node{ + node = &Node{ svcMgr: background.NewServiceManager(logger), } var startOk bool defer func() { if !startOk { + if cErr := node.svcMgr.Ctx.Err(); cErr != nil { + err = cErr + } + node.Stop() node.Cleanup() } }() - if err := cmdCommon.Init(); err != nil { + if err = cmdCommon.Init(); err != nil { // Common stuff like logger not correcty initialized. Print to stderr _, _ = fmt.Fprintln(os.Stderr, err) return nil, err @@ -512,8 +521,6 @@ func newNode(testNode bool) (*Node, error) { // nolint: gocyclo // Load configured values for all registered crash points. crash.LoadViperArgValues() - var err error - // Open the common node store. node.commonStore, err = persistent.NewCommonStore(dataDir) if err != nil {