From 2e31cd34e68958d0fad0c10add4e038b4409d216 Mon Sep 17 00:00:00 2001
From: Evgenii Stratonikov <evgeniy@nspcc.ru>
Date: Tue, 18 May 2021 10:40:21 +0300
Subject: [PATCH] [#502] innerring: synchronize validators on mainnet alphabet
 update

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
---
 pkg/innerring/innerring.go                    |  4 +++
 .../processors/governance/handlers.go         | 21 +++++++++++--
 .../processors/governance/processor.go        | 14 +++++++--
 pkg/morph/client/client.go                    |  5 +++
 pkg/morph/event/rolemanagement/designate.go   | 31 +++++++++++++++++++
 .../event/rolemanagement/designate_test.go    | 27 ++++++++++++++++
 6 files changed, 98 insertions(+), 4 deletions(-)
 create mode 100644 pkg/morph/event/rolemanagement/designate.go
 create mode 100644 pkg/morph/event/rolemanagement/designate_test.go

diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go
index 0f789db9..1f091d21 100644
--- a/pkg/innerring/innerring.go
+++ b/pkg/innerring/innerring.go
@@ -490,6 +490,10 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
 		}
 	} else {
 		alphaSync = governanceProcessor.HandleAlphabetSync
+		err = bindMainnetProcessor(governanceProcessor, server)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	// create netmap processor
diff --git a/pkg/innerring/processors/governance/handlers.go b/pkg/innerring/processors/governance/handlers.go
index 1b41f0c9..9b6ceb8d 100644
--- a/pkg/innerring/processors/governance/handlers.go
+++ b/pkg/innerring/processors/governance/handlers.go
@@ -1,12 +1,29 @@
 package governance
 
 import (
+	"github.com/nspcc-dev/neo-go/pkg/core/native"
+	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
+	"github.com/nspcc-dev/neofs-node/pkg/morph/event/rolemanagement"
 	"go.uber.org/zap"
 )
 
-func (gp *Processor) HandleAlphabetSync(_ event.Event) {
-	gp.log.Info("new event", zap.String("type", "sync"))
+func (gp *Processor) HandleAlphabetSync(e event.Event) {
+	var typ string
+
+	switch et := e.(type) {
+	case Sync:
+		typ = "sync"
+	case rolemanagement.Designate:
+		if et.Role != noderoles.NeoFSAlphabet {
+			return
+		}
+		typ = native.DesignationEventName
+	default:
+		return
+	}
+
+	gp.log.Info("new event", zap.String("type", typ))
 
 	// send event to the worker pool
 
diff --git a/pkg/innerring/processors/governance/processor.go b/pkg/innerring/processors/governance/processor.go
index 3e98150f..e663469f 100644
--- a/pkg/innerring/processors/governance/processor.go
+++ b/pkg/innerring/processors/governance/processor.go
@@ -4,11 +4,13 @@ import (
 	"errors"
 	"fmt"
 
+	"github.com/nspcc-dev/neo-go/pkg/core/native"
 	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
 	"github.com/nspcc-dev/neo-go/pkg/util"
 	"github.com/nspcc-dev/neofs-node/pkg/innerring/config"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/client"
 	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
+	"github.com/nspcc-dev/neofs-node/pkg/morph/event/rolemanagement"
 	"github.com/panjf2000/ants/v2"
 	"go.uber.org/zap"
 )
@@ -111,12 +113,20 @@ func New(p *Params) (*Processor, error) {
 
 // ListenerParsers for the 'event.Listener' event producer.
 func (gp *Processor) ListenerParsers() []event.ParserInfo {
-	return nil
+	var pi event.ParserInfo
+	pi.SetScriptHash(gp.mainnetClient.GetDesignateHash())
+	pi.SetType(event.TypeFromString(native.DesignationEventName))
+	pi.SetParser(rolemanagement.ParseDesignate)
+	return []event.ParserInfo{pi}
 }
 
 // ListenerHandlers for the 'event.Listener' event producer.
 func (gp *Processor) ListenerHandlers() []event.HandlerInfo {
-	return nil
+	var hi event.HandlerInfo
+	hi.SetScriptHash(gp.mainnetClient.GetDesignateHash())
+	hi.SetType(event.TypeFromString(native.DesignationEventName))
+	hi.SetHandler(gp.HandleAlphabetSync)
+	return []event.HandlerInfo{hi}
 }
 
 // TimersHandlers for the 'Timers' event producer.
diff --git a/pkg/morph/client/client.go b/pkg/morph/client/client.go
index 52e8e565..e97f63e2 100644
--- a/pkg/morph/client/client.go
+++ b/pkg/morph/client/client.go
@@ -236,6 +236,11 @@ func (c *Client) NeoFSAlphabetList() (keys.PublicKeys, error) {
 	return list, nil
 }
 
+// GetDesignateHash returns hash of the native `RoleManagement` contract.
+func (c *Client) GetDesignateHash() util.Uint160 {
+	return c.designate
+}
+
 func (c *Client) roleList(r noderoles.Role) (keys.PublicKeys, error) {
 	height, err := c.client.GetBlockCount()
 	if err != nil {
diff --git a/pkg/morph/event/rolemanagement/designate.go b/pkg/morph/event/rolemanagement/designate.go
new file mode 100644
index 00000000..700f224f
--- /dev/null
+++ b/pkg/morph/event/rolemanagement/designate.go
@@ -0,0 +1,31 @@
+package rolemanagement
+
+import (
+	"fmt"
+
+	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
+	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
+	"github.com/nspcc-dev/neofs-node/pkg/morph/event"
+)
+
+// Designate represents designation event of the mainnet RoleManagement contract.
+type Designate struct {
+	Role noderoles.Role
+}
+
+// MorphEvent implements Neo:Morph Event interface.
+func (Designate) MorphEvent() {}
+
+// ParseDesignate from notification into container event structure.
+func ParseDesignate(params []stackitem.Item) (event.Event, error) {
+	if len(params) != 2 {
+		return nil, event.WrongNumberOfParameters(2, len(params))
+	}
+
+	bi, err := params[0].TryInteger()
+	if err != nil {
+		return nil, fmt.Errorf("invalid stackitem type: %w", err)
+	}
+
+	return Designate{Role: noderoles.Role(bi.Int64())}, nil
+}
diff --git a/pkg/morph/event/rolemanagement/designate_test.go b/pkg/morph/event/rolemanagement/designate_test.go
new file mode 100644
index 00000000..8c1dc014
--- /dev/null
+++ b/pkg/morph/event/rolemanagement/designate_test.go
@@ -0,0 +1,27 @@
+package rolemanagement
+
+import (
+	"testing"
+
+	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
+	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
+	"github.com/stretchr/testify/require"
+)
+
+func TestParseRoleUpdate(t *testing.T) {
+	t.Run("wrong number of arguments", func(t *testing.T) {
+		_, err := ParseDesignate([]stackitem.Item{})
+		require.Error(t, err)
+	})
+	t.Run("invalid item type", func(t *testing.T) {
+		args := []stackitem.Item{stackitem.NewMap(), stackitem.Make(123)}
+		_, err := ParseDesignate(args)
+		require.Error(t, err)
+	})
+	t.Run("good", func(t *testing.T) {
+		args := []stackitem.Item{stackitem.Make(int(noderoles.NeoFSAlphabet)), stackitem.Make(123)}
+		e, err := ParseDesignate(args)
+		require.NoError(t, err)
+		require.Equal(t, noderoles.NeoFSAlphabet, e.(Designate).Role)
+	})
+}