2020-07-24 13:54:03 +00:00
|
|
|
package innerring
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-06-09 15:49:10 +00:00
|
|
|
"encoding/hex"
|
2021-05-18 08:12:51 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-02-09 14:57:51 +00:00
|
|
|
"io"
|
2021-06-09 15:49:10 +00:00
|
|
|
"net"
|
2020-07-24 13:54:03 +00:00
|
|
|
|
2021-01-22 15:01:44 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
2021-08-05 14:17:07 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2020-11-13 11:47:23 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-12-11 08:33:27 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
2021-02-02 11:12:41 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/config"
|
2020-10-12 10:26:05 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/alphabet"
|
2020-12-18 09:27:19 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/audit"
|
2020-07-24 13:54:03 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/balance"
|
2020-08-11 12:14:08 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/container"
|
2021-03-25 13:24:44 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/governance"
|
2020-07-24 13:54:03 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/neofs"
|
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap"
|
2021-06-18 10:42:03 +00:00
|
|
|
nodevalidator "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation"
|
|
|
|
addrvalidator "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation/maddress"
|
2021-11-28 12:57:52 +00:00
|
|
|
subnetvalidator "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation/subnet"
|
2021-03-31 15:41:47 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/reputation"
|
2021-01-28 19:51:41 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement"
|
2021-01-26 10:33:28 +00:00
|
|
|
auditSettlement "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/audit"
|
2021-07-21 15:15:56 +00:00
|
|
|
timerEvent "github.com/nspcc-dev/neofs-node/pkg/innerring/timers"
|
2021-12-27 12:24:05 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/metrics"
|
2020-07-24 13:54:03 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
|
2022-01-31 12:32:51 +00:00
|
|
|
auditClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/audit"
|
2022-01-31 09:24:25 +00:00
|
|
|
balanceClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
|
2022-01-31 13:34:01 +00:00
|
|
|
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
2022-01-31 10:15:36 +00:00
|
|
|
neofsClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/neofs"
|
2022-01-31 11:04:59 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/morph/client/neofsid"
|
2022-01-31 11:58:55 +00:00
|
|
|
nmClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
2022-01-31 12:19:10 +00:00
|
|
|
repClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/reputation"
|
2021-11-28 12:57:52 +00:00
|
|
|
morphsubnet "github.com/nspcc-dev/neofs-node/pkg/morph/client/subnet"
|
2020-07-24 13:54:03 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
|
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/morph/subscriber"
|
2021-04-15 13:50:34 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/morph/timer"
|
2020-12-22 00:28:42 +00:00
|
|
|
audittask "github.com/nspcc-dev/neofs-node/pkg/services/audit/taskmanager"
|
2021-06-09 15:49:10 +00:00
|
|
|
control "github.com/nspcc-dev/neofs-node/pkg/services/control/ir"
|
|
|
|
controlsrv "github.com/nspcc-dev/neofs-node/pkg/services/control/ir/server"
|
2021-06-11 17:13:24 +00:00
|
|
|
reputationcommon "github.com/nspcc-dev/neofs-node/pkg/services/reputation/common"
|
2020-12-23 16:53:11 +00:00
|
|
|
util2 "github.com/nspcc-dev/neofs-node/pkg/util"
|
2021-05-31 08:55:38 +00:00
|
|
|
utilConfig "github.com/nspcc-dev/neofs-node/pkg/util/config"
|
2020-10-27 10:49:34 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/util/precision"
|
2021-09-06 13:01:50 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/util/state"
|
2020-12-22 00:28:42 +00:00
|
|
|
"github.com/panjf2000/ants/v2"
|
2020-07-24 13:54:03 +00:00
|
|
|
"github.com/spf13/viper"
|
|
|
|
"go.uber.org/atomic"
|
|
|
|
"go.uber.org/zap"
|
2021-06-09 15:49:10 +00:00
|
|
|
"google.golang.org/grpc"
|
2020-07-24 13:54:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
// Server is the inner ring application structure, that contains all event
|
|
|
|
// processors, shared variables and event handlers.
|
|
|
|
Server struct {
|
|
|
|
log *zap.Logger
|
|
|
|
|
|
|
|
// event producers
|
|
|
|
morphListener event.Listener
|
|
|
|
mainnetListener event.Listener
|
2021-04-15 13:50:34 +00:00
|
|
|
blockTimers []*timer.BlockTimer
|
|
|
|
epochTimer *timer.BlockTimer
|
2020-07-24 13:54:03 +00:00
|
|
|
|
|
|
|
// global state
|
2021-03-23 12:44:09 +00:00
|
|
|
morphClient *client.Client
|
|
|
|
mainnetClient *client.Client
|
|
|
|
epochCounter atomic.Uint64
|
2021-10-11 17:09:52 +00:00
|
|
|
epochDuration atomic.Uint64
|
2021-03-23 12:44:09 +00:00
|
|
|
statusIndex *innerRingIndexer
|
|
|
|
precision precision.Fixed8Converter
|
2022-01-31 12:32:51 +00:00
|
|
|
auditClient *auditClient.Client
|
2021-06-09 15:41:58 +00:00
|
|
|
healthStatus atomic.Value
|
2022-01-31 09:24:25 +00:00
|
|
|
balanceClient *balanceClient.Client
|
2022-01-31 11:58:55 +00:00
|
|
|
netmapClient *nmClient.Client
|
2021-09-06 13:01:50 +00:00
|
|
|
persistate *state.PersistentStorage
|
2020-07-24 13:54:03 +00:00
|
|
|
|
2021-12-27 12:24:05 +00:00
|
|
|
// metrics
|
|
|
|
metrics *metrics.InnerRingServiceMetrics
|
|
|
|
|
2021-05-04 08:50:13 +00:00
|
|
|
// notary configuration
|
|
|
|
feeConfig *config.FeeConfig
|
|
|
|
mainNotaryConfig *notaryConfig
|
|
|
|
sideNotaryConfig *notaryConfig
|
2021-02-24 15:46:01 +00:00
|
|
|
|
2020-10-13 14:25:25 +00:00
|
|
|
// internal variables
|
2021-07-21 15:15:56 +00:00
|
|
|
key *keys.PrivateKey
|
|
|
|
pubKey []byte
|
|
|
|
contracts *contracts
|
|
|
|
predefinedValidators keys.PublicKeys
|
|
|
|
initialEpochTickDelta uint32
|
2021-09-06 12:58:40 +00:00
|
|
|
withoutMainNet bool
|
2021-07-21 15:15:56 +00:00
|
|
|
|
|
|
|
// runtime processors
|
|
|
|
netmapProcessor *netmap.Processor
|
2020-12-22 00:28:42 +00:00
|
|
|
|
|
|
|
workers []func(context.Context)
|
2021-02-09 14:57:51 +00:00
|
|
|
|
|
|
|
// Set of local resources that must be
|
|
|
|
// initialized at the very beginning of
|
|
|
|
// Server's work, (e.g. opening files).
|
|
|
|
//
|
|
|
|
// If any starter returns an error, Server's
|
|
|
|
// starting fails immediately.
|
|
|
|
starters []func() error
|
|
|
|
|
|
|
|
// Set of local resources that must be
|
|
|
|
// released at Server's work completion
|
|
|
|
// (e.g closing files).
|
|
|
|
//
|
|
|
|
// Closer's wrong outcome shouldn't be critical.
|
|
|
|
//
|
|
|
|
// Errors are logged.
|
|
|
|
closers []func() error
|
2021-06-09 15:49:10 +00:00
|
|
|
|
|
|
|
// Set of component runners which
|
|
|
|
// should report start errors
|
|
|
|
// to the application.
|
|
|
|
runners []func(chan<- error)
|
2021-11-26 12:19:20 +00:00
|
|
|
|
|
|
|
subnetHandler
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
chainParams struct {
|
|
|
|
log *zap.Logger
|
|
|
|
cfg *viper.Viper
|
2021-05-31 08:55:38 +00:00
|
|
|
key *keys.PrivateKey
|
2020-07-24 13:54:03 +00:00
|
|
|
name string
|
2021-08-05 14:17:07 +00:00
|
|
|
sgn *transaction.Signer
|
2021-09-06 13:01:50 +00:00
|
|
|
from uint32 // block height
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
morphPrefix = "morph"
|
|
|
|
mainnetPrefix = "mainnet"
|
2021-02-24 15:46:01 +00:00
|
|
|
|
|
|
|
// extra blocks to overlap two deposits, we do that to make sure that
|
2021-04-01 17:17:53 +00:00
|
|
|
// there won't be any blocks without deposited assets in notary contract;
|
|
|
|
// make sure it is bigger than any extra rounding value in notary client.
|
|
|
|
notaryExtraBlocks = 300
|
2021-02-25 16:53:30 +00:00
|
|
|
// amount of tries before notary deposit timeout.
|
|
|
|
notaryDepositTimeout = 100
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2021-04-29 13:50:46 +00:00
|
|
|
errDepositTimeout = errors.New("notary deposit didn't appear in the network")
|
2021-04-27 11:07:06 +00:00
|
|
|
errDepositFail = errors.New("notary tx has faulted")
|
2020-07-24 13:54:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Start runs all event providers.
|
2021-06-09 15:45:59 +00:00
|
|
|
func (s *Server) Start(ctx context.Context, intError chan<- error) (err error) {
|
|
|
|
s.setHealthStatus(control.HealthStatus_STARTING)
|
|
|
|
defer func() {
|
|
|
|
if err == nil {
|
|
|
|
s.setHealthStatus(control.HealthStatus_READY)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-02-09 14:57:51 +00:00
|
|
|
for _, starter := range s.starters {
|
|
|
|
if err := starter(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-09 15:49:10 +00:00
|
|
|
err = s.initConfigFromBlockchain()
|
2020-10-13 14:25:25 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-05-04 08:50:13 +00:00
|
|
|
if !s.mainNotaryConfig.disabled {
|
|
|
|
err = s.initNotary(ctx,
|
|
|
|
s.depositMainNotary,
|
|
|
|
s.awaitMainNotaryDeposit,
|
|
|
|
"waiting to accept main notary deposit",
|
|
|
|
)
|
2021-04-29 13:50:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-04 08:50:13 +00:00
|
|
|
}
|
2021-02-24 15:46:01 +00:00
|
|
|
|
2021-05-04 08:50:13 +00:00
|
|
|
if !s.sideNotaryConfig.disabled {
|
|
|
|
err = s.initNotary(ctx,
|
|
|
|
s.depositSideNotary,
|
|
|
|
s.awaitSideNotaryDeposit,
|
|
|
|
"waiting to accept side notary deposit",
|
|
|
|
)
|
2021-04-29 13:50:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-25 16:53:30 +00:00
|
|
|
}
|
|
|
|
|
2021-11-10 11:05:51 +00:00
|
|
|
prm := governance.VoteValidatorPrm{}
|
|
|
|
prm.Validators = s.predefinedValidators
|
|
|
|
|
2020-11-13 11:47:23 +00:00
|
|
|
// vote for sidechain validator if it is prepared in config
|
2021-11-10 11:05:51 +00:00
|
|
|
err = s.voteForSidechainValidator(prm)
|
2020-11-13 11:47:23 +00:00
|
|
|
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()))
|
|
|
|
}
|
|
|
|
|
2021-07-21 15:15:56 +00:00
|
|
|
// tick initial epoch
|
|
|
|
initialEpochTicker := timer.NewOneTickTimer(
|
|
|
|
timer.StaticBlockMeter(s.initialEpochTickDelta),
|
|
|
|
func() {
|
|
|
|
s.netmapProcessor.HandleNewEpochTick(timerEvent.NewEpochTick{})
|
|
|
|
})
|
|
|
|
s.addBlockTimer(initialEpochTicker)
|
|
|
|
|
2020-10-13 15:40:35 +00:00
|
|
|
morphErr := make(chan error)
|
|
|
|
mainnnetErr := make(chan error)
|
|
|
|
|
|
|
|
// anonymous function to multiplex error channels
|
|
|
|
go func() {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case err := <-morphErr:
|
2021-05-18 08:12:51 +00:00
|
|
|
intError <- fmt.Errorf("sidechain: %w", err)
|
2020-10-13 15:40:35 +00:00
|
|
|
case err := <-mainnnetErr:
|
2021-05-18 08:12:51 +00:00
|
|
|
intError <- fmt.Errorf("mainnet: %w", err)
|
2020-10-13 15:40:35 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-02-09 11:18:14 +00:00
|
|
|
s.morphListener.RegisterBlockHandler(func(b *block.Block) {
|
2021-01-25 12:04:00 +00:00
|
|
|
s.log.Debug("new block",
|
2021-01-22 15:01:44 +00:00
|
|
|
zap.Uint32("index", b.Index),
|
|
|
|
)
|
|
|
|
|
2021-09-06 13:01:50 +00:00
|
|
|
err = s.persistate.SetUInt32(persistateSideChainLastBlockKey, b.Index)
|
|
|
|
if err != nil {
|
|
|
|
s.log.Warn("can't update persistent state",
|
|
|
|
zap.String("chain", "side"),
|
|
|
|
zap.Uint32("block_index", b.Index))
|
|
|
|
}
|
|
|
|
|
2021-01-22 15:49:52 +00:00
|
|
|
s.tickTimers()
|
2021-01-22 15:01:44 +00:00
|
|
|
})
|
|
|
|
|
2021-09-06 13:01:50 +00:00
|
|
|
if !s.withoutMainNet {
|
|
|
|
s.mainnetListener.RegisterBlockHandler(func(b *block.Block) {
|
|
|
|
err = s.persistate.SetUInt32(persistateMainChainLastBlockKey, b.Index)
|
|
|
|
if err != nil {
|
|
|
|
s.log.Warn("can't update persistent state",
|
|
|
|
zap.String("chain", "main"),
|
|
|
|
zap.Uint32("block_index", b.Index))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-06-09 15:49:10 +00:00
|
|
|
for _, runner := range s.runners {
|
|
|
|
runner(intError)
|
|
|
|
}
|
|
|
|
|
2021-01-25 13:47:01 +00:00
|
|
|
go s.morphListener.ListenWithError(ctx, morphErr) // listen for neo:morph events
|
|
|
|
go s.mainnetListener.ListenWithError(ctx, mainnnetErr) // listen for neo:mainnet events
|
|
|
|
|
2021-01-22 15:49:52 +00:00
|
|
|
if err := s.startBlockTimers(); err != nil {
|
2021-05-18 08:12:51 +00:00
|
|
|
return fmt.Errorf("could not start block timers: %w", err)
|
2021-01-22 15:01:44 +00:00
|
|
|
}
|
|
|
|
|
2020-12-22 00:28:42 +00:00
|
|
|
s.startWorkers(ctx)
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-22 00:28:42 +00:00
|
|
|
func (s *Server) startWorkers(ctx context.Context) {
|
|
|
|
for _, w := range s.workers {
|
|
|
|
go w(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
// Stop closes all subscription channels.
|
|
|
|
func (s *Server) Stop() {
|
2021-06-09 15:45:59 +00:00
|
|
|
s.setHealthStatus(control.HealthStatus_SHUTTING_DOWN)
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
go s.morphListener.Stop()
|
2022-04-05 10:20:23 +00:00
|
|
|
go s.mainnetListener.Stop()
|
2021-02-09 14:57:51 +00:00
|
|
|
|
|
|
|
for _, c := range s.closers {
|
|
|
|
if err := c(); err != nil {
|
|
|
|
s.log.Warn("closer error",
|
|
|
|
zap.String("error", err.Error()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 06:51:06 +00:00
|
|
|
func (s *Server) registerNoErrCloser(c func()) {
|
|
|
|
s.registerCloser(func() error {
|
|
|
|
c()
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-02-09 14:57:51 +00:00
|
|
|
func (s *Server) registerIOCloser(c io.Closer) {
|
|
|
|
s.registerCloser(c.Close)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) registerCloser(f func() error) {
|
|
|
|
s.closers = append(s.closers, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) registerStarter(f func() error) {
|
|
|
|
s.starters = append(s.starters, f)
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// New creates instance of inner ring sever structure.
|
|
|
|
func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error) {
|
2020-10-13 14:25:25 +00:00
|
|
|
var err error
|
2020-07-24 13:54:03 +00:00
|
|
|
server := &Server{log: log}
|
|
|
|
|
2021-06-09 15:45:59 +00:00
|
|
|
server.setHealthStatus(control.HealthStatus_HEALTH_STATUS_UNDEFINED)
|
|
|
|
|
2021-04-29 13:50:46 +00:00
|
|
|
// parse notary support
|
2021-05-04 08:50:13 +00:00
|
|
|
server.feeConfig = config.NewFeeConfig(cfg)
|
2021-04-29 13:50:46 +00:00
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
// prepare inner ring node private key
|
2021-05-31 08:55:38 +00:00
|
|
|
acc, err := utilConfig.LoadAccount(
|
|
|
|
cfg.GetString("wallet.path"),
|
|
|
|
cfg.GetString("wallet.address"),
|
|
|
|
cfg.GetString("wallet.password"))
|
2020-07-24 13:54:03 +00:00
|
|
|
if err != nil {
|
2021-05-31 08:55:38 +00:00
|
|
|
return nil, fmt.Errorf("ir: %w", err)
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
2021-05-31 08:55:38 +00:00
|
|
|
server.key = acc.PrivateKey()
|
|
|
|
|
2021-09-06 13:01:50 +00:00
|
|
|
server.persistate, err = initPersistentStateStorage(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
server.registerCloser(server.persistate.Close)
|
|
|
|
|
|
|
|
fromSideChainBlock, err := server.persistate.UInt32(persistateSideChainLastBlockKey)
|
|
|
|
if err != nil {
|
|
|
|
fromSideChainBlock = 0
|
|
|
|
log.Warn("can't get last processed side chain block number", zap.String("error", err.Error()))
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
morphChain := &chainParams{
|
|
|
|
log: log,
|
|
|
|
cfg: cfg,
|
2020-10-13 14:25:25 +00:00
|
|
|
key: server.key,
|
2020-07-24 13:54:03 +00:00
|
|
|
name: morphPrefix,
|
2021-09-06 13:01:50 +00:00
|
|
|
from: fromSideChainBlock,
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create morph listener
|
|
|
|
server.morphListener, err = createListener(ctx, morphChain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// create morph client
|
2021-07-23 14:37:56 +00:00
|
|
|
server.morphClient, err = createClient(ctx, morphChain)
|
2020-07-24 13:54:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-29 12:42:48 +00:00
|
|
|
if err := server.morphClient.SetGroupSignerScope(); err != nil {
|
|
|
|
morphChain.log.Info("failed to set group signer scope, continue with Global", zap.Error(err))
|
|
|
|
}
|
2020-07-24 13:54:03 +00:00
|
|
|
|
2021-09-06 12:58:40 +00:00
|
|
|
server.withoutMainNet = cfg.GetBool("without_mainnet")
|
2021-07-23 14:37:56 +00:00
|
|
|
|
2021-09-06 12:58:40 +00:00
|
|
|
if server.withoutMainNet {
|
2021-02-21 09:26:18 +00:00
|
|
|
// This works as long as event Listener starts listening loop once,
|
|
|
|
// otherwise Server.Start will run two similar routines.
|
|
|
|
// This behavior most likely will not change.
|
|
|
|
server.mainnetListener = server.morphListener
|
|
|
|
server.mainnetClient = server.morphClient
|
|
|
|
} else {
|
|
|
|
mainnetChain := morphChain
|
|
|
|
mainnetChain.name = mainnetPrefix
|
2021-08-05 14:17:07 +00:00
|
|
|
mainnetChain.sgn = &transaction.Signer{Scopes: transaction.CalledByEntry}
|
2021-02-21 09:26:18 +00:00
|
|
|
|
2021-09-06 13:01:50 +00:00
|
|
|
fromMainChainBlock, err := server.persistate.UInt32(persistateMainChainLastBlockKey)
|
|
|
|
if err != nil {
|
|
|
|
fromMainChainBlock = 0
|
|
|
|
log.Warn("can't get last processed main chain block number", zap.String("error", err.Error()))
|
|
|
|
}
|
|
|
|
mainnetChain.from = fromMainChainBlock
|
|
|
|
|
2021-02-21 09:26:18 +00:00
|
|
|
// create mainnet listener
|
|
|
|
server.mainnetListener, err = createListener(ctx, mainnetChain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 13:54:03 +00:00
|
|
|
|
2021-02-21 09:26:18 +00:00
|
|
|
// create mainnet client
|
2021-07-23 14:37:56 +00:00
|
|
|
server.mainnetClient, err = createClient(ctx, mainnetChain)
|
2021-02-21 09:26:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
2021-07-23 14:37:56 +00:00
|
|
|
server.mainNotaryConfig, server.sideNotaryConfig = parseNotaryConfigs(
|
|
|
|
cfg,
|
|
|
|
server.morphClient.ProbeNotary(),
|
2021-09-06 12:58:40 +00:00
|
|
|
!server.withoutMainNet && server.mainnetClient.ProbeNotary(), // if mainnet disabled then notary flag must be disabled too
|
2021-07-23 14:37:56 +00:00
|
|
|
)
|
|
|
|
|
2021-08-19 14:18:41 +00:00
|
|
|
log.Debug("notary support",
|
|
|
|
zap.Bool("sidechain_enabled", !server.sideNotaryConfig.disabled),
|
|
|
|
zap.Bool("mainchain_enabled", !server.mainNotaryConfig.disabled),
|
|
|
|
)
|
|
|
|
|
2021-07-23 14:37:56 +00:00
|
|
|
// get all script hashes of contracts
|
|
|
|
server.contracts, err = parseContracts(
|
|
|
|
cfg,
|
2021-08-31 13:02:15 +00:00
|
|
|
server.morphClient,
|
2021-09-06 12:58:40 +00:00
|
|
|
server.withoutMainNet,
|
2021-07-23 14:37:56 +00:00
|
|
|
server.mainNotaryConfig.disabled,
|
|
|
|
server.sideNotaryConfig.disabled,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !server.sideNotaryConfig.disabled {
|
|
|
|
// enable notary support in the side client
|
|
|
|
err = server.morphClient.EnableNotarySupport(
|
|
|
|
client.WithProxyContract(server.contracts.proxy),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not enable side chain notary support: %w", err)
|
|
|
|
}
|
2021-08-15 18:17:10 +00:00
|
|
|
|
|
|
|
server.morphListener.EnableNotarySupport(server.contracts.proxy, server.morphClient.Committee, server.morphClient)
|
2021-07-23 14:37:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !server.mainNotaryConfig.disabled {
|
|
|
|
// enable notary support in the main client
|
|
|
|
err = server.mainnetClient.EnableNotarySupport(
|
|
|
|
client.WithProxyContract(server.contracts.processing),
|
|
|
|
client.WithAlphabetSource(server.morphClient.Committee),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not enable main chain notary support: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// parse default validators
|
|
|
|
server.predefinedValidators, err = parsePredefinedValidators(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("ir: can't parse predefined validators list: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-05-31 08:55:38 +00:00
|
|
|
server.pubKey = server.key.PublicKey().Bytes()
|
2020-12-22 00:28:42 +00:00
|
|
|
|
2020-12-24 09:47:20 +00:00
|
|
|
auditPool, err := ants.NewPool(cfg.GetInt("audit.task.exec_pool_size"))
|
2020-12-22 00:28:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-21 10:39:01 +00:00
|
|
|
fee := server.feeConfig.SideChainFee()
|
|
|
|
|
2021-07-01 16:59:34 +00:00
|
|
|
// do not use TryNotary() in audit wrapper
|
|
|
|
// audit operations do not require multisignatures
|
2022-01-31 12:32:51 +00:00
|
|
|
server.auditClient, err = auditClient.NewFromMorph(server.morphClient, server.contracts.audit, fee)
|
2020-12-22 00:28:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-12-07 09:54:21 +00:00
|
|
|
// form morph container client's options
|
2022-01-31 13:34:01 +00:00
|
|
|
morphCnrOpts := make([]cntClient.Option, 0, 3)
|
2021-12-07 09:54:21 +00:00
|
|
|
morphCnrOpts = append(morphCnrOpts,
|
2022-01-31 13:34:01 +00:00
|
|
|
cntClient.TryNotary(),
|
|
|
|
cntClient.AsAlphabet(),
|
2021-12-07 09:54:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if server.sideNotaryConfig.disabled {
|
|
|
|
// in non-notary environments we customize fee for named container registration
|
|
|
|
// because it takes much more additional GAS than other operations.
|
|
|
|
morphCnrOpts = append(morphCnrOpts,
|
2022-01-31 13:34:01 +00:00
|
|
|
cntClient.WithCustomFeeForNamedPut(server.feeConfig.NamedContainerRegistrationFee()),
|
2021-12-07 09:54:21 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-01-31 13:34:01 +00:00
|
|
|
cnrClient, err := cntClient.NewFromMorph(server.morphClient, server.contracts.container, fee, morphCnrOpts...)
|
2021-01-28 19:51:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-31 11:58:55 +00:00
|
|
|
server.netmapClient, err = nmClient.NewFromMorph(server.morphClient, server.contracts.netmap, fee, nmClient.TryNotary(), nmClient.AsAlphabet())
|
2021-01-28 19:51:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-31 09:24:25 +00:00
|
|
|
server.balanceClient, err = balanceClient.NewFromMorph(server.morphClient, server.contracts.balance, fee, balanceClient.TryNotary(), balanceClient.AsAlphabet())
|
2021-01-28 19:51:41 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-31 12:19:10 +00:00
|
|
|
repClient, err := repClient.NewFromMorph(server.morphClient, server.contracts.reputation, fee, repClient.TryNotary(), repClient.AsAlphabet())
|
2021-03-31 15:41:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-31 11:04:59 +00:00
|
|
|
neofsIDClient, err := neofsid.NewFromMorph(server.morphClient, server.contracts.neofsID, fee, neofsid.TryNotary(), neofsid.AsAlphabet())
|
2021-05-19 12:46:45 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-01-31 10:15:36 +00:00
|
|
|
neofsCli, err := neofsClient.NewFromMorph(server.mainnetClient, server.contracts.neofs,
|
|
|
|
server.feeConfig.MainChainFee(), neofsClient.TryNotary(), neofsClient.AsAlphabet())
|
2021-06-01 11:35:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-11-28 12:57:52 +00:00
|
|
|
// initialize morph client of Subnet contract
|
|
|
|
clientMode := morphsubnet.NotaryAlphabet
|
|
|
|
|
|
|
|
if server.sideNotaryConfig.disabled {
|
|
|
|
clientMode = morphsubnet.NonNotary
|
|
|
|
}
|
|
|
|
|
|
|
|
subnetInitPrm := morphsubnet.InitPrm{}
|
|
|
|
subnetInitPrm.SetBaseClient(server.morphClient)
|
|
|
|
subnetInitPrm.SetContractAddress(server.contracts.subnet)
|
|
|
|
subnetInitPrm.SetMode(clientMode)
|
|
|
|
|
|
|
|
subnetClient := &morphsubnet.Client{}
|
|
|
|
err = subnetClient.Init(subnetInitPrm)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not initialize subnet client: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-07-22 09:45:25 +00:00
|
|
|
var irf irFetcher
|
|
|
|
|
2022-01-11 09:57:07 +00:00
|
|
|
if server.withoutMainNet || !server.mainNotaryConfig.disabled {
|
|
|
|
// if mainchain is disabled we should use NeoFSAlphabetList client method according to its docs
|
|
|
|
// (naming `...WithNotary` will not always be correct)
|
2021-07-22 09:45:25 +00:00
|
|
|
irf = NewIRFetcherWithNotary(server.morphClient)
|
|
|
|
} else {
|
|
|
|
irf = NewIRFetcherWithoutNotary(server.netmapClient)
|
|
|
|
}
|
|
|
|
|
|
|
|
server.statusIndex = newInnerRingIndexer(
|
|
|
|
server.morphClient,
|
|
|
|
irf,
|
|
|
|
server.key.PublicKey(),
|
|
|
|
cfg.GetDuration("indexer.cache_timeout"),
|
|
|
|
)
|
|
|
|
|
2021-02-02 11:12:41 +00:00
|
|
|
// create global runtime config reader
|
2021-05-31 11:50:11 +00:00
|
|
|
globalConfig := config.NewGlobalConfigReader(cfg, server.netmapClient)
|
2021-02-02 11:12:41 +00:00
|
|
|
|
2020-12-23 08:44:29 +00:00
|
|
|
clientCache := newClientCache(&clientCacheParams{
|
|
|
|
Log: log,
|
2021-05-31 08:55:38 +00:00
|
|
|
Key: &server.key.PrivateKey,
|
2020-12-23 08:44:29 +00:00
|
|
|
SGTimeout: cfg.GetDuration("audit.timeout.get"),
|
|
|
|
HeadTimeout: cfg.GetDuration("audit.timeout.head"),
|
|
|
|
RangeTimeout: cfg.GetDuration("audit.timeout.rangehash"),
|
|
|
|
})
|
2020-12-22 12:14:50 +00:00
|
|
|
|
2021-05-31 06:51:06 +00:00
|
|
|
server.registerNoErrCloser(clientCache.cache.CloseAll)
|
|
|
|
|
2020-12-23 16:53:11 +00:00
|
|
|
pdpPoolSize := cfg.GetInt("audit.pdp.pairs_pool_size")
|
2020-12-25 07:45:59 +00:00
|
|
|
porPoolSize := cfg.GetInt("audit.por.pool_size")
|
2020-12-23 16:53:11 +00:00
|
|
|
|
2021-01-29 07:42:40 +00:00
|
|
|
// create audit processor dependencies
|
2020-12-22 00:28:42 +00:00
|
|
|
auditTaskManager := audittask.New(
|
|
|
|
audittask.WithQueueCapacity(cfg.GetUint32("audit.task.queue_capacity")),
|
|
|
|
audittask.WithWorkerPool(auditPool),
|
|
|
|
audittask.WithLogger(log),
|
2020-12-22 12:14:50 +00:00
|
|
|
audittask.WithContainerCommunicator(clientCache),
|
2020-12-23 16:53:11 +00:00
|
|
|
audittask.WithMaxPDPSleepInterval(cfg.GetDuration("audit.pdp.max_sleep_interval")),
|
|
|
|
audittask.WithPDPWorkerPoolGenerator(func() (util2.WorkerPool, error) {
|
2020-12-24 09:47:20 +00:00
|
|
|
return ants.NewPool(pdpPoolSize)
|
2020-12-23 16:53:11 +00:00
|
|
|
}),
|
2020-12-24 11:24:25 +00:00
|
|
|
audittask.WithPoRWorkerPoolGenerator(func() (util2.WorkerPool, error) {
|
|
|
|
return ants.NewPool(porPoolSize)
|
|
|
|
}),
|
2020-12-22 00:28:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
server.workers = append(server.workers, auditTaskManager.Listen)
|
|
|
|
|
2020-12-18 09:27:19 +00:00
|
|
|
// create audit processor
|
|
|
|
auditProcessor, err := audit.New(&audit.Params{
|
2021-05-31 11:50:11 +00:00
|
|
|
Log: log,
|
|
|
|
NetmapClient: server.netmapClient,
|
|
|
|
ContainerClient: cnrClient,
|
|
|
|
IRList: server,
|
2021-10-27 12:12:05 +00:00
|
|
|
SGSource: clientCache,
|
2021-05-31 11:50:11 +00:00
|
|
|
Key: &server.key.PrivateKey,
|
|
|
|
RPCSearchTimeout: cfg.GetDuration("audit.timeout.search"),
|
|
|
|
TaskManager: auditTaskManager,
|
|
|
|
Reporter: server,
|
2020-12-18 09:27:19 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-01-29 07:42:40 +00:00
|
|
|
// create settlement processor dependencies
|
2021-02-01 12:40:07 +00:00
|
|
|
settlementDeps := &settlementDeps{
|
2021-06-03 15:55:43 +00:00
|
|
|
globalConfig: globalConfig,
|
|
|
|
log: server.log,
|
2022-01-31 13:34:01 +00:00
|
|
|
cnrSrc: cntClient.AsContainerSource(cnrClient),
|
2021-06-03 15:55:43 +00:00
|
|
|
auditClient: server.auditClient,
|
2021-05-31 11:50:11 +00:00
|
|
|
nmSrc: server.netmapClient,
|
2021-06-03 15:55:43 +00:00
|
|
|
clientCache: clientCache,
|
2021-05-31 11:50:11 +00:00
|
|
|
balanceClient: server.balanceClient,
|
2021-01-28 19:51:41 +00:00
|
|
|
}
|
|
|
|
|
2021-02-01 12:40:07 +00:00
|
|
|
auditCalcDeps := &auditSettlementDeps{
|
|
|
|
settlementDeps: settlementDeps,
|
|
|
|
}
|
|
|
|
|
2021-02-01 16:20:33 +00:00
|
|
|
basicSettlementDeps := &basicIncomeSettlementDeps{
|
|
|
|
settlementDeps: settlementDeps,
|
|
|
|
cnrClient: cnrClient,
|
|
|
|
}
|
|
|
|
|
2021-01-28 19:51:41 +00:00
|
|
|
auditSettlementCalc := auditSettlement.NewCalculator(
|
|
|
|
&auditSettlement.CalculatorPrm{
|
|
|
|
ResultStorage: auditCalcDeps,
|
|
|
|
ContainerStorage: auditCalcDeps,
|
|
|
|
PlacementCalculator: auditCalcDeps,
|
|
|
|
SGStorage: auditCalcDeps,
|
|
|
|
AccountStorage: auditCalcDeps,
|
|
|
|
Exchanger: auditCalcDeps,
|
2021-04-07 10:53:13 +00:00
|
|
|
AuditFeeFetcher: auditCalcDeps,
|
2021-01-28 19:51:41 +00:00
|
|
|
},
|
|
|
|
auditSettlement.WithLogger(server.log),
|
|
|
|
)
|
|
|
|
|
2021-01-29 07:42:40 +00:00
|
|
|
// create settlement processor
|
2021-01-28 19:51:41 +00:00
|
|
|
settlementProcessor := settlement.New(
|
|
|
|
settlement.Prm{
|
|
|
|
AuditProcessor: (*auditSettlementCalculator)(auditSettlementCalc),
|
2021-02-01 16:20:33 +00:00
|
|
|
BasicIncome: &basicSettlementConstructor{dep: basicSettlementDeps},
|
|
|
|
State: server,
|
2021-01-28 19:51:41 +00:00
|
|
|
},
|
|
|
|
settlement.WithLogger(server.log),
|
|
|
|
)
|
|
|
|
|
2021-02-09 15:03:43 +00:00
|
|
|
locodeValidator, err := server.newLocodeValidator(cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-11-28 12:57:52 +00:00
|
|
|
subnetValidator, err := subnetvalidator.New(
|
|
|
|
subnetvalidator.Prm{
|
|
|
|
SubnetClient: subnetClient,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-04 10:47:20 +00:00
|
|
|
var alphaSync event.Handler
|
|
|
|
|
2021-09-30 08:46:37 +00:00
|
|
|
if server.withoutMainNet || cfg.GetBool("governance.disable") {
|
2021-05-04 10:47:20 +00:00
|
|
|
alphaSync = func(event.Event) {
|
|
|
|
log.Debug("alphabet keys sync is disabled")
|
|
|
|
}
|
|
|
|
} else {
|
2021-07-09 11:33:11 +00:00
|
|
|
// create governance processor
|
|
|
|
governanceProcessor, err := governance.New(&governance.Params{
|
|
|
|
Log: log,
|
2022-01-31 10:15:36 +00:00
|
|
|
NeoFSClient: neofsCli,
|
2021-07-09 11:33:11 +00:00
|
|
|
NetmapClient: server.netmapClient,
|
|
|
|
AlphabetState: server,
|
|
|
|
EpochState: server,
|
|
|
|
Voter: server,
|
2021-07-22 10:04:37 +00:00
|
|
|
IRFetcher: irf,
|
2021-07-09 11:33:11 +00:00
|
|
|
MorphClient: server.morphClient,
|
|
|
|
MainnetClient: server.mainnetClient,
|
|
|
|
NotaryDisabled: server.sideNotaryConfig.disabled,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-05-04 10:47:20 +00:00
|
|
|
alphaSync = governanceProcessor.HandleAlphabetSync
|
2021-05-18 07:40:21 +00:00
|
|
|
err = bindMainnetProcessor(governanceProcessor, server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-05-04 10:47:20 +00:00
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
// create netmap processor
|
2021-07-21 15:15:56 +00:00
|
|
|
server.netmapProcessor, err = netmap.New(&netmap.Params{
|
2020-10-29 16:09:45 +00:00
|
|
|
Log: log,
|
|
|
|
PoolSize: cfg.GetInt("workers.netmap"),
|
2021-05-31 11:50:11 +00:00
|
|
|
NetmapClient: server.netmapClient,
|
2021-01-29 07:42:40 +00:00
|
|
|
EpochTimer: server,
|
2020-10-29 16:09:45 +00:00
|
|
|
EpochState: server,
|
2021-03-23 15:20:44 +00:00
|
|
|
AlphabetState: server,
|
2020-10-29 16:09:45 +00:00
|
|
|
CleanupEnabled: cfg.GetBool("netmap_cleaner.enabled"),
|
|
|
|
CleanupThreshold: cfg.GetUint64("netmap_cleaner.threshold"),
|
2021-01-29 07:48:47 +00:00
|
|
|
ContainerWrapper: cnrClient,
|
2021-01-29 07:42:40 +00:00
|
|
|
HandleAudit: server.onlyActiveEventHandler(
|
|
|
|
auditProcessor.StartAuditHandler(),
|
|
|
|
),
|
2021-11-01 15:55:25 +00:00
|
|
|
NotaryDepositHandler: server.onlyAlphabetEventHandler(
|
|
|
|
server.notaryHandler,
|
|
|
|
),
|
2021-03-23 15:20:44 +00:00
|
|
|
AuditSettlementsHandler: server.onlyAlphabetEventHandler(
|
2021-01-29 07:42:40 +00:00
|
|
|
settlementProcessor.HandleAuditEvent,
|
|
|
|
),
|
2021-05-04 10:47:20 +00:00
|
|
|
AlphabetSyncHandler: alphaSync,
|
2021-06-18 10:42:03 +00:00
|
|
|
NodeValidator: nodevalidator.New(
|
|
|
|
addrvalidator.New(),
|
|
|
|
locodeValidator,
|
2021-11-28 12:57:52 +00:00
|
|
|
subnetValidator,
|
2021-06-18 10:42:03 +00:00
|
|
|
),
|
2021-09-08 13:54:45 +00:00
|
|
|
NotaryDisabled: server.sideNotaryConfig.disabled,
|
2021-11-26 14:16:03 +00:00
|
|
|
SubnetContract: &server.contracts.subnet,
|
2020-07-24 13:54:03 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-21 15:15:56 +00:00
|
|
|
err = bindMorphProcessor(server.netmapProcessor, server)
|
2020-07-24 13:54:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-11 12:14:08 +00:00
|
|
|
// container processor
|
|
|
|
containerProcessor, err := container.New(&container.Params{
|
2021-09-15 10:50:07 +00:00
|
|
|
Log: log,
|
|
|
|
PoolSize: cfg.GetInt("workers.container"),
|
|
|
|
AlphabetState: server,
|
|
|
|
ContainerClient: cnrClient,
|
|
|
|
NeoFSIDClient: neofsIDClient,
|
|
|
|
NetworkState: server.netmapClient,
|
|
|
|
NotaryDisabled: server.sideNotaryConfig.disabled,
|
2021-12-01 12:45:35 +00:00
|
|
|
SubnetClient: subnetClient,
|
2020-08-11 12:14:08 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bindMorphProcessor(containerProcessor, server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 13:54:03 +00:00
|
|
|
|
|
|
|
// create balance processor
|
|
|
|
balanceProcessor, err := balance.New(&balance.Params{
|
2021-09-15 10:50:07 +00:00
|
|
|
Log: log,
|
|
|
|
PoolSize: cfg.GetInt("workers.balance"),
|
2022-01-31 10:15:36 +00:00
|
|
|
NeoFSClient: neofsCli,
|
2021-09-15 10:50:07 +00:00
|
|
|
AlphabetState: server,
|
|
|
|
Converter: &server.precision,
|
2020-07-24 13:54:03 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bindMorphProcessor(balanceProcessor, server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-06 12:58:40 +00:00
|
|
|
if !server.withoutMainNet {
|
2021-07-09 11:33:11 +00:00
|
|
|
// create mainnnet neofs processor
|
|
|
|
neofsProcessor, err := neofs.New(&neofs.Params{
|
|
|
|
Log: log,
|
|
|
|
PoolSize: cfg.GetInt("workers.neofs"),
|
|
|
|
NeoFSContract: server.contracts.neofs,
|
|
|
|
NeoFSIDClient: neofsIDClient,
|
|
|
|
BalanceClient: server.balanceClient,
|
|
|
|
NetmapClient: server.netmapClient,
|
|
|
|
MorphClient: server.morphClient,
|
|
|
|
EpochState: server,
|
|
|
|
AlphabetState: server,
|
|
|
|
Converter: &server.precision,
|
|
|
|
MintEmitCacheSize: cfg.GetInt("emit.mint.cache_size"),
|
|
|
|
MintEmitThreshold: cfg.GetUint64("emit.mint.threshold"),
|
|
|
|
MintEmitValue: fixedn.Fixed8(cfg.GetInt64("emit.mint.value")),
|
|
|
|
GasBalanceThreshold: cfg.GetInt64("emit.gas.balance_threshold"),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 13:54:03 +00:00
|
|
|
|
2021-07-09 11:33:11 +00:00
|
|
|
err = bindMainnetProcessor(neofsProcessor, server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
2020-10-12 10:26:05 +00:00
|
|
|
// create alphabet processor
|
2021-01-29 07:42:40 +00:00
|
|
|
alphabetProcessor, err := alphabet.New(&alphabet.Params{
|
2020-10-12 10:26:05 +00:00
|
|
|
Log: log,
|
|
|
|
PoolSize: cfg.GetInt("workers.alphabet"),
|
2020-10-13 14:25:25 +00:00
|
|
|
AlphabetContracts: server.contracts.alphabet,
|
2021-05-31 11:50:11 +00:00
|
|
|
NetmapClient: server.netmapClient,
|
2020-10-12 10:26:05 +00:00
|
|
|
MorphClient: server.morphClient,
|
|
|
|
IRList: server,
|
2020-11-03 08:12:39 +00:00
|
|
|
StorageEmission: cfg.GetUint64("emit.storage.amount"),
|
2020-10-12 10:26:05 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bindMorphProcessor(alphabetProcessor, server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-31 15:41:47 +00:00
|
|
|
// create reputation processor
|
|
|
|
reputationProcessor, err := reputation.New(&reputation.Params{
|
2021-09-15 10:50:07 +00:00
|
|
|
Log: log,
|
|
|
|
PoolSize: cfg.GetInt("workers.reputation"),
|
|
|
|
EpochState: server,
|
|
|
|
AlphabetState: server,
|
|
|
|
ReputationWrapper: repClient,
|
2021-06-11 17:13:24 +00:00
|
|
|
ManagerBuilder: reputationcommon.NewManagerBuilder(
|
|
|
|
reputationcommon.ManagersPrm{
|
2021-05-31 11:50:11 +00:00
|
|
|
NetMapSource: server.netmapClient,
|
2021-06-11 17:13:24 +00:00
|
|
|
},
|
|
|
|
),
|
2021-09-08 15:20:02 +00:00
|
|
|
NotaryDisabled: server.sideNotaryConfig.disabled,
|
2021-03-31 15:41:47 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = bindMorphProcessor(reputationProcessor, server)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-01-29 07:42:40 +00:00
|
|
|
// initialize epoch timers
|
|
|
|
server.epochTimer = newEpochTimer(&epochTimerArgs{
|
2021-02-02 14:17:51 +00:00
|
|
|
l: server.log,
|
2021-11-01 15:55:25 +00:00
|
|
|
newEpochHandlers: server.newEpochTickHandlers(),
|
2021-02-02 14:17:51 +00:00
|
|
|
cnrWrapper: cnrClient,
|
|
|
|
epoch: server,
|
|
|
|
stopEstimationDMul: cfg.GetUint32("timers.stop_estimation.mul"),
|
|
|
|
stopEstimationDDiv: cfg.GetUint32("timers.stop_estimation.div"),
|
|
|
|
collectBasicIncome: subEpochEventHandler{
|
|
|
|
handler: settlementProcessor.HandleIncomeCollectionEvent,
|
|
|
|
durationMul: cfg.GetUint32("timers.collect_basic_income.mul"),
|
|
|
|
durationDiv: cfg.GetUint32("timers.collect_basic_income.div"),
|
|
|
|
},
|
|
|
|
distributeBasicIncome: subEpochEventHandler{
|
|
|
|
handler: settlementProcessor.HandleIncomeDistributionEvent,
|
|
|
|
durationMul: cfg.GetUint32("timers.distribute_basic_income.mul"),
|
|
|
|
durationDiv: cfg.GetUint32("timers.distribute_basic_income.div"),
|
|
|
|
},
|
2021-01-29 07:42:40 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
server.addBlockTimer(server.epochTimer)
|
|
|
|
|
|
|
|
// initialize emission timer
|
|
|
|
emissionTimer := newEmissionTimer(&emitTimerArgs{
|
|
|
|
ap: alphabetProcessor,
|
|
|
|
emitDuration: cfg.GetUint32("timers.emit"),
|
|
|
|
})
|
|
|
|
|
|
|
|
server.addBlockTimer(emissionTimer)
|
|
|
|
|
2021-06-09 15:49:10 +00:00
|
|
|
controlSvcEndpoint := cfg.GetString("control.grpc.endpoint")
|
|
|
|
if controlSvcEndpoint != "" {
|
|
|
|
authKeysStr := cfg.GetStringSlice("control.authorized_keys")
|
|
|
|
authKeys := make([][]byte, 0, len(authKeysStr))
|
|
|
|
|
|
|
|
for i := range authKeysStr {
|
|
|
|
key, err := hex.DecodeString(authKeysStr[i])
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not parse Control authorized key %s: %w",
|
|
|
|
authKeysStr[i],
|
|
|
|
err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
authKeys = append(authKeys, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
var p controlsrv.Prm
|
|
|
|
|
|
|
|
p.SetPrivateKey(*server.key)
|
|
|
|
p.SetHealthChecker(server)
|
|
|
|
|
|
|
|
controlSvc := controlsrv.New(p,
|
|
|
|
controlsrv.WithAllowedKeys(authKeys),
|
|
|
|
)
|
|
|
|
|
|
|
|
grpcControlSrv := grpc.NewServer()
|
|
|
|
control.RegisterControlServiceServer(grpcControlSrv, controlSvc)
|
|
|
|
|
|
|
|
server.runners = append(server.runners, func(ch chan<- error) {
|
|
|
|
lis, err := net.Listen("tcp", controlSvcEndpoint)
|
|
|
|
if err != nil {
|
|
|
|
ch <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
ch <- grpcControlSrv.Serve(lis)
|
|
|
|
}()
|
|
|
|
})
|
|
|
|
|
|
|
|
server.registerNoErrCloser(grpcControlSrv.GracefulStop)
|
|
|
|
} else {
|
|
|
|
log.Info("no Control server endpoint specified, service is disabled")
|
|
|
|
}
|
|
|
|
|
2021-11-26 12:19:20 +00:00
|
|
|
server.initSubnet(subnetConfig{
|
|
|
|
queueSize: cfg.GetUint32("workers.subnet"),
|
|
|
|
})
|
|
|
|
|
2021-12-27 12:24:05 +00:00
|
|
|
if cfg.GetString("metrics.address") != "" {
|
|
|
|
m := metrics.NewInnerRingMetrics()
|
|
|
|
server.metrics = &m
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
return server, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func createListener(ctx context.Context, p *chainParams) (event.Listener, error) {
|
2021-09-15 15:57:43 +00:00
|
|
|
// config name left unchanged for compatibility, may be its better to rename it to "endpoints"
|
|
|
|
endpoints := p.cfg.GetStringSlice(p.name + ".endpoint.notification")
|
|
|
|
if len(endpoints) == 0 {
|
|
|
|
return nil, errors.New("missing morph notification endpoints")
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
sub subscriber.Subscriber
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
dialTimeout := p.cfg.GetDuration(p.name + ".dial_timeout")
|
|
|
|
|
|
|
|
for i := range endpoints {
|
|
|
|
sub, err = subscriber.New(ctx, &subscriber.Params{
|
|
|
|
Log: p.log,
|
|
|
|
Endpoint: endpoints[i],
|
|
|
|
DialTimeout: dialTimeout,
|
|
|
|
StartFromBlock: p.from,
|
|
|
|
})
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
p.log.Info("failed to establish websocket neo event listener, trying another",
|
|
|
|
zap.String("endpoint", endpoints[i]),
|
|
|
|
zap.String("error", err.Error()),
|
|
|
|
)
|
2020-07-24 13:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
listener, err := event.NewListener(event.ListenerParams{
|
|
|
|
Logger: p.log,
|
|
|
|
Subscriber: sub,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return listener, err
|
|
|
|
}
|
|
|
|
|
2021-07-23 14:37:56 +00:00
|
|
|
func createClient(ctx context.Context, p *chainParams) (*client.Client, error) {
|
2021-08-26 07:59:02 +00:00
|
|
|
// config name left unchanged for compatibility, may be its better to rename it to "endpoints" or "clients"
|
|
|
|
endpoints := p.cfg.GetStringSlice(p.name + ".endpoint.client")
|
|
|
|
if len(endpoints) == 0 {
|
|
|
|
return nil, fmt.Errorf("%s chain client endpoints not provided", p.name)
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
return client.New(
|
2021-05-31 08:55:40 +00:00
|
|
|
p.key,
|
2021-08-26 07:59:02 +00:00
|
|
|
endpoints[0],
|
2020-07-24 13:54:03 +00:00
|
|
|
client.WithContext(ctx),
|
|
|
|
client.WithLogger(p.log),
|
2021-03-13 15:22:27 +00:00
|
|
|
client.WithDialTimeout(p.cfg.GetDuration(p.name+".dial_timeout")),
|
2021-08-05 14:17:07 +00:00
|
|
|
client.WithSigner(p.sgn),
|
2021-08-26 07:59:02 +00:00
|
|
|
client.WithExtraEndpoints(endpoints[1:]),
|
2020-07-24 13:54:03 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-03-25 07:34:27 +00:00
|
|
|
func parsePredefinedValidators(cfg *viper.Viper) (keys.PublicKeys, error) {
|
2020-11-13 11:47:23 +00:00
|
|
|
publicKeyStrings := cfg.GetStringSlice("morph.validators")
|
|
|
|
|
|
|
|
return ParsePublicKeysFromStrings(publicKeyStrings)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParsePublicKeysFromStrings returns slice of neo public keys from slice
|
|
|
|
// of hex encoded strings.
|
2021-03-25 07:34:27 +00:00
|
|
|
func ParsePublicKeysFromStrings(pubKeys []string) (keys.PublicKeys, error) {
|
|
|
|
publicKeys := make(keys.PublicKeys, 0, len(pubKeys))
|
2020-11-13 11:47:23 +00:00
|
|
|
|
|
|
|
for i := range pubKeys {
|
|
|
|
key, err := keys.NewPublicKeyFromString(pubKeys[i])
|
|
|
|
if err != nil {
|
2021-05-18 08:12:51 +00:00
|
|
|
return nil, fmt.Errorf("can't decode public key: %w", err)
|
2020-11-13 11:47:23 +00:00
|
|
|
}
|
|
|
|
|
2021-03-25 07:34:27 +00:00
|
|
|
publicKeys = append(publicKeys, key)
|
2020-11-13 11:47:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return publicKeys, nil
|
|
|
|
}
|
|
|
|
|
2020-10-13 14:25:25 +00:00
|
|
|
func (s *Server) initConfigFromBlockchain() error {
|
2020-07-24 13:54:03 +00:00
|
|
|
// get current epoch
|
2021-05-31 11:50:11 +00:00
|
|
|
epoch, err := s.netmapClient.Epoch()
|
2021-05-21 07:45:15 +00:00
|
|
|
if err != nil {
|
2021-10-11 17:09:52 +00:00
|
|
|
return fmt.Errorf("can't read epoch number: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get current epoch duration
|
|
|
|
epochDuration, err := s.netmapClient.EpochDuration()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("can't read epoch duration: %w", err)
|
2021-05-21 07:45:15 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 10:49:34 +00:00
|
|
|
// get balance precision
|
2021-05-31 11:50:11 +00:00
|
|
|
balancePrecision, err := s.balanceClient.Decimals()
|
2020-10-27 10:49:34 +00:00
|
|
|
if err != nil {
|
2021-05-18 08:12:51 +00:00
|
|
|
return fmt.Errorf("can't read balance contract precision: %w", err)
|
2020-10-27 10:49:34 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 11:04:09 +00:00
|
|
|
s.epochCounter.Store(epoch)
|
|
|
|
s.epochDuration.Store(epochDuration)
|
|
|
|
s.precision.SetBalancePrecision(balancePrecision)
|
|
|
|
|
2021-07-21 15:15:56 +00:00
|
|
|
// get next epoch delta tick
|
|
|
|
s.initialEpochTickDelta, err = s.nextEpochBlockDelta()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
s.log.Debug("read config from blockchain",
|
2020-10-12 09:13:19 +00:00
|
|
|
zap.Bool("active", s.IsActive()),
|
2021-03-23 15:20:44 +00:00
|
|
|
zap.Bool("alphabet", s.IsAlphabet()),
|
2021-05-31 11:50:11 +00:00
|
|
|
zap.Uint64("epoch", epoch),
|
|
|
|
zap.Uint32("precision", balancePrecision),
|
2021-07-21 15:15:56 +00:00
|
|
|
zap.Uint32("init_epoch_tick_delta", s.initialEpochTickDelta),
|
2020-07-24 13:54:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2021-01-22 15:49:52 +00:00
|
|
|
|
2021-07-21 15:15:56 +00:00
|
|
|
func (s *Server) nextEpochBlockDelta() (uint32, error) {
|
|
|
|
epochBlock, err := s.netmapClient.LastEpochBlock()
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("can't read last epoch block: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
blockHeight, err := s.morphClient.BlockCount()
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("can't get side chain height: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-10-14 11:04:09 +00:00
|
|
|
delta := uint32(s.epochDuration.Load()) + epochBlock
|
2021-07-21 15:15:56 +00:00
|
|
|
if delta < blockHeight {
|
|
|
|
return 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return delta - blockHeight, nil
|
|
|
|
}
|
|
|
|
|
2021-01-29 07:42:40 +00:00
|
|
|
// onlyActiveHandler wrapper around event handler that executes it
|
|
|
|
// only if inner ring node state is active.
|
2021-01-26 10:33:28 +00:00
|
|
|
func (s *Server) onlyActiveEventHandler(f event.Handler) event.Handler {
|
|
|
|
return func(ev event.Event) {
|
|
|
|
if s.IsActive() {
|
|
|
|
f(ev)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-24 15:46:01 +00:00
|
|
|
|
2021-03-23 15:20:44 +00:00
|
|
|
// onlyAlphabet wrapper around event handler that executes it
|
|
|
|
// only if inner ring node is alphabet node.
|
|
|
|
func (s *Server) onlyAlphabetEventHandler(f event.Handler) event.Handler {
|
|
|
|
return func(ev event.Event) {
|
|
|
|
if s.IsAlphabet() {
|
|
|
|
f(ev)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-11 17:10:45 +00:00
|
|
|
|
2021-11-01 15:55:25 +00:00
|
|
|
func (s *Server) newEpochTickHandlers() []newEpochHandler {
|
2021-10-11 17:10:45 +00:00
|
|
|
newEpochHandlers := []newEpochHandler{
|
|
|
|
func() {
|
|
|
|
s.netmapProcessor.HandleNewEpochTick(timerEvent.NewEpochTick{})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return newEpochHandlers
|
|
|
|
}
|