diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index 5da8762c..cb97edbb 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -34,10 +34,10 @@ type ( localTimers *timers.Timers // global state - morphClient *client.Client - mainnetClient *client.Client - epochCounter atomic.Uint64 - activeState atomic.Bool + morphClient *client.Client + mainnetClient *client.Client + epochCounter atomic.Uint64 + innerRingIndex atomic.Int32 // todo: export error channel } @@ -307,17 +307,17 @@ func initConfigFromBlockchain(s *Server, c *contracts, key *ecdsa.PublicKey) err return errors.Wrap(err, "can't read epoch") } - // check if node inside inner ring list - state, err := invoke.IsInnerRing(s.mainnetClient, c.neofs, key) + // check if node inside inner ring list and what index it has + index, err := invoke.InnerRingIndex(s.mainnetClient, c.neofs, key) if err != nil { return errors.Wrap(err, "can't read inner ring list") } s.epochCounter.Store(uint64(epoch)) - s.activeState.Store(state) + s.innerRingIndex.Store(index) s.log.Debug("read config from blockchain", - zap.Bool("active", state), + zap.Bool("active", s.IsActive()), zap.Int64("epoch", epoch), ) diff --git a/pkg/innerring/invoke/neofs.go b/pkg/innerring/invoke/neofs.go index f8cb2b33..b6ace992 100644 --- a/pkg/innerring/invoke/neofs.go +++ b/pkg/innerring/invoke/neofs.go @@ -1,6 +1,7 @@ package invoke import ( + "bytes" "crypto/ecdsa" "github.com/nspcc-dev/neo-go/pkg/util" @@ -29,6 +30,7 @@ const ( extraFee = 1_5000_0000 // 1.5 Fixed8 gas checkIsInnerRingMethod = "isInnerRing" + innerRingListMethod = "innerRingList" chequeMethod = "cheque" ) @@ -66,3 +68,44 @@ func CashOutCheque(cli *client.Client, con util.Uint160, p *ChequeParams) error p.LockAccount.BytesBE(), ) } + +// InnerRingIndex returns index of the `key` in the inner ring list from sidechain. +// If key is not in the inner ring list, then returns `-1`. +func InnerRingIndex(cli *client.Client, con util.Uint160, key *ecdsa.PublicKey) (int32, error) { + if cli == nil { + return 0, client.ErrNilClient + } + + nodePublicKey := crypto.MarshalPublicKey(key) + + data, err := cli.TestInvoke(con, innerRingListMethod) + if err != nil { + return 0, err + } + + irNodes, err := client.ArrayFromStackItem(data[0]) + if err != nil { + return 0, err + } + + var result int32 = -1 + + for i := range irNodes { + key, err := client.ArrayFromStackItem(irNodes[i]) + if err != nil { + return 0, err + } + + keyValue, err := client.BytesFromStackItem(key[0]) + if err != nil { + return 0, err + } + + if bytes.Equal(keyValue, nodePublicKey) { + result = int32(i) + break + } + } + + return result, nil +} diff --git a/pkg/innerring/state.go b/pkg/innerring/state.go index 378cc241..ef36566d 100644 --- a/pkg/innerring/state.go +++ b/pkg/innerring/state.go @@ -13,5 +13,11 @@ func (s *Server) SetEpochCounter(val uint64) { // IsActive is a getter for a global active flag state. func (s *Server) IsActive() bool { - return s.activeState.Load() + return s.innerRingIndex.Load() >= 0 +} + +// Index is a getter for a global index of node in inner ring list. Negative +// index means that node is not in the inner ring list. +func (s *Server) Index() int32 { + return s.innerRingIndex.Load() }