Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invocatons of alphabet vote method #170

Merged
merged 6 commits into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/neofs-ir/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func defaultConfiguration(cfg *viper.Viper) {
cfg.SetDefault("morph.endpoint.client", "")
cfg.SetDefault("morph.endpoint.notification", "")
cfg.SetDefault("morph.dial_timeout", "10s")
cfg.SetDefault("morph.validators", []string{})

cfg.SetDefault("mainnet.endpoint.client", "")
cfg.SetDefault("mainnet.endpoint.notification", "")
Expand Down
19 changes: 19 additions & 0 deletions cmd/neofs-ir/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"flag"
"fmt"
"os"
"strings"

"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-node/misc"
"github.com/nspcc-dev/neofs-node/pkg/innerring"
"github.com/nspcc-dev/neofs-node/pkg/util/grace"
Expand All @@ -30,6 +32,7 @@ func exitErr(err error) {

func main() {
configFile := flag.String("config", "", "path to config")
validators := flag.String("vote", "", "hex encoded public keys split with comma")
versionFlag := flag.Bool("version", false, "neofs-ir node version")
flag.Parse()

Expand All @@ -55,6 +58,16 @@ func main() {
exitErr(err)
}

if len(*validators) != 0 {
validatorKeys, err := parsePublicKeysFromString(*validators)
exitErr(err)

err = innerRing.InitAndVoteForSidechainValidator(validatorKeys)
exitErr(err)

return
}

// start pprof if enabled
if pprof != nil {
pprof.Start(ctx)
Expand Down Expand Up @@ -86,3 +99,9 @@ func main() {

log.Info("application stopped")
}

func parsePublicKeysFromString(argument string) ([]keys.PublicKey, error) {
publicKeysString := strings.Split(argument, ",")

return innerring.ParsePublicKeysFromStrings(publicKeysString)
}
43 changes: 41 additions & 2 deletions pkg/innerring/innerring.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/ecdsa"

"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-node/pkg/innerring/invoke"
Expand Down Expand Up @@ -42,8 +43,9 @@ type (
precision precision.Fixed8Converter

// internal variables
key *ecdsa.PrivateKey
contracts *contracts
key *ecdsa.PrivateKey
contracts *contracts
predefinedValidators []keys.PublicKey
}

contracts struct {
Expand Down Expand Up @@ -82,6 +84,14 @@ func (s *Server) Start(ctx context.Context, intError chan<- error) error {
return err
}

// vote for sidechain validator if it is prepared in config
err = s.voteForSidechainValidator(s.predefinedValidators)
if err != nil {
// we don't stop inner ring execution on this error
s.log.Warn("can't vote for prepared validators",
zap.String("error", err.Error()))
}

s.localTimers.Start(ctx) // local timers start ticking

morphErr := make(chan error)
Expand Down Expand Up @@ -128,6 +138,12 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
return nil, err
}

// parse default validators
server.predefinedValidators, err = parsePredefinedValidators(cfg)
if err != nil {
return nil, errors.Wrap(err, "ir: can't parse predefined validators list")
}

// create local timer instance
server.localTimers = timers.New(&timers.Params{
Log: log,
Expand Down Expand Up @@ -355,6 +371,29 @@ func parseContracts(cfg *viper.Viper) (*contracts, error) {
return result, nil
}

func parsePredefinedValidators(cfg *viper.Viper) ([]keys.PublicKey, error) {
publicKeyStrings := cfg.GetStringSlice("morph.validators")

return ParsePublicKeysFromStrings(publicKeyStrings)
}

// ParsePublicKeysFromStrings returns slice of neo public keys from slice
// of hex encoded strings.
func ParsePublicKeysFromStrings(pubKeys []string) ([]keys.PublicKey, error) {
publicKeys := make([]keys.PublicKey, 0, len(pubKeys))

for i := range pubKeys {
key, err := keys.NewPublicKeyFromString(pubKeys[i])
if err != nil {
return nil, errors.Wrap(err, "can't decode public key")
}

publicKeys = append(publicKeys, *key)
}

return publicKeys, nil
}

func parseAlphabetContracts(cfg *viper.Viper) (res [7]util.Uint160, err error) {
// list of glagolic script letters that represent alphabet contracts
glagolic := []string{"az", "buky", "vedi", "glagoli", "dobro", "jest", "zhivete"}
Expand Down
16 changes: 16 additions & 0 deletions pkg/innerring/invoke/alphabet.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package invoke

import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
)

const (
emitMethod = "emit"
voteMethod = "vote"
)

// AlphabetEmit invokes emit method on alphabet contract.
Expand All @@ -18,3 +20,17 @@ func AlphabetEmit(cli *client.Client, con util.Uint160) error {
// there is no signature collecting, so we don't need extra fee
return cli.Invoke(con, 0, emitMethod)
}

// AlphabetVote invokes vote method on alphabet contract.
func AlphabetVote(cli *client.Client, con util.Uint160, epoch uint64, keys []keys.PublicKey) error {
if cli == nil {
return client.ErrNilClient
}

binaryKeys := make([][]byte, 0, len(keys))
for i := range keys {
binaryKeys = append(binaryKeys, keys[i].Bytes())
}

return cli.Invoke(con, feeOneGas, voteMethod, int64(epoch), binaryKeys)
}
46 changes: 46 additions & 0 deletions pkg/innerring/state.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package innerring

import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-node/pkg/innerring/invoke"
"go.uber.org/zap"
)

// EpochCounter is a getter for a global epoch counter.
func (s *Server) EpochCounter() uint64 {
return s.epochCounter.Load()
Expand All @@ -21,3 +27,43 @@ func (s *Server) IsActive() bool {
func (s *Server) Index() int32 {
return s.innerRingIndex.Load()
}

func (s *Server) voteForSidechainValidator(validators []keys.PublicKey) error {
index := s.Index()
if index < 0 || index >= alphabetContractsN {
s.log.Info("ignore validator vote: node not in alphabet range")

return nil
}

if len(validators) == 0 {
s.log.Info("ignore validator vote: empty validators list")

return nil
}

epoch := s.EpochCounter()

for i := range s.contracts.alphabet {
err := invoke.AlphabetVote(s.morphClient, s.contracts.alphabet[i], epoch, validators)
if err != nil {
s.log.Warn("can't invoke vote method in alphabet contract",
zap.Int("alphabet_index", i),
zap.Uint64("epoch", epoch))
}
}

return nil
}

// InitAndVoteForSidechainValidator is a public function to use outside of
// inner ring daemon execution. It initialize inner ring structure with data
// from blockchain and then calls vote method on corresponding alphabet contract.
func (s *Server) InitAndVoteForSidechainValidator(validators []keys.PublicKey) error {
err := s.initConfigFromBlockchain()
if err != nil {
return err
}

return s.voteForSidechainValidator(validators)
}
2 changes: 1 addition & 1 deletion pkg/morph/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (c *Client) Invoke(contract util.Uint160, fee util.Fixed8, method string, a

c.logger.Debug("neo client invoke",
zap.String("method", method),
zap.Stringer("tx_hash", txHash))
zap.Stringer("tx_hash", txHash.Reverse()))

return nil
}
Expand Down