[#708] innerring: Synchronize initial epoch tick

When Inner Ring node starts, it should sync nearest epoch tick
event based on the block of the latest epoch. Otherwise epoch
ticking can be stopped, because ballots or notary transactions
are valid for limited period of time.

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2021-07-21 18:15:56 +03:00 committed by Alex Vanin
parent 67b3682348
commit 62efa3f098

View file

@ -25,6 +25,7 @@ import (
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/reputation"
"github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement"
auditSettlement "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/settlement/audit"
timerEvent "github.com/nspcc-dev/neofs-node/pkg/innerring/timers"
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
auditWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/audit/wrapper"
balanceWrapper "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance/wrapper"
@ -83,6 +84,10 @@ type (
pubKey []byte
contracts *contracts
predefinedValidators keys.PublicKeys
initialEpochTickDelta uint32
// runtime processors
netmapProcessor *netmap.Processor
workers []func(context.Context)
@ -201,6 +206,14 @@ func (s *Server) Start(ctx context.Context, intError chan<- error) (err error) {
zap.String("error", err.Error()))
}
// tick initial epoch
initialEpochTicker := timer.NewOneTickTimer(
timer.StaticBlockMeter(s.initialEpochTickDelta),
func() {
s.netmapProcessor.HandleNewEpochTick(timerEvent.NewEpochTick{})
})
s.addBlockTimer(initialEpochTicker)
morphErr := make(chan error)
mainnnetErr := make(chan error)
@ -564,7 +577,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
}
// create netmap processor
netmapProcessor, err := netmap.New(&netmap.Params{
server.netmapProcessor, err = netmap.New(&netmap.Params{
Log: log,
PoolSize: cfg.GetInt("workers.netmap"),
NetmapContract: server.contracts.netmap,
@ -591,7 +604,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
return nil, err
}
err = bindMorphProcessor(netmapProcessor, server)
err = bindMorphProcessor(server.netmapProcessor, server)
if err != nil {
return nil, err
}
@ -708,7 +721,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper) (*Server, error
// initialize epoch timers
server.epochTimer = newEpochTimer(&epochTimerArgs{
l: server.log,
nm: netmapProcessor,
nm: server.netmapProcessor,
cnrWrapper: cnrClient,
epoch: server,
epochDuration: globalConfig.EpochDuration,
@ -966,6 +979,12 @@ func (s *Server) initConfigFromBlockchain() error {
return fmt.Errorf("can't read balance contract precision: %w", err)
}
// get next epoch delta tick
s.initialEpochTickDelta, err = s.nextEpochBlockDelta()
if err != nil {
return err
}
s.epochCounter.Store(epoch)
s.precision.SetBalancePrecision(balancePrecision)
@ -974,11 +993,36 @@ func (s *Server) initConfigFromBlockchain() error {
zap.Bool("alphabet", s.IsAlphabet()),
zap.Uint64("epoch", epoch),
zap.Uint32("precision", balancePrecision),
zap.Uint32("init_epoch_tick_delta", s.initialEpochTickDelta),
)
return nil
}
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)
}
epochDuration, err := s.netmapClient.EpochDuration()
if err != nil {
return 0, fmt.Errorf("can't get epoch duration: %w", err)
}
delta := uint32(epochDuration) + epochBlock
if delta < blockHeight {
return 0, nil
}
return delta - blockHeight, nil
}
// onlyActiveHandler wrapper around event handler that executes it
// only if inner ring node state is active.
func (s *Server) onlyActiveEventHandler(f event.Handler) event.Handler {