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 }