From 15b4e0a8cd91ce7b0c0b8a14af9c5e83267add6e Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 24 Nov 2023 15:24:02 +0300 Subject: [PATCH] services: adjust StateRoot service initialisation Perform initialisation of StateRoot service with designated StateValidator's node list in the service constructor. There's no need to wait until the next role update event, and it may lead to inaccuraces in service work on SIGHUP/server restart. A part of #3228. Signed-off-by: Anna Shaleva --- pkg/services/stateroot/service.go | 19 +++++++++++++++++++ pkg/services/stateroot/service_test.go | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/pkg/services/stateroot/service.go b/pkg/services/stateroot/service.go index 5e34546e4..e7123e88c 100644 --- a/pkg/services/stateroot/service.go +++ b/pkg/services/stateroot/service.go @@ -2,6 +2,7 @@ package stateroot import ( "errors" + "fmt" "sync" "sync/atomic" "time" @@ -9,6 +10,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/block" + "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/stateroot" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -22,6 +24,7 @@ type ( // Ledger is an interface to Blockchain sufficient for Service. Ledger interface { GetConfig() config.Blockchain + GetDesignatedByRole(role noderoles.Role) (keys.PublicKeys, uint32, error) HeaderHeight() uint32 SubscribeForBlocks(ch chan *block.Block) UnsubscribeFromBlocks(ch chan *block.Block) @@ -40,6 +43,10 @@ type ( // to Shutdown on the same instance are no-op. The instance that was stopped can // not be started again by calling Start (use a new instance if needed). Shutdown() + // IsAuthorized returns whether state root service currently is authorized to sign + // state roots. It returns true iff designated StateValidator node's account + // provided to the state root service in decrypted state. + IsAuthorized() bool } service struct { @@ -116,6 +123,12 @@ func New(cfg config.StateRoot, sm *stateroot.Module, log *zap.Logger, bc Ledger, return nil, errors.New("no wallet account could be unlocked") } + keys, h, err := bc.GetDesignatedByRole(noderoles.StateValidator) + if err != nil { + return nil, fmt.Errorf("failed to get designated StateValidators: %w", err) + } + s.updateValidators(h, keys) + s.SetUpdateValidatorsCallback(s.updateValidators) } return s, nil @@ -173,3 +186,9 @@ func (s *service) updateValidators(height uint32, pubs keys.PublicKeys) { } } } + +// IsAuthorized implements Service interface. +func (s *service) IsAuthorized() bool { + _, acc := s.getAccount() + return acc != nil +} diff --git a/pkg/services/stateroot/service_test.go b/pkg/services/stateroot/service_test.go index 18c6ea2ff..5f75d4cff 100644 --- a/pkg/services/stateroot/service_test.go +++ b/pkg/services/stateroot/service_test.go @@ -148,6 +148,25 @@ func TestStateRoot(t *testing.T) { require.Equal(t, h, r.Witness[0].ScriptHash()) } +func TestStateRoot_GenesisRole(t *testing.T) { + _, _, accs := newMajorityMultisigWithGAS(t, 2) + + bc, _, _ := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) { + c.Genesis.Roles = map[noderoles.Role]keys.PublicKeys{ + noderoles.StateValidator: {accs[0].PublicKey(), accs[1].PublicKey()}, + } + }) + + tmpDir := t.TempDir() + w := createAndWriteWallet(t, accs[0], filepath.Join(tmpDir, "w"), "pass") + cfg := createStateRootConfig(w.Path(), "pass") + srMod := bc.GetStateModule().(*corestate.Module) // Take full responsibility here. + srv, err := stateroot.New(cfg, srMod, zaptest.NewLogger(t), bc, nil) + require.NoError(t, err) + + require.True(t, srv.IsAuthorized()) +} + type memoryStore struct { *storage.MemoryStore }