From 24122177a1812b037fc356af726db5e065d2cfcd Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 29 Dec 2022 18:51:42 +0800 Subject: [PATCH 01/32] init monitor message framework --- api/coreservice.go | 1 + api/serverV2.go | 7 +++ config/config.go | 3 ++ dispatcher/dispatcher.go | 92 +++++++++++++++++++++++++++++---------- server/cronjob/config.go | 18 ++++++++ server/cronjob/monitor.go | 58 ++++++++++++++++++++++++ server/itx/server.go | 23 +++++++++- 7 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 server/cronjob/config.go create mode 100644 server/cronjob/monitor.go diff --git a/api/coreservice.go b/api/coreservice.go index 96cb4a7dc0..ccd9b13ebe 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -158,6 +158,7 @@ type ( chainListener apitypes.Listener electionCommittee committee.Committee readCache *ReadCache + delegatesMonitor map[string]*iotextypes.ConsensusMessage } // jobDesc provides a struct to get and store logs in core.LogsInRange diff --git a/api/serverV2.go b/api/serverV2.go index 65b9832826..3ece2a133a 100644 --- a/api/serverV2.go +++ b/api/serverV2.go @@ -21,6 +21,7 @@ import ( "github.com/iotexproject/iotex-core/blocksync" "github.com/iotexproject/iotex-core/pkg/tracer" "github.com/iotexproject/iotex-core/state/factory" + "github.com/iotexproject/iotex-proto/golang/iotextypes" ) // ServerV2 provides api for user to interact with blockchain data @@ -134,3 +135,9 @@ func (svr *ServerV2) ReceiveBlock(blk *block.Block) error { func (svr *ServerV2) CoreService() CoreService { return svr.core } + +// HandleMonitorMsg handle monitor msg +func (svr *ServerV2) HandleMonitorMsg(msg *iotextypes.ConsensusMessage) error { + // save msg to core.delegatesMonitor + return nil +} diff --git a/config/config.go b/config/config.go index 352a06d276..4412009f64 100644 --- a/config/config.go +++ b/config/config.go @@ -25,6 +25,7 @@ import ( "github.com/iotexproject/iotex-core/dispatcher" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/log" + "github.com/iotexproject/iotex-core/server/cronjob" ) // IMPORTANT: to define a config, add a field or a new config type to the existing config types. In addition, provide @@ -80,6 +81,7 @@ var ( DB: db.DefaultConfig, Indexer: blockindex.DefaultConfig, Genesis: genesis.Default, + Cronjob: cronjob.DefaultConfig, } // ErrInvalidCfg indicates the invalid config value @@ -129,6 +131,7 @@ type ( Log log.GlobalConfig `yaml:"log"` SubLogs map[string]log.GlobalConfig `yaml:"subLogs"` Genesis genesis.Genesis `yaml:"genesis"` + Cronjob cronjob.Config `yaml:"cronjob"` } // Validate is the interface of validating the config diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 70c910e412..b4ea031d0e 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -55,6 +55,11 @@ type Subscriber interface { HandleConsensusMsg(*iotextypes.ConsensusMessage) error } +// MsgSubscriber is the dispatcher msg subscriber interface +type MsgSubscriber interface { + HandleMonitorMsg(*iotextypes.ConsensusMessage) error +} + // Dispatcher is used by peers, handles incoming block and header notifications and relays announcements of new blocks. type Dispatcher interface { lifecycle.StartStopper @@ -67,18 +72,30 @@ type Dispatcher interface { // HandleTell handles the incoming tell message. The transportation layer semantics is exact once. The sender is // given for the sake of replying the message HandleTell(context.Context, uint32, peer.AddrInfo, proto.Message) + // AddMsgSubscriber add msg subscriber + AddMsgSubscriber(MsgSubscriber) } -var requestMtc = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "iotex_dispatch_request", - Help: "Dispatcher request counter.", - }, - []string{"method", "succeed"}, +var ( + requestMtc = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "iotex_dispatch_request", + Help: "Dispatcher request counter.", + }, + []string{"method", "succeed"}, + ) + delegateHeightGauge = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "iotex_p2p_delegate_height_gauge", + Help: "delegate height", + }, + []string{"address", "version"}, + ) ) func init() { prometheus.MustRegister(requestMtc) + prometheus.MustRegister(delegateHeightGauge) } // blockMsg packages a proto block message. @@ -118,22 +135,24 @@ func (m actionMsg) ChainID() uint32 { // IotxDispatcher is the request and event dispatcher for iotx node. type IotxDispatcher struct { - started int32 - shutdown int32 - actionChanLock sync.RWMutex - blockChanLock sync.RWMutex - syncChanLock sync.RWMutex - actionChan chan *actionMsg - blockChan chan *blockMsg - syncChan chan *blockSyncMsg - eventAudit map[iotexrpc.MessageType]int - eventAuditLock sync.RWMutex - wg sync.WaitGroup - quit chan struct{} - subscribers map[uint32]Subscriber - subscribersMU sync.RWMutex - peerLastSync map[string]time.Time - syncInterval time.Duration + started int32 + shutdown int32 + actionChanLock sync.RWMutex + blockChanLock sync.RWMutex + syncChanLock sync.RWMutex + actionChan chan *actionMsg + blockChan chan *blockMsg + syncChan chan *blockSyncMsg + eventAudit map[iotexrpc.MessageType]int + eventAuditLock sync.RWMutex + wg sync.WaitGroup + quit chan struct{} + subscribers map[uint32]Subscriber + subscribersMU sync.RWMutex + peerLastSync map[string]time.Time + syncInterval time.Duration + msgSubscribers []MsgSubscriber + msgSubscribersMU sync.RWMutex } // NewDispatcher creates a new Dispatcher @@ -161,6 +180,15 @@ func (d *IotxDispatcher) AddSubscriber( d.subscribersMU.Unlock() } +// AddMsgSubscriber adds a subscriber to dispatcher +func (d *IotxDispatcher) AddMsgSubscriber( + subscriber MsgSubscriber, +) { + d.msgSubscribersMU.Lock() + d.msgSubscribers = append(d.msgSubscribers, subscriber) + d.msgSubscribersMU.Unlock() +} + // Start starts the dispatcher. func (d *IotxDispatcher) Start(ctx context.Context) error { if atomic.AddInt32(&d.started, 1) != 1 { @@ -345,6 +373,10 @@ func (d *IotxDispatcher) dispatchAction(ctx context.Context, chainID uint32, msg subscriber.ReportFullness(ctx, iotexrpc.MessageType_ACTION, float32(l)/float32(c)) } +func (d *IotxDispatcher) dispatchMonitorMessage(ctx context.Context, peer string, msg proto.Message) { + // save metrics +} + // dispatchBlock adds the passed block message to the news handling queue. func (d *IotxDispatcher) dispatchBlock(ctx context.Context, chainID uint32, peer string, msg proto.Message) { if atomic.LoadInt32(&d.shutdown) != 0 { @@ -408,8 +440,22 @@ func (d *IotxDispatcher) dispatchBlockSyncReq(ctx context.Context, chainID uint3 subscriber.ReportFullness(ctx, iotexrpc.MessageType_BLOCK_REQUEST, float32(l)/float32(c)) } +func (d *IotxDispatcher) handleBroadcastMsg(ctx context.Context, chainID uint32, peer string, message proto.Message) { + for _, sub := range d.msgSubscribers { + switch msg := message.(type) { + case *iotextypes.ConsensusMessage: + if err := sub.HandleMonitorMsg(msg); err != nil { + log.L().Debug("Failed to handle consensus message", zap.Error(err)) + } + default: + } + } +} + // HandleBroadcast handles incoming broadcast message func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, peer string, message proto.Message) { + d.handleBroadcastMsg(ctx, chainID, peer, message) + subscriber := d.subscriber(chainID) if subscriber == nil { log.L().Warn("chainID has not been registered in dispatcher.", zap.Uint32("chainID", chainID)) @@ -425,6 +471,8 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, pe d.dispatchAction(ctx, chainID, message) case *iotextypes.Block: d.dispatchBlock(ctx, chainID, peer, message) + case *iotextypes.ConsensusVote: + d.dispatchMonitorMessage(ctx, peer, msg) default: msgType, _ := goproto.GetTypeFromRPCMsg(message) log.L().Warn("Unexpected msgType handled by HandleBroadcast.", zap.Any("msgType", msgType)) diff --git a/server/cronjob/config.go b/server/cronjob/config.go new file mode 100644 index 0000000000..80e3315581 --- /dev/null +++ b/server/cronjob/config.go @@ -0,0 +1,18 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package cronjob + +import "time" + +// Config is the cronjob config +type Config struct { + MonitorInterval time.Duration `yaml:"monitorInterval"` +} + +// DefaultConfig is the default config +var DefaultConfig = Config{ + MonitorInterval: 5 * time.Minute, +} diff --git a/server/cronjob/monitor.go b/server/cronjob/monitor.go new file mode 100644 index 0000000000..4ef00923f0 --- /dev/null +++ b/server/cronjob/monitor.go @@ -0,0 +1,58 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package cronjob + +import ( + "context" + "time" + + "github.com/iotexproject/iotex-core/blockchain" + "github.com/iotexproject/iotex-core/p2p" + "github.com/iotexproject/iotex-proto/golang/iotextypes" +) + +// CronJob interface +type CronJob interface { + Run() + Interval() time.Duration +} + +type cronInterval time.Duration + +func (i cronInterval) Interval() time.Duration { + return time.Duration(i) +} + +type monitorJob struct { + cronInterval + agent p2p.Agent + bc blockchain.Blockchain +} + +// NewMonitorCronjob new monitor cronjob +func NewMonitorCronjob(agent p2p.Agent, bc blockchain.Blockchain, interval time.Duration) CronJob { + return &monitorJob{ + cronInterval: cronInterval(interval), + agent: agent, + bc: bc, + } +} + +func (j *monitorJob) Run() { + // ver := version.PackageVersion + j.agent.BroadcastOutbound(context.Background(), &iotextypes.ConsensusMessage{ + Height: j.bc.TipHeight(), + }) +} + +// NewCronJobs create cronjobs +func NewCronJobs(cfg Config, agent p2p.Agent, bc blockchain.Blockchain) []CronJob { + res := []CronJob{} + if cfg.MonitorInterval > 0 { + res = append(res, NewMonitorCronjob(agent, bc, cfg.MonitorInterval)) + } + return res +} diff --git a/server/itx/server.go b/server/itx/server.go index f96207cb51..642f8ef613 100644 --- a/server/itx/server.go +++ b/server/itx/server.go @@ -22,10 +22,12 @@ import ( "github.com/iotexproject/iotex-core/dispatcher" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/ha" + "github.com/iotexproject/iotex-core/pkg/lifecycle" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/pkg/probe" "github.com/iotexproject/iotex-core/pkg/routine" "github.com/iotexproject/iotex-core/pkg/util/httputil" + "github.com/iotexproject/iotex-core/server/cronjob" ) // Server is the iotex server instance containing all components. @@ -39,6 +41,7 @@ type Server struct { initializedSubChains map[uint32]bool mutex sync.RWMutex subModuleCancel context.CancelFunc + tasks []lifecycle.StartStopper } // NewServer creates a new server @@ -88,9 +91,17 @@ func newServer(cfg config.Config, testing bool) (*Server, error) { return nil, errors.Wrap(err, "failed to add api server as subscriber") } } + + tasks := []lifecycle.StartStopper{} + jobs := cronjob.NewCronJobs(cfg.Cronjob, p2pAgent, cs.Blockchain()) + for i := range jobs { + tasks = append(tasks, routine.NewRecurringTask(jobs[i].Run, jobs[i].Interval())) + } + // TODO: explorer dependency deleted here at #1085, need to revive by migrating to api chains[cs.ChainID()] = cs dispatcher.AddSubscriber(cs.ChainID(), cs) + dispatcher.AddMsgSubscriber(apiServer) svr := Server{ cfg: cfg, p2pAgent: p2pAgent, @@ -99,6 +110,7 @@ func newServer(cfg config.Config, testing bool) (*Server, error) { chainservices: chains, apiServers: apiServers, initializedSubChains: map[uint32]bool{}, + tasks: tasks, } // Setup sub-chain starter // TODO: sub-chain infra should use main-chain API instead of protocol directly @@ -125,13 +137,22 @@ func (s *Server) Start(ctx context.Context) error { if err := s.dispatcher.Start(cctx); err != nil { return errors.Wrap(err, "error when starting dispatcher") } - + for i := range s.tasks { + if err := s.tasks[i].Start(cctx); err != nil { + return errors.Wrapf(err, "error when starting task %v", i) + } + } return nil } // Stop stops the server func (s *Server) Stop(ctx context.Context) error { defer s.subModuleCancel() + for i := range s.tasks { + if err := s.tasks[i].Stop(ctx); err != nil { + return errors.Wrapf(err, "error when stopping task %v", i) + } + } if err := s.p2pAgent.Stop(ctx); err != nil { // notest return errors.Wrap(err, "error when stopping P2P agent") From 0f7038858e8892ba15dc342b8de90be5ca1696df Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 30 Dec 2022 14:37:27 +0800 Subject: [PATCH 02/32] init broadcast framework --- api/coreservice.go | 10 ++++- api/serverV2.go | 5 +-- chainservice/builder.go | 7 ++++ chainservice/chainservice.go | 20 ++++++++++ config/config.go | 5 ++- dispatcher/dispatcher.go | 76 +++++++++++------------------------- go.mod | 4 ++ go.sum | 5 +-- server/itx/monitor.go | 36 +++++++++++++++++ server/itx/server.go | 23 +---------- 10 files changed, 107 insertions(+), 84 deletions(-) create mode 100644 server/itx/monitor.go diff --git a/api/coreservice.go b/api/coreservice.go index ccd9b13ebe..454b981fcf 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -140,6 +140,8 @@ type ( ReceiveBlock(blk *block.Block) error // BlockHashByBlockHeight returns block hash by block height BlockHashByBlockHeight(blkHeight uint64) (hash.Hash256, error) + // HandleMonitorMsg handle monitor msg + HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error } // coreService implements the CoreService interface @@ -158,7 +160,7 @@ type ( chainListener apitypes.Listener electionCommittee committee.Committee readCache *ReadCache - delegatesMonitor map[string]*iotextypes.ConsensusMessage + delegatesMonitor map[string]*iotextypes.Monitor } // jobDesc provides a struct to get and store logs in core.LogsInRange @@ -1565,3 +1567,9 @@ func (core *coreService) SyncingProgress() (uint64, uint64, uint64) { startingHeight, currentHeight, targetHeight, _ := core.bs.SyncStatus() return startingHeight, currentHeight, targetHeight } + +// HandleMonitorMsg handle monitor msg +func (core *coreService) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { + // update delegateMonitor + return nil +} diff --git a/api/serverV2.go b/api/serverV2.go index 3ece2a133a..5a252f5632 100644 --- a/api/serverV2.go +++ b/api/serverV2.go @@ -137,7 +137,6 @@ func (svr *ServerV2) CoreService() CoreService { } // HandleMonitorMsg handle monitor msg -func (svr *ServerV2) HandleMonitorMsg(msg *iotextypes.ConsensusMessage) error { - // save msg to core.delegatesMonitor - return nil +func (svr *ServerV2) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { + return svr.core.HandleMonitorMsg(ctx, peer, msg) } diff --git a/chainservice/builder.go b/chainservice/builder.go index 12703c2b41..96aced7a2d 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -627,3 +627,10 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) return cs, nil } + +// SetMonitorHandler sets the monitor handler instance +func (builder *Builder) SetMonitorHandler(handler monitorMsgHandler) *Builder { + builder.createInstance() + builder.cs.monitorHandler = handler + return builder +} diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 4b46a2255f..b638d3ca63 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -61,6 +61,10 @@ var ( ) ) +type monitorMsgHandler interface { + HandleMonitorMsg(context.Context, string, *iotextypes.Monitor) error +} + func init() { prometheus.MustRegister(_apiCallWithChainIDMtc) prometheus.MustRegister(_apiCallWithOutChainIDMtc) @@ -84,6 +88,8 @@ type ChainService struct { candidateIndexer *poll.CandidateIndexer candBucketsIndexer *staking.CandidatesBucketsIndexer registry *protocol.Registry + monitorHandler monitorMsgHandler + monitorBroadcaster lifecycle.StartStopper } // Start starts the server @@ -163,6 +169,11 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err return cs.consensus.HandleConsensusMsg(msg) } +// HandleMonitorMsg handles monitor message. +func (cs *ChainService) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { + return cs.monitorHandler.HandleMonitorMsg(ctx, peer, msg) +} + // ChainID returns ChainID. func (cs *ChainService) ChainID() uint32 { return cs.chain.ChainID() } @@ -199,6 +210,15 @@ func (cs *ChainService) BlockSync() blocksync.BlockSync { // Registry returns a pointer to the registry func (cs *ChainService) Registry() *protocol.Registry { return cs.registry } +// SetMonitorHandler set the monitor handler +func (cs *ChainService) SetMonitorHandler(handler monitorMsgHandler) { cs.monitorHandler = handler } + +// SetMonitorBroadcaster sets the block sync instance +func (cs *ChainService) SetMonitorBroadcaster(mb lifecycle.StartStopper) { + cs.monitorBroadcaster = mb + cs.lifecycle.Add(mb) +} + // NewAPIServer creates a new api server func (cs *ChainService) NewAPIServer(cfg api.Config, plugins map[int]interface{}) (*api.ServerV2, error) { if cfg.GRPCPort == 0 && cfg.HTTPPort == 0 { diff --git a/config/config.go b/config/config.go index 4412009f64..212670e70f 100644 --- a/config/config.go +++ b/config/config.go @@ -104,8 +104,9 @@ type ( // System is the system config System struct { // Active is the status of the node. True means active and false means stand-by - Active bool `yaml:"active"` - HeartbeatInterval time.Duration `yaml:"heartbeatInterval"` + Active bool `yaml:"active"` + HeartbeatInterval time.Duration `yaml:"heartbeatInterval"` + MonitorBroadcastInterval time.Duration `yaml:"monitorBroadcastInterval"` // HTTPProfilingPort is the port number to access golang performance profiling data of a blockchain node. It is // 0 by default, meaning performance profiling has been disabled HTTPAdminPort int `yaml:"httpAdminPort"` diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index b4ea031d0e..5539ed0188 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -53,11 +53,7 @@ type Subscriber interface { HandleBlock(context.Context, string, *iotextypes.Block) error HandleSyncRequest(context.Context, peer.AddrInfo, *iotexrpc.BlockSync) error HandleConsensusMsg(*iotextypes.ConsensusMessage) error -} - -// MsgSubscriber is the dispatcher msg subscriber interface -type MsgSubscriber interface { - HandleMonitorMsg(*iotextypes.ConsensusMessage) error + HandleMonitorMsg(context.Context, string, *iotextypes.Monitor) error } // Dispatcher is used by peers, handles incoming block and header notifications and relays announcements of new blocks. @@ -72,8 +68,6 @@ type Dispatcher interface { // HandleTell handles the incoming tell message. The transportation layer semantics is exact once. The sender is // given for the sake of replying the message HandleTell(context.Context, uint32, peer.AddrInfo, proto.Message) - // AddMsgSubscriber add msg subscriber - AddMsgSubscriber(MsgSubscriber) } var ( @@ -135,24 +129,22 @@ func (m actionMsg) ChainID() uint32 { // IotxDispatcher is the request and event dispatcher for iotx node. type IotxDispatcher struct { - started int32 - shutdown int32 - actionChanLock sync.RWMutex - blockChanLock sync.RWMutex - syncChanLock sync.RWMutex - actionChan chan *actionMsg - blockChan chan *blockMsg - syncChan chan *blockSyncMsg - eventAudit map[iotexrpc.MessageType]int - eventAuditLock sync.RWMutex - wg sync.WaitGroup - quit chan struct{} - subscribers map[uint32]Subscriber - subscribersMU sync.RWMutex - peerLastSync map[string]time.Time - syncInterval time.Duration - msgSubscribers []MsgSubscriber - msgSubscribersMU sync.RWMutex + started int32 + shutdown int32 + actionChanLock sync.RWMutex + blockChanLock sync.RWMutex + syncChanLock sync.RWMutex + actionChan chan *actionMsg + blockChan chan *blockMsg + syncChan chan *blockSyncMsg + eventAudit map[iotexrpc.MessageType]int + eventAuditLock sync.RWMutex + wg sync.WaitGroup + quit chan struct{} + subscribers map[uint32]Subscriber + subscribersMU sync.RWMutex + peerLastSync map[string]time.Time + syncInterval time.Duration } // NewDispatcher creates a new Dispatcher @@ -180,15 +172,6 @@ func (d *IotxDispatcher) AddSubscriber( d.subscribersMU.Unlock() } -// AddMsgSubscriber adds a subscriber to dispatcher -func (d *IotxDispatcher) AddMsgSubscriber( - subscriber MsgSubscriber, -) { - d.msgSubscribersMU.Lock() - d.msgSubscribers = append(d.msgSubscribers, subscriber) - d.msgSubscribersMU.Unlock() -} - // Start starts the dispatcher. func (d *IotxDispatcher) Start(ctx context.Context) error { if atomic.AddInt32(&d.started, 1) != 1 { @@ -373,10 +356,6 @@ func (d *IotxDispatcher) dispatchAction(ctx context.Context, chainID uint32, msg subscriber.ReportFullness(ctx, iotexrpc.MessageType_ACTION, float32(l)/float32(c)) } -func (d *IotxDispatcher) dispatchMonitorMessage(ctx context.Context, peer string, msg proto.Message) { - // save metrics -} - // dispatchBlock adds the passed block message to the news handling queue. func (d *IotxDispatcher) dispatchBlock(ctx context.Context, chainID uint32, peer string, msg proto.Message) { if atomic.LoadInt32(&d.shutdown) != 0 { @@ -440,22 +419,8 @@ func (d *IotxDispatcher) dispatchBlockSyncReq(ctx context.Context, chainID uint3 subscriber.ReportFullness(ctx, iotexrpc.MessageType_BLOCK_REQUEST, float32(l)/float32(c)) } -func (d *IotxDispatcher) handleBroadcastMsg(ctx context.Context, chainID uint32, peer string, message proto.Message) { - for _, sub := range d.msgSubscribers { - switch msg := message.(type) { - case *iotextypes.ConsensusMessage: - if err := sub.HandleMonitorMsg(msg); err != nil { - log.L().Debug("Failed to handle consensus message", zap.Error(err)) - } - default: - } - } -} - // HandleBroadcast handles incoming broadcast message func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, peer string, message proto.Message) { - d.handleBroadcastMsg(ctx, chainID, peer, message) - subscriber := d.subscriber(chainID) if subscriber == nil { log.L().Warn("chainID has not been registered in dispatcher.", zap.Uint32("chainID", chainID)) @@ -471,8 +436,11 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, pe d.dispatchAction(ctx, chainID, message) case *iotextypes.Block: d.dispatchBlock(ctx, chainID, peer, message) - case *iotextypes.ConsensusVote: - d.dispatchMonitorMessage(ctx, peer, msg) + case *iotextypes.Monitor: + if err := subscriber.HandleMonitorMsg(ctx, peer, msg); err != nil { + log.L().Debug("Failed to handle monitor message.", zap.Error(err)) + } + // update delegateHeightGauge metric default: msgType, _ := goproto.GetTypeFromRPCMsg(message) log.L().Warn("Unexpected msgType handled by HandleBroadcast.", zap.Any("msgType", msgType)) diff --git a/go.mod b/go.mod index 2eb7ac6e47..8f7f54b87f 100644 --- a/go.mod +++ b/go.mod @@ -203,3 +203,7 @@ require ( replace github.com/ethereum/go-ethereum => github.com/iotexproject/go-ethereum v0.4.2 replace golang.org/x/xerrors => golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 + +// replace github.com/iotexproject/iotex-proto v0.5.10 => github.com/envestcc/iotex-proto v0.0.0-20221230052651-5f53099aee3e + +replace github.com/iotexproject/iotex-proto => /Users/chenchen/dev/iotex-proto diff --git a/go.sum b/go.sum index c5f000b1fe..425de79434 100644 --- a/go.sum +++ b/go.sum @@ -505,9 +505,6 @@ github.com/iotexproject/iotex-antenna-go/v2 v2.5.1 h1:Z7X0qXxc/4hSSE3koBaFRpLAdi github.com/iotexproject/iotex-antenna-go/v2 v2.5.1/go.mod h1:8pDZcM45M0gY6jm3PoM20rzoD2Z0vg3Hg64RS4c3qx0= github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d h1:/j1xCAC9YiG/8UKqYvycS/v3ddVsb1G7AMyLXOjeYI0= github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d/go.mod h1:GRWevxtqQ4gPMrd7Qxhr29/7aTgvjiTp+rFI9KMMZEo= -github.com/iotexproject/iotex-proto v0.5.0/go.mod h1:Xg6REkv+nTZN+OC22xXIQuqKdTWWHwOAJEXCoMpDwtI= -github.com/iotexproject/iotex-proto v0.5.10 h1:+7Hw8KYposo0tJxgIEnPRpKU/TlQGMNn1S0tpSUz6RI= -github.com/iotexproject/iotex-proto v0.5.10/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -1446,6 +1443,7 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1544,6 +1542,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/server/itx/monitor.go b/server/itx/monitor.go new file mode 100644 index 0000000000..3d219edf96 --- /dev/null +++ b/server/itx/monitor.go @@ -0,0 +1,36 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package itx + +import ( + "context" + + "github.com/iotexproject/iotex-core/blockchain" + "github.com/iotexproject/iotex-core/p2p" + "github.com/iotexproject/iotex-core/pkg/version" + "github.com/iotexproject/iotex-proto/golang/iotextypes" +) + +type MonitorBroadcaster struct { + agent p2p.Agent + bc blockchain.Blockchain +} + +// NewMonitorBroadcaster new monitor broadcaster +func NewMonitorBroadcaster(agent p2p.Agent, bc blockchain.Blockchain) *MonitorBroadcaster { + return &MonitorBroadcaster{ + agent: agent, + bc: bc, + } +} + +// Broadcast broadcast monitor msg +func (j *MonitorBroadcaster) Broadcast() { + j.agent.BroadcastOutbound(context.Background(), &iotextypes.Monitor{ + Version: version.PackageVersion, + Height: j.bc.TipHeight(), + }) +} diff --git a/server/itx/server.go b/server/itx/server.go index 642f8ef613..c7e7d8a242 100644 --- a/server/itx/server.go +++ b/server/itx/server.go @@ -22,12 +22,10 @@ import ( "github.com/iotexproject/iotex-core/dispatcher" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/ha" - "github.com/iotexproject/iotex-core/pkg/lifecycle" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/pkg/probe" "github.com/iotexproject/iotex-core/pkg/routine" "github.com/iotexproject/iotex-core/pkg/util/httputil" - "github.com/iotexproject/iotex-core/server/cronjob" ) // Server is the iotex server instance containing all components. @@ -41,7 +39,6 @@ type Server struct { initializedSubChains map[uint32]bool mutex sync.RWMutex subModuleCancel context.CancelFunc - tasks []lifecycle.StartStopper } // NewServer creates a new server @@ -90,18 +87,13 @@ func newServer(cfg config.Config, testing bool) (*Server, error) { if err := cs.Blockchain().AddSubscriber(apiServer); err != nil { return nil, errors.Wrap(err, "failed to add api server as subscriber") } - } - - tasks := []lifecycle.StartStopper{} - jobs := cronjob.NewCronJobs(cfg.Cronjob, p2pAgent, cs.Blockchain()) - for i := range jobs { - tasks = append(tasks, routine.NewRecurringTask(jobs[i].Run, jobs[i].Interval())) + cs.SetMonitorHandler(apiServer) + cs.SetMonitorBroadcaster(routine.NewRecurringTask(NewMonitorBroadcaster(p2pAgent, cs.Blockchain()).Broadcast, cfg.System.MonitorBroadcastInterval)) } // TODO: explorer dependency deleted here at #1085, need to revive by migrating to api chains[cs.ChainID()] = cs dispatcher.AddSubscriber(cs.ChainID(), cs) - dispatcher.AddMsgSubscriber(apiServer) svr := Server{ cfg: cfg, p2pAgent: p2pAgent, @@ -110,7 +102,6 @@ func newServer(cfg config.Config, testing bool) (*Server, error) { chainservices: chains, apiServers: apiServers, initializedSubChains: map[uint32]bool{}, - tasks: tasks, } // Setup sub-chain starter // TODO: sub-chain infra should use main-chain API instead of protocol directly @@ -137,22 +128,12 @@ func (s *Server) Start(ctx context.Context) error { if err := s.dispatcher.Start(cctx); err != nil { return errors.Wrap(err, "error when starting dispatcher") } - for i := range s.tasks { - if err := s.tasks[i].Start(cctx); err != nil { - return errors.Wrapf(err, "error when starting task %v", i) - } - } return nil } // Stop stops the server func (s *Server) Stop(ctx context.Context) error { defer s.subModuleCancel() - for i := range s.tasks { - if err := s.tasks[i].Stop(ctx); err != nil { - return errors.Wrapf(err, "error when stopping task %v", i) - } - } if err := s.p2pAgent.Stop(ctx); err != nil { // notest return errors.Wrap(err, "error when stopping P2P agent") From 55075586d732e6e465dd5b6204f16f2b0ba309e8 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 30 Dec 2022 14:39:50 +0800 Subject: [PATCH 03/32] update broadcast framework --- config/config.go | 3 -- server/cronjob/config.go | 18 ------------ server/cronjob/monitor.go | 58 --------------------------------------- 3 files changed, 79 deletions(-) delete mode 100644 server/cronjob/config.go delete mode 100644 server/cronjob/monitor.go diff --git a/config/config.go b/config/config.go index 212670e70f..6c17f66a39 100644 --- a/config/config.go +++ b/config/config.go @@ -25,7 +25,6 @@ import ( "github.com/iotexproject/iotex-core/dispatcher" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/log" - "github.com/iotexproject/iotex-core/server/cronjob" ) // IMPORTANT: to define a config, add a field or a new config type to the existing config types. In addition, provide @@ -81,7 +80,6 @@ var ( DB: db.DefaultConfig, Indexer: blockindex.DefaultConfig, Genesis: genesis.Default, - Cronjob: cronjob.DefaultConfig, } // ErrInvalidCfg indicates the invalid config value @@ -132,7 +130,6 @@ type ( Log log.GlobalConfig `yaml:"log"` SubLogs map[string]log.GlobalConfig `yaml:"subLogs"` Genesis genesis.Genesis `yaml:"genesis"` - Cronjob cronjob.Config `yaml:"cronjob"` } // Validate is the interface of validating the config diff --git a/server/cronjob/config.go b/server/cronjob/config.go deleted file mode 100644 index 80e3315581..0000000000 --- a/server/cronjob/config.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2022 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package cronjob - -import "time" - -// Config is the cronjob config -type Config struct { - MonitorInterval time.Duration `yaml:"monitorInterval"` -} - -// DefaultConfig is the default config -var DefaultConfig = Config{ - MonitorInterval: 5 * time.Minute, -} diff --git a/server/cronjob/monitor.go b/server/cronjob/monitor.go deleted file mode 100644 index 4ef00923f0..0000000000 --- a/server/cronjob/monitor.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2022 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package cronjob - -import ( - "context" - "time" - - "github.com/iotexproject/iotex-core/blockchain" - "github.com/iotexproject/iotex-core/p2p" - "github.com/iotexproject/iotex-proto/golang/iotextypes" -) - -// CronJob interface -type CronJob interface { - Run() - Interval() time.Duration -} - -type cronInterval time.Duration - -func (i cronInterval) Interval() time.Duration { - return time.Duration(i) -} - -type monitorJob struct { - cronInterval - agent p2p.Agent - bc blockchain.Blockchain -} - -// NewMonitorCronjob new monitor cronjob -func NewMonitorCronjob(agent p2p.Agent, bc blockchain.Blockchain, interval time.Duration) CronJob { - return &monitorJob{ - cronInterval: cronInterval(interval), - agent: agent, - bc: bc, - } -} - -func (j *monitorJob) Run() { - // ver := version.PackageVersion - j.agent.BroadcastOutbound(context.Background(), &iotextypes.ConsensusMessage{ - Height: j.bc.TipHeight(), - }) -} - -// NewCronJobs create cronjobs -func NewCronJobs(cfg Config, agent p2p.Agent, bc blockchain.Blockchain) []CronJob { - res := []CronJob{} - if cfg.MonitorInterval > 0 { - res = append(res, NewMonitorCronjob(agent, bc, cfg.MonitorInterval)) - } - return res -} From 47e97d569c8e1fd0d69358b17e0b9a08eb8cf63f Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 30 Dec 2022 14:42:55 +0800 Subject: [PATCH 04/32] update broadcast framework --- chainservice/builder.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/chainservice/builder.go b/chainservice/builder.go index 96aced7a2d..12703c2b41 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -627,10 +627,3 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) return cs, nil } - -// SetMonitorHandler sets the monitor handler instance -func (builder *Builder) SetMonitorHandler(handler monitorMsgHandler) *Builder { - builder.createInstance() - builder.cs.monitorHandler = handler - return builder -} From 935f9cc2d0255b06403cd937eb8a69ada03debf9 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 3 Jan 2023 21:13:35 +0800 Subject: [PATCH 05/32] add node package to handle node info manager --- api/coreservice.go | 37 ++++++++---------- api/serverV2.go | 10 ++--- chainservice/builder.go | 8 ++++ chainservice/chainservice.go | 21 +++++----- config/config.go | 2 + dispatcher/dispatcher.go | 8 ---- node/config.go | 12 ++++++ node/metric.go | 20 ++++++++++ node/node.go | 75 ++++++++++++++++++++++++++++++++++++ server/itx/monitor.go | 36 ----------------- server/itx/server.go | 2 - 11 files changed, 145 insertions(+), 86 deletions(-) create mode 100644 node/config.go create mode 100644 node/metric.go create mode 100644 node/node.go delete mode 100644 server/itx/monitor.go diff --git a/api/coreservice.go b/api/coreservice.go index 454b981fcf..5c9764febb 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -49,6 +49,7 @@ import ( "github.com/iotexproject/iotex-core/blocksync" "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/gasstation" + "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/pkg/tracer" "github.com/iotexproject/iotex-core/pkg/version" @@ -140,8 +141,6 @@ type ( ReceiveBlock(blk *block.Block) error // BlockHashByBlockHeight returns block hash by block height BlockHashByBlockHeight(blkHeight uint64) (hash.Hash256, error) - // HandleMonitorMsg handle monitor msg - HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error } // coreService implements the CoreService interface @@ -160,7 +159,7 @@ type ( chainListener apitypes.Listener electionCommittee committee.Committee readCache *ReadCache - delegatesMonitor map[string]*iotextypes.Monitor + delegateManager node.NodeManager } // jobDesc provides a struct to get and store logs in core.LogsInRange @@ -210,6 +209,7 @@ func newCoreService( bfIndexer blockindex.BloomFilterIndexer, actPool actpool.ActPool, registry *protocol.Registry, + dm node.NodeManager, opts ...Option, ) (CoreService, error) { if cfg == (Config{}) { @@ -222,18 +222,19 @@ func newCoreService( } core := coreService{ - bc: chain, - bs: bs, - sf: sf, - dao: dao, - indexer: indexer, - bfIndexer: bfIndexer, - ap: actPool, - cfg: cfg, - registry: registry, - chainListener: NewChainListener(500), - gs: gasstation.NewGasStation(chain, dao, cfg.GasStation), - readCache: NewReadCache(), + bc: chain, + bs: bs, + sf: sf, + dao: dao, + indexer: indexer, + bfIndexer: bfIndexer, + ap: actPool, + cfg: cfg, + registry: registry, + chainListener: NewChainListener(500), + gs: gasstation.NewGasStation(chain, dao, cfg.GasStation), + readCache: NewReadCache(), + delegateManager: dm, } for _, opt := range opts { @@ -1567,9 +1568,3 @@ func (core *coreService) SyncingProgress() (uint64, uint64, uint64) { startingHeight, currentHeight, targetHeight, _ := core.bs.SyncStatus() return startingHeight, currentHeight, targetHeight } - -// HandleMonitorMsg handle monitor msg -func (core *coreService) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { - // update delegateMonitor - return nil -} diff --git a/api/serverV2.go b/api/serverV2.go index 5a252f5632..02a834e332 100644 --- a/api/serverV2.go +++ b/api/serverV2.go @@ -19,9 +19,9 @@ import ( "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/blockindex" "github.com/iotexproject/iotex-core/blocksync" + "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/pkg/tracer" "github.com/iotexproject/iotex-core/state/factory" - "github.com/iotexproject/iotex-proto/golang/iotextypes" ) // ServerV2 provides api for user to interact with blockchain data @@ -44,9 +44,10 @@ func NewServerV2( bfIndexer blockindex.BloomFilterIndexer, actPool actpool.ActPool, registry *protocol.Registry, + dm node.NodeManager, opts ...Option, ) (*ServerV2, error) { - coreAPI, err := newCoreService(cfg, chain, bs, sf, dao, indexer, bfIndexer, actPool, registry, opts...) + coreAPI, err := newCoreService(cfg, chain, bs, sf, dao, indexer, bfIndexer, actPool, registry, dm, opts...) if err != nil { return nil, err } @@ -135,8 +136,3 @@ func (svr *ServerV2) ReceiveBlock(blk *block.Block) error { func (svr *ServerV2) CoreService() CoreService { return svr.core } - -// HandleMonitorMsg handle monitor msg -func (svr *ServerV2) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { - return svr.core.HandleMonitorMsg(ctx, peer, msg) -} diff --git a/chainservice/builder.go b/chainservice/builder.go index 12703c2b41..04bdf48c1f 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -31,6 +31,7 @@ import ( "github.com/iotexproject/iotex-core/consensus" rp "github.com/iotexproject/iotex-core/consensus/scheme/rolldpos" "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/state/factory" @@ -377,6 +378,12 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B return blockchain.NewBlockchain(builder.cfg.Chain, builder.cfg.Genesis, builder.cs.blockdao, factory.NewMinter(builder.cs.factory, builder.cs.actpool), chainOpts...) } +func (builder *Builder) buildNodeManager() { + dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.consensus, builder.cs.p2pAgent, builder.cs.chain) + builder.cs.delegateManager = dm + builder.cs.lifecycle.Add(dm) +} + func (builder *Builder) buildBlockSyncer() error { if builder.cs.blocksync != nil { return nil @@ -622,6 +629,7 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) if err := builder.buildBlockSyncer(); err != nil { return nil, err } + builder.buildNodeManager() cs := builder.cs builder.cs = nil diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index b638d3ca63..8090e91b20 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -31,6 +31,7 @@ import ( "github.com/iotexproject/iotex-core/blockindex" "github.com/iotexproject/iotex-core/blocksync" "github.com/iotexproject/iotex-core/consensus" + "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/lifecycle" "github.com/iotexproject/iotex-core/pkg/log" @@ -88,8 +89,7 @@ type ChainService struct { candidateIndexer *poll.CandidateIndexer candBucketsIndexer *staking.CandidatesBucketsIndexer registry *protocol.Registry - monitorHandler monitorMsgHandler - monitorBroadcaster lifecycle.StartStopper + delegateManager node.NodeManager } // Start starts the server @@ -171,7 +171,12 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err // HandleMonitorMsg handles monitor message. func (cs *ChainService) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { - return cs.monitorHandler.HandleMonitorMsg(ctx, peer, msg) + cs.delegateManager.UpdateNode(&node.Node{ + Addr: peer, + Height: msg.Height, + Version: msg.Version, + }) + return nil } // ChainID returns ChainID. @@ -210,15 +215,6 @@ func (cs *ChainService) BlockSync() blocksync.BlockSync { // Registry returns a pointer to the registry func (cs *ChainService) Registry() *protocol.Registry { return cs.registry } -// SetMonitorHandler set the monitor handler -func (cs *ChainService) SetMonitorHandler(handler monitorMsgHandler) { cs.monitorHandler = handler } - -// SetMonitorBroadcaster sets the block sync instance -func (cs *ChainService) SetMonitorBroadcaster(mb lifecycle.StartStopper) { - cs.monitorBroadcaster = mb - cs.lifecycle.Add(mb) -} - // NewAPIServer creates a new api server func (cs *ChainService) NewAPIServer(cfg api.Config, plugins map[int]interface{}) (*api.ServerV2, error) { if cfg.GRPCPort == 0 && cfg.HTTPPort == 0 { @@ -242,6 +238,7 @@ func (cs *ChainService) NewAPIServer(cfg api.Config, plugins map[int]interface{} cs.bfIndexer, cs.actpool, cs.registry, + cs.delegateManager, apiServerOptions..., ) if err != nil { diff --git a/config/config.go b/config/config.go index 6c17f66a39..6dda245117 100644 --- a/config/config.go +++ b/config/config.go @@ -23,6 +23,7 @@ import ( "github.com/iotexproject/iotex-core/consensus/consensusfsm" "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/dispatcher" + "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/log" ) @@ -130,6 +131,7 @@ type ( Log log.GlobalConfig `yaml:"log"` SubLogs map[string]log.GlobalConfig `yaml:"subLogs"` Genesis genesis.Genesis `yaml:"genesis"` + Node node.Config `yaml:"node"` } // Validate is the interface of validating the config diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 5539ed0188..13692d3552 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -78,18 +78,10 @@ var ( }, []string{"method", "succeed"}, ) - delegateHeightGauge = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "iotex_p2p_delegate_height_gauge", - Help: "delegate height", - }, - []string{"address", "version"}, - ) ) func init() { prometheus.MustRegister(requestMtc) - prometheus.MustRegister(delegateHeightGauge) } // blockMsg packages a proto block message. diff --git a/node/config.go b/node/config.go new file mode 100644 index 0000000000..c24fd039f3 --- /dev/null +++ b/node/config.go @@ -0,0 +1,12 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package node + +import "time" + +type Config struct { + NodeInfoBroadcastInterval time.Duration `yaml:"nodeInfoBroadcastInterval"` +} diff --git a/node/metric.go b/node/metric.go new file mode 100644 index 0000000000..d7b2e41561 --- /dev/null +++ b/node/metric.go @@ -0,0 +1,20 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package node + +import "github.com/prometheus/client_golang/prometheus" + +var nodeDelegateHeightGauge = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "iotex_node_delegate_height_gauge", + Help: "delegate height", + }, + []string{"address", "version"}, +) + +func init() { + prometheus.MustRegister(nodeDelegateHeightGauge) +} diff --git a/node/node.go b/node/node.go new file mode 100644 index 0000000000..4514b81617 --- /dev/null +++ b/node/node.go @@ -0,0 +1,75 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package node + +import ( + "context" + + "github.com/iotexproject/iotex-core/blockchain" + "github.com/iotexproject/iotex-core/consensus" + "github.com/iotexproject/iotex-core/p2p" + "github.com/iotexproject/iotex-core/pkg/lifecycle" + "github.com/iotexproject/iotex-core/pkg/routine" + "github.com/iotexproject/iotex-core/pkg/version" + "github.com/iotexproject/iotex-proto/golang/iotextypes" +) + +type Node struct { + Addr string + Height uint64 + Version string +} + +// NodeManager manage nodes on the blockchain +type NodeManager interface { + lifecycle.StartStopper + UpdateNode(*Node) + GetNode(addr string) *Node +} + +type delegateManager struct { + cfg Config + nodeMap map[string]*Node + consensus consensus.Consensus + broadcaster lifecycle.StartStopper + p2pAgent p2p.Agent + bc blockchain.Blockchain +} + +func NewDelegateManager(cfg *Config, consensus consensus.Consensus, p2pAgent p2p.Agent, bc blockchain.Blockchain) NodeManager { + dm := &delegateManager{ + cfg: *cfg, + nodeMap: make(map[string]*Node), + consensus: consensus, + p2pAgent: p2pAgent, + bc: bc, + } + dm.broadcaster = routine.NewRecurringTask(dm.broadcast, cfg.NodeInfoBroadcastInterval) + return dm +} + +func (dm *delegateManager) Start(ctx context.Context) error { + return dm.broadcaster.Start(ctx) +} +func (dm *delegateManager) Stop(ctx context.Context) error { + return dm.broadcaster.Stop(ctx) +} +func (dm *delegateManager) UpdateNode(node *Node) { + // update dm.nodeMap + n := *node + dm.nodeMap[node.Addr] = &n + // update metric + nodeDelegateHeightGauge.WithLabelValues("address", node.Addr, "version", node.Version).Set(float64(node.Height)) +} +func (dm *delegateManager) GetNode(addr string) *Node { + return dm.nodeMap[addr] +} +func (dm *delegateManager) broadcast() { + dm.p2pAgent.BroadcastOutbound(context.Background(), &iotextypes.Monitor{ + Height: dm.bc.TipHeight(), + Version: version.PackageVersion, + }) +} diff --git a/server/itx/monitor.go b/server/itx/monitor.go deleted file mode 100644 index 3d219edf96..0000000000 --- a/server/itx/monitor.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2022 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package itx - -import ( - "context" - - "github.com/iotexproject/iotex-core/blockchain" - "github.com/iotexproject/iotex-core/p2p" - "github.com/iotexproject/iotex-core/pkg/version" - "github.com/iotexproject/iotex-proto/golang/iotextypes" -) - -type MonitorBroadcaster struct { - agent p2p.Agent - bc blockchain.Blockchain -} - -// NewMonitorBroadcaster new monitor broadcaster -func NewMonitorBroadcaster(agent p2p.Agent, bc blockchain.Blockchain) *MonitorBroadcaster { - return &MonitorBroadcaster{ - agent: agent, - bc: bc, - } -} - -// Broadcast broadcast monitor msg -func (j *MonitorBroadcaster) Broadcast() { - j.agent.BroadcastOutbound(context.Background(), &iotextypes.Monitor{ - Version: version.PackageVersion, - Height: j.bc.TipHeight(), - }) -} diff --git a/server/itx/server.go b/server/itx/server.go index c7e7d8a242..ff2be39bb9 100644 --- a/server/itx/server.go +++ b/server/itx/server.go @@ -87,8 +87,6 @@ func newServer(cfg config.Config, testing bool) (*Server, error) { if err := cs.Blockchain().AddSubscriber(apiServer); err != nil { return nil, errors.Wrap(err, "failed to add api server as subscriber") } - cs.SetMonitorHandler(apiServer) - cs.SetMonitorBroadcaster(routine.NewRecurringTask(NewMonitorBroadcaster(p2pAgent, cs.Blockchain()).Broadcast, cfg.System.MonitorBroadcastInterval)) } // TODO: explorer dependency deleted here at #1085, need to revive by migrating to api From 3ecc432f734bb923eaad3f4c7760ddb63378ad96 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 3 Jan 2023 23:02:49 +0800 Subject: [PATCH 06/32] update --- chainservice/chainservice.go | 8 ++------ config/config.go | 5 ++--- dispatcher/dispatcher.go | 7 +++---- node/node.go | 2 +- server/itx/server.go | 1 - 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 8090e91b20..8a2ef050af 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -62,10 +62,6 @@ var ( ) ) -type monitorMsgHandler interface { - HandleMonitorMsg(context.Context, string, *iotextypes.Monitor) error -} - func init() { prometheus.MustRegister(_apiCallWithChainIDMtc) prometheus.MustRegister(_apiCallWithOutChainIDMtc) @@ -169,8 +165,8 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err return cs.consensus.HandleConsensusMsg(msg) } -// HandleMonitorMsg handles monitor message. -func (cs *ChainService) HandleMonitorMsg(ctx context.Context, peer string, msg *iotextypes.Monitor) error { +// HandleNodeInfoMsg handles nodeinfo message. +func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg *iotextypes.NodeInfo) error { cs.delegateManager.UpdateNode(&node.Node{ Addr: peer, Height: msg.Height, diff --git a/config/config.go b/config/config.go index 6dda245117..8ff3936cba 100644 --- a/config/config.go +++ b/config/config.go @@ -103,9 +103,8 @@ type ( // System is the system config System struct { // Active is the status of the node. True means active and false means stand-by - Active bool `yaml:"active"` - HeartbeatInterval time.Duration `yaml:"heartbeatInterval"` - MonitorBroadcastInterval time.Duration `yaml:"monitorBroadcastInterval"` + Active bool `yaml:"active"` + HeartbeatInterval time.Duration `yaml:"heartbeatInterval"` // HTTPProfilingPort is the port number to access golang performance profiling data of a blockchain node. It is // 0 by default, meaning performance profiling has been disabled HTTPAdminPort int `yaml:"httpAdminPort"` diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 13692d3552..25446b2735 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -53,7 +53,7 @@ type Subscriber interface { HandleBlock(context.Context, string, *iotextypes.Block) error HandleSyncRequest(context.Context, peer.AddrInfo, *iotexrpc.BlockSync) error HandleConsensusMsg(*iotextypes.ConsensusMessage) error - HandleMonitorMsg(context.Context, string, *iotextypes.Monitor) error + HandleNodeInfoMsg(context.Context, string, *iotextypes.NodeInfo) error } // Dispatcher is used by peers, handles incoming block and header notifications and relays announcements of new blocks. @@ -428,11 +428,10 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, pe d.dispatchAction(ctx, chainID, message) case *iotextypes.Block: d.dispatchBlock(ctx, chainID, peer, message) - case *iotextypes.Monitor: - if err := subscriber.HandleMonitorMsg(ctx, peer, msg); err != nil { + case *iotextypes.NodeInfo: + if err := subscriber.HandleNodeInfoMsg(ctx, peer, msg); err != nil { log.L().Debug("Failed to handle monitor message.", zap.Error(err)) } - // update delegateHeightGauge metric default: msgType, _ := goproto.GetTypeFromRPCMsg(message) log.L().Warn("Unexpected msgType handled by HandleBroadcast.", zap.Any("msgType", msgType)) diff --git a/node/node.go b/node/node.go index 4514b81617..5c8cdcca44 100644 --- a/node/node.go +++ b/node/node.go @@ -68,7 +68,7 @@ func (dm *delegateManager) GetNode(addr string) *Node { return dm.nodeMap[addr] } func (dm *delegateManager) broadcast() { - dm.p2pAgent.BroadcastOutbound(context.Background(), &iotextypes.Monitor{ + dm.p2pAgent.BroadcastOutbound(context.Background(), &iotextypes.NodeInfo{ Height: dm.bc.TipHeight(), Version: version.PackageVersion, }) diff --git a/server/itx/server.go b/server/itx/server.go index ff2be39bb9..811d784e21 100644 --- a/server/itx/server.go +++ b/server/itx/server.go @@ -88,7 +88,6 @@ func newServer(cfg config.Config, testing bool) (*Server, error) { return nil, errors.Wrap(err, "failed to add api server as subscriber") } } - // TODO: explorer dependency deleted here at #1085, need to revive by migrating to api chains[cs.ChainID()] = cs dispatcher.AddSubscriber(cs.ChainID(), cs) From 1090b2aa3cd450f9a921ee74813ff02fdf58368b Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 6 Jan 2023 16:31:30 +0800 Subject: [PATCH 07/32] add node info request and response message --- chainservice/builder.go | 2 +- chainservice/chainservice.go | 25 ++++++++++++++--- dispatcher/dispatcher.go | 27 ++++++++++++++++--- node/config.go | 3 ++- node/node.go | 52 ++++++++++++++++++++++++------------ 5 files changed, 83 insertions(+), 26 deletions(-) diff --git a/chainservice/builder.go b/chainservice/builder.go index 04bdf48c1f..1365203444 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -379,7 +379,7 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B } func (builder *Builder) buildNodeManager() { - dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.consensus, builder.cs.p2pAgent, builder.cs.chain) + dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain) builder.cs.delegateManager = dm builder.cs.lifecycle.Add(dm) } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 8a2ef050af..1c731ed144 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -166,15 +166,34 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err } // HandleNodeInfoMsg handles nodeinfo message. -func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg *iotextypes.NodeInfo) error { +func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg *iotextypes.ResponseNodeInfoMessage) error { cs.delegateManager.UpdateNode(&node.Node{ Addr: peer, - Height: msg.Height, - Version: msg.Version, + Height: msg.Info.Height, + Version: msg.Info.Version, }) return nil } +// HandleRequestNodeInfoMsg handles request node info message +func (cs *ChainService) HandleRequestNodeInfoMsg(ctx context.Context, peerID string, msg *iotextypes.RequestNodeInfoMessage) error { + peers, err := cs.p2pAgent.ConnectedPeers() + if err != nil { + return err + } + var target *peer.AddrInfo + for i := range peers { + if peers[i].ID.Pretty() == peerID { + target = &peers[i] + break + } + } + if target == nil { + return errors.Errorf("unicast node info msg failed: target peerID %s is not connected", peerID) + } + return cs.delegateManager.TellNodeInfo(ctx, *target) +} + // ChainID returns ChainID. func (cs *ChainService) ChainID() uint32 { return cs.chain.ChainID() } diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 25446b2735..930e2877e9 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -53,7 +53,8 @@ type Subscriber interface { HandleBlock(context.Context, string, *iotextypes.Block) error HandleSyncRequest(context.Context, peer.AddrInfo, *iotexrpc.BlockSync) error HandleConsensusMsg(*iotextypes.ConsensusMessage) error - HandleNodeInfoMsg(context.Context, string, *iotextypes.NodeInfo) error + HandleRequestNodeInfoMsg(context.Context, string, *iotextypes.RequestNodeInfoMessage) error + HandleNodeInfoMsg(context.Context, string, *iotextypes.ResponseNodeInfoMessage) error } // Dispatcher is used by peers, handles incoming block and header notifications and relays announcements of new blocks. @@ -428,9 +429,9 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, pe d.dispatchAction(ctx, chainID, message) case *iotextypes.Block: d.dispatchBlock(ctx, chainID, peer, message) - case *iotextypes.NodeInfo: - if err := subscriber.HandleNodeInfoMsg(ctx, peer, msg); err != nil { - log.L().Debug("Failed to handle monitor message.", zap.Error(err)) + case *iotextypes.RequestNodeInfoMessage: + if err := subscriber.HandleRequestNodeInfoMsg(ctx, peer, msg); err != nil { + log.L().Warn("Failed to handle request node info message.", zap.Error(err)) } default: msgType, _ := goproto.GetTypeFromRPCMsg(message) @@ -449,11 +450,29 @@ func (d *IotxDispatcher) HandleTell(ctx context.Context, chainID uint32, peer pe d.dispatchBlockSyncReq(ctx, chainID, peer, message) case iotexrpc.MessageType_BLOCK: d.dispatchBlock(ctx, chainID, peer.ID.Pretty(), message) + case iotexrpc.MessageType_NODE_INFO: + d.dispatchNodeInfo(ctx, chainID, peer.ID.Pretty(), message) default: log.L().Warn("Unexpected msgType handled by HandleTell.", zap.Any("msgType", msgType)) } } +func (d *IotxDispatcher) dispatchNodeInfo(ctx context.Context, chainID uint32, peer string, message proto.Message) { + if atomic.LoadInt32(&d.shutdown) != 0 { + return + } + subscriber := d.subscriber(chainID) + if subscriber == nil { + log.L().Debug("no subscriber for this chain id, drop the node info", zap.Uint32("chain id", chainID)) + return + } + + if err := subscriber.HandleNodeInfoMsg(ctx, peer, message.(*iotextypes.ResponseNodeInfoMessage)); err != nil { + log.L().Warn("failed to handle node info message", zap.Error(err)) + return + } +} + func (d *IotxDispatcher) updateEventAudit(t iotexrpc.MessageType) { d.eventAuditLock.Lock() defer d.eventAuditLock.Unlock() diff --git a/node/config.go b/node/config.go index c24fd039f3..b7c4e6f376 100644 --- a/node/config.go +++ b/node/config.go @@ -7,6 +7,7 @@ package node import "time" +// Config node config type Config struct { - NodeInfoBroadcastInterval time.Duration `yaml:"nodeInfoBroadcastInterval"` + RequestNodeInfoInterval time.Duration `yaml:"requestNodeInfoInterval"` } diff --git a/node/node.go b/node/node.go index 5c8cdcca44..9d5162bf73 100644 --- a/node/node.go +++ b/node/node.go @@ -9,12 +9,13 @@ import ( "context" "github.com/iotexproject/iotex-core/blockchain" - "github.com/iotexproject/iotex-core/consensus" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/lifecycle" "github.com/iotexproject/iotex-core/pkg/routine" "github.com/iotexproject/iotex-core/pkg/version" "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/libp2p/go-libp2p-core/peer" + "google.golang.org/protobuf/types/known/timestamppb" ) type Node struct { @@ -27,36 +28,38 @@ type Node struct { type NodeManager interface { lifecycle.StartStopper UpdateNode(*Node) - GetNode(addr string) *Node + GetNode(addr string) Node + TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error } type delegateManager struct { cfg Config nodeMap map[string]*Node - consensus consensus.Consensus broadcaster lifecycle.StartStopper p2pAgent p2p.Agent bc blockchain.Blockchain } -func NewDelegateManager(cfg *Config, consensus consensus.Consensus, p2pAgent p2p.Agent, bc blockchain.Blockchain) NodeManager { +// NewDelegateManager new delegate manager +func NewDelegateManager(cfg *Config, p2pAgent p2p.Agent, bc blockchain.Blockchain) NodeManager { dm := &delegateManager{ - cfg: *cfg, - nodeMap: make(map[string]*Node), - consensus: consensus, - p2pAgent: p2pAgent, - bc: bc, + cfg: *cfg, + nodeMap: make(map[string]*Node), + p2pAgent: p2pAgent, + bc: bc, } - dm.broadcaster = routine.NewRecurringTask(dm.broadcast, cfg.NodeInfoBroadcastInterval) + dm.broadcaster = routine.NewRecurringTask(dm.requestNodeInfo, cfg.RequestNodeInfoInterval) return dm } func (dm *delegateManager) Start(ctx context.Context) error { return dm.broadcaster.Start(ctx) } + func (dm *delegateManager) Stop(ctx context.Context) error { return dm.broadcaster.Stop(ctx) } + func (dm *delegateManager) UpdateNode(node *Node) { // update dm.nodeMap n := *node @@ -64,12 +67,27 @@ func (dm *delegateManager) UpdateNode(node *Node) { // update metric nodeDelegateHeightGauge.WithLabelValues("address", node.Addr, "version", node.Version).Set(float64(node.Height)) } -func (dm *delegateManager) GetNode(addr string) *Node { - return dm.nodeMap[addr] + +func (dm *delegateManager) GetNode(addr string) Node { + return *dm.nodeMap[addr] +} + +func (dm *delegateManager) requestNodeInfo() { + req := &iotextypes.RequestNodeInfoMessage{ + Timestamp: timestamppb.Now(), + } + // TODO: add sign for msg + dm.p2pAgent.BroadcastOutbound(context.Background(), req) } -func (dm *delegateManager) broadcast() { - dm.p2pAgent.BroadcastOutbound(context.Background(), &iotextypes.NodeInfo{ - Height: dm.bc.TipHeight(), - Version: version.PackageVersion, - }) + +func (dm *delegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { + req := &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: version.PackageVersion, + Height: dm.bc.TipHeight(), + Timestamp: timestamppb.Now(), + }, + } + // TODO: add sign for msg + return dm.p2pAgent.UnicastOutbound(ctx, peer, req) } From 6eb404db8b70ed435c3d27f66d19e4bff01b43ae Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 6 Jan 2023 17:16:36 +0800 Subject: [PATCH 08/32] remove delegate manager dependency --- api/coreservice.go | 4 +- api/serverV2.go | 2 +- chainservice/chainservice.go | 8 +--- node/manager.go | 89 ++++++++++++++++++++++++++++++++++ node/node.go | 93 ------------------------------------ 5 files changed, 94 insertions(+), 102 deletions(-) create mode 100644 node/manager.go delete mode 100644 node/node.go diff --git a/api/coreservice.go b/api/coreservice.go index 5c9764febb..e5ba027f3b 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -159,7 +159,7 @@ type ( chainListener apitypes.Listener electionCommittee committee.Committee readCache *ReadCache - delegateManager node.NodeManager + delegateManager *node.DelegateManager } // jobDesc provides a struct to get and store logs in core.LogsInRange @@ -209,7 +209,7 @@ func newCoreService( bfIndexer blockindex.BloomFilterIndexer, actPool actpool.ActPool, registry *protocol.Registry, - dm node.NodeManager, + dm *node.DelegateManager, opts ...Option, ) (CoreService, error) { if cfg == (Config{}) { diff --git a/api/serverV2.go b/api/serverV2.go index 02a834e332..f54b000847 100644 --- a/api/serverV2.go +++ b/api/serverV2.go @@ -44,7 +44,7 @@ func NewServerV2( bfIndexer blockindex.BloomFilterIndexer, actPool actpool.ActPool, registry *protocol.Registry, - dm node.NodeManager, + dm *node.DelegateManager, opts ...Option, ) (*ServerV2, error) { coreAPI, err := newCoreService(cfg, chain, bs, sf, dao, indexer, bfIndexer, actPool, registry, dm, opts...) diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 1c731ed144..afceeb05d0 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -85,7 +85,7 @@ type ChainService struct { candidateIndexer *poll.CandidateIndexer candBucketsIndexer *staking.CandidatesBucketsIndexer registry *protocol.Registry - delegateManager node.NodeManager + delegateManager *node.DelegateManager } // Start starts the server @@ -167,11 +167,7 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err // HandleNodeInfoMsg handles nodeinfo message. func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg *iotextypes.ResponseNodeInfoMessage) error { - cs.delegateManager.UpdateNode(&node.Node{ - Addr: peer, - Height: msg.Info.Height, - Version: msg.Info.Version, - }) + cs.delegateManager.UpdateNode(peer, msg.Info) return nil } diff --git a/node/manager.go b/node/manager.go new file mode 100644 index 0000000000..74be7ee0ee --- /dev/null +++ b/node/manager.go @@ -0,0 +1,89 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package node + +import ( + "context" + + "github.com/iotexproject/iotex-core/pkg/lifecycle" + "github.com/iotexproject/iotex-core/pkg/routine" + "github.com/iotexproject/iotex-core/pkg/version" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/libp2p/go-libp2p-core/peer" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type ( + transmitter interface { + BroadcastOutbound(context.Context, proto.Message) error + UnicastOutbound(context.Context, peer.AddrInfo, proto.Message) error + } + + heightable interface { + TipHeight() uint64 + } + + // DelegateManager manage delegate node info + DelegateManager struct { + cfg Config + nodeMap map[string]iotextypes.NodeInfo + broadcaster lifecycle.StartStopper + transmitter transmitter + heightable heightable + } +) + +// NewDelegateManager new delegate manager +func NewDelegateManager(cfg *Config, t transmitter, h heightable) *DelegateManager { + dm := &DelegateManager{ + cfg: *cfg, + nodeMap: make(map[string]iotextypes.NodeInfo), + transmitter: t, + heightable: h, + } + dm.broadcaster = routine.NewRecurringTask(dm.requestNodeInfo, cfg.RequestNodeInfoInterval) + return dm +} + +// Start start delegate broadcast task +func (dm *DelegateManager) Start(ctx context.Context) error { + return dm.broadcaster.Start(ctx) +} + +// Stop stop delegate broadcast task +func (dm *DelegateManager) Stop(ctx context.Context) error { + return dm.broadcaster.Stop(ctx) +} + +// UpdateNode update node info +func (dm *DelegateManager) UpdateNode(addr string, node *iotextypes.NodeInfo) { + // update dm.nodeMap + dm.nodeMap[addr] = *node + // update metric + nodeDelegateHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) +} + +func (dm *DelegateManager) requestNodeInfo() { + req := &iotextypes.RequestNodeInfoMessage{ + Timestamp: timestamppb.Now(), + } + // TODO: add sign for msg + dm.transmitter.BroadcastOutbound(context.Background(), req) +} + +// TellNodeInfo tell node info to peer +func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { + req := &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: version.PackageVersion, + Height: dm.heightable.TipHeight(), + Timestamp: timestamppb.Now(), + }, + } + // TODO: add sign for msg + return dm.transmitter.UnicastOutbound(ctx, peer, req) +} diff --git a/node/node.go b/node/node.go deleted file mode 100644 index 9d5162bf73..0000000000 --- a/node/node.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2022 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package node - -import ( - "context" - - "github.com/iotexproject/iotex-core/blockchain" - "github.com/iotexproject/iotex-core/p2p" - "github.com/iotexproject/iotex-core/pkg/lifecycle" - "github.com/iotexproject/iotex-core/pkg/routine" - "github.com/iotexproject/iotex-core/pkg/version" - "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/libp2p/go-libp2p-core/peer" - "google.golang.org/protobuf/types/known/timestamppb" -) - -type Node struct { - Addr string - Height uint64 - Version string -} - -// NodeManager manage nodes on the blockchain -type NodeManager interface { - lifecycle.StartStopper - UpdateNode(*Node) - GetNode(addr string) Node - TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error -} - -type delegateManager struct { - cfg Config - nodeMap map[string]*Node - broadcaster lifecycle.StartStopper - p2pAgent p2p.Agent - bc blockchain.Blockchain -} - -// NewDelegateManager new delegate manager -func NewDelegateManager(cfg *Config, p2pAgent p2p.Agent, bc blockchain.Blockchain) NodeManager { - dm := &delegateManager{ - cfg: *cfg, - nodeMap: make(map[string]*Node), - p2pAgent: p2pAgent, - bc: bc, - } - dm.broadcaster = routine.NewRecurringTask(dm.requestNodeInfo, cfg.RequestNodeInfoInterval) - return dm -} - -func (dm *delegateManager) Start(ctx context.Context) error { - return dm.broadcaster.Start(ctx) -} - -func (dm *delegateManager) Stop(ctx context.Context) error { - return dm.broadcaster.Stop(ctx) -} - -func (dm *delegateManager) UpdateNode(node *Node) { - // update dm.nodeMap - n := *node - dm.nodeMap[node.Addr] = &n - // update metric - nodeDelegateHeightGauge.WithLabelValues("address", node.Addr, "version", node.Version).Set(float64(node.Height)) -} - -func (dm *delegateManager) GetNode(addr string) Node { - return *dm.nodeMap[addr] -} - -func (dm *delegateManager) requestNodeInfo() { - req := &iotextypes.RequestNodeInfoMessage{ - Timestamp: timestamppb.Now(), - } - // TODO: add sign for msg - dm.p2pAgent.BroadcastOutbound(context.Background(), req) -} - -func (dm *delegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { - req := &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ - Version: version.PackageVersion, - Height: dm.bc.TipHeight(), - Timestamp: timestamppb.Now(), - }, - } - // TODO: add sign for msg - return dm.p2pAgent.UnicastOutbound(ctx, peer, req) -} From 98884a21eed57af1352bccca3cce21953d5a92bf Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 10 Jan 2023 00:40:22 +0800 Subject: [PATCH 09/32] add message sign --- chainservice/builder.go | 2 +- chainservice/chainservice.go | 4 +- node/manager.go | 91 +++++++++++++++++++++++++++++------- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/chainservice/builder.go b/chainservice/builder.go index 1365203444..3c5a4a4a8a 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -379,7 +379,7 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B } func (builder *Builder) buildNodeManager() { - dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain) + dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey(), nil) builder.cs.delegateManager = dm builder.cs.lifecycle.Add(dm) } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index afceeb05d0..631cba8a07 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -167,7 +167,7 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err // HandleNodeInfoMsg handles nodeinfo message. func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg *iotextypes.ResponseNodeInfoMessage) error { - cs.delegateManager.UpdateNode(peer, msg.Info) + cs.delegateManager.HandleNodeInfo(ctx, peer, msg) return nil } @@ -185,7 +185,7 @@ func (cs *ChainService) HandleRequestNodeInfoMsg(ctx context.Context, peerID str } } if target == nil { - return errors.Errorf("unicast node info msg failed: target peerID %s is not connected", peerID) + return errors.Errorf("unicast node info msg failed: target peerID %s is not connected, peers size=%v, %v", peerID, len(peers), peers) } return cs.delegateManager.TellNodeInfo(ctx, *target) } diff --git a/node/manager.go b/node/manager.go index 74be7ee0ee..41779b5d95 100644 --- a/node/manager.go +++ b/node/manager.go @@ -8,11 +8,14 @@ package node import ( "context" - "github.com/iotexproject/iotex-core/pkg/lifecycle" + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/pkg/routine" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/iotexproject/iotex-core/pkg/version" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/libp2p/go-libp2p-core/peer" + "go.uber.org/zap" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -21,31 +24,43 @@ type ( transmitter interface { BroadcastOutbound(context.Context, proto.Message) error UnicastOutbound(context.Context, peer.AddrInfo, proto.Message) error + Info() (peer.AddrInfo, error) } heightable interface { TipHeight() uint64 } + signer interface { + Sign([]byte) ([]byte, error) + } + signVerifier interface { + Verify(pk, hash, sig []byte) bool + } + // DelegateManager manage delegate node info DelegateManager struct { - cfg Config - nodeMap map[string]iotextypes.NodeInfo - broadcaster lifecycle.StartStopper - transmitter transmitter - heightable heightable + cfg Config + nodeMap map[string]iotextypes.NodeInfo + broadcaster *routine.RecurringTask + transmitter transmitter + heightable heightable + signer signer + signVerifier signVerifier } ) // NewDelegateManager new delegate manager -func NewDelegateManager(cfg *Config, t transmitter, h heightable) *DelegateManager { +func NewDelegateManager(cfg *Config, t transmitter, h heightable, s signer, sv signVerifier) *DelegateManager { dm := &DelegateManager{ - cfg: *cfg, - nodeMap: make(map[string]iotextypes.NodeInfo), - transmitter: t, - heightable: h, + cfg: *cfg, + nodeMap: make(map[string]iotextypes.NodeInfo), + transmitter: t, + heightable: h, + signer: s, + signVerifier: sv, } - dm.broadcaster = routine.NewRecurringTask(dm.requestNodeInfo, cfg.RequestNodeInfoInterval) + dm.broadcaster = routine.NewRecurringTask(dm.RequestNodeInfo, cfg.RequestNodeInfoInterval) return dm } @@ -59,6 +74,16 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { return dm.broadcaster.Stop(ctx) } +// HandleNodeInfo handle node info message +func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, addr string, node *iotextypes.ResponseNodeInfoMessage) { + // sign verify + // if !dm.verifyNodeInfo(addr, node) { + // log.L().Warn("node info message verify failed", zap.String("addr", addr)) + // return + // } + dm.UpdateNode(addr, node.Info) +} + // UpdateNode update node info func (dm *DelegateManager) UpdateNode(addr string, node *iotextypes.NodeInfo) { // update dm.nodeMap @@ -67,16 +92,29 @@ func (dm *DelegateManager) UpdateNode(addr string, node *iotextypes.NodeInfo) { nodeDelegateHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) } -func (dm *DelegateManager) requestNodeInfo() { - req := &iotextypes.RequestNodeInfoMessage{ - Timestamp: timestamppb.Now(), +// RequestNodeInfo broadcast request node info message +func (dm *DelegateManager) RequestNodeInfo() { + log.L().Info("delegateManager request node info") + if err := dm.transmitter.BroadcastOutbound(context.Background(), &iotextypes.RequestNodeInfoMessage{}); err != nil { + log.L().Error("delegateManager request node info failed", zap.Error(err)) + } + + // manually update self node info for broadcast message to myself will be ignored + peer, err := dm.transmitter.Info() + if err != nil { + log.L().Error("delegateManager get self info failed", zap.Error(err)) + return } - // TODO: add sign for msg - dm.transmitter.BroadcastOutbound(context.Background(), req) + dm.UpdateNode(peer.ID.Pretty(), &iotextypes.NodeInfo{ + Version: version.PackageVersion, + Height: dm.heightable.TipHeight(), + Timestamp: timestamppb.Now(), + }) } // TellNodeInfo tell node info to peer func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { + log.L().Info("delegateManager tell node info", zap.Any("peer", peer.ID.Pretty())) req := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ Version: version.PackageVersion, @@ -84,6 +122,23 @@ func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) Timestamp: timestamppb.Now(), }, } - // TODO: add sign for msg + // add sign for msg + // dm.signNodeInfo(req) return dm.transmitter.UnicastOutbound(ctx, peer, req) } + +func (dm *DelegateManager) signNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) error { + h := hash.Hash256b(byteutil.Must(proto.Marshal(msg.Info))) + sign, err := dm.signer.Sign(h[:]) + if err != nil { + return err + } + msg.Signature = sign + return nil +} + +func (dm *DelegateManager) verifyNodeInfo(peer string, msg *iotextypes.ResponseNodeInfoMessage) bool { + pk := []byte{} + hash := []byte{} + return dm.signVerifier.Verify(pk, hash, msg.Signature) +} From eb56750ccf6bf7564aa8deedcaa59d9c93474f05 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 10 Jan 2023 13:01:24 +0800 Subject: [PATCH 10/32] add sign for node info message --- chainservice/builder.go | 2 +- node/manager.go | 67 ++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/chainservice/builder.go b/chainservice/builder.go index 3c5a4a4a8a..a99641dbcd 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -379,7 +379,7 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B } func (builder *Builder) buildNodeManager() { - dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey(), nil) + dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) builder.cs.delegateManager = dm builder.cs.lifecycle.Add(dm) } diff --git a/node/manager.go b/node/manager.go index 41779b5d95..128425f4f4 100644 --- a/node/manager.go +++ b/node/manager.go @@ -8,6 +8,7 @@ package node import ( "context" + "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/pkg/routine" @@ -34,31 +35,26 @@ type ( signer interface { Sign([]byte) ([]byte, error) } - signVerifier interface { - Verify(pk, hash, sig []byte) bool - } // DelegateManager manage delegate node info DelegateManager struct { - cfg Config - nodeMap map[string]iotextypes.NodeInfo - broadcaster *routine.RecurringTask - transmitter transmitter - heightable heightable - signer signer - signVerifier signVerifier + cfg Config + nodeMap map[string]iotextypes.NodeInfo + broadcaster *routine.RecurringTask + transmitter transmitter + heightable heightable + signer signer } ) // NewDelegateManager new delegate manager -func NewDelegateManager(cfg *Config, t transmitter, h heightable, s signer, sv signVerifier) *DelegateManager { +func NewDelegateManager(cfg *Config, t transmitter, h heightable, s signer) *DelegateManager { dm := &DelegateManager{ - cfg: *cfg, - nodeMap: make(map[string]iotextypes.NodeInfo), - transmitter: t, - heightable: h, - signer: s, - signVerifier: sv, + cfg: *cfg, + nodeMap: make(map[string]iotextypes.NodeInfo), + transmitter: t, + heightable: h, + signer: s, } dm.broadcaster = routine.NewRecurringTask(dm.RequestNodeInfo, cfg.RequestNodeInfoInterval) return dm @@ -76,7 +72,7 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { // HandleNodeInfo handle node info message func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, addr string, node *iotextypes.ResponseNodeInfoMessage) { - // sign verify + // TODO sign verify // if !dm.verifyNodeInfo(addr, node) { // log.L().Warn("node info message verify failed", zap.String("addr", addr)) // return @@ -105,11 +101,12 @@ func (dm *DelegateManager) RequestNodeInfo() { log.L().Error("delegateManager get self info failed", zap.Error(err)) return } - dm.UpdateNode(peer.ID.Pretty(), &iotextypes.NodeInfo{ + msg := &iotextypes.NodeInfo{ Version: version.PackageVersion, Height: dm.heightable.TipHeight(), Timestamp: timestamppb.Now(), - }) + } + dm.UpdateNode(peer.ID.Pretty(), msg) } // TellNodeInfo tell node info to peer @@ -123,22 +120,36 @@ func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) }, } // add sign for msg - // dm.signNodeInfo(req) + sign, err := dm.signNodeInfo(req) + if err != nil { + return err + } + req.Signature = sign + return dm.transmitter.UnicastOutbound(ctx, peer, req) } -func (dm *DelegateManager) signNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) error { - h := hash.Hash256b(byteutil.Must(proto.Marshal(msg.Info))) +func (dm *DelegateManager) signNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) ([]byte, error) { + h := dm.hashNodeInfo(msg) sign, err := dm.signer.Sign(h[:]) if err != nil { - return err + return nil, err } - msg.Signature = sign - return nil + return sign, nil +} + +func (dm *DelegateManager) hashNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) hash.Hash256 { + return hash.Hash256b(byteutil.Must(proto.Marshal(msg.Info))) } func (dm *DelegateManager) verifyNodeInfo(peer string, msg *iotextypes.ResponseNodeInfoMessage) bool { pk := []byte{} - hash := []byte{} - return dm.signVerifier.Verify(pk, hash, msg.Signature) + hash := dm.hashNodeInfo(msg) + pubK, err := crypto.BytesToPublicKey(pk) + if err != nil { + log.L().Warn("convert bytes to publickey failed", zap.Error(err)) + return false + } + + return pubK.Verify(hash[:], msg.Signature) } From 37af5512316824853e308d81f8bfba62ac38c1f6 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 10 Jan 2023 13:15:19 +0800 Subject: [PATCH 11/32] fix unittest error --- api/coreservice.go | 28 ++++++++++++---------------- api/serverV2.go | 4 +--- chainservice/chainservice.go | 1 - config/config.go | 1 + dispatcher/dispatcher_test.go | 8 ++++++++ node/config.go | 3 +++ 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/api/coreservice.go b/api/coreservice.go index e5ba027f3b..96cb4a7dc0 100644 --- a/api/coreservice.go +++ b/api/coreservice.go @@ -49,7 +49,6 @@ import ( "github.com/iotexproject/iotex-core/blocksync" "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/gasstation" - "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/pkg/tracer" "github.com/iotexproject/iotex-core/pkg/version" @@ -159,7 +158,6 @@ type ( chainListener apitypes.Listener electionCommittee committee.Committee readCache *ReadCache - delegateManager *node.DelegateManager } // jobDesc provides a struct to get and store logs in core.LogsInRange @@ -209,7 +207,6 @@ func newCoreService( bfIndexer blockindex.BloomFilterIndexer, actPool actpool.ActPool, registry *protocol.Registry, - dm *node.DelegateManager, opts ...Option, ) (CoreService, error) { if cfg == (Config{}) { @@ -222,19 +219,18 @@ func newCoreService( } core := coreService{ - bc: chain, - bs: bs, - sf: sf, - dao: dao, - indexer: indexer, - bfIndexer: bfIndexer, - ap: actPool, - cfg: cfg, - registry: registry, - chainListener: NewChainListener(500), - gs: gasstation.NewGasStation(chain, dao, cfg.GasStation), - readCache: NewReadCache(), - delegateManager: dm, + bc: chain, + bs: bs, + sf: sf, + dao: dao, + indexer: indexer, + bfIndexer: bfIndexer, + ap: actPool, + cfg: cfg, + registry: registry, + chainListener: NewChainListener(500), + gs: gasstation.NewGasStation(chain, dao, cfg.GasStation), + readCache: NewReadCache(), } for _, opt := range opts { diff --git a/api/serverV2.go b/api/serverV2.go index f54b000847..65b9832826 100644 --- a/api/serverV2.go +++ b/api/serverV2.go @@ -19,7 +19,6 @@ import ( "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/blockindex" "github.com/iotexproject/iotex-core/blocksync" - "github.com/iotexproject/iotex-core/node" "github.com/iotexproject/iotex-core/pkg/tracer" "github.com/iotexproject/iotex-core/state/factory" ) @@ -44,10 +43,9 @@ func NewServerV2( bfIndexer blockindex.BloomFilterIndexer, actPool actpool.ActPool, registry *protocol.Registry, - dm *node.DelegateManager, opts ...Option, ) (*ServerV2, error) { - coreAPI, err := newCoreService(cfg, chain, bs, sf, dao, indexer, bfIndexer, actPool, registry, dm, opts...) + coreAPI, err := newCoreService(cfg, chain, bs, sf, dao, indexer, bfIndexer, actPool, registry, opts...) if err != nil { return nil, err } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 631cba8a07..541d23f3f1 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -249,7 +249,6 @@ func (cs *ChainService) NewAPIServer(cfg api.Config, plugins map[int]interface{} cs.bfIndexer, cs.actpool, cs.registry, - cs.delegateManager, apiServerOptions..., ) if err != nil { diff --git a/config/config.go b/config/config.go index 8ff3936cba..478328160d 100644 --- a/config/config.go +++ b/config/config.go @@ -81,6 +81,7 @@ var ( DB: db.DefaultConfig, Indexer: blockindex.DefaultConfig, Genesis: genesis.Default, + Node: node.DefaultConfig, } // ErrInvalidCfg indicates the invalid config value diff --git a/dispatcher/dispatcher_test.go b/dispatcher/dispatcher_test.go index bc56e26e07..7e4d1b3b85 100644 --- a/dispatcher/dispatcher_test.go +++ b/dispatcher/dispatcher_test.go @@ -98,3 +98,11 @@ func (ds *dummySubscriber) HandleSyncRequest(context.Context, peer.AddrInfo, *io func (ds *dummySubscriber) HandleAction(context.Context, *iotextypes.Action) error { return nil } func (ds *dummySubscriber) HandleConsensusMsg(*iotextypes.ConsensusMessage) error { return nil } + +func (ds *dummySubscriber) HandleRequestNodeInfoMsg(context.Context, string, *iotextypes.RequestNodeInfoMessage) error { + return nil +} + +func (ds *dummySubscriber) HandleNodeInfoMsg(context.Context, string, *iotextypes.ResponseNodeInfoMessage) error { + return nil +} diff --git a/node/config.go b/node/config.go index b7c4e6f376..1f75d1dd2b 100644 --- a/node/config.go +++ b/node/config.go @@ -11,3 +11,6 @@ import "time" type Config struct { RequestNodeInfoInterval time.Duration `yaml:"requestNodeInfoInterval"` } + +// DefaultConfig is the default config +var DefaultConfig = Config{} From 96d185a4e560327dcca1545c646db7000d60506c Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 11 Jan 2023 10:09:14 +0800 Subject: [PATCH 12/32] add unittest for node --- dispatcher/dispatcher_test.go | 2 + go.mod | 2 +- misc/scripts/mockgen.sh | 7 + node/manager.go | 16 +- node/manager_test.go | 275 ++++++++++++++++++++++++++++ test/mock/mock_node/mock_manager.go | 155 ++++++++++++++++ 6 files changed, 453 insertions(+), 4 deletions(-) create mode 100644 node/manager_test.go create mode 100644 test/mock/mock_node/mock_manager.go diff --git a/dispatcher/dispatcher_test.go b/dispatcher/dispatcher_test.go index 7e4d1b3b85..429bfcbc48 100644 --- a/dispatcher/dispatcher_test.go +++ b/dispatcher/dispatcher_test.go @@ -52,6 +52,8 @@ func setTestCase() []proto.Message { &iotextypes.Block{}, &iotexrpc.BlockSync{}, &testingpb.TestPayload{}, + &iotextypes.RequestNodeInfoMessage{}, + &iotextypes.ResponseNodeInfoMessage{}, } } diff --git a/go.mod b/go.mod index 8f7f54b87f..4538f1a270 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( ) require ( + github.com/prometheus/client_model v0.2.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/shirou/gopsutil/v3 v3.22.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.34.0 @@ -173,7 +174,6 @@ require ( github.com/pierrec/lz4 v2.0.5+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.26.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect github.com/rjeczalik/notify v0.9.2 // indirect diff --git a/misc/scripts/mockgen.sh b/misc/scripts/mockgen.sh index d96bc1cf73..3e26023a44 100755 --- a/misc/scripts/mockgen.sh +++ b/misc/scripts/mockgen.sh @@ -147,3 +147,10 @@ mockgen -destination=./test/mock/mock_web3server/mock_web3server.go \ -source=./api/web3server.go \ -package=mock_web3server \ Web3Handler + +mkdir -p ./test/mock/mock_node +mockgen -destination=./test/mock/mock_node/mock_manager.go \ + -source=./node/manager.go \ + -package=mock_node \ + transmitter heightable signer + diff --git a/node/manager.go b/node/manager.go index 128425f4f4..7fb43d4779 100644 --- a/node/manager.go +++ b/node/manager.go @@ -56,18 +56,28 @@ func NewDelegateManager(cfg *Config, t transmitter, h heightable, s signer) *Del heightable: h, signer: s, } - dm.broadcaster = routine.NewRecurringTask(dm.RequestNodeInfo, cfg.RequestNodeInfoInterval) + // disable broadcast if RequestNodeInfoInterval == 0 + if cfg.RequestNodeInfoInterval > 0 { + dm.broadcaster = routine.NewRecurringTask(dm.RequestNodeInfo, cfg.RequestNodeInfoInterval) + } + return dm } // Start start delegate broadcast task func (dm *DelegateManager) Start(ctx context.Context) error { - return dm.broadcaster.Start(ctx) + if dm.broadcaster != nil { + return dm.broadcaster.Start(ctx) + } + return nil } // Stop stop delegate broadcast task func (dm *DelegateManager) Stop(ctx context.Context) error { - return dm.broadcaster.Stop(ctx) + if dm.broadcaster != nil { + return dm.broadcaster.Stop(ctx) + } + return nil } // HandleNodeInfo handle node info message diff --git a/node/manager_test.go b/node/manager_test.go new file mode 100644 index 0000000000..86ce91771e --- /dev/null +++ b/node/manager_test.go @@ -0,0 +1,275 @@ +// Copyright (c) 2022 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package node + +import ( + "context" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/iotexproject/iotex-core/pkg/routine" + "github.com/iotexproject/iotex-core/test/mock/mock_node" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/libp2p/go-libp2p-core/peer" + dto "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestNewDelegateManager(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + hMock := mock_node.NewMockheightable(ctrl) + tMock := mock_node.NewMocktransmitter(ctrl) + sMock := mock_node.NewMocksigner(ctrl) + + type args struct { + cfg *Config + t transmitter + h heightable + s signer + } + tests := []struct { + name string + args args + want *DelegateManager + broadcasterIsNull bool + }{ + { + "disable_broadcast", + args{&Config{}, tMock, hMock, sMock}, + &DelegateManager{ + cfg: Config{}, + nodeMap: map[string]iotextypes.NodeInfo{}, + transmitter: tMock, + heightable: hMock, + signer: sMock, + }, + true, + }, + { + "enable_broadcast", + args{&Config{time.Second * 3}, tMock, hMock, sMock}, + &DelegateManager{ + cfg: Config{time.Second * 3}, + nodeMap: map[string]iotextypes.NodeInfo{}, + transmitter: tMock, + heightable: hMock, + signer: sMock, + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewDelegateManager(tt.args.cfg, tt.args.t, tt.args.h, tt.args.s) + require.Equal(t, tt.want.cfg, got.cfg) + require.Equal(t, tt.want.nodeMap, got.nodeMap) + require.Equal(t, tt.want.transmitter, got.transmitter) + require.Equal(t, tt.want.heightable, got.heightable) + require.Equal(t, tt.want.signer, got.signer) + require.Equal(t, tt.broadcasterIsNull, got.broadcaster == nil) + }) + } +} + +func TestDelegateManager_HandleNodeInfo(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + hMock := mock_node.NewMockheightable(ctrl) + tMock := mock_node.NewMocktransmitter(ctrl) + sMock := mock_node.NewMocksigner(ctrl) + + type fields struct { + cfg Config + nodeMap map[string]iotextypes.NodeInfo + broadcaster *routine.RecurringTask + transmitter transmitter + heightable heightable + signer signer + } + type args struct { + ctx context.Context + addr string + node *iotextypes.ResponseNodeInfoMessage + } + tests := []struct { + name string + fields fields + args args + }{ + { + "", + fields{ + cfg: Config{}, + nodeMap: map[string]iotextypes.NodeInfo{}, + transmitter: tMock, + heightable: hMock, + signer: sMock, + }, + args{ + context.Background(), + "abc", + &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: "v1.8.0", + Height: 200, + Timestamp: timestamppb.Now(), + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dm := &DelegateManager{ + cfg: tt.fields.cfg, + nodeMap: tt.fields.nodeMap, + broadcaster: tt.fields.broadcaster, + transmitter: tt.fields.transmitter, + heightable: tt.fields.heightable, + signer: tt.fields.signer, + } + dm.HandleNodeInfo(tt.args.ctx, tt.args.addr, tt.args.node) + + require.Equal(t, tt.args.node.Info.Height, dm.nodeMap[tt.args.addr].Height) + require.Equal(t, tt.args.node.Info.Version, dm.nodeMap[tt.args.addr].Version) + require.Equal(t, tt.args.node.Info.Timestamp.String(), dm.nodeMap[tt.args.addr].Timestamp.String()) + + m := dto.Metric{} + nodeDelegateHeightGauge.WithLabelValues(tt.args.addr, tt.args.node.Info.Version).Write(&m) + require.Equal(t, tt.args.node.Info.Height, uint64(m.Gauge.GetValue())) + }) + } +} + +func TestDelegateManager_RequestNodeInfo(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + hMock := mock_node.NewMockheightable(ctrl) + tMock := mock_node.NewMocktransmitter(ctrl) + sMock := mock_node.NewMocksigner(ctrl) + + type fields struct { + cfg Config + nodeMap map[string]iotextypes.NodeInfo + broadcaster *routine.RecurringTask + transmitter transmitter + heightable heightable + signer signer + } + tests := []struct { + name string + fields fields + }{ + { + "update_self", + fields{ + Config{}, + map[string]iotextypes.NodeInfo{}, + nil, + tMock, + hMock, + sMock, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dm := &DelegateManager{ + cfg: tt.fields.cfg, + nodeMap: tt.fields.nodeMap, + broadcaster: tt.fields.broadcaster, + transmitter: tt.fields.transmitter, + heightable: tt.fields.heightable, + signer: tt.fields.signer, + } + peerID := peer.AddrInfo{ID: "abcd"} + height := uint64(200) + tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) + tMock.EXPECT().Info().Return(peerID, nil).Times(1) + hMock.EXPECT().TipHeight().Return(height).Times(1) + dm.RequestNodeInfo() + + require.Equal(t, height, dm.nodeMap[peerID.ID.Pretty()].Height) + }) + } +} + +func TestDelegateManager_TellNodeInfo(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + hMock := mock_node.NewMockheightable(ctrl) + tMock := mock_node.NewMocktransmitter(ctrl) + sMock := mock_node.NewMocksigner(ctrl) + + type fields struct { + cfg Config + nodeMap map[string]iotextypes.NodeInfo + broadcaster *routine.RecurringTask + transmitter transmitter + heightable heightable + signer signer + } + type args struct { + ctx context.Context + peer peer.AddrInfo + height uint64 + sign []byte + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + "", + fields{ + Config{}, + map[string]iotextypes.NodeInfo{}, + nil, + tMock, + hMock, + sMock, + }, + args{ + context.Background(), + peer.AddrInfo{ID: "abcd"}, + 200, + []byte("xxxxxx"), + }, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dm := &DelegateManager{ + cfg: tt.fields.cfg, + nodeMap: tt.fields.nodeMap, + broadcaster: tt.fields.broadcaster, + transmitter: tt.fields.transmitter, + heightable: tt.fields.heightable, + signer: tt.fields.signer, + } + message := &iotextypes.ResponseNodeInfoMessage{} + hMock.EXPECT().TipHeight().Return(tt.args.height).Times(1) + tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error { + *message = *msg.(*iotextypes.ResponseNodeInfoMessage) + return nil + }).Times(1) + sMock.EXPECT().Sign(gomock.Any()).Return(tt.args.sign, nil).Times(1) + if err := dm.TellNodeInfo(tt.args.ctx, tt.args.peer); (err != nil) != tt.wantErr { + t.Errorf("DelegateManager.TellNodeInfo() error = %v, wantErr %v", err, tt.wantErr) + } + + require.Equal(t, message.Info.Height, tt.args.height) + require.Equal(t, message.Signature, tt.args.sign) + }) + } +} diff --git a/test/mock/mock_node/mock_manager.go b/test/mock/mock_node/mock_manager.go new file mode 100644 index 0000000000..bb5aa65743 --- /dev/null +++ b/test/mock/mock_node/mock_manager.go @@ -0,0 +1,155 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./node/manager.go + +// Package mock_node is a generated GoMock package. +package mock_node + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + peer "github.com/libp2p/go-libp2p-core/peer" + proto "google.golang.org/protobuf/proto" +) + +// Mocktransmitter is a mock of transmitter interface. +type Mocktransmitter struct { + ctrl *gomock.Controller + recorder *MocktransmitterMockRecorder +} + +// MocktransmitterMockRecorder is the mock recorder for Mocktransmitter. +type MocktransmitterMockRecorder struct { + mock *Mocktransmitter +} + +// NewMocktransmitter creates a new mock instance. +func NewMocktransmitter(ctrl *gomock.Controller) *Mocktransmitter { + mock := &Mocktransmitter{ctrl: ctrl} + mock.recorder = &MocktransmitterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mocktransmitter) EXPECT() *MocktransmitterMockRecorder { + return m.recorder +} + +// BroadcastOutbound mocks base method. +func (m *Mocktransmitter) BroadcastOutbound(arg0 context.Context, arg1 proto.Message) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BroadcastOutbound", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// BroadcastOutbound indicates an expected call of BroadcastOutbound. +func (mr *MocktransmitterMockRecorder) BroadcastOutbound(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastOutbound", reflect.TypeOf((*Mocktransmitter)(nil).BroadcastOutbound), arg0, arg1) +} + +// Info mocks base method. +func (m *Mocktransmitter) Info() (peer.AddrInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Info") + ret0, _ := ret[0].(peer.AddrInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Info indicates an expected call of Info. +func (mr *MocktransmitterMockRecorder) Info() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*Mocktransmitter)(nil).Info)) +} + +// UnicastOutbound mocks base method. +func (m *Mocktransmitter) UnicastOutbound(arg0 context.Context, arg1 peer.AddrInfo, arg2 proto.Message) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnicastOutbound", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnicastOutbound indicates an expected call of UnicastOutbound. +func (mr *MocktransmitterMockRecorder) UnicastOutbound(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnicastOutbound", reflect.TypeOf((*Mocktransmitter)(nil).UnicastOutbound), arg0, arg1, arg2) +} + +// Mockheightable is a mock of heightable interface. +type Mockheightable struct { + ctrl *gomock.Controller + recorder *MockheightableMockRecorder +} + +// MockheightableMockRecorder is the mock recorder for Mockheightable. +type MockheightableMockRecorder struct { + mock *Mockheightable +} + +// NewMockheightable creates a new mock instance. +func NewMockheightable(ctrl *gomock.Controller) *Mockheightable { + mock := &Mockheightable{ctrl: ctrl} + mock.recorder = &MockheightableMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mockheightable) EXPECT() *MockheightableMockRecorder { + return m.recorder +} + +// TipHeight mocks base method. +func (m *Mockheightable) TipHeight() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TipHeight") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// TipHeight indicates an expected call of TipHeight. +func (mr *MockheightableMockRecorder) TipHeight() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TipHeight", reflect.TypeOf((*Mockheightable)(nil).TipHeight)) +} + +// Mocksigner is a mock of signer interface. +type Mocksigner struct { + ctrl *gomock.Controller + recorder *MocksignerMockRecorder +} + +// MocksignerMockRecorder is the mock recorder for Mocksigner. +type MocksignerMockRecorder struct { + mock *Mocksigner +} + +// NewMocksigner creates a new mock instance. +func NewMocksigner(ctrl *gomock.Controller) *Mocksigner { + mock := &Mocksigner{ctrl: ctrl} + mock.recorder = &MocksignerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *Mocksigner) EXPECT() *MocksignerMockRecorder { + return m.recorder +} + +// Sign mocks base method. +func (m *Mocksigner) Sign(arg0 []byte) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Sign", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Sign indicates an expected call of Sign. +func (mr *MocksignerMockRecorder) Sign(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*Mocksigner)(nil).Sign), arg0) +} From 5c0b500424139cdd61c791c74c5f657c763aca8a Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 11 Jan 2023 23:07:53 +0800 Subject: [PATCH 13/32] add pubkey in nodeinfo message --- node/manager.go | 76 ++++------- node/manager_test.go | 136 +++++++++++++------ test/mock/mock_dispatcher/mock_dispatcher.go | 28 ++++ test/mock/mock_node/mock_manager.go | 58 ++++---- 4 files changed, 184 insertions(+), 114 deletions(-) diff --git a/node/manager.go b/node/manager.go index 7fb43d4779..d0def98f5d 100644 --- a/node/manager.go +++ b/node/manager.go @@ -25,14 +25,14 @@ type ( transmitter interface { BroadcastOutbound(context.Context, proto.Message) error UnicastOutbound(context.Context, peer.AddrInfo, proto.Message) error - Info() (peer.AddrInfo, error) } heightable interface { TipHeight() uint64 } - signer interface { + privateKey interface { + PublicKey() crypto.PublicKey Sign([]byte) ([]byte, error) } @@ -43,18 +43,18 @@ type ( broadcaster *routine.RecurringTask transmitter transmitter heightable heightable - signer signer + privKey privateKey } ) // NewDelegateManager new delegate manager -func NewDelegateManager(cfg *Config, t transmitter, h heightable, s signer) *DelegateManager { +func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privateKey) *DelegateManager { dm := &DelegateManager{ cfg: *cfg, nodeMap: make(map[string]iotextypes.NodeInfo), transmitter: t, heightable: h, - signer: s, + privKey: privKey, } // disable broadcast if RequestNodeInfoInterval == 0 if cfg.RequestNodeInfoInterval > 0 { @@ -81,13 +81,20 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { } // HandleNodeInfo handle node info message -func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, addr string, node *iotextypes.ResponseNodeInfoMessage) { - // TODO sign verify - // if !dm.verifyNodeInfo(addr, node) { - // log.L().Warn("node info message verify failed", zap.String("addr", addr)) - // return - // } - dm.UpdateNode(addr, node.Info) +func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, msg *iotextypes.ResponseNodeInfoMessage) { + // verify signature + pubKey, err := crypto.BytesToPublicKey(msg.Pubkey) + if err != nil { + log.L().Warn("delegate manager convert to publick key failed", zap.Error(err)) + return + } + hash := hashNodeInfo(msg) + if !pubKey.Verify(hash[:], msg.Signature) { + log.L().Warn("delegate manager node info message verify failed", zap.String("peer", peerID)) + return + } + + dm.UpdateNode(pubKey.Address().String(), msg.Info) } // UpdateNode update node info @@ -100,37 +107,35 @@ func (dm *DelegateManager) UpdateNode(addr string, node *iotextypes.NodeInfo) { // RequestNodeInfo broadcast request node info message func (dm *DelegateManager) RequestNodeInfo() { - log.L().Info("delegateManager request node info") + log.L().Info("delegate manager request node info") + + // broadcast request meesage if err := dm.transmitter.BroadcastOutbound(context.Background(), &iotextypes.RequestNodeInfoMessage{}); err != nil { - log.L().Error("delegateManager request node info failed", zap.Error(err)) + log.L().Error("delegate manager request node info failed", zap.Error(err)) } // manually update self node info for broadcast message to myself will be ignored - peer, err := dm.transmitter.Info() - if err != nil { - log.L().Error("delegateManager get self info failed", zap.Error(err)) - return - } - msg := &iotextypes.NodeInfo{ + dm.UpdateNode(dm.privKey.PublicKey().Address().String(), &iotextypes.NodeInfo{ Version: version.PackageVersion, Height: dm.heightable.TipHeight(), Timestamp: timestamppb.Now(), - } - dm.UpdateNode(peer.ID.Pretty(), msg) + }) } // TellNodeInfo tell node info to peer func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { - log.L().Info("delegateManager tell node info", zap.Any("peer", peer.ID.Pretty())) + log.L().Info("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) req := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ Version: version.PackageVersion, Height: dm.heightable.TipHeight(), Timestamp: timestamppb.Now(), }, + Pubkey: dm.privKey.PublicKey().Bytes(), } // add sign for msg - sign, err := dm.signNodeInfo(req) + h := hashNodeInfo(req) + sign, err := dm.privKey.Sign(h[:]) if err != nil { return err } @@ -139,27 +144,6 @@ func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) return dm.transmitter.UnicastOutbound(ctx, peer, req) } -func (dm *DelegateManager) signNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) ([]byte, error) { - h := dm.hashNodeInfo(msg) - sign, err := dm.signer.Sign(h[:]) - if err != nil { - return nil, err - } - return sign, nil -} - -func (dm *DelegateManager) hashNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) hash.Hash256 { +func hashNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) hash.Hash256 { return hash.Hash256b(byteutil.Must(proto.Marshal(msg.Info))) } - -func (dm *DelegateManager) verifyNodeInfo(peer string, msg *iotextypes.ResponseNodeInfoMessage) bool { - pk := []byte{} - hash := dm.hashNodeInfo(msg) - pubK, err := crypto.BytesToPublicKey(pk) - if err != nil { - log.L().Warn("convert bytes to publickey failed", zap.Error(err)) - return false - } - - return pubK.Verify(hash[:], msg.Signature) -} diff --git a/node/manager_test.go b/node/manager_test.go index 86ce91771e..ce5c72cd67 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -11,6 +11,7 @@ import ( "time" "github.com/golang/mock/gomock" + "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/iotex-core/pkg/routine" "github.com/iotexproject/iotex-core/test/mock/mock_node" "github.com/iotexproject/iotex-proto/golang/iotextypes" @@ -26,13 +27,13 @@ func TestNewDelegateManager(t *testing.T) { defer ctrl.Finish() hMock := mock_node.NewMockheightable(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - sMock := mock_node.NewMocksigner(ctrl) + pMock := mock_node.NewMockprivateKey(ctrl) type args struct { cfg *Config t transmitter h heightable - s signer + p privateKey } tests := []struct { name string @@ -42,37 +43,37 @@ func TestNewDelegateManager(t *testing.T) { }{ { "disable_broadcast", - args{&Config{}, tMock, hMock, sMock}, + args{&Config{}, tMock, hMock, pMock}, &DelegateManager{ cfg: Config{}, nodeMap: map[string]iotextypes.NodeInfo{}, transmitter: tMock, heightable: hMock, - signer: sMock, + privKey: pMock, }, true, }, { "enable_broadcast", - args{&Config{time.Second * 3}, tMock, hMock, sMock}, + args{&Config{time.Second * 3}, tMock, hMock, pMock}, &DelegateManager{ cfg: Config{time.Second * 3}, nodeMap: map[string]iotextypes.NodeInfo{}, transmitter: tMock, heightable: hMock, - signer: sMock, + privKey: pMock, }, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := NewDelegateManager(tt.args.cfg, tt.args.t, tt.args.h, tt.args.s) + got := NewDelegateManager(tt.args.cfg, tt.args.t, tt.args.h, tt.args.p) require.Equal(t, tt.want.cfg, got.cfg) require.Equal(t, tt.want.nodeMap, got.nodeMap) require.Equal(t, tt.want.transmitter, got.transmitter) require.Equal(t, tt.want.heightable, got.heightable) - require.Equal(t, tt.want.signer, got.signer) + require.Equal(t, tt.want.privKey, got.privKey) require.Equal(t, tt.broadcasterIsNull, got.broadcaster == nil) }) } @@ -83,7 +84,12 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { defer ctrl.Finish() hMock := mock_node.NewMockheightable(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - sMock := mock_node.NewMocksigner(ctrl) + pMock := mock_node.NewMockprivateKey(ctrl) + + privKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } type fields struct { cfg Config @@ -91,7 +97,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { broadcaster *routine.RecurringTask transmitter transmitter heightable heightable - signer signer + privKey privateKey } type args struct { ctx context.Context @@ -102,27 +108,64 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { name string fields fields args args + valid bool }{ { - "", + "valid", fields{ cfg: Config{}, nodeMap: map[string]iotextypes.NodeInfo{}, transmitter: tMock, heightable: hMock, - signer: sMock, + privKey: pMock, }, args{ context.Background(), "abc", - &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ - Version: "v1.8.0", - Height: 200, - Timestamp: timestamppb.Now(), - }, - }, + func() *iotextypes.ResponseNodeInfoMessage { + msg := &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: "v1.8.0", + Height: 200, + Timestamp: timestamppb.Now(), + }, + } + hash := hashNodeInfo(msg) + msg.Signature, _ = privKey.Sign(hash[:]) + msg.Pubkey = privKey.PublicKey().Bytes() + return msg + }(), }, + true, + }, + { + "invalid", + fields{ + cfg: Config{}, + nodeMap: map[string]iotextypes.NodeInfo{}, + transmitter: tMock, + heightable: hMock, + privKey: pMock, + }, + args{ + context.Background(), + "abc", + func() *iotextypes.ResponseNodeInfoMessage { + msg := &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: "v1.8.0", + Height: 200, + Timestamp: timestamppb.Now(), + }, + } + hash := hashNodeInfo(msg) + msg.Signature, _ = privKey.Sign(hash[:]) + privKey2, _ := crypto.GenerateKey() + msg.Pubkey = privKey2.PublicKey().Bytes() + return msg + }(), + }, + false, }, } for _, tt := range tests { @@ -133,17 +176,29 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { broadcaster: tt.fields.broadcaster, transmitter: tt.fields.transmitter, heightable: tt.fields.heightable, - signer: tt.fields.signer, + privKey: tt.fields.privKey, } dm.HandleNodeInfo(tt.args.ctx, tt.args.addr, tt.args.node) + pubKey, err := crypto.BytesToPublicKey(tt.args.node.Pubkey) + if err != nil { + t.Fatal(err) + } + addr := pubKey.Address().String() + if tt.valid { + require.Equal(t, tt.args.node.Info.Height, dm.nodeMap[addr].Height) + require.Equal(t, tt.args.node.Info.Version, dm.nodeMap[addr].Version) + require.Equal(t, tt.args.node.Info.Timestamp.String(), dm.nodeMap[addr].Timestamp.String()) - require.Equal(t, tt.args.node.Info.Height, dm.nodeMap[tt.args.addr].Height) - require.Equal(t, tt.args.node.Info.Version, dm.nodeMap[tt.args.addr].Version) - require.Equal(t, tt.args.node.Info.Timestamp.String(), dm.nodeMap[tt.args.addr].Timestamp.String()) - - m := dto.Metric{} - nodeDelegateHeightGauge.WithLabelValues(tt.args.addr, tt.args.node.Info.Version).Write(&m) - require.Equal(t, tt.args.node.Info.Height, uint64(m.Gauge.GetValue())) + m := dto.Metric{} + nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) + require.Equal(t, tt.args.node.Info.Height, uint64(m.Gauge.GetValue())) + } else { + _, ok := dm.nodeMap[addr] + require.False(t, ok) + m := dto.Metric{} + nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) + require.Equal(t, uint64(0), uint64(m.Gauge.GetValue())) + } }) } } @@ -153,7 +208,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { defer ctrl.Finish() hMock := mock_node.NewMockheightable(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - sMock := mock_node.NewMocksigner(ctrl) + pMock := mock_node.NewMockprivateKey(ctrl) type fields struct { cfg Config @@ -161,7 +216,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { broadcaster *routine.RecurringTask transmitter transmitter heightable heightable - signer signer + privateKey privateKey } tests := []struct { name string @@ -175,7 +230,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { nil, tMock, hMock, - sMock, + pMock, }, }, } @@ -187,16 +242,17 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { broadcaster: tt.fields.broadcaster, transmitter: tt.fields.transmitter, heightable: tt.fields.heightable, - signer: tt.fields.signer, + privKey: tt.fields.privateKey, } - peerID := peer.AddrInfo{ID: "abcd"} + height := uint64(200) + privK, _ := crypto.GenerateKey() tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) - tMock.EXPECT().Info().Return(peerID, nil).Times(1) hMock.EXPECT().TipHeight().Return(height).Times(1) + pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) dm.RequestNodeInfo() - require.Equal(t, height, dm.nodeMap[peerID.ID.Pretty()].Height) + require.Equal(t, height, dm.nodeMap[privK.PublicKey().Address().String()].Height) }) } } @@ -206,7 +262,7 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { defer ctrl.Finish() hMock := mock_node.NewMockheightable(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - sMock := mock_node.NewMocksigner(ctrl) + pMock := mock_node.NewMockprivateKey(ctrl) type fields struct { cfg Config @@ -214,7 +270,7 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { broadcaster *routine.RecurringTask transmitter transmitter heightable heightable - signer signer + privateKey privateKey } type args struct { ctx context.Context @@ -236,7 +292,7 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { nil, tMock, hMock, - sMock, + pMock, }, args{ context.Background(), @@ -255,15 +311,17 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { broadcaster: tt.fields.broadcaster, transmitter: tt.fields.transmitter, heightable: tt.fields.heightable, - signer: tt.fields.signer, + privKey: tt.fields.privateKey, } + privK, _ := crypto.GenerateKey() message := &iotextypes.ResponseNodeInfoMessage{} hMock.EXPECT().TipHeight().Return(tt.args.height).Times(1) tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error { *message = *msg.(*iotextypes.ResponseNodeInfoMessage) return nil }).Times(1) - sMock.EXPECT().Sign(gomock.Any()).Return(tt.args.sign, nil).Times(1) + pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) + pMock.EXPECT().Sign(gomock.Any()).Return(tt.args.sign, nil).Times(1) if err := dm.TellNodeInfo(tt.args.ctx, tt.args.peer); (err != nil) != tt.wantErr { t.Errorf("DelegateManager.TellNodeInfo() error = %v, wantErr %v", err, tt.wantErr) } diff --git a/test/mock/mock_dispatcher/mock_dispatcher.go b/test/mock/mock_dispatcher/mock_dispatcher.go index 33db450d83..db5250dd19 100644 --- a/test/mock/mock_dispatcher/mock_dispatcher.go +++ b/test/mock/mock_dispatcher/mock_dispatcher.go @@ -81,6 +81,34 @@ func (mr *MockSubscriberMockRecorder) HandleConsensusMsg(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleConsensusMsg", reflect.TypeOf((*MockSubscriber)(nil).HandleConsensusMsg), arg0) } +// HandleNodeInfoMsg mocks base method. +func (m *MockSubscriber) HandleNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.ResponseNodeInfoMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleNodeInfoMsg", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleNodeInfoMsg indicates an expected call of HandleNodeInfoMsg. +func (mr *MockSubscriberMockRecorder) HandleNodeInfoMsg(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleNodeInfoMsg", reflect.TypeOf((*MockSubscriber)(nil).HandleNodeInfoMsg), arg0, arg1, arg2) +} + +// HandleRequestNodeInfoMsg mocks base method. +func (m *MockSubscriber) HandleRequestNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.RequestNodeInfoMessage) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleRequestNodeInfoMsg", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleRequestNodeInfoMsg indicates an expected call of HandleRequestNodeInfoMsg. +func (mr *MockSubscriberMockRecorder) HandleRequestNodeInfoMsg(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleRequestNodeInfoMsg", reflect.TypeOf((*MockSubscriber)(nil).HandleRequestNodeInfoMsg), arg0, arg1, arg2) +} + // HandleSyncRequest mocks base method. func (m *MockSubscriber) HandleSyncRequest(arg0 context.Context, arg1 peer.AddrInfo, arg2 *iotexrpc.BlockSync) error { m.ctrl.T.Helper() diff --git a/test/mock/mock_node/mock_manager.go b/test/mock/mock_node/mock_manager.go index bb5aa65743..7c9b6e0922 100644 --- a/test/mock/mock_node/mock_manager.go +++ b/test/mock/mock_node/mock_manager.go @@ -9,6 +9,7 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" + crypto "github.com/iotexproject/go-pkgs/crypto" peer "github.com/libp2p/go-libp2p-core/peer" proto "google.golang.org/protobuf/proto" ) @@ -50,21 +51,6 @@ func (mr *MocktransmitterMockRecorder) BroadcastOutbound(arg0, arg1 interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastOutbound", reflect.TypeOf((*Mocktransmitter)(nil).BroadcastOutbound), arg0, arg1) } -// Info mocks base method. -func (m *Mocktransmitter) Info() (peer.AddrInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Info") - ret0, _ := ret[0].(peer.AddrInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Info indicates an expected call of Info. -func (mr *MocktransmitterMockRecorder) Info() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*Mocktransmitter)(nil).Info)) -} - // UnicastOutbound mocks base method. func (m *Mocktransmitter) UnicastOutbound(arg0 context.Context, arg1 peer.AddrInfo, arg2 proto.Message) error { m.ctrl.T.Helper() @@ -116,31 +102,45 @@ func (mr *MockheightableMockRecorder) TipHeight() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TipHeight", reflect.TypeOf((*Mockheightable)(nil).TipHeight)) } -// Mocksigner is a mock of signer interface. -type Mocksigner struct { +// MockprivateKey is a mock of privateKey interface. +type MockprivateKey struct { ctrl *gomock.Controller - recorder *MocksignerMockRecorder + recorder *MockprivateKeyMockRecorder } -// MocksignerMockRecorder is the mock recorder for Mocksigner. -type MocksignerMockRecorder struct { - mock *Mocksigner +// MockprivateKeyMockRecorder is the mock recorder for MockprivateKey. +type MockprivateKeyMockRecorder struct { + mock *MockprivateKey } -// NewMocksigner creates a new mock instance. -func NewMocksigner(ctrl *gomock.Controller) *Mocksigner { - mock := &Mocksigner{ctrl: ctrl} - mock.recorder = &MocksignerMockRecorder{mock} +// NewMockprivateKey creates a new mock instance. +func NewMockprivateKey(ctrl *gomock.Controller) *MockprivateKey { + mock := &MockprivateKey{ctrl: ctrl} + mock.recorder = &MockprivateKeyMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *Mocksigner) EXPECT() *MocksignerMockRecorder { +func (m *MockprivateKey) EXPECT() *MockprivateKeyMockRecorder { return m.recorder } +// PublicKey mocks base method. +func (m *MockprivateKey) PublicKey() crypto.PublicKey { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PublicKey") + ret0, _ := ret[0].(crypto.PublicKey) + return ret0 +} + +// PublicKey indicates an expected call of PublicKey. +func (mr *MockprivateKeyMockRecorder) PublicKey() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicKey", reflect.TypeOf((*MockprivateKey)(nil).PublicKey)) +} + // Sign mocks base method. -func (m *Mocksigner) Sign(arg0 []byte) ([]byte, error) { +func (m *MockprivateKey) Sign(arg0 []byte) ([]byte, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Sign", arg0) ret0, _ := ret[0].([]byte) @@ -149,7 +149,7 @@ func (m *Mocksigner) Sign(arg0 []byte) ([]byte, error) { } // Sign indicates an expected call of Sign. -func (mr *MocksignerMockRecorder) Sign(arg0 interface{}) *gomock.Call { +func (mr *MockprivateKeyMockRecorder) Sign(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*Mocksigner)(nil).Sign), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*MockprivateKey)(nil).Sign), arg0) } From 6e191c63e90b40da1a2112d07cddab54233c9878 Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 11 Jan 2023 23:26:20 +0800 Subject: [PATCH 14/32] fix compile error --- dispatcher/dispatcher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 4374a46a88..9f8b7ad324 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -460,7 +460,7 @@ func (d *IotxDispatcher) HandleTell(ctx context.Context, chainID uint32, peer pe } func (d *IotxDispatcher) dispatchNodeInfo(ctx context.Context, chainID uint32, peer string, message proto.Message) { - if atomic.LoadInt32(&d.shutdown) != 0 { + if !d.IsReady() { return } subscriber := d.subscriber(chainID) From 46608796c911dffa2581877352e4a9a3b1824cdd Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 11 Jan 2023 23:32:03 +0800 Subject: [PATCH 15/32] update go.mod --- go.mod | 4 ++-- go.sum | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4538f1a270..3bd8217eed 100644 --- a/go.mod +++ b/go.mod @@ -204,6 +204,6 @@ replace github.com/ethereum/go-ethereum => github.com/iotexproject/go-ethereum v replace golang.org/x/xerrors => golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 -// replace github.com/iotexproject/iotex-proto v0.5.10 => github.com/envestcc/iotex-proto v0.0.0-20221230052651-5f53099aee3e +replace github.com/iotexproject/iotex-proto => github.com/envestcc/iotex-proto v0.0.0-20230111152952-64e97c18b1b1 -replace github.com/iotexproject/iotex-proto => /Users/chenchen/dev/iotex-proto +// replace github.com/iotexproject/iotex-proto => /Users/chenchen/dev/iotex-proto diff --git a/go.sum b/go.sum index 425de79434..db4cc066a9 100644 --- a/go.sum +++ b/go.sum @@ -219,6 +219,8 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envestcc/iotex-proto v0.0.0-20230111152952-64e97c18b1b1 h1:98KGzfnsMv2h5bZsxFuP8Yn0xRg9LPBGV4cfEgR61K4= +github.com/envestcc/iotex-proto v0.0.0-20230111152952-64e97c18b1b1/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= From 4284fa846ea56e32be061b56321d286d978b6967 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 12 Jan 2023 13:42:53 +0800 Subject: [PATCH 16/32] refactor node unittest --- node/manager_test.go | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/node/manager_test.go b/node/manager_test.go index ce5c72cd67..123cdaf58d 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -29,6 +29,8 @@ func TestNewDelegateManager(t *testing.T) { tMock := mock_node.NewMocktransmitter(ctrl) pMock := mock_node.NewMockprivateKey(ctrl) + require := require.New(t) + type args struct { cfg *Config t transmitter @@ -69,12 +71,12 @@ func TestNewDelegateManager(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := NewDelegateManager(tt.args.cfg, tt.args.t, tt.args.h, tt.args.p) - require.Equal(t, tt.want.cfg, got.cfg) - require.Equal(t, tt.want.nodeMap, got.nodeMap) - require.Equal(t, tt.want.transmitter, got.transmitter) - require.Equal(t, tt.want.heightable, got.heightable) - require.Equal(t, tt.want.privKey, got.privKey) - require.Equal(t, tt.broadcasterIsNull, got.broadcaster == nil) + require.Equal(tt.want.cfg, got.cfg) + require.Equal(tt.want.nodeMap, got.nodeMap) + require.Equal(tt.want.transmitter, got.transmitter) + require.Equal(tt.want.heightable, got.heightable) + require.Equal(tt.want.privKey, got.privKey) + require.Equal(tt.broadcasterIsNull, got.broadcaster == nil) }) } } @@ -86,6 +88,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { tMock := mock_node.NewMocktransmitter(ctrl) pMock := mock_node.NewMockprivateKey(ctrl) + require := require.New(t) privKey, err := crypto.GenerateKey() if err != nil { t.Fatal(err) @@ -185,19 +188,19 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { } addr := pubKey.Address().String() if tt.valid { - require.Equal(t, tt.args.node.Info.Height, dm.nodeMap[addr].Height) - require.Equal(t, tt.args.node.Info.Version, dm.nodeMap[addr].Version) - require.Equal(t, tt.args.node.Info.Timestamp.String(), dm.nodeMap[addr].Timestamp.String()) + require.Equal(tt.args.node.Info.Height, dm.nodeMap[addr].Height) + require.Equal(tt.args.node.Info.Version, dm.nodeMap[addr].Version) + require.Equal(tt.args.node.Info.Timestamp.String(), dm.nodeMap[addr].Timestamp.String()) m := dto.Metric{} nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) - require.Equal(t, tt.args.node.Info.Height, uint64(m.Gauge.GetValue())) + require.Equal(tt.args.node.Info.Height, uint64(m.Gauge.GetValue())) } else { _, ok := dm.nodeMap[addr] - require.False(t, ok) + require.False(ok) m := dto.Metric{} nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) - require.Equal(t, uint64(0), uint64(m.Gauge.GetValue())) + require.Equal(uint64(0), uint64(m.Gauge.GetValue())) } }) } @@ -210,6 +213,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { tMock := mock_node.NewMocktransmitter(ctrl) pMock := mock_node.NewMockprivateKey(ctrl) + require := require.New(t) type fields struct { cfg Config nodeMap map[string]iotextypes.NodeInfo @@ -252,7 +256,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) dm.RequestNodeInfo() - require.Equal(t, height, dm.nodeMap[privK.PublicKey().Address().String()].Height) + require.Equal(height, dm.nodeMap[privK.PublicKey().Address().String()].Height) }) } } @@ -264,6 +268,7 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { tMock := mock_node.NewMocktransmitter(ctrl) pMock := mock_node.NewMockprivateKey(ctrl) + require := require.New(t) type fields struct { cfg Config nodeMap map[string]iotextypes.NodeInfo @@ -326,8 +331,8 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { t.Errorf("DelegateManager.TellNodeInfo() error = %v, wantErr %v", err, tt.wantErr) } - require.Equal(t, message.Info.Height, tt.args.height) - require.Equal(t, message.Signature, tt.args.sign) + require.Equal(message.Info.Height, tt.args.height) + require.Equal(message.Signature, tt.args.sign) }) } } From fbb6983f2dda6ae07b08d2676e2697daed9679bc Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 12 Jan 2023 22:38:57 +0800 Subject: [PATCH 17/32] refactor unittest --- node/manager_test.go | 94 ++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 65 deletions(-) diff --git a/node/manager_test.go b/node/manager_test.go index 123cdaf58d..4f235eeaf9 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -269,70 +269,34 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { pMock := mock_node.NewMockprivateKey(ctrl) require := require.New(t) - type fields struct { - cfg Config - nodeMap map[string]iotextypes.NodeInfo - broadcaster *routine.RecurringTask - transmitter transmitter - heightable heightable - privateKey privateKey - } - type args struct { - ctx context.Context - peer peer.AddrInfo - height uint64 - sign []byte - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - { - "", - fields{ - Config{}, - map[string]iotextypes.NodeInfo{}, - nil, - tMock, - hMock, - pMock, - }, - args{ - context.Background(), - peer.AddrInfo{ID: "abcd"}, - 200, - []byte("xxxxxx"), - }, - false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - dm := &DelegateManager{ - cfg: tt.fields.cfg, - nodeMap: tt.fields.nodeMap, - broadcaster: tt.fields.broadcaster, - transmitter: tt.fields.transmitter, - heightable: tt.fields.heightable, - privKey: tt.fields.privateKey, - } - privK, _ := crypto.GenerateKey() - message := &iotextypes.ResponseNodeInfoMessage{} - hMock.EXPECT().TipHeight().Return(tt.args.height).Times(1) - tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error { - *message = *msg.(*iotextypes.ResponseNodeInfoMessage) - return nil - }).Times(1) - pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) - pMock.EXPECT().Sign(gomock.Any()).Return(tt.args.sign, nil).Times(1) - if err := dm.TellNodeInfo(tt.args.ctx, tt.args.peer); (err != nil) != tt.wantErr { - t.Errorf("DelegateManager.TellNodeInfo() error = %v, wantErr %v", err, tt.wantErr) - } - require.Equal(message.Info.Height, tt.args.height) - require.Equal(message.Signature, tt.args.sign) - }) - } + t.Run("tell", func(t *testing.T) { + dm := &DelegateManager{ + cfg: Config{}, + nodeMap: map[string]iotextypes.NodeInfo{}, + broadcaster: nil, + transmitter: tMock, + heightable: hMock, + privKey: pMock, + } + height := uint64(200) + sign := []byte("xxxxxx") + privK, _ := crypto.GenerateKey() + message := &iotextypes.ResponseNodeInfoMessage{} + + hMock.EXPECT().TipHeight().Return(height).Times(1) + tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error { + *message = *msg.(*iotextypes.ResponseNodeInfoMessage) + return nil + }).Times(1) + pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) + pMock.EXPECT().Sign(gomock.Any()).Return(sign, nil).Times(1) + + err := dm.TellNodeInfo(context.Background(), peer.AddrInfo{}) + + require.NoError(err) + require.Equal(message.Info.Height, height) + require.Equal(message.Signature, sign) + }) + } From 19cf0881904d2e15c5efa92ec240ae4bac10ec9b Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 13 Jan 2023 09:39:39 +0800 Subject: [PATCH 18/32] convert NodeManager.UpdateNode to private --- node/manager.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/node/manager.go b/node/manager.go index d0def98f5d..cf33d5b083 100644 --- a/node/manager.go +++ b/node/manager.go @@ -94,11 +94,11 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms return } - dm.UpdateNode(pubKey.Address().String(), msg.Info) + dm.updateNode(pubKey.Address().String(), msg.Info) } -// UpdateNode update node info -func (dm *DelegateManager) UpdateNode(addr string, node *iotextypes.NodeInfo) { +// updateNode update node info +func (dm *DelegateManager) updateNode(addr string, node *iotextypes.NodeInfo) { // update dm.nodeMap dm.nodeMap[addr] = *node // update metric @@ -115,7 +115,7 @@ func (dm *DelegateManager) RequestNodeInfo() { } // manually update self node info for broadcast message to myself will be ignored - dm.UpdateNode(dm.privKey.PublicKey().Address().String(), &iotextypes.NodeInfo{ + dm.updateNode(dm.privKey.PublicKey().Address().String(), &iotextypes.NodeInfo{ Version: version.PackageVersion, Height: dm.heightable.TipHeight(), Timestamp: timestamppb.Now(), From b9cd38a15c76d7e9a99dfd2f3b1c4b58835004bf Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 13 Jan 2023 14:28:59 +0800 Subject: [PATCH 19/32] use recovered pubkey from sign to verify --- go.mod | 4 +--- go.sum | 4 ++-- node/manager.go | 17 +++++++++-------- node/manager_test.go | 36 ++++++++++++++++++++++++++++-------- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 3bd8217eed..2f6a3d68c5 100644 --- a/go.mod +++ b/go.mod @@ -204,6 +204,4 @@ replace github.com/ethereum/go-ethereum => github.com/iotexproject/go-ethereum v replace golang.org/x/xerrors => golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 -replace github.com/iotexproject/iotex-proto => github.com/envestcc/iotex-proto v0.0.0-20230111152952-64e97c18b1b1 - -// replace github.com/iotexproject/iotex-proto => /Users/chenchen/dev/iotex-proto +replace github.com/iotexproject/iotex-proto => github.com/envestcc/iotex-proto v0.0.0-20230113062505-e182a7f5aafe diff --git a/go.sum b/go.sum index db4cc066a9..cded1eb533 100644 --- a/go.sum +++ b/go.sum @@ -219,8 +219,8 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envestcc/iotex-proto v0.0.0-20230111152952-64e97c18b1b1 h1:98KGzfnsMv2h5bZsxFuP8Yn0xRg9LPBGV4cfEgR61K4= -github.com/envestcc/iotex-proto v0.0.0-20230111152952-64e97c18b1b1/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= +github.com/envestcc/iotex-proto v0.0.0-20230113062505-e182a7f5aafe h1:1yuc2o+/IkuT/sOyNaFM7SNXgNNXHw9bkqqv7mog5Dc= +github.com/envestcc/iotex-proto v0.0.0-20230113062505-e182a7f5aafe/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/node/manager.go b/node/manager.go index cf33d5b083..616f9b5f0a 100644 --- a/node/manager.go +++ b/node/manager.go @@ -82,19 +82,20 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { // HandleNodeInfo handle node info message func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, msg *iotextypes.ResponseNodeInfoMessage) { - // verify signature - pubKey, err := crypto.BytesToPublicKey(msg.Pubkey) + // recover pubkey + hash := hashNodeInfo(msg) + pubKey, err := crypto.RecoverPubkey(hash[:], msg.Signature) if err != nil { - log.L().Warn("delegate manager convert to publick key failed", zap.Error(err)) + log.L().Warn("delegate manager recover pubkey failed", zap.Error(err)) return } - hash := hashNodeInfo(msg) - if !pubKey.Verify(hash[:], msg.Signature) { - log.L().Warn("delegate manager node info message verify failed", zap.String("peer", peerID)) + // verify signature + if pubKey.Address().String() != msg.Info.Address { + log.L().Warn("delegate manager node info message verify failed", zap.String("address", msg.Info.Address)) return } - dm.updateNode(pubKey.Address().String(), msg.Info) + dm.updateNode(msg.Info.Address, msg.Info) } // updateNode update node info @@ -130,8 +131,8 @@ func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) Version: version.PackageVersion, Height: dm.heightable.TipHeight(), Timestamp: timestamppb.Now(), + Address: dm.privKey.PublicKey().Address().String(), }, - Pubkey: dm.privKey.PublicKey().Bytes(), } // add sign for msg h := hashNodeInfo(req) diff --git a/node/manager_test.go b/node/manager_test.go index 4f235eeaf9..2db7a69171 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -131,11 +131,11 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { Version: "v1.8.0", Height: 200, Timestamp: timestamppb.Now(), + Address: privKey.PublicKey().Address().String(), }, } hash := hashNodeInfo(msg) msg.Signature, _ = privKey.Sign(hash[:]) - msg.Pubkey = privKey.PublicKey().Bytes() return msg }(), }, @@ -154,17 +154,17 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { context.Background(), "abc", func() *iotextypes.ResponseNodeInfoMessage { + privKey2, _ := crypto.GenerateKey() msg := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ Version: "v1.8.0", Height: 200, Timestamp: timestamppb.Now(), + Address: privKey2.PublicKey().Address().String(), }, } hash := hashNodeInfo(msg) msg.Signature, _ = privKey.Sign(hash[:]) - privKey2, _ := crypto.GenerateKey() - msg.Pubkey = privKey2.PublicKey().Bytes() return msg }(), }, @@ -182,11 +182,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { privKey: tt.fields.privKey, } dm.HandleNodeInfo(tt.args.ctx, tt.args.addr, tt.args.node) - pubKey, err := crypto.BytesToPublicKey(tt.args.node.Pubkey) - if err != nil { - t.Fatal(err) - } - addr := pubKey.Address().String() + addr := tt.args.node.Info.Address if tt.valid { require.Equal(tt.args.node.Info.Height, dm.nodeMap[addr].Height) require.Equal(tt.args.node.Info.Version, dm.nodeMap[addr].Version) @@ -300,3 +296,27 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { }) } + +func TestPubkey(t *testing.T) { + masterKey := "96f0aa5e8523d6a28dc35c927274be4e931e74eaa720b418735debfcbfe712b8" + sk, err := crypto.HexStringToPrivateKey(masterKey) + if err != nil { + t.Fatal(err) + } + ioPubKey := sk.PublicKey() + ioAddr := ioPubKey.Address().String() + + hash := []byte("testtesttesttesttesttesttesttest") + sign, err := sk.Sign(hash) + if err != nil { + t.Fatal(err) + } + + recovPubKey, err := crypto.RecoverPubkey(hash, sign) + if err != nil { + t.Fatal(err) + } + recovAddr := recovPubKey.Address().String() + + t.Log("ioAddr=", ioAddr, "recovAddr", recovAddr) +} From fb8f2a9f525918d321fad0e8347c286a9c1b68ff Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 13 Jan 2023 15:01:37 +0800 Subject: [PATCH 20/32] fix comment --- node/manager.go | 37 +++++++++++++++++++++++++++---------- node/manager_test.go | 18 +++++++++--------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/node/manager.go b/node/manager.go index 616f9b5f0a..402bdc9673 100644 --- a/node/manager.go +++ b/node/manager.go @@ -7,6 +7,7 @@ package node import ( "context" + "time" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" @@ -16,6 +17,7 @@ import ( "github.com/iotexproject/iotex-core/pkg/version" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/libp2p/go-libp2p-core/peer" + "github.com/pkg/errors" "go.uber.org/zap" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" @@ -36,10 +38,18 @@ type ( Sign([]byte) ([]byte, error) } + // NodeInfo node infomation + NodeInfo struct { + Version string + Height uint64 + Timestamp time.Time + Address string + } + // DelegateManager manage delegate node info DelegateManager struct { cfg Config - nodeMap map[string]iotextypes.NodeInfo + nodeMap map[string]NodeInfo broadcaster *routine.RecurringTask transmitter transmitter heightable heightable @@ -51,7 +61,7 @@ type ( func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privateKey) *DelegateManager { dm := &DelegateManager{ cfg: *cfg, - nodeMap: make(map[string]iotextypes.NodeInfo), + nodeMap: make(map[string]NodeInfo), transmitter: t, heightable: h, privKey: privKey, @@ -82,6 +92,7 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { // HandleNodeInfo handle node info message func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, msg *iotextypes.ResponseNodeInfoMessage) { + log.L().Debug("delegate manager handle node info") // recover pubkey hash := hashNodeInfo(msg) pubKey, err := crypto.RecoverPubkey(hash[:], msg.Signature) @@ -95,11 +106,17 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms return } - dm.updateNode(msg.Info.Address, msg.Info) + dm.updateNode(&NodeInfo{ + Version: msg.Info.Version, + Height: msg.Info.Height, + Timestamp: msg.Info.Timestamp.AsTime(), + Address: msg.Info.Address, + }) } // updateNode update node info -func (dm *DelegateManager) updateNode(addr string, node *iotextypes.NodeInfo) { +func (dm *DelegateManager) updateNode(node *NodeInfo) { + addr := node.Address // update dm.nodeMap dm.nodeMap[addr] = *node // update metric @@ -108,24 +125,24 @@ func (dm *DelegateManager) updateNode(addr string, node *iotextypes.NodeInfo) { // RequestNodeInfo broadcast request node info message func (dm *DelegateManager) RequestNodeInfo() { - log.L().Info("delegate manager request node info") - + log.L().Debug("delegate manager request node info") // broadcast request meesage if err := dm.transmitter.BroadcastOutbound(context.Background(), &iotextypes.RequestNodeInfoMessage{}); err != nil { log.L().Error("delegate manager request node info failed", zap.Error(err)) } // manually update self node info for broadcast message to myself will be ignored - dm.updateNode(dm.privKey.PublicKey().Address().String(), &iotextypes.NodeInfo{ + dm.updateNode(&NodeInfo{ Version: version.PackageVersion, Height: dm.heightable.TipHeight(), - Timestamp: timestamppb.Now(), + Timestamp: time.Now(), + Address: dm.privKey.PublicKey().Address().String(), }) } // TellNodeInfo tell node info to peer func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { - log.L().Info("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) + log.L().Debug("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) req := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ Version: version.PackageVersion, @@ -138,7 +155,7 @@ func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) h := hashNodeInfo(req) sign, err := dm.privKey.Sign(h[:]) if err != nil { - return err + return errors.Wrap(err, "sign node info message failed") } req.Signature = sign diff --git a/node/manager_test.go b/node/manager_test.go index 2db7a69171..ae67cc191c 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -48,7 +48,7 @@ func TestNewDelegateManager(t *testing.T) { args{&Config{}, tMock, hMock, pMock}, &DelegateManager{ cfg: Config{}, - nodeMap: map[string]iotextypes.NodeInfo{}, + nodeMap: map[string]NodeInfo{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -60,7 +60,7 @@ func TestNewDelegateManager(t *testing.T) { args{&Config{time.Second * 3}, tMock, hMock, pMock}, &DelegateManager{ cfg: Config{time.Second * 3}, - nodeMap: map[string]iotextypes.NodeInfo{}, + nodeMap: map[string]NodeInfo{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -96,7 +96,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { type fields struct { cfg Config - nodeMap map[string]iotextypes.NodeInfo + nodeMap map[string]NodeInfo broadcaster *routine.RecurringTask transmitter transmitter heightable heightable @@ -117,7 +117,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { "valid", fields{ cfg: Config{}, - nodeMap: map[string]iotextypes.NodeInfo{}, + nodeMap: map[string]NodeInfo{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -145,7 +145,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { "invalid", fields{ cfg: Config{}, - nodeMap: map[string]iotextypes.NodeInfo{}, + nodeMap: map[string]NodeInfo{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -186,7 +186,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { if tt.valid { require.Equal(tt.args.node.Info.Height, dm.nodeMap[addr].Height) require.Equal(tt.args.node.Info.Version, dm.nodeMap[addr].Version) - require.Equal(tt.args.node.Info.Timestamp.String(), dm.nodeMap[addr].Timestamp.String()) + require.Equal(tt.args.node.Info.Timestamp.AsTime().String(), dm.nodeMap[addr].Timestamp.String()) m := dto.Metric{} nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) @@ -212,7 +212,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { require := require.New(t) type fields struct { cfg Config - nodeMap map[string]iotextypes.NodeInfo + nodeMap map[string]NodeInfo broadcaster *routine.RecurringTask transmitter transmitter heightable heightable @@ -226,7 +226,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { "update_self", fields{ Config{}, - map[string]iotextypes.NodeInfo{}, + map[string]NodeInfo{}, nil, tMock, hMock, @@ -269,7 +269,7 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { t.Run("tell", func(t *testing.T) { dm := &DelegateManager{ cfg: Config{}, - nodeMap: map[string]iotextypes.NodeInfo{}, + nodeMap: map[string]NodeInfo{}, broadcaster: nil, transmitter: tMock, heightable: hMock, From 5f9bbfdeb2ba48180f1baea4bebe1875e6fd339d Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 13 Jan 2023 19:34:50 +0800 Subject: [PATCH 21/32] simplify finding in array --- chainservice/chainservice.go | 19 ++++++++----------- go.mod | 3 ++- go.sum | 11 ++++++----- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 541d23f3f1..53fde5ba39 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -12,6 +12,7 @@ import ( "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" "github.com/iotexproject/iotex-address/address" @@ -175,19 +176,15 @@ func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg func (cs *ChainService) HandleRequestNodeInfoMsg(ctx context.Context, peerID string, msg *iotextypes.RequestNodeInfoMessage) error { peers, err := cs.p2pAgent.ConnectedPeers() if err != nil { - return err - } - var target *peer.AddrInfo - for i := range peers { - if peers[i].ID.Pretty() == peerID { - target = &peers[i] - break - } + return errors.Wrap(err, "get connected peers failed") } - if target == nil { - return errors.Errorf("unicast node info msg failed: target peerID %s is not connected, peers size=%v, %v", peerID, len(peers), peers) + id := slices.IndexFunc(peers, func(p peer.AddrInfo) bool { + return p.ID.Pretty() == peerID + }) + if id < 0 { + return errors.Errorf("unicast node info msg failed: target peerID %s is not connected", peerID) } - return cs.delegateManager.TellNodeInfo(ctx, *target) + return cs.delegateManager.TellNodeInfo(ctx, peers[id]) } // ChainID returns ChainID. diff --git a/go.mod b/go.mod index 2f6a3d68c5..a26219dd16 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/shirou/gopsutil/v3 v3.22.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.34.0 + golang.org/x/exp v0.0.0-20230111222715-75897c7a292a golang.org/x/text v0.3.7 ) @@ -192,7 +193,7 @@ require ( go.opentelemetry.io/otel/metric v0.31.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect + golang.org/x/sys v0.1.0 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect diff --git a/go.sum b/go.sum index cded1eb533..0382bb5651 100644 --- a/go.sum +++ b/go.sum @@ -1376,6 +1376,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20230111222715-75897c7a292a h1:/YWeLOBWYV5WAQORVPkZF3Pq9IppkcT72GKnWjNf5W8= +golang.org/x/exp v0.0.0-20230111222715-75897c7a292a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1397,8 +1399,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1546,8 +1548,8 @@ golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -1610,9 +1612,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 h1:P6iTFmrTQqWrqLZPX1VMzCUbCRCAUXSUsSpkEOvWzJ0= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= From 1a10a7b693e43e48010cabce1e28ed3f35158447 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 13 Jan 2023 22:33:09 +0800 Subject: [PATCH 22/32] fix lint error --- node/manager.go | 14 +++++++------- node/manager_test.go | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/node/manager.go b/node/manager.go index 402bdc9673..42a4154370 100644 --- a/node/manager.go +++ b/node/manager.go @@ -38,8 +38,8 @@ type ( Sign([]byte) ([]byte, error) } - // NodeInfo node infomation - NodeInfo struct { + // Info node infomation + Info struct { Version string Height uint64 Timestamp time.Time @@ -49,7 +49,7 @@ type ( // DelegateManager manage delegate node info DelegateManager struct { cfg Config - nodeMap map[string]NodeInfo + nodeMap map[string]Info broadcaster *routine.RecurringTask transmitter transmitter heightable heightable @@ -61,7 +61,7 @@ type ( func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privateKey) *DelegateManager { dm := &DelegateManager{ cfg: *cfg, - nodeMap: make(map[string]NodeInfo), + nodeMap: make(map[string]Info), transmitter: t, heightable: h, privKey: privKey, @@ -106,7 +106,7 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms return } - dm.updateNode(&NodeInfo{ + dm.updateNode(&Info{ Version: msg.Info.Version, Height: msg.Info.Height, Timestamp: msg.Info.Timestamp.AsTime(), @@ -115,7 +115,7 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms } // updateNode update node info -func (dm *DelegateManager) updateNode(node *NodeInfo) { +func (dm *DelegateManager) updateNode(node *Info) { addr := node.Address // update dm.nodeMap dm.nodeMap[addr] = *node @@ -132,7 +132,7 @@ func (dm *DelegateManager) RequestNodeInfo() { } // manually update self node info for broadcast message to myself will be ignored - dm.updateNode(&NodeInfo{ + dm.updateNode(&Info{ Version: version.PackageVersion, Height: dm.heightable.TipHeight(), Timestamp: time.Now(), diff --git a/node/manager_test.go b/node/manager_test.go index ae67cc191c..f65981a453 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -48,7 +48,7 @@ func TestNewDelegateManager(t *testing.T) { args{&Config{}, tMock, hMock, pMock}, &DelegateManager{ cfg: Config{}, - nodeMap: map[string]NodeInfo{}, + nodeMap: map[string]Info{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -60,7 +60,7 @@ func TestNewDelegateManager(t *testing.T) { args{&Config{time.Second * 3}, tMock, hMock, pMock}, &DelegateManager{ cfg: Config{time.Second * 3}, - nodeMap: map[string]NodeInfo{}, + nodeMap: map[string]Info{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -96,7 +96,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { type fields struct { cfg Config - nodeMap map[string]NodeInfo + nodeMap map[string]Info broadcaster *routine.RecurringTask transmitter transmitter heightable heightable @@ -117,7 +117,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { "valid", fields{ cfg: Config{}, - nodeMap: map[string]NodeInfo{}, + nodeMap: map[string]Info{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -145,7 +145,7 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { "invalid", fields{ cfg: Config{}, - nodeMap: map[string]NodeInfo{}, + nodeMap: map[string]Info{}, transmitter: tMock, heightable: hMock, privKey: pMock, @@ -212,7 +212,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { require := require.New(t) type fields struct { cfg Config - nodeMap map[string]NodeInfo + nodeMap map[string]Info broadcaster *routine.RecurringTask transmitter transmitter heightable heightable @@ -226,7 +226,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { "update_self", fields{ Config{}, - map[string]NodeInfo{}, + map[string]Info{}, nil, tMock, hMock, @@ -269,7 +269,7 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { t.Run("tell", func(t *testing.T) { dm := &DelegateManager{ cfg: Config{}, - nodeMap: map[string]NodeInfo{}, + nodeMap: map[string]Info{}, broadcaster: nil, transmitter: tMock, heightable: hMock, From 8d53cd46d14e926956f02ac498eae3035f850de3 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 16 Jan 2023 11:44:43 +0800 Subject: [PATCH 23/32] add unicast single request message --- dispatcher/dispatcher.go | 17 ++++++++++----- node/manager.go | 34 ++++++++++++++++++++--------- node/manager_test.go | 47 +++++++++++++++++++++++----------------- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 9f8b7ad324..eefed55c9c 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -452,7 +452,7 @@ func (d *IotxDispatcher) HandleTell(ctx context.Context, chainID uint32, peer pe d.dispatchBlockSyncReq(ctx, chainID, peer, message) case iotexrpc.MessageType_BLOCK: d.dispatchBlock(ctx, chainID, peer.ID.Pretty(), message) - case iotexrpc.MessageType_NODE_INFO: + case iotexrpc.MessageType_NODE_INFO_REQUEST, iotexrpc.MessageType_NODE_INFO: d.dispatchNodeInfo(ctx, chainID, peer.ID.Pretty(), message) default: log.L().Warn("Unexpected msgType handled by HandleTell.", zap.Any("msgType", msgType)) @@ -468,10 +468,17 @@ func (d *IotxDispatcher) dispatchNodeInfo(ctx context.Context, chainID uint32, p log.L().Debug("no subscriber for this chain id, drop the node info", zap.Uint32("chain id", chainID)) return } - - if err := subscriber.HandleNodeInfoMsg(ctx, peer, message.(*iotextypes.ResponseNodeInfoMessage)); err != nil { - log.L().Warn("failed to handle node info message", zap.Error(err)) - return + switch msg := message.(type) { + case *iotextypes.ResponseNodeInfoMessage: + if err := subscriber.HandleNodeInfoMsg(ctx, peer, msg); err != nil { + log.L().Warn("failed to handle node info message", zap.Error(err)) + } + case *iotextypes.RequestNodeInfoMessage: + if err := subscriber.HandleRequestNodeInfoMsg(ctx, peer, msg); err != nil { + log.L().Warn("failed to handle request node info message", zap.Error(err)) + } + default: + log.L().Warn("Unexpected nodeinfo msgType.", zap.Any("msgType", msg)) } } diff --git a/node/manager.go b/node/manager.go index 42a4154370..6e39689488 100644 --- a/node/manager.go +++ b/node/manager.go @@ -7,6 +7,7 @@ package node import ( "context" + "sync" "time" "github.com/iotexproject/go-pkgs/crypto" @@ -48,12 +49,13 @@ type ( // DelegateManager manage delegate node info DelegateManager struct { - cfg Config - nodeMap map[string]Info - broadcaster *routine.RecurringTask - transmitter transmitter - heightable heightable - privKey privateKey + cfg Config + nodeMap map[string]Info + nodeMapMutex sync.Mutex + broadcaster *routine.RecurringTask + transmitter transmitter + heightable heightable + privKey privateKey } ) @@ -68,7 +70,7 @@ func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privat } // disable broadcast if RequestNodeInfoInterval == 0 if cfg.RequestNodeInfoInterval > 0 { - dm.broadcaster = routine.NewRecurringTask(dm.RequestNodeInfo, cfg.RequestNodeInfoInterval) + dm.broadcaster = routine.NewRecurringTask(dm.RequestAllNodeInfoAsync, cfg.RequestNodeInfoInterval) } return dm @@ -117,15 +119,18 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms // updateNode update node info func (dm *DelegateManager) updateNode(node *Info) { addr := node.Address + dm.nodeMapMutex.Lock() + defer dm.nodeMapMutex.Unlock() + // update dm.nodeMap dm.nodeMap[addr] = *node // update metric nodeDelegateHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) } -// RequestNodeInfo broadcast request node info message -func (dm *DelegateManager) RequestNodeInfo() { - log.L().Debug("delegate manager request node info") +// RequestAllNodeInfoAsync broadcast request node info message +func (dm *DelegateManager) RequestAllNodeInfoAsync() { + log.L().Debug("delegate manager request all node info") // broadcast request meesage if err := dm.transmitter.BroadcastOutbound(context.Background(), &iotextypes.RequestNodeInfoMessage{}); err != nil { log.L().Error("delegate manager request node info failed", zap.Error(err)) @@ -140,6 +145,15 @@ func (dm *DelegateManager) RequestNodeInfo() { }) } +// RequestSingleNodeInfoAsync unicast request node info message +func (dm *DelegateManager) RequestSingleNodeInfoAsync(peer peer.AddrInfo) { + log.L().Debug("delegate manager request one node info", zap.String("peer", peer.ID.Pretty())) + // unicast request meesage + if err := dm.transmitter.UnicastOutbound(context.Background(), peer, &iotextypes.RequestNodeInfoMessage{}); err != nil { + log.L().Error("delegate manager request one node info failed", zap.Error(err)) + } +} + // TellNodeInfo tell node info to peer func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { log.L().Debug("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) diff --git a/node/manager_test.go b/node/manager_test.go index f65981a453..857a5675ec 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -250,7 +250,7 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) hMock.EXPECT().TipHeight().Return(height).Times(1) pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) - dm.RequestNodeInfo() + dm.RequestAllNodeInfoAsync() require.Equal(height, dm.nodeMap[privK.PublicKey().Address().String()].Height) }) @@ -297,26 +297,33 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { } -func TestPubkey(t *testing.T) { - masterKey := "96f0aa5e8523d6a28dc35c927274be4e931e74eaa720b418735debfcbfe712b8" - sk, err := crypto.HexStringToPrivateKey(masterKey) - if err != nil { - t.Fatal(err) - } - ioPubKey := sk.PublicKey() - ioAddr := ioPubKey.Address().String() +func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + hMock := mock_node.NewMockheightable(ctrl) + tMock := mock_node.NewMocktransmitter(ctrl) + pMock := mock_node.NewMockprivateKey(ctrl) - hash := []byte("testtesttesttesttesttesttesttest") - sign, err := sk.Sign(hash) - if err != nil { - t.Fatal(err) - } + require := require.New(t) + t.Run("request_single", func(t *testing.T) { + dm := &DelegateManager{ + cfg: Config{}, + nodeMap: map[string]Info{}, + transmitter: tMock, + heightable: hMock, + privKey: pMock, + } + var paramPeer peer.AddrInfo + var paramMsg iotextypes.RequestNodeInfoMessage + targetPeer := peer.AddrInfo{ID: peer.ID("xxxx")} + tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(_ context.Context, p peer.AddrInfo, msg proto.Message) { + paramPeer = p + paramMsg = *msg.(*iotextypes.RequestNodeInfoMessage) + }).Times(1) + dm.RequestSingleNodeInfoAsync(targetPeer) - recovPubKey, err := crypto.RecoverPubkey(hash, sign) - if err != nil { - t.Fatal(err) - } - recovAddr := recovPubKey.Address().String() + require.Equal(targetPeer, paramPeer) + require.Equal(iotextypes.RequestNodeInfoMessage{}, paramMsg) + }) - t.Log("ioAddr=", ioAddr, "recovAddr", recovAddr) } From ebbec6965e0b3f2b4e5cff73006e11b56616db53 Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 18 Jan 2023 17:09:01 +0800 Subject: [PATCH 24/32] node push(broadcast) node info message proactively and periodically --- dispatcher/dispatcher.go | 6 +- node/config.go | 8 +- node/manager.go | 65 ++++++--- node/manager_test.go | 296 ++++++++++++--------------------------- 4 files changed, 147 insertions(+), 228 deletions(-) diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index eefed55c9c..310d6d556a 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -431,9 +431,9 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, pe d.dispatchAction(ctx, chainID, message) case *iotextypes.Block: d.dispatchBlock(ctx, chainID, peer, message) - case *iotextypes.RequestNodeInfoMessage: - if err := subscriber.HandleRequestNodeInfoMsg(ctx, peer, msg); err != nil { - log.L().Warn("Failed to handle request node info message.", zap.Error(err)) + case *iotextypes.ResponseNodeInfoMessage: + if err := subscriber.HandleNodeInfoMsg(ctx, peer, msg); err != nil { + log.L().Warn("Failed to handle node info message.", zap.Error(err)) } default: msgType, _ := goproto.GetTypeFromRPCMsg(message) diff --git a/node/config.go b/node/config.go index 1f75d1dd2b..afe2364881 100644 --- a/node/config.go +++ b/node/config.go @@ -9,8 +9,12 @@ import "time" // Config node config type Config struct { - RequestNodeInfoInterval time.Duration `yaml:"requestNodeInfoInterval"` + OnlyDelegateBroadcast bool `yaml:"onlyDelegateBroadcast"` + BroadcastNodeInfoInterval time.Duration `yaml:"broadcastNodeInfoInterval"` } // DefaultConfig is the default config -var DefaultConfig = Config{} +var DefaultConfig = Config{ + OnlyDelegateBroadcast: true, + BroadcastNodeInfoInterval: 5 * time.Minute, +} diff --git a/node/manager.go b/node/manager.go index 6e39689488..36d46f6da8 100644 --- a/node/manager.go +++ b/node/manager.go @@ -68,11 +68,18 @@ func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privat heightable: h, privKey: privKey, } - // disable broadcast if RequestNodeInfoInterval == 0 - if cfg.RequestNodeInfoInterval > 0 { - dm.broadcaster = routine.NewRecurringTask(dm.RequestAllNodeInfoAsync, cfg.RequestNodeInfoInterval) - } + dm.broadcaster = routine.NewRecurringTask(func() { + // delegates and nodes who are turned on will broadcast + if !dm.isDelegate() && dm.cfg.OnlyDelegateBroadcast { + log.L().Debug("delegate manager general node disabled node info broadcast") + return + } + + if err := dm.BroadcastNodeInfo(context.Background()); err != nil { + log.L().Error("delegate manager broadcast node info failed", zap.Error(err)) + } + }, cfg.BroadcastNodeInfoInterval) return dm } @@ -128,35 +135,49 @@ func (dm *DelegateManager) updateNode(node *Info) { nodeDelegateHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) } -// RequestAllNodeInfoAsync broadcast request node info message -func (dm *DelegateManager) RequestAllNodeInfoAsync() { - log.L().Debug("delegate manager request all node info") +// BroadcastNodeInfo broadcast request node info message +func (dm *DelegateManager) BroadcastNodeInfo(ctx context.Context) error { + log.L().Debug("delegate manager broadcast node info") + req, err := dm.genNodeInfoMsg() + if err != nil { + return err + } + // broadcast request meesage - if err := dm.transmitter.BroadcastOutbound(context.Background(), &iotextypes.RequestNodeInfoMessage{}); err != nil { - log.L().Error("delegate manager request node info failed", zap.Error(err)) + if err := dm.transmitter.BroadcastOutbound(ctx, req); err != nil { + return err } // manually update self node info for broadcast message to myself will be ignored dm.updateNode(&Info{ - Version: version.PackageVersion, - Height: dm.heightable.TipHeight(), - Timestamp: time.Now(), - Address: dm.privKey.PublicKey().Address().String(), + Version: req.Info.Version, + Height: req.Info.Height, + Timestamp: req.Info.Timestamp.AsTime(), + Address: req.Info.Address, }) + + return nil } // RequestSingleNodeInfoAsync unicast request node info message -func (dm *DelegateManager) RequestSingleNodeInfoAsync(peer peer.AddrInfo) { +func (dm *DelegateManager) RequestSingleNodeInfoAsync(ctx context.Context, peer peer.AddrInfo) error { log.L().Debug("delegate manager request one node info", zap.String("peer", peer.ID.Pretty())) - // unicast request meesage - if err := dm.transmitter.UnicastOutbound(context.Background(), peer, &iotextypes.RequestNodeInfoMessage{}); err != nil { - log.L().Error("delegate manager request one node info failed", zap.Error(err)) - } + + return dm.transmitter.UnicastOutbound(ctx, peer, &iotextypes.RequestNodeInfoMessage{}) } // TellNodeInfo tell node info to peer func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { log.L().Debug("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) + req, err := dm.genNodeInfoMsg() + if err != nil { + return err + } + + return dm.transmitter.UnicastOutbound(ctx, peer, req) +} + +func (dm *DelegateManager) genNodeInfoMsg() (*iotextypes.ResponseNodeInfoMessage, error) { req := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ Version: version.PackageVersion, @@ -169,11 +190,15 @@ func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) h := hashNodeInfo(req) sign, err := dm.privKey.Sign(h[:]) if err != nil { - return errors.Wrap(err, "sign node info message failed") + return nil, errors.Wrap(err, "sign node info message failed") } req.Signature = sign + return req, nil +} - return dm.transmitter.UnicastOutbound(ctx, peer, req) +func (dm *DelegateManager) isDelegate() bool { + // TODO whether i am delegate + return false } func hashNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) hash.Hash256 { diff --git a/node/manager_test.go b/node/manager_test.go index 857a5675ec..52d23ff16b 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -12,7 +12,6 @@ import ( "github.com/golang/mock/gomock" "github.com/iotexproject/go-pkgs/crypto" - "github.com/iotexproject/iotex-core/pkg/routine" "github.com/iotexproject/iotex-core/test/mock/mock_node" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/libp2p/go-libp2p-core/peer" @@ -31,54 +30,40 @@ func TestNewDelegateManager(t *testing.T) { require := require.New(t) - type args struct { - cfg *Config - t transmitter - h heightable - p privateKey - } - tests := []struct { - name string - args args - want *DelegateManager - broadcasterIsNull bool - }{ - { - "disable_broadcast", - args{&Config{}, tMock, hMock, pMock}, - &DelegateManager{ - cfg: Config{}, - nodeMap: map[string]Info{}, - transmitter: tMock, - heightable: hMock, - privKey: pMock, - }, - true, - }, - { - "enable_broadcast", - args{&Config{time.Second * 3}, tMock, hMock, pMock}, - &DelegateManager{ - cfg: Config{time.Second * 3}, - nodeMap: map[string]Info{}, - transmitter: tMock, - heightable: hMock, - privKey: pMock, - }, - false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := NewDelegateManager(tt.args.cfg, tt.args.t, tt.args.h, tt.args.p) - require.Equal(tt.want.cfg, got.cfg) - require.Equal(tt.want.nodeMap, got.nodeMap) - require.Equal(tt.want.transmitter, got.transmitter) - require.Equal(tt.want.heightable, got.heightable) - require.Equal(tt.want.privKey, got.privKey) - require.Equal(tt.broadcasterIsNull, got.broadcaster == nil) - }) - } + t.Run("disable_broadcast", func(t *testing.T) { + cfg := Config{true, 100 * time.Millisecond} + got := NewDelegateManager(&cfg, tMock, hMock, pMock) + require.Equal(cfg, got.cfg) + require.Equal(map[string]Info{}, got.nodeMap) + require.Equal(tMock, got.transmitter) + require.Equal(hMock, got.heightable) + require.Equal(pMock, got.privKey) + require.Equal(true, got.broadcaster != nil) + tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Times(0) + err := got.Start(context.Background()) + require.NoError(err) + time.Sleep(time.Second) + }) + + t.Run("enable_broadcast", func(t *testing.T) { + cfg := Config{false, 100 * time.Millisecond} + got := NewDelegateManager(&cfg, tMock, hMock, pMock) + require.Equal(cfg, got.cfg) + require.Equal(map[string]Info{}, got.nodeMap) + require.Equal(tMock, got.transmitter) + require.Equal(hMock, got.heightable) + require.Equal(pMock, got.privKey) + require.Equal(true, got.broadcaster != nil) + + privK, _ := crypto.GenerateKey() + hMock.EXPECT().TipHeight().Return(uint64(10)).AnyTimes() + pMock.EXPECT().PublicKey().Return(privK.PublicKey()).AnyTimes() + pMock.EXPECT().Sign(gomock.Any()).Return([]byte("xxxxxx"), nil).AnyTimes() + tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).MinTimes(1) + err := got.Start(context.Background()) + require.NoError(err) + time.Sleep(time.Second) + }) } func TestDelegateManager_HandleNodeInfo(t *testing.T) { @@ -90,119 +75,55 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { require := require.New(t) privKey, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - type fields struct { - cfg Config - nodeMap map[string]Info - broadcaster *routine.RecurringTask - transmitter transmitter - heightable heightable - privKey privateKey - } - type args struct { - ctx context.Context - addr string - node *iotextypes.ResponseNodeInfoMessage - } - tests := []struct { - name string - fields fields - args args - valid bool - }{ - { - "valid", - fields{ - cfg: Config{}, - nodeMap: map[string]Info{}, - transmitter: tMock, - heightable: hMock, - privKey: pMock, - }, - args{ - context.Background(), - "abc", - func() *iotextypes.ResponseNodeInfoMessage { - msg := &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ - Version: "v1.8.0", - Height: 200, - Timestamp: timestamppb.Now(), - Address: privKey.PublicKey().Address().String(), - }, - } - hash := hashNodeInfo(msg) - msg.Signature, _ = privKey.Sign(hash[:]) - return msg - }(), + require.NoError(err) + + t.Run("verify_pass", func(t *testing.T) { + msg := &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: "v1.8.0", + Height: 200, + Timestamp: timestamppb.Now(), + Address: privKey.PublicKey().Address().String(), }, - true, - }, - { - "invalid", - fields{ - cfg: Config{}, - nodeMap: map[string]Info{}, - transmitter: tMock, - heightable: hMock, - privKey: pMock, - }, - args{ - context.Background(), - "abc", - func() *iotextypes.ResponseNodeInfoMessage { - privKey2, _ := crypto.GenerateKey() - msg := &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ - Version: "v1.8.0", - Height: 200, - Timestamp: timestamppb.Now(), - Address: privKey2.PublicKey().Address().String(), - }, - } - hash := hashNodeInfo(msg) - msg.Signature, _ = privKey.Sign(hash[:]) - return msg - }(), - }, - false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - dm := &DelegateManager{ - cfg: tt.fields.cfg, - nodeMap: tt.fields.nodeMap, - broadcaster: tt.fields.broadcaster, - transmitter: tt.fields.transmitter, - heightable: tt.fields.heightable, - privKey: tt.fields.privKey, - } - dm.HandleNodeInfo(tt.args.ctx, tt.args.addr, tt.args.node) - addr := tt.args.node.Info.Address - if tt.valid { - require.Equal(tt.args.node.Info.Height, dm.nodeMap[addr].Height) - require.Equal(tt.args.node.Info.Version, dm.nodeMap[addr].Version) - require.Equal(tt.args.node.Info.Timestamp.AsTime().String(), dm.nodeMap[addr].Timestamp.String()) + } + hash := hashNodeInfo(msg) + msg.Signature, _ = privKey.Sign(hash[:]) + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, pMock) + dm.HandleNodeInfo(context.Background(), "abc", msg) + addr := msg.Info.Address + require.Equal(msg.Info.Height, dm.nodeMap[addr].Height) + require.Equal(msg.Info.Version, dm.nodeMap[addr].Version) + require.Equal(msg.Info.Timestamp.AsTime().String(), dm.nodeMap[addr].Timestamp.String()) + m := dto.Metric{} + nodeDelegateHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) + require.Equal(msg.Info.Height, uint64(m.Gauge.GetValue())) + }) - m := dto.Metric{} - nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) - require.Equal(tt.args.node.Info.Height, uint64(m.Gauge.GetValue())) - } else { - _, ok := dm.nodeMap[addr] - require.False(ok) - m := dto.Metric{} - nodeDelegateHeightGauge.WithLabelValues(addr, tt.args.node.Info.Version).Write(&m) - require.Equal(uint64(0), uint64(m.Gauge.GetValue())) - } - }) - } + t.Run("verify_unpass", func(t *testing.T) { + privKey2, _ := crypto.GenerateKey() + msg := &iotextypes.ResponseNodeInfoMessage{ + Info: &iotextypes.NodeInfo{ + Version: "v1.8.0", + Height: 200, + Timestamp: timestamppb.Now(), + Address: privKey2.PublicKey().Address().String(), + }, + } + hash := hashNodeInfo(msg) + msg.Signature, _ = privKey.Sign(hash[:]) + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, pMock) + dm.HandleNodeInfo(context.Background(), "abc", msg) + addr := msg.Info.Address + + _, ok := dm.nodeMap[addr] + require.False(ok) + m := dto.Metric{} + nodeDelegateHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) + require.Equal(uint64(0), uint64(m.Gauge.GetValue())) + }) } -func TestDelegateManager_RequestNodeInfo(t *testing.T) { +func TestDelegateManager_BroadcastNodeInfo(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() hMock := mock_node.NewMockheightable(ctrl) @@ -210,51 +131,21 @@ func TestDelegateManager_RequestNodeInfo(t *testing.T) { pMock := mock_node.NewMockprivateKey(ctrl) require := require.New(t) - type fields struct { - cfg Config - nodeMap map[string]Info - broadcaster *routine.RecurringTask - transmitter transmitter - heightable heightable - privateKey privateKey - } - tests := []struct { - name string - fields fields - }{ - { - "update_self", - fields{ - Config{}, - map[string]Info{}, - nil, - tMock, - hMock, - pMock, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - dm := &DelegateManager{ - cfg: tt.fields.cfg, - nodeMap: tt.fields.nodeMap, - broadcaster: tt.fields.broadcaster, - transmitter: tt.fields.transmitter, - heightable: tt.fields.heightable, - privKey: tt.fields.privateKey, - } - height := uint64(200) - privK, _ := crypto.GenerateKey() - tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) - hMock.EXPECT().TipHeight().Return(height).Times(1) - pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) - dm.RequestAllNodeInfoAsync() + t.Run("update_self", func(t *testing.T) { + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, pMock) - require.Equal(height, dm.nodeMap[privK.PublicKey().Address().String()].Height) - }) - } + height := uint64(200) + privK, _ := crypto.GenerateKey() + tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) + hMock.EXPECT().TipHeight().Return(height).Times(1) + pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) + pMock.EXPECT().Sign(gomock.Any()).Return([]byte(""), nil).Times(1) + err := dm.BroadcastNodeInfo(context.Background()) + + require.NoError(err) + require.Equal(height, dm.nodeMap[privK.PublicKey().Address().String()].Height) + }) } func TestDelegateManager_TellNodeInfo(t *testing.T) { @@ -294,7 +185,6 @@ func TestDelegateManager_TellNodeInfo(t *testing.T) { require.Equal(message.Info.Height, height) require.Equal(message.Signature, sign) }) - } func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { @@ -320,7 +210,7 @@ func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { paramPeer = p paramMsg = *msg.(*iotextypes.RequestNodeInfoMessage) }).Times(1) - dm.RequestSingleNodeInfoAsync(targetPeer) + dm.RequestSingleNodeInfoAsync(context.Background(), targetPeer) require.Equal(targetPeer, paramPeer) require.Equal(iotextypes.RequestNodeInfoMessage{}, paramMsg) From cbc2a66806172f9ca11f6420f8aaa5a8ffd89c68 Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 25 Jan 2023 13:55:58 +0800 Subject: [PATCH 25/32] fix comment --- chainservice/chainservice.go | 2 +- go.mod | 4 +- go.sum | 7 +- misc/scripts/mockgen.sh | 2 +- node/manager.go | 88 +++++++++------- node/manager_test.go | 158 +++++++++++++--------------- node/metric.go | 20 ---- test/mock/mock_node/mock_manager.go | 96 +++++------------ 8 files changed, 160 insertions(+), 217 deletions(-) delete mode 100644 node/metric.go diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 53fde5ba39..4b692d887b 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -184,7 +184,7 @@ func (cs *ChainService) HandleRequestNodeInfoMsg(ctx context.Context, peerID str if id < 0 { return errors.Errorf("unicast node info msg failed: target peerID %s is not connected", peerID) } - return cs.delegateManager.TellNodeInfo(ctx, peers[id]) + return cs.delegateManager.HandleNodeInfoRequest(ctx, peers[id]) } // ChainID returns ChainID. diff --git a/go.mod b/go.mod index a26219dd16..00420b6a1a 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/iotexproject/iotex-address v0.2.8 github.com/iotexproject/iotex-antenna-go/v2 v2.5.1 github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d - github.com/iotexproject/iotex-proto v0.5.10 + github.com/iotexproject/iotex-proto v0.5.11 github.com/libp2p/go-libp2p-core v0.8.5 github.com/mattn/go-sqlite3 v1.14.8 // indirect github.com/miguelmota/go-ethereum-hdwallet v0.1.1 @@ -204,5 +204,3 @@ require ( replace github.com/ethereum/go-ethereum => github.com/iotexproject/go-ethereum v0.4.2 replace golang.org/x/xerrors => golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3 - -replace github.com/iotexproject/iotex-proto => github.com/envestcc/iotex-proto v0.0.0-20230113062505-e182a7f5aafe diff --git a/go.sum b/go.sum index 0382bb5651..ed39cfa2bd 100644 --- a/go.sum +++ b/go.sum @@ -219,8 +219,6 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envestcc/iotex-proto v0.0.0-20230113062505-e182a7f5aafe h1:1yuc2o+/IkuT/sOyNaFM7SNXgNNXHw9bkqqv7mog5Dc= -github.com/envestcc/iotex-proto v0.0.0-20230113062505-e182a7f5aafe/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -507,6 +505,9 @@ github.com/iotexproject/iotex-antenna-go/v2 v2.5.1 h1:Z7X0qXxc/4hSSE3koBaFRpLAdi github.com/iotexproject/iotex-antenna-go/v2 v2.5.1/go.mod h1:8pDZcM45M0gY6jm3PoM20rzoD2Z0vg3Hg64RS4c3qx0= github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d h1:/j1xCAC9YiG/8UKqYvycS/v3ddVsb1G7AMyLXOjeYI0= github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d/go.mod h1:GRWevxtqQ4gPMrd7Qxhr29/7aTgvjiTp+rFI9KMMZEo= +github.com/iotexproject/iotex-proto v0.5.0/go.mod h1:Xg6REkv+nTZN+OC22xXIQuqKdTWWHwOAJEXCoMpDwtI= +github.com/iotexproject/iotex-proto v0.5.11 h1:NcxU8Mq7eYQ7EWXoQIY4qw8221c98l8OsOfMmw/fVtA= +github.com/iotexproject/iotex-proto v0.5.11/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -1447,7 +1448,6 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1546,7 +1546,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/misc/scripts/mockgen.sh b/misc/scripts/mockgen.sh index 3e26023a44..18670ac2e7 100755 --- a/misc/scripts/mockgen.sh +++ b/misc/scripts/mockgen.sh @@ -152,5 +152,5 @@ mkdir -p ./test/mock/mock_node mockgen -destination=./test/mock/mock_node/mock_manager.go \ -source=./node/manager.go \ -package=mock_node \ - transmitter heightable signer + transmitter heightable diff --git a/node/manager.go b/node/manager.go index 36d46f6da8..bcd40084d3 100644 --- a/node/manager.go +++ b/node/manager.go @@ -19,6 +19,7 @@ import ( "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" @@ -28,23 +29,20 @@ type ( transmitter interface { BroadcastOutbound(context.Context, proto.Message) error UnicastOutbound(context.Context, peer.AddrInfo, proto.Message) error + Info() (peer.AddrInfo, error) } - heightable interface { + chain interface { TipHeight() uint64 } - privateKey interface { - PublicKey() crypto.PublicKey - Sign([]byte) ([]byte, error) - } - // Info node infomation Info struct { Version string Height uint64 Timestamp time.Time Address string + PeerID string } // DelegateManager manage delegate node info @@ -52,24 +50,41 @@ type ( cfg Config nodeMap map[string]Info nodeMapMutex sync.Mutex - broadcaster *routine.RecurringTask - transmitter transmitter - heightable heightable - privKey privateKey + myVersion string + myAddress string + + broadcastTask *routine.RecurringTask + transmitter transmitter + chain chain + privKey crypto.PrivateKey } ) +var nodeDelegateHeightGauge = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "iotex_node_delegate_height_gauge", + Help: "delegate height", + }, + []string{"address", "version"}, +) + +func init() { + prometheus.MustRegister(nodeDelegateHeightGauge) +} + // NewDelegateManager new delegate manager -func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privateKey) *DelegateManager { +func NewDelegateManager(cfg *Config, t transmitter, h chain, privKey crypto.PrivateKey) *DelegateManager { dm := &DelegateManager{ cfg: *cfg, nodeMap: make(map[string]Info), transmitter: t, - heightable: h, + chain: h, privKey: privKey, + myVersion: version.PackageVersion, + myAddress: privKey.PublicKey().Address().String(), } - dm.broadcaster = routine.NewRecurringTask(func() { + dm.broadcastTask = routine.NewRecurringTask(func() { // delegates and nodes who are turned on will broadcast if !dm.isDelegate() && dm.cfg.OnlyDelegateBroadcast { log.L().Debug("delegate manager general node disabled node info broadcast") @@ -85,16 +100,16 @@ func NewDelegateManager(cfg *Config, t transmitter, h heightable, privKey privat // Start start delegate broadcast task func (dm *DelegateManager) Start(ctx context.Context) error { - if dm.broadcaster != nil { - return dm.broadcaster.Start(ctx) + if dm.broadcastTask != nil { + return dm.broadcastTask.Start(ctx) } return nil } // Stop stop delegate broadcast task func (dm *DelegateManager) Stop(ctx context.Context) error { - if dm.broadcaster != nil { - return dm.broadcaster.Stop(ctx) + if dm.broadcastTask != nil { + return dm.broadcastTask.Stop(ctx) } return nil } @@ -103,15 +118,15 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, msg *iotextypes.ResponseNodeInfoMessage) { log.L().Debug("delegate manager handle node info") // recover pubkey - hash := hashNodeInfo(msg) + hash := hashNodeInfo(msg.Info) pubKey, err := crypto.RecoverPubkey(hash[:], msg.Signature) if err != nil { log.L().Warn("delegate manager recover pubkey failed", zap.Error(err)) return } // verify signature - if pubKey.Address().String() != msg.Info.Address { - log.L().Warn("delegate manager node info message verify failed", zap.String("address", msg.Info.Address)) + if addr := pubKey.Address().String(); addr != msg.Info.Address { + log.L().Warn("delegate manager node info message verify failed", zap.String("expected", addr), zap.String("recieved", msg.Info.Address)) return } @@ -120,6 +135,7 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms Height: msg.Info.Height, Timestamp: msg.Info.Timestamp.AsTime(), Address: msg.Info.Address, + PeerID: peerID, }) } @@ -142,57 +158,57 @@ func (dm *DelegateManager) BroadcastNodeInfo(ctx context.Context) error { if err != nil { return err } - // broadcast request meesage if err := dm.transmitter.BroadcastOutbound(ctx, req); err != nil { return err } - // manually update self node info for broadcast message to myself will be ignored + peer, err := dm.transmitter.Info() + if err != nil { + return err + } dm.updateNode(&Info{ Version: req.Info.Version, Height: req.Info.Height, Timestamp: req.Info.Timestamp.AsTime(), Address: req.Info.Address, + PeerID: peer.ID.Pretty(), }) - return nil } // RequestSingleNodeInfoAsync unicast request node info message func (dm *DelegateManager) RequestSingleNodeInfoAsync(ctx context.Context, peer peer.AddrInfo) error { log.L().Debug("delegate manager request one node info", zap.String("peer", peer.ID.Pretty())) - return dm.transmitter.UnicastOutbound(ctx, peer, &iotextypes.RequestNodeInfoMessage{}) } -// TellNodeInfo tell node info to peer -func (dm *DelegateManager) TellNodeInfo(ctx context.Context, peer peer.AddrInfo) error { +// HandleNodeInfoRequest tell node info to peer +func (dm *DelegateManager) HandleNodeInfoRequest(ctx context.Context, peer peer.AddrInfo) error { log.L().Debug("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) req, err := dm.genNodeInfoMsg() if err != nil { return err } - return dm.transmitter.UnicastOutbound(ctx, peer, req) } func (dm *DelegateManager) genNodeInfoMsg() (*iotextypes.ResponseNodeInfoMessage, error) { req := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ - Version: version.PackageVersion, - Height: dm.heightable.TipHeight(), + Version: dm.myVersion, + Height: dm.chain.TipHeight(), Timestamp: timestamppb.Now(), - Address: dm.privKey.PublicKey().Address().String(), + Address: dm.myAddress, }, } - // add sign for msg - h := hashNodeInfo(req) - sign, err := dm.privKey.Sign(h[:]) + // add sig for msg + h := hashNodeInfo(req.Info) + sig, err := dm.privKey.Sign(h[:]) if err != nil { return nil, errors.Wrap(err, "sign node info message failed") } - req.Signature = sign + req.Signature = sig return req, nil } @@ -201,6 +217,6 @@ func (dm *DelegateManager) isDelegate() bool { return false } -func hashNodeInfo(msg *iotextypes.ResponseNodeInfoMessage) hash.Hash256 { - return hash.Hash256b(byteutil.Must(proto.Marshal(msg.Info))) +func hashNodeInfo(msg *iotextypes.NodeInfo) hash.Hash256 { + return hash.Hash256b(byteutil.Must(proto.Marshal(msg))) } diff --git a/node/manager_test.go b/node/manager_test.go index 52d23ff16b..bc91bf546d 100644 --- a/node/manager_test.go +++ b/node/manager_test.go @@ -22,46 +22,45 @@ import ( ) func TestNewDelegateManager(t *testing.T) { + require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockheightable(ctrl) + hMock := mock_node.NewMockchain(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - pMock := mock_node.NewMockprivateKey(ctrl) - - require := require.New(t) + privK, err := crypto.GenerateKey() + require.NoError(err) t.Run("disable_broadcast", func(t *testing.T) { cfg := Config{true, 100 * time.Millisecond} - got := NewDelegateManager(&cfg, tMock, hMock, pMock) - require.Equal(cfg, got.cfg) - require.Equal(map[string]Info{}, got.nodeMap) - require.Equal(tMock, got.transmitter) - require.Equal(hMock, got.heightable) - require.Equal(pMock, got.privKey) - require.Equal(true, got.broadcaster != nil) + dm := NewDelegateManager(&cfg, tMock, hMock, privK) + require.Equal(cfg, dm.cfg) + require.Equal(map[string]Info{}, dm.nodeMap) + require.Equal(tMock, dm.transmitter) + require.Equal(hMock, dm.chain) + require.Equal(privK, dm.privKey) + require.Equal(true, dm.broadcastTask != nil) tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Times(0) - err := got.Start(context.Background()) + err := dm.Start(context.Background()) require.NoError(err) + defer dm.Stop(context.Background()) time.Sleep(time.Second) }) t.Run("enable_broadcast", func(t *testing.T) { cfg := Config{false, 100 * time.Millisecond} - got := NewDelegateManager(&cfg, tMock, hMock, pMock) - require.Equal(cfg, got.cfg) - require.Equal(map[string]Info{}, got.nodeMap) - require.Equal(tMock, got.transmitter) - require.Equal(hMock, got.heightable) - require.Equal(pMock, got.privKey) - require.Equal(true, got.broadcaster != nil) - - privK, _ := crypto.GenerateKey() - hMock.EXPECT().TipHeight().Return(uint64(10)).AnyTimes() - pMock.EXPECT().PublicKey().Return(privK.PublicKey()).AnyTimes() - pMock.EXPECT().Sign(gomock.Any()).Return([]byte("xxxxxx"), nil).AnyTimes() + dm := NewDelegateManager(&cfg, tMock, hMock, privK) + require.Equal(cfg, dm.cfg) + require.Equal(map[string]Info{}, dm.nodeMap) + require.Equal(tMock, dm.transmitter) + require.Equal(hMock, dm.chain) + require.Equal(privK, dm.privKey) + require.Equal(true, dm.broadcastTask != nil) + tMock.EXPECT().Info().Return(peer.AddrInfo{}, nil).MinTimes(1) + hMock.EXPECT().TipHeight().Return(uint64(10)).MinTimes(1) tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).MinTimes(1) - err := got.Start(context.Background()) + err := dm.Start(context.Background()) require.NoError(err) + defer dm.Stop(context.Background()) time.Sleep(time.Second) }) } @@ -69,9 +68,8 @@ func TestNewDelegateManager(t *testing.T) { func TestDelegateManager_HandleNodeInfo(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockheightable(ctrl) + hMock := mock_node.NewMockchain(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - pMock := mock_node.NewMockprivateKey(ctrl) require := require.New(t) privKey, err := crypto.GenerateKey() @@ -86,20 +84,22 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { Address: privKey.PublicKey().Address().String(), }, } - hash := hashNodeInfo(msg) + hash := hashNodeInfo(msg.Info) msg.Signature, _ = privKey.Sign(hash[:]) - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, pMock) + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) dm.HandleNodeInfo(context.Background(), "abc", msg) addr := msg.Info.Address - require.Equal(msg.Info.Height, dm.nodeMap[addr].Height) - require.Equal(msg.Info.Version, dm.nodeMap[addr].Version) - require.Equal(msg.Info.Timestamp.AsTime().String(), dm.nodeMap[addr].Timestamp.String()) + nodeGot := dm.nodeMap[addr] + require.Equal(msg.Info.Height, nodeGot.Height) + require.Equal(msg.Info.Version, nodeGot.Version) + require.Equal(msg.Info.Timestamp.AsTime().String(), nodeGot.Timestamp.String()) + require.Equal("abc", nodeGot.PeerID) m := dto.Metric{} nodeDelegateHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) require.Equal(msg.Info.Height, uint64(m.Gauge.GetValue())) }) - t.Run("verify_unpass", func(t *testing.T) { + t.Run("verify_fail", func(t *testing.T) { privKey2, _ := crypto.GenerateKey() msg := &iotextypes.ResponseNodeInfoMessage{ Info: &iotextypes.NodeInfo{ @@ -108,13 +108,11 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { Timestamp: timestamppb.Now(), Address: privKey2.PublicKey().Address().String(), }, + Signature: []byte("xxxx"), } - hash := hashNodeInfo(msg) - msg.Signature, _ = privKey.Sign(hash[:]) - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, pMock) + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) dm.HandleNodeInfo(context.Background(), "abc", msg) addr := msg.Info.Address - _, ok := dm.nodeMap[addr] require.False(ok) m := dto.Metric{} @@ -124,94 +122,84 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { } func TestDelegateManager_BroadcastNodeInfo(t *testing.T) { + require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockheightable(ctrl) + hMock := mock_node.NewMockchain(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - pMock := mock_node.NewMockprivateKey(ctrl) - - require := require.New(t) + privKey, err := crypto.GenerateKey() + require.NoError(err) t.Run("update_self", func(t *testing.T) { - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, pMock) - + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) height := uint64(200) - privK, _ := crypto.GenerateKey() - tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) + peerID, err := peer.IDFromString("12D3KooWF2fns5ZWKbPfx2U1wQDdxoTK2D6HC3ortbSAQYR4BQp4") + require.NoError(err) hMock.EXPECT().TipHeight().Return(height).Times(1) - pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) - pMock.EXPECT().Sign(gomock.Any()).Return([]byte(""), nil).Times(1) - err := dm.BroadcastNodeInfo(context.Background()) - + tMock.EXPECT().Info().Return(peer.AddrInfo{ID: peerID}, nil).Times(1) + tMock.EXPECT().BroadcastOutbound(gomock.Any(), gomock.Any()).Return(nil).Times(1) + err = dm.BroadcastNodeInfo(context.Background()) require.NoError(err) - require.Equal(height, dm.nodeMap[privK.PublicKey().Address().String()].Height) + addr := privKey.PublicKey().Address().String() + nodeGot := dm.nodeMap[addr] + require.Equal(height, nodeGot.Height) + require.Equal(dm.myVersion, nodeGot.Version) + require.Equal(addr, nodeGot.Address) + require.Equal(peerID.Pretty(), nodeGot.PeerID) }) } -func TestDelegateManager_TellNodeInfo(t *testing.T) { +func TestDelegateManager_HandleNodeInfoRequest(t *testing.T) { + require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockheightable(ctrl) + hMock := mock_node.NewMockchain(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - pMock := mock_node.NewMockprivateKey(ctrl) - - require := require.New(t) + privKey, err := crypto.GenerateKey() + require.NoError(err) - t.Run("tell", func(t *testing.T) { - dm := &DelegateManager{ - cfg: Config{}, - nodeMap: map[string]Info{}, - broadcaster: nil, - transmitter: tMock, - heightable: hMock, - privKey: pMock, - } + t.Run("unicast", func(t *testing.T) { + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) height := uint64(200) - sign := []byte("xxxxxx") - privK, _ := crypto.GenerateKey() + var sig []byte message := &iotextypes.ResponseNodeInfoMessage{} - hMock.EXPECT().TipHeight().Return(height).Times(1) tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error { *message = *msg.(*iotextypes.ResponseNodeInfoMessage) + hash := hashNodeInfo(message.Info) + sig, _ = dm.privKey.Sign(hash[:]) return nil }).Times(1) - pMock.EXPECT().PublicKey().Return(privK.PublicKey()).Times(1) - pMock.EXPECT().Sign(gomock.Any()).Return(sign, nil).Times(1) - - err := dm.TellNodeInfo(context.Background(), peer.AddrInfo{}) - + err := dm.HandleNodeInfoRequest(context.Background(), peer.AddrInfo{}) require.NoError(err) require.Equal(message.Info.Height, height) - require.Equal(message.Signature, sign) + require.Equal(message.Info.Version, dm.myVersion) + require.Equal(message.Info.Address, dm.myAddress) + require.Equal(message.Signature, sig) }) } func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { + require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockheightable(ctrl) + hMock := mock_node.NewMockchain(ctrl) tMock := mock_node.NewMocktransmitter(ctrl) - pMock := mock_node.NewMockprivateKey(ctrl) + privKey, err := crypto.GenerateKey() + require.NoError(err) - require := require.New(t) t.Run("request_single", func(t *testing.T) { - dm := &DelegateManager{ - cfg: Config{}, - nodeMap: map[string]Info{}, - transmitter: tMock, - heightable: hMock, - privKey: pMock, - } + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) var paramPeer peer.AddrInfo var paramMsg iotextypes.RequestNodeInfoMessage - targetPeer := peer.AddrInfo{ID: peer.ID("xxxx")} + peerID, err := peer.IDFromString("12D3KooWF2fns5ZWKbPfx2U1wQDdxoTK2D6HC3ortbSAQYR4BQp4") + require.NoError(err) + targetPeer := peer.AddrInfo{ID: peerID} tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(_ context.Context, p peer.AddrInfo, msg proto.Message) { paramPeer = p paramMsg = *msg.(*iotextypes.RequestNodeInfoMessage) }).Times(1) dm.RequestSingleNodeInfoAsync(context.Background(), targetPeer) - require.Equal(targetPeer, paramPeer) require.Equal(iotextypes.RequestNodeInfoMessage{}, paramMsg) }) diff --git a/node/metric.go b/node/metric.go deleted file mode 100644 index d7b2e41561..0000000000 --- a/node/metric.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2022 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package node - -import "github.com/prometheus/client_golang/prometheus" - -var nodeDelegateHeightGauge = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Name: "iotex_node_delegate_height_gauge", - Help: "delegate height", - }, - []string{"address", "version"}, -) - -func init() { - prometheus.MustRegister(nodeDelegateHeightGauge) -} diff --git a/test/mock/mock_node/mock_manager.go b/test/mock/mock_node/mock_manager.go index 7c9b6e0922..7e5faa913b 100644 --- a/test/mock/mock_node/mock_manager.go +++ b/test/mock/mock_node/mock_manager.go @@ -9,7 +9,6 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" - crypto "github.com/iotexproject/go-pkgs/crypto" peer "github.com/libp2p/go-libp2p-core/peer" proto "google.golang.org/protobuf/proto" ) @@ -51,6 +50,21 @@ func (mr *MocktransmitterMockRecorder) BroadcastOutbound(arg0, arg1 interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BroadcastOutbound", reflect.TypeOf((*Mocktransmitter)(nil).BroadcastOutbound), arg0, arg1) } +// Info mocks base method. +func (m *Mocktransmitter) Info() (peer.AddrInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Info") + ret0, _ := ret[0].(peer.AddrInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Info indicates an expected call of Info. +func (mr *MocktransmitterMockRecorder) Info() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*Mocktransmitter)(nil).Info)) +} + // UnicastOutbound mocks base method. func (m *Mocktransmitter) UnicastOutbound(arg0 context.Context, arg1 peer.AddrInfo, arg2 proto.Message) error { m.ctrl.T.Helper() @@ -65,31 +79,31 @@ func (mr *MocktransmitterMockRecorder) UnicastOutbound(arg0, arg1, arg2 interfac return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnicastOutbound", reflect.TypeOf((*Mocktransmitter)(nil).UnicastOutbound), arg0, arg1, arg2) } -// Mockheightable is a mock of heightable interface. -type Mockheightable struct { +// Mockchain is a mock of chain interface. +type Mockchain struct { ctrl *gomock.Controller - recorder *MockheightableMockRecorder + recorder *MockchainMockRecorder } -// MockheightableMockRecorder is the mock recorder for Mockheightable. -type MockheightableMockRecorder struct { - mock *Mockheightable +// MockchainMockRecorder is the mock recorder for Mockchain. +type MockchainMockRecorder struct { + mock *Mockchain } -// NewMockheightable creates a new mock instance. -func NewMockheightable(ctrl *gomock.Controller) *Mockheightable { - mock := &Mockheightable{ctrl: ctrl} - mock.recorder = &MockheightableMockRecorder{mock} +// NewMockchain creates a new mock instance. +func NewMockchain(ctrl *gomock.Controller) *Mockchain { + mock := &Mockchain{ctrl: ctrl} + mock.recorder = &MockchainMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *Mockheightable) EXPECT() *MockheightableMockRecorder { +func (m *Mockchain) EXPECT() *MockchainMockRecorder { return m.recorder } // TipHeight mocks base method. -func (m *Mockheightable) TipHeight() uint64 { +func (m *Mockchain) TipHeight() uint64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "TipHeight") ret0, _ := ret[0].(uint64) @@ -97,59 +111,7 @@ func (m *Mockheightable) TipHeight() uint64 { } // TipHeight indicates an expected call of TipHeight. -func (mr *MockheightableMockRecorder) TipHeight() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TipHeight", reflect.TypeOf((*Mockheightable)(nil).TipHeight)) -} - -// MockprivateKey is a mock of privateKey interface. -type MockprivateKey struct { - ctrl *gomock.Controller - recorder *MockprivateKeyMockRecorder -} - -// MockprivateKeyMockRecorder is the mock recorder for MockprivateKey. -type MockprivateKeyMockRecorder struct { - mock *MockprivateKey -} - -// NewMockprivateKey creates a new mock instance. -func NewMockprivateKey(ctrl *gomock.Controller) *MockprivateKey { - mock := &MockprivateKey{ctrl: ctrl} - mock.recorder = &MockprivateKeyMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockprivateKey) EXPECT() *MockprivateKeyMockRecorder { - return m.recorder -} - -// PublicKey mocks base method. -func (m *MockprivateKey) PublicKey() crypto.PublicKey { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PublicKey") - ret0, _ := ret[0].(crypto.PublicKey) - return ret0 -} - -// PublicKey indicates an expected call of PublicKey. -func (mr *MockprivateKeyMockRecorder) PublicKey() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublicKey", reflect.TypeOf((*MockprivateKey)(nil).PublicKey)) -} - -// Sign mocks base method. -func (m *MockprivateKey) Sign(arg0 []byte) ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Sign", arg0) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Sign indicates an expected call of Sign. -func (mr *MockprivateKeyMockRecorder) Sign(arg0 interface{}) *gomock.Call { +func (mr *MockchainMockRecorder) TipHeight() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sign", reflect.TypeOf((*MockprivateKey)(nil).Sign), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TipHeight", reflect.TypeOf((*Mockchain)(nil).TipHeight)) } From e09792b843ad9ae1f2263a8b124b0591f202c76b Mon Sep 17 00:00:00 2001 From: envestcc Date: Sat, 28 Jan 2023 19:16:55 +0800 Subject: [PATCH 26/32] chang node to nodeinfo --- chainservice/builder.go | 4 +-- chainservice/chainservice.go | 4 +-- config/config.go | 6 ++--- misc/scripts/mockgen.sh | 10 ++++---- {node => nodeinfo}/config.go | 2 +- {node => nodeinfo}/manager.go | 2 +- {node => nodeinfo}/manager_test.go | 25 +++++++++---------- .../mock_manager.go | 6 ++--- 8 files changed, 29 insertions(+), 30 deletions(-) rename {node => nodeinfo}/config.go (97%) rename {node => nodeinfo}/manager.go (99%) rename {node => nodeinfo}/manager_test.go (92%) rename test/mock/{mock_node => mock_nodeinfo}/mock_manager.go (97%) diff --git a/chainservice/builder.go b/chainservice/builder.go index a99641dbcd..0abd3304e1 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -31,7 +31,7 @@ import ( "github.com/iotexproject/iotex-core/consensus" rp "github.com/iotexproject/iotex-core/consensus/scheme/rolldpos" "github.com/iotexproject/iotex-core/db" - "github.com/iotexproject/iotex-core/node" + "github.com/iotexproject/iotex-core/nodeinfo" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-core/state/factory" @@ -379,7 +379,7 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B } func (builder *Builder) buildNodeManager() { - dm := node.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) + dm := nodeinfo.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) builder.cs.delegateManager = dm builder.cs.lifecycle.Add(dm) } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 4b692d887b..56d056f148 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -32,7 +32,7 @@ import ( "github.com/iotexproject/iotex-core/blockindex" "github.com/iotexproject/iotex-core/blocksync" "github.com/iotexproject/iotex-core/consensus" - "github.com/iotexproject/iotex-core/node" + "github.com/iotexproject/iotex-core/nodeinfo" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/lifecycle" "github.com/iotexproject/iotex-core/pkg/log" @@ -86,7 +86,7 @@ type ChainService struct { candidateIndexer *poll.CandidateIndexer candBucketsIndexer *staking.CandidatesBucketsIndexer registry *protocol.Registry - delegateManager *node.DelegateManager + delegateManager *nodeinfo.DelegateManager } // Start starts the server diff --git a/config/config.go b/config/config.go index 1d08668d2a..c33e39c4df 100644 --- a/config/config.go +++ b/config/config.go @@ -23,7 +23,7 @@ import ( "github.com/iotexproject/iotex-core/consensus/consensusfsm" "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/dispatcher" - "github.com/iotexproject/iotex-core/node" + "github.com/iotexproject/iotex-core/nodeinfo" "github.com/iotexproject/iotex-core/p2p" "github.com/iotexproject/iotex-core/pkg/log" ) @@ -81,7 +81,7 @@ var ( DB: db.DefaultConfig, Indexer: blockindex.DefaultConfig, Genesis: genesis.Default, - Node: node.DefaultConfig, + Node: nodeinfo.DefaultConfig, } // ErrInvalidCfg indicates the invalid config value @@ -132,7 +132,7 @@ type ( Log log.GlobalConfig `yaml:"log"` SubLogs map[string]log.GlobalConfig `yaml:"subLogs"` Genesis genesis.Genesis `yaml:"genesis"` - Node node.Config `yaml:"node"` + Node nodeinfo.Config `yaml:"node"` } // Validate is the interface of validating the config diff --git a/misc/scripts/mockgen.sh b/misc/scripts/mockgen.sh index 18670ac2e7..fb3a437fb5 100755 --- a/misc/scripts/mockgen.sh +++ b/misc/scripts/mockgen.sh @@ -148,9 +148,9 @@ mockgen -destination=./test/mock/mock_web3server/mock_web3server.go \ -package=mock_web3server \ Web3Handler -mkdir -p ./test/mock/mock_node -mockgen -destination=./test/mock/mock_node/mock_manager.go \ - -source=./node/manager.go \ - -package=mock_node \ - transmitter heightable +mkdir -p ./test/mock/mock_nodeinfo +mockgen -destination=./test/mock/mock_nodeinfo/mock_manager.go \ + -source=./nodeinfo/manager.go \ + -package=mock_nodeinfo \ + transmitter chain diff --git a/node/config.go b/nodeinfo/config.go similarity index 97% rename from node/config.go rename to nodeinfo/config.go index afe2364881..02d9e31a27 100644 --- a/node/config.go +++ b/nodeinfo/config.go @@ -3,7 +3,7 @@ // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. -package node +package nodeinfo import "time" diff --git a/node/manager.go b/nodeinfo/manager.go similarity index 99% rename from node/manager.go rename to nodeinfo/manager.go index bcd40084d3..ac75ee2825 100644 --- a/node/manager.go +++ b/nodeinfo/manager.go @@ -3,7 +3,7 @@ // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. -package node +package nodeinfo import ( "context" diff --git a/node/manager_test.go b/nodeinfo/manager_test.go similarity index 92% rename from node/manager_test.go rename to nodeinfo/manager_test.go index bc91bf546d..33304e8880 100644 --- a/node/manager_test.go +++ b/nodeinfo/manager_test.go @@ -3,7 +3,7 @@ // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. -package node +package nodeinfo import ( "context" @@ -12,7 +12,7 @@ import ( "github.com/golang/mock/gomock" "github.com/iotexproject/go-pkgs/crypto" - "github.com/iotexproject/iotex-core/test/mock/mock_node" + "github.com/iotexproject/iotex-core/test/mock/mock_nodeinfo" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/libp2p/go-libp2p-core/peer" dto "github.com/prometheus/client_model/go" @@ -25,8 +25,8 @@ func TestNewDelegateManager(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockchain(ctrl) - tMock := mock_node.NewMocktransmitter(ctrl) + hMock := mock_nodeinfo.NewMockchain(ctrl) + tMock := mock_nodeinfo.NewMocktransmitter(ctrl) privK, err := crypto.GenerateKey() require.NoError(err) @@ -68,8 +68,8 @@ func TestNewDelegateManager(t *testing.T) { func TestDelegateManager_HandleNodeInfo(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockchain(ctrl) - tMock := mock_node.NewMocktransmitter(ctrl) + hMock := mock_nodeinfo.NewMockchain(ctrl) + tMock := mock_nodeinfo.NewMocktransmitter(ctrl) require := require.New(t) privKey, err := crypto.GenerateKey() @@ -125,8 +125,8 @@ func TestDelegateManager_BroadcastNodeInfo(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockchain(ctrl) - tMock := mock_node.NewMocktransmitter(ctrl) + hMock := mock_nodeinfo.NewMockchain(ctrl) + tMock := mock_nodeinfo.NewMocktransmitter(ctrl) privKey, err := crypto.GenerateKey() require.NoError(err) @@ -153,8 +153,8 @@ func TestDelegateManager_HandleNodeInfoRequest(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockchain(ctrl) - tMock := mock_node.NewMocktransmitter(ctrl) + hMock := mock_nodeinfo.NewMockchain(ctrl) + tMock := mock_nodeinfo.NewMocktransmitter(ctrl) privKey, err := crypto.GenerateKey() require.NoError(err) @@ -183,8 +183,8 @@ func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { require := require.New(t) ctrl := gomock.NewController(t) defer ctrl.Finish() - hMock := mock_node.NewMockchain(ctrl) - tMock := mock_node.NewMocktransmitter(ctrl) + hMock := mock_nodeinfo.NewMockchain(ctrl) + tMock := mock_nodeinfo.NewMocktransmitter(ctrl) privKey, err := crypto.GenerateKey() require.NoError(err) @@ -203,5 +203,4 @@ func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { require.Equal(targetPeer, paramPeer) require.Equal(iotextypes.RequestNodeInfoMessage{}, paramMsg) }) - } diff --git a/test/mock/mock_node/mock_manager.go b/test/mock/mock_nodeinfo/mock_manager.go similarity index 97% rename from test/mock/mock_node/mock_manager.go rename to test/mock/mock_nodeinfo/mock_manager.go index 7e5faa913b..71d26a5232 100644 --- a/test/mock/mock_node/mock_manager.go +++ b/test/mock/mock_nodeinfo/mock_manager.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./node/manager.go +// Source: ./nodeinfo/manager.go -// Package mock_node is a generated GoMock package. -package mock_node +// Package mock_nodeinfo is a generated GoMock package. +package mock_nodeinfo import ( context "context" From 0016e7f7b4296c2fcaa05788a07d3e3bed8f05da Mon Sep 17 00:00:00 2001 From: envestcc Date: Sun, 29 Jan 2023 10:20:27 +0800 Subject: [PATCH 27/32] add e2etest for nodeinfo --- chainservice/builder.go | 6 +- chainservice/chainservice.go | 5 ++ config/config.go | 10 +-- e2etest/nodeinfo_test.go | 132 +++++++++++++++++++++++++++++++++++ nodeinfo/manager.go | 9 +++ nodeinfo/manager_test.go | 28 ++++++++ 6 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 e2etest/nodeinfo_test.go diff --git a/chainservice/builder.go b/chainservice/builder.go index 0abd3304e1..853e01cb87 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -378,8 +378,8 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B return blockchain.NewBlockchain(builder.cfg.Chain, builder.cfg.Genesis, builder.cs.blockdao, factory.NewMinter(builder.cs.factory, builder.cs.actpool), chainOpts...) } -func (builder *Builder) buildNodeManager() { - dm := nodeinfo.NewDelegateManager(&builder.cfg.Node, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) +func (builder *Builder) buildDelegateManager() { + dm := nodeinfo.NewDelegateManager(&builder.cfg.NodeInfo, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) builder.cs.delegateManager = dm builder.cs.lifecycle.Add(dm) } @@ -629,7 +629,7 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) if err := builder.buildBlockSyncer(); err != nil { return nil, err } - builder.buildNodeManager() + builder.buildDelegateManager() cs := builder.cs builder.cs = nil diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 56d056f148..48a1f2d794 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -220,6 +220,11 @@ func (cs *ChainService) BlockSync() blocksync.BlockSync { return cs.blocksync } +// DelegateManager returns the delegate manager +func (cs *ChainService) DelegateManager() *nodeinfo.DelegateManager { + return cs.delegateManager +} + // Registry returns a pointer to the registry func (cs *ChainService) Registry() *protocol.Registry { return cs.registry } diff --git a/config/config.go b/config/config.go index c33e39c4df..0c295be452 100644 --- a/config/config.go +++ b/config/config.go @@ -78,10 +78,10 @@ var ( StartSubChainInterval: 10 * time.Second, SystemLogDBPath: "/var/log", }, - DB: db.DefaultConfig, - Indexer: blockindex.DefaultConfig, - Genesis: genesis.Default, - Node: nodeinfo.DefaultConfig, + DB: db.DefaultConfig, + Indexer: blockindex.DefaultConfig, + Genesis: genesis.Default, + NodeInfo: nodeinfo.DefaultConfig, } // ErrInvalidCfg indicates the invalid config value @@ -132,7 +132,7 @@ type ( Log log.GlobalConfig `yaml:"log"` SubLogs map[string]log.GlobalConfig `yaml:"subLogs"` Genesis genesis.Genesis `yaml:"genesis"` - Node nodeinfo.Config `yaml:"node"` + NodeInfo nodeinfo.Config `yaml:"nodeinfo"` } // Validate is the interface of validating the config diff --git a/e2etest/nodeinfo_test.go b/e2etest/nodeinfo_test.go new file mode 100644 index 0000000000..1785512364 --- /dev/null +++ b/e2etest/nodeinfo_test.go @@ -0,0 +1,132 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package e2etest + +import ( + "context" + "testing" + "time" + + "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/config" + "github.com/iotexproject/iotex-core/server/itx" + "github.com/iotexproject/iotex-core/testutil" + "github.com/stretchr/testify/require" +) + +func newNodeInfoTestConfig(triePath, dBPath, idxDBPath string) (config.Config, func(), error) { + cfg, err := newTestConfig() + if err != nil { + return cfg, nil, err + } + testTriePath, err := testutil.PathOfTempFile(triePath) + if err != nil { + return cfg, nil, err + } + testDBPath, err := testutil.PathOfTempFile(dBPath) + if err != nil { + return cfg, nil, err + } + indexDBPath, err := testutil.PathOfTempFile(idxDBPath) + if err != nil { + return cfg, nil, err + } + cfg.Chain.TrieDBPatchFile = "" + cfg.Chain.TrieDBPath = testTriePath + cfg.Chain.ChainDBPath = testDBPath + cfg.Chain.IndexDBPath = indexDBPath + return cfg, func() { + testutil.CleanupPath(testTriePath) + testutil.CleanupPath(testDBPath) + testutil.CleanupPath(indexDBPath) + }, nil +} + +func TestBroadcastNodeInfo(t *testing.T) { + require := require.New(t) + + cfgSender, teardown, err := newNodeInfoTestConfig("trie.test", "db.test", "indexdb.test") + require.NoError(err) + defer teardown() + cfgSender.NodeInfo.OnlyDelegateBroadcast = false + cfgSender.NodeInfo.BroadcastNodeInfoInterval = time.Second + cfgSender.Network.ReconnectInterval = 2 * time.Second + srvSender, err := itx.NewServer(cfgSender) + require.NoError(err) + ctxSender := genesis.WithGenesisContext(context.Background(), cfgSender.Genesis) + err = srvSender.Start(ctxSender) + require.NoError(err) + defer func() { + require.NoError(srvSender.Stop(ctxSender)) + }() + addrsSender, err := srvSender.P2PAgent().Self() + require.NoError(err) + + cfgReciever, teardown2, err := newNodeInfoTestConfig("trie2.test", "db2.test", "indexdb2.test") + require.NoError(err) + defer teardown2() + cfgReciever.Network.BootstrapNodes = []string{validNetworkAddr(addrsSender)} + cfgReciever.Network.ReconnectInterval = 2 * time.Second + srvReciever, err := itx.NewServer(cfgReciever) + require.NoError(err) + ctxReciever := genesis.WithGenesisContext(context.Background(), cfgReciever.Genesis) + err = srvReciever.Start(ctxReciever) + require.NoError(err) + defer func() { + require.NoError(srvReciever.Stop(ctxReciever)) + }() + + // check if there is sender's info in reciever delegatemanager + time.Sleep(5 * time.Second) + addrSender := cfgSender.Chain.ProducerAddress().String() + _, ok := srvReciever.ChainService(cfgReciever.Chain.ID).DelegateManager().GetNodeByAddr(addrSender) + require.True(ok) +} + +func TestUnicastNodeInfo(t *testing.T) { + require := require.New(t) + + cfgReciever, teardown2, err := newNodeInfoTestConfig("trie2.test", "db2.test", "indexdb2.test") + require.NoError(err) + defer teardown2() + cfgReciever.Network.ReconnectInterval = 2 * time.Second + srvReciever, err := itx.NewServer(cfgReciever) + require.NoError(err) + ctxReciever := genesis.WithGenesisContext(context.Background(), cfgReciever.Genesis) + err = srvReciever.Start(ctxReciever) + require.NoError(err) + defer func() { + require.NoError(srvReciever.Stop(ctxReciever)) + }() + addrsReciever, err := srvReciever.P2PAgent().Self() + require.NoError(err) + + cfgSender, teardown, err := newNodeInfoTestConfig("trie.test", "db.test", "indexdb.test") + require.NoError(err) + defer teardown() + cfgSender.Network.ReconnectInterval = 2 * time.Second + cfgSender.Network.BootstrapNodes = []string{validNetworkAddr(addrsReciever)} + srvSender, err := itx.NewServer(cfgSender) + require.NoError(err) + ctxSender := genesis.WithGenesisContext(context.Background(), cfgSender.Genesis) + err = srvSender.Start(ctxSender) + require.NoError(err) + defer func() { + require.NoError(srvSender.Stop(ctxSender)) + }() + + // check if there is reciever's info in sender delegatemanager + time.Sleep(5 * time.Second) + peerReciever, err := srvReciever.P2PAgent().Info() + require.NoError(err) + dmSender := srvSender.ChainService(cfgSender.Chain.ID).DelegateManager() + err = dmSender.RequestSingleNodeInfoAsync(context.Background(), peerReciever) + require.NoError(err) + time.Sleep(5 * time.Second) + addrReciever := cfgReciever.Chain.ProducerAddress().String() + _, ok := dmSender.GetNodeByAddr(addrReciever) + require.True(ok) +} diff --git a/nodeinfo/manager.go b/nodeinfo/manager.go index ac75ee2825..d8fea54274 100644 --- a/nodeinfo/manager.go +++ b/nodeinfo/manager.go @@ -151,6 +151,15 @@ func (dm *DelegateManager) updateNode(node *Info) { nodeDelegateHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) } +// GetNodeByAddr get node info by address +func (dm *DelegateManager) GetNodeByAddr(addr string) (info Info, ok bool) { + dm.nodeMapMutex.Lock() + defer dm.nodeMapMutex.Unlock() + + info, ok = dm.nodeMap[addr] + return +} + // BroadcastNodeInfo broadcast request node info message func (dm *DelegateManager) BroadcastNodeInfo(ctx context.Context) error { log.L().Debug("delegate manager broadcast node info") diff --git a/nodeinfo/manager_test.go b/nodeinfo/manager_test.go index 33304e8880..8133aaa53a 100644 --- a/nodeinfo/manager_test.go +++ b/nodeinfo/manager_test.go @@ -204,3 +204,31 @@ func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { require.Equal(iotextypes.RequestNodeInfoMessage{}, paramMsg) }) } + +func TestDelegateManager_GetNodeByAddr(t *testing.T) { + require := require.New(t) + ctrl := gomock.NewController(t) + defer ctrl.Finish() + hMock := mock_nodeinfo.NewMockchain(ctrl) + tMock := mock_nodeinfo.NewMocktransmitter(ctrl) + privKey, err := crypto.GenerateKey() + require.NoError(err) + + dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm.updateNode(&Info{Address: "1"}) + dm.updateNode(&Info{Address: "2"}) + + t.Run("exist", func(t *testing.T) { + info, ok := dm.GetNodeByAddr("1") + require.True(ok) + require.Equal(Info{Address: "1"}, info) + info, ok = dm.GetNodeByAddr("2") + require.True(ok) + require.Equal(Info{Address: "2"}, info) + }) + t.Run("not_exist", func(t *testing.T) { + _, ok := dm.GetNodeByAddr("3") + require.False(ok) + }) + +} From 0c6e7ed1a7ce125acfcd020609bcbcf732582e0d Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 1 Feb 2023 15:49:31 +0800 Subject: [PATCH 28/32] fix comment --- chainservice/builder.go | 8 +- chainservice/chainservice.go | 31 ++--- dispatcher/dispatcher.go | 43 ++++--- dispatcher/dispatcher_test.go | 8 +- e2etest/nodeinfo_test.go | 22 ++-- go.mod | 20 ++-- go.sum | 49 ++++---- nodeinfo/config.go | 4 +- nodeinfo/manager.go | 113 +++++++++---------- nodeinfo/manager_test.go | 78 ++++++------- test/mock/mock_dispatcher/mock_dispatcher.go | 4 +- 11 files changed, 187 insertions(+), 193 deletions(-) diff --git a/chainservice/builder.go b/chainservice/builder.go index 853e01cb87..86cbc66cf8 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -378,9 +378,9 @@ func (builder *Builder) createBlockchain(forSubChain, forTest bool) blockchain.B return blockchain.NewBlockchain(builder.cfg.Chain, builder.cfg.Genesis, builder.cs.blockdao, factory.NewMinter(builder.cs.factory, builder.cs.actpool), chainOpts...) } -func (builder *Builder) buildDelegateManager() { - dm := nodeinfo.NewDelegateManager(&builder.cfg.NodeInfo, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) - builder.cs.delegateManager = dm +func (builder *Builder) buildNodeInfoManager() { + dm := nodeinfo.NewInfoManager(&builder.cfg.NodeInfo, builder.cs.p2pAgent, builder.cs.chain, builder.cfg.Chain.ProducerPrivateKey()) + builder.cs.nodeInfoManager = dm builder.cs.lifecycle.Add(dm) } @@ -629,7 +629,7 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) if err := builder.buildBlockSyncer(); err != nil { return nil, err } - builder.buildDelegateManager() + builder.buildNodeInfoManager() cs := builder.cs builder.cs = nil diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 48a1f2d794..fc41d3339d 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -12,7 +12,6 @@ import ( "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" - "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" "github.com/iotexproject/iotex-address/address" @@ -86,7 +85,7 @@ type ChainService struct { candidateIndexer *poll.CandidateIndexer candBucketsIndexer *staking.CandidatesBucketsIndexer registry *protocol.Registry - delegateManager *nodeinfo.DelegateManager + nodeInfoManager *nodeinfo.InfoManager } // Start starts the server @@ -166,25 +165,15 @@ func (cs *ChainService) HandleConsensusMsg(msg *iotextypes.ConsensusMessage) err return cs.consensus.HandleConsensusMsg(msg) } -// HandleNodeInfoMsg handles nodeinfo message. -func (cs *ChainService) HandleNodeInfoMsg(ctx context.Context, peer string, msg *iotextypes.ResponseNodeInfoMessage) error { - cs.delegateManager.HandleNodeInfo(ctx, peer, msg) +// HandleNodeInfo handles nodeinfo message. +func (cs *ChainService) HandleNodeInfo(ctx context.Context, peer string, msg *iotextypes.NodeInfo) error { + cs.nodeInfoManager.HandleNodeInfo(ctx, peer, msg) return nil } -// HandleRequestNodeInfoMsg handles request node info message -func (cs *ChainService) HandleRequestNodeInfoMsg(ctx context.Context, peerID string, msg *iotextypes.RequestNodeInfoMessage) error { - peers, err := cs.p2pAgent.ConnectedPeers() - if err != nil { - return errors.Wrap(err, "get connected peers failed") - } - id := slices.IndexFunc(peers, func(p peer.AddrInfo) bool { - return p.ID.Pretty() == peerID - }) - if id < 0 { - return errors.Errorf("unicast node info msg failed: target peerID %s is not connected", peerID) - } - return cs.delegateManager.HandleNodeInfoRequest(ctx, peers[id]) +// HandleNodeInfoRequest handles request node info message +func (cs *ChainService) HandleNodeInfoRequest(ctx context.Context, peer peer.AddrInfo, msg *iotextypes.NodeInfoRequest) error { + return cs.nodeInfoManager.HandleNodeInfoRequest(ctx, peer) } // ChainID returns ChainID. @@ -220,9 +209,9 @@ func (cs *ChainService) BlockSync() blocksync.BlockSync { return cs.blocksync } -// DelegateManager returns the delegate manager -func (cs *ChainService) DelegateManager() *nodeinfo.DelegateManager { - return cs.delegateManager +// NodeInfoManager returns the delegate manager +func (cs *ChainService) NodeInfoManager() *nodeinfo.InfoManager { + return cs.nodeInfoManager } // Registry returns a pointer to the registry diff --git a/dispatcher/dispatcher.go b/dispatcher/dispatcher.go index 310d6d556a..c8103fd579 100644 --- a/dispatcher/dispatcher.go +++ b/dispatcher/dispatcher.go @@ -51,8 +51,8 @@ type Subscriber interface { HandleBlock(context.Context, string, *iotextypes.Block) error HandleSyncRequest(context.Context, peer.AddrInfo, *iotexrpc.BlockSync) error HandleConsensusMsg(*iotextypes.ConsensusMessage) error - HandleRequestNodeInfoMsg(context.Context, string, *iotextypes.RequestNodeInfoMessage) error - HandleNodeInfoMsg(context.Context, string, *iotextypes.ResponseNodeInfoMessage) error + HandleNodeInfoRequest(context.Context, peer.AddrInfo, *iotextypes.NodeInfoRequest) error + HandleNodeInfo(context.Context, string, *iotextypes.NodeInfo) error } // Dispatcher is used by peers, handles incoming block and header notifications and relays announcements of new blocks. @@ -431,8 +431,8 @@ func (d *IotxDispatcher) HandleBroadcast(ctx context.Context, chainID uint32, pe d.dispatchAction(ctx, chainID, message) case *iotextypes.Block: d.dispatchBlock(ctx, chainID, peer, message) - case *iotextypes.ResponseNodeInfoMessage: - if err := subscriber.HandleNodeInfoMsg(ctx, peer, msg); err != nil { + case *iotextypes.NodeInfo: + if err := subscriber.HandleNodeInfo(ctx, peer, msg); err != nil { log.L().Warn("Failed to handle node info message.", zap.Error(err)) } default: @@ -452,14 +452,16 @@ func (d *IotxDispatcher) HandleTell(ctx context.Context, chainID uint32, peer pe d.dispatchBlockSyncReq(ctx, chainID, peer, message) case iotexrpc.MessageType_BLOCK: d.dispatchBlock(ctx, chainID, peer.ID.Pretty(), message) - case iotexrpc.MessageType_NODE_INFO_REQUEST, iotexrpc.MessageType_NODE_INFO: - d.dispatchNodeInfo(ctx, chainID, peer.ID.Pretty(), message) + case iotexrpc.MessageType_NODE_INFO_REQUEST: + d.dispatchNodeInfoRequest(ctx, chainID, peer, message.(*iotextypes.NodeInfoRequest)) + case iotexrpc.MessageType_NODE_INFO: + d.dispatchNodeInfo(ctx, chainID, peer.ID.Pretty(), message.(*iotextypes.NodeInfo)) default: log.L().Warn("Unexpected msgType handled by HandleTell.", zap.Any("msgType", msgType)) } } -func (d *IotxDispatcher) dispatchNodeInfo(ctx context.Context, chainID uint32, peer string, message proto.Message) { +func (d *IotxDispatcher) dispatchNodeInfoRequest(ctx context.Context, chainID uint32, peer peer.AddrInfo, message *iotextypes.NodeInfoRequest) { if !d.IsReady() { return } @@ -468,17 +470,22 @@ func (d *IotxDispatcher) dispatchNodeInfo(ctx context.Context, chainID uint32, p log.L().Debug("no subscriber for this chain id, drop the node info", zap.Uint32("chain id", chainID)) return } - switch msg := message.(type) { - case *iotextypes.ResponseNodeInfoMessage: - if err := subscriber.HandleNodeInfoMsg(ctx, peer, msg); err != nil { - log.L().Warn("failed to handle node info message", zap.Error(err)) - } - case *iotextypes.RequestNodeInfoMessage: - if err := subscriber.HandleRequestNodeInfoMsg(ctx, peer, msg); err != nil { - log.L().Warn("failed to handle request node info message", zap.Error(err)) - } - default: - log.L().Warn("Unexpected nodeinfo msgType.", zap.Any("msgType", msg)) + if err := subscriber.HandleNodeInfoRequest(ctx, peer, message); err != nil { + log.L().Warn("failed to handle request node info message", zap.Error(err)) + } +} + +func (d *IotxDispatcher) dispatchNodeInfo(ctx context.Context, chainID uint32, peerID string, message *iotextypes.NodeInfo) { + if !d.IsReady() { + return + } + subscriber := d.subscriber(chainID) + if subscriber == nil { + log.L().Debug("no subscriber for this chain id, drop the node info", zap.Uint32("chain id", chainID)) + return + } + if err := subscriber.HandleNodeInfo(ctx, peerID, message); err != nil { + log.L().Warn("failed to handle node info message", zap.Error(err)) } } diff --git a/dispatcher/dispatcher_test.go b/dispatcher/dispatcher_test.go index 429bfcbc48..9c07a2c132 100644 --- a/dispatcher/dispatcher_test.go +++ b/dispatcher/dispatcher_test.go @@ -52,8 +52,8 @@ func setTestCase() []proto.Message { &iotextypes.Block{}, &iotexrpc.BlockSync{}, &testingpb.TestPayload{}, - &iotextypes.RequestNodeInfoMessage{}, - &iotextypes.ResponseNodeInfoMessage{}, + &iotextypes.NodeInfoRequest{}, + &iotextypes.NodeInfo{}, } } @@ -101,10 +101,10 @@ func (ds *dummySubscriber) HandleAction(context.Context, *iotextypes.Action) err func (ds *dummySubscriber) HandleConsensusMsg(*iotextypes.ConsensusMessage) error { return nil } -func (ds *dummySubscriber) HandleRequestNodeInfoMsg(context.Context, string, *iotextypes.RequestNodeInfoMessage) error { +func (ds *dummySubscriber) HandleNodeInfoRequest(context.Context, peer.AddrInfo, *iotextypes.NodeInfoRequest) error { return nil } -func (ds *dummySubscriber) HandleNodeInfoMsg(context.Context, string, *iotextypes.ResponseNodeInfoMessage) error { +func (ds *dummySubscriber) HandleNodeInfo(context.Context, string, *iotextypes.NodeInfo) error { return nil } diff --git a/e2etest/nodeinfo_test.go b/e2etest/nodeinfo_test.go index 1785512364..0eb4b9d95b 100644 --- a/e2etest/nodeinfo_test.go +++ b/e2etest/nodeinfo_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/require" ) -func newNodeInfoTestConfig(triePath, dBPath, idxDBPath string) (config.Config, func(), error) { +func newConfigForNodeInfoTest(triePath, dBPath, idxDBPath string) (config.Config, func(), error) { cfg, err := newTestConfig() if err != nil { return cfg, nil, err @@ -48,10 +48,10 @@ func newNodeInfoTestConfig(triePath, dBPath, idxDBPath string) (config.Config, f func TestBroadcastNodeInfo(t *testing.T) { require := require.New(t) - cfgSender, teardown, err := newNodeInfoTestConfig("trie.test", "db.test", "indexdb.test") + cfgSender, teardown, err := newConfigForNodeInfoTest("trie.test", "db.test", "indexdb.test") require.NoError(err) defer teardown() - cfgSender.NodeInfo.OnlyDelegateBroadcast = false + cfgSender.NodeInfo.EnableBroadcastNodeInfo = true cfgSender.NodeInfo.BroadcastNodeInfoInterval = time.Second cfgSender.Network.ReconnectInterval = 2 * time.Second srvSender, err := itx.NewServer(cfgSender) @@ -65,7 +65,7 @@ func TestBroadcastNodeInfo(t *testing.T) { addrsSender, err := srvSender.P2PAgent().Self() require.NoError(err) - cfgReciever, teardown2, err := newNodeInfoTestConfig("trie2.test", "db2.test", "indexdb2.test") + cfgReciever, teardown2, err := newConfigForNodeInfoTest("trie2.test", "db2.test", "indexdb2.test") require.NoError(err) defer teardown2() cfgReciever.Network.BootstrapNodes = []string{validNetworkAddr(addrsSender)} @@ -80,16 +80,17 @@ func TestBroadcastNodeInfo(t *testing.T) { }() // check if there is sender's info in reciever delegatemanager - time.Sleep(5 * time.Second) + require.NoError(srvSender.ChainService(cfgSender.Chain.ID).NodeInfoManager().BroadcastNodeInfo(context.Background())) + time.Sleep(1 * time.Second) addrSender := cfgSender.Chain.ProducerAddress().String() - _, ok := srvReciever.ChainService(cfgReciever.Chain.ID).DelegateManager().GetNodeByAddr(addrSender) + _, ok := srvReciever.ChainService(cfgReciever.Chain.ID).NodeInfoManager().GetNodeByAddr(addrSender) require.True(ok) } func TestUnicastNodeInfo(t *testing.T) { require := require.New(t) - cfgReciever, teardown2, err := newNodeInfoTestConfig("trie2.test", "db2.test", "indexdb2.test") + cfgReciever, teardown2, err := newConfigForNodeInfoTest("trie2.test", "db2.test", "indexdb2.test") require.NoError(err) defer teardown2() cfgReciever.Network.ReconnectInterval = 2 * time.Second @@ -104,7 +105,7 @@ func TestUnicastNodeInfo(t *testing.T) { addrsReciever, err := srvReciever.P2PAgent().Self() require.NoError(err) - cfgSender, teardown, err := newNodeInfoTestConfig("trie.test", "db.test", "indexdb.test") + cfgSender, teardown, err := newConfigForNodeInfoTest("trie.test", "db.test", "indexdb.test") require.NoError(err) defer teardown() cfgSender.Network.ReconnectInterval = 2 * time.Second @@ -119,13 +120,12 @@ func TestUnicastNodeInfo(t *testing.T) { }() // check if there is reciever's info in sender delegatemanager - time.Sleep(5 * time.Second) peerReciever, err := srvReciever.P2PAgent().Info() require.NoError(err) - dmSender := srvSender.ChainService(cfgSender.Chain.ID).DelegateManager() + dmSender := srvSender.ChainService(cfgSender.Chain.ID).NodeInfoManager() err = dmSender.RequestSingleNodeInfoAsync(context.Background(), peerReciever) require.NoError(err) - time.Sleep(5 * time.Second) + time.Sleep(1 * time.Second) addrReciever := cfgReciever.Chain.ProducerAddress().String() _, ok := dmSender.GetNodeByAddr(addrReciever) require.True(ok) diff --git a/go.mod b/go.mod index 00420b6a1a..db539b7522 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/ethereum/go-ethereum v1.10.21 github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a github.com/go-redis/redis/v8 v8.11.4 - github.com/golang/mock v1.4.4 + github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 github.com/gorilla/websocket v1.4.2 @@ -20,7 +20,7 @@ require ( github.com/iotexproject/iotex-address v0.2.8 github.com/iotexproject/iotex-antenna-go/v2 v2.5.1 github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d - github.com/iotexproject/iotex-proto v0.5.11 + github.com/iotexproject/iotex-proto v0.5.12 github.com/libp2p/go-libp2p-core v0.8.5 github.com/mattn/go-sqlite3 v1.14.8 // indirect github.com/miguelmota/go-ethereum-hdwallet v0.1.1 @@ -45,10 +45,10 @@ require ( go.uber.org/config v1.3.1 go.uber.org/zap v1.16.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - golang.org/x/net v0.0.0-20220607020251-c690dde0001d + golang.org/x/net v0.3.0 golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde - google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb - google.golang.org/grpc v1.43.0 + google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa + google.golang.org/grpc v1.51.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -58,11 +58,11 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/shirou/gopsutil/v3 v3.22.2 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.34.0 - golang.org/x/exp v0.0.0-20230111222715-75897c7a292a - golang.org/x/text v0.3.7 + golang.org/x/text v0.5.0 ) require ( + cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/benbjohnson/clock v1.0.3 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -86,7 +86,6 @@ require ( github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/uuid v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect @@ -193,9 +192,10 @@ require ( go.opentelemetry.io/otel/metric v0.31.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/term v0.3.0 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect + golang.org/x/tools v0.2.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index ed39cfa2bd..4b24432935 100644 --- a/go.sum +++ b/go.sum @@ -9,11 +9,14 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/compute v1.14.0 h1:hfm2+FfxVmnRlh6LpB7cg1ZNU+5edAHmW679JePztk0= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -145,11 +148,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= @@ -225,7 +224,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= @@ -319,8 +317,9 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -357,7 +356,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -402,7 +401,6 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= @@ -506,8 +504,8 @@ github.com/iotexproject/iotex-antenna-go/v2 v2.5.1/go.mod h1:8pDZcM45M0gY6jm3PoM github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d h1:/j1xCAC9YiG/8UKqYvycS/v3ddVsb1G7AMyLXOjeYI0= github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d/go.mod h1:GRWevxtqQ4gPMrd7Qxhr29/7aTgvjiTp+rFI9KMMZEo= github.com/iotexproject/iotex-proto v0.5.0/go.mod h1:Xg6REkv+nTZN+OC22xXIQuqKdTWWHwOAJEXCoMpDwtI= -github.com/iotexproject/iotex-proto v0.5.11 h1:NcxU8Mq7eYQ7EWXoQIY4qw8221c98l8OsOfMmw/fVtA= -github.com/iotexproject/iotex-proto v0.5.11/go.mod h1:OfmLvjBmy5EYeLxxDv6kesJq+Mm3Adn5GKgDJgF9G9U= +github.com/iotexproject/iotex-proto v0.5.12 h1:s65DbejTT/c5dBtlQykyPV4V7L6efDuOOGJiqu57LPw= +github.com/iotexproject/iotex-proto v0.5.12/go.mod h1:6Xan740KoIFyw/ZztVpum5jac6Z++o1whMWDIY1SrQk= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -1270,6 +1268,7 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.elastic.co/ecszap v1.0.0 h1:PdQkRUeraR3XHJ14T7JMa+ncU0XXrVrcEN/BoRa2nMI= @@ -1377,8 +1376,6 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20230111222715-75897c7a292a h1:/YWeLOBWYV5WAQORVPkZF3Pq9IppkcT72GKnWjNf5W8= -golang.org/x/exp v0.0.0-20230111222715-75897c7a292a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1448,8 +1445,8 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1547,12 +1544,12 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1561,8 +1558,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1612,7 +1610,9 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= @@ -1661,8 +1661,8 @@ google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201211151036-40ec1c210f7a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw= -google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa h1:GZXdWYIKckxQE2EcLHLvF+KLF+bIwoxGdMUxTZizueg= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1684,8 +1684,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1698,7 +1698,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/nodeinfo/config.go b/nodeinfo/config.go index 02d9e31a27..b5fdc98095 100644 --- a/nodeinfo/config.go +++ b/nodeinfo/config.go @@ -9,12 +9,12 @@ import "time" // Config node config type Config struct { - OnlyDelegateBroadcast bool `yaml:"onlyDelegateBroadcast"` + EnableBroadcastNodeInfo bool `yaml:"enableBroadcastNodeInfo"` BroadcastNodeInfoInterval time.Duration `yaml:"broadcastNodeInfoInterval"` } // DefaultConfig is the default config var DefaultConfig = Config{ - OnlyDelegateBroadcast: true, + EnableBroadcastNodeInfo: false, BroadcastNodeInfoInterval: 5 * time.Minute, } diff --git a/nodeinfo/manager.go b/nodeinfo/manager.go index d8fea54274..d88353159b 100644 --- a/nodeinfo/manager.go +++ b/nodeinfo/manager.go @@ -7,15 +7,11 @@ package nodeinfo import ( "context" - "sync" "time" + "github.com/iotexproject/go-pkgs/cache/lru" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" - "github.com/iotexproject/iotex-core/pkg/log" - "github.com/iotexproject/iotex-core/pkg/routine" - "github.com/iotexproject/iotex-core/pkg/util/byteutil" - "github.com/iotexproject/iotex-core/pkg/version" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" @@ -23,6 +19,11 @@ import ( "go.uber.org/zap" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/iotexproject/iotex-core/pkg/log" + "github.com/iotexproject/iotex-core/pkg/routine" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" + "github.com/iotexproject/iotex-core/pkg/version" ) type ( @@ -45,13 +46,11 @@ type ( PeerID string } - // DelegateManager manage delegate node info - DelegateManager struct { - cfg Config - nodeMap map[string]Info - nodeMapMutex sync.Mutex - myVersion string - myAddress string + // InfoManager manage delegate node info + InfoManager struct { + nodeMap *lru.Cache + version string + address string broadcastTask *routine.RecurringTask transmitter transmitter @@ -60,46 +59,47 @@ type ( } ) -var nodeDelegateHeightGauge = prometheus.NewGaugeVec( +const _nodeMapSizeLimit = 1000 + +var _nodeInfoHeightGauge = prometheus.NewGaugeVec( prometheus.GaugeOpts{ - Name: "iotex_node_delegate_height_gauge", - Help: "delegate height", + Name: "iotex_node_info_height_gauge", + Help: "height info of node", }, []string{"address", "version"}, ) func init() { - prometheus.MustRegister(nodeDelegateHeightGauge) + prometheus.MustRegister(_nodeInfoHeightGauge) } -// NewDelegateManager new delegate manager -func NewDelegateManager(cfg *Config, t transmitter, h chain, privKey crypto.PrivateKey) *DelegateManager { - dm := &DelegateManager{ - cfg: *cfg, - nodeMap: make(map[string]Info), +// NewInfoManager new info manager +func NewInfoManager(cfg *Config, t transmitter, h chain, privKey crypto.PrivateKey) *InfoManager { + dm := &InfoManager{ + nodeMap: lru.New(_nodeMapSizeLimit), transmitter: t, chain: h, privKey: privKey, - myVersion: version.PackageVersion, - myAddress: privKey.PublicKey().Address().String(), + version: version.PackageVersion, + address: privKey.PublicKey().Address().String(), } dm.broadcastTask = routine.NewRecurringTask(func() { // delegates and nodes who are turned on will broadcast - if !dm.isDelegate() && dm.cfg.OnlyDelegateBroadcast { - log.L().Debug("delegate manager general node disabled node info broadcast") + if !cfg.EnableBroadcastNodeInfo && !dm.isDelegate() { + log.L().Debug("nodeinfo manager general node disabled node info broadcast") return } if err := dm.BroadcastNodeInfo(context.Background()); err != nil { - log.L().Error("delegate manager broadcast node info failed", zap.Error(err)) + log.L().Error("nodeinfo manager broadcast node info failed", zap.Error(err)) } }, cfg.BroadcastNodeInfoInterval) return dm } // Start start delegate broadcast task -func (dm *DelegateManager) Start(ctx context.Context) error { +func (dm *InfoManager) Start(ctx context.Context) error { if dm.broadcastTask != nil { return dm.broadcastTask.Start(ctx) } @@ -107,7 +107,7 @@ func (dm *DelegateManager) Start(ctx context.Context) error { } // Stop stop delegate broadcast task -func (dm *DelegateManager) Stop(ctx context.Context) error { +func (dm *InfoManager) Stop(ctx context.Context) error { if dm.broadcastTask != nil { return dm.broadcastTask.Stop(ctx) } @@ -115,18 +115,18 @@ func (dm *DelegateManager) Stop(ctx context.Context) error { } // HandleNodeInfo handle node info message -func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, msg *iotextypes.ResponseNodeInfoMessage) { - log.L().Debug("delegate manager handle node info") +func (dm *InfoManager) HandleNodeInfo(ctx context.Context, peerID string, msg *iotextypes.NodeInfo) { + log.L().Debug("nodeinfo manager handle node info") // recover pubkey hash := hashNodeInfo(msg.Info) pubKey, err := crypto.RecoverPubkey(hash[:], msg.Signature) if err != nil { - log.L().Warn("delegate manager recover pubkey failed", zap.Error(err)) + log.L().Warn("nodeinfo manager recover pubkey failed", zap.Error(err)) return } // verify signature if addr := pubKey.Address().String(); addr != msg.Info.Address { - log.L().Warn("delegate manager node info message verify failed", zap.String("expected", addr), zap.String("recieved", msg.Info.Address)) + log.L().Warn("nodeinfo manager node info message verify failed", zap.String("expected", addr), zap.String("recieved", msg.Info.Address)) return } @@ -140,29 +140,26 @@ func (dm *DelegateManager) HandleNodeInfo(ctx context.Context, peerID string, ms } // updateNode update node info -func (dm *DelegateManager) updateNode(node *Info) { +func (dm *InfoManager) updateNode(node *Info) { addr := node.Address - dm.nodeMapMutex.Lock() - defer dm.nodeMapMutex.Unlock() - // update dm.nodeMap - dm.nodeMap[addr] = *node + dm.nodeMap.Add(addr, *node) // update metric - nodeDelegateHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) + _nodeInfoHeightGauge.WithLabelValues(addr, node.Version).Set(float64(node.Height)) } // GetNodeByAddr get node info by address -func (dm *DelegateManager) GetNodeByAddr(addr string) (info Info, ok bool) { - dm.nodeMapMutex.Lock() - defer dm.nodeMapMutex.Unlock() - - info, ok = dm.nodeMap[addr] - return +func (dm *InfoManager) GetNodeByAddr(addr string) (Info, bool) { + info, ok := dm.nodeMap.Get(addr) + if !ok { + return Info{}, false + } + return info.(Info), true } // BroadcastNodeInfo broadcast request node info message -func (dm *DelegateManager) BroadcastNodeInfo(ctx context.Context) error { - log.L().Debug("delegate manager broadcast node info") +func (dm *InfoManager) BroadcastNodeInfo(ctx context.Context) error { + log.L().Debug("nodeinfo manager broadcast node info") req, err := dm.genNodeInfoMsg() if err != nil { return err @@ -187,14 +184,14 @@ func (dm *DelegateManager) BroadcastNodeInfo(ctx context.Context) error { } // RequestSingleNodeInfoAsync unicast request node info message -func (dm *DelegateManager) RequestSingleNodeInfoAsync(ctx context.Context, peer peer.AddrInfo) error { - log.L().Debug("delegate manager request one node info", zap.String("peer", peer.ID.Pretty())) - return dm.transmitter.UnicastOutbound(ctx, peer, &iotextypes.RequestNodeInfoMessage{}) +func (dm *InfoManager) RequestSingleNodeInfoAsync(ctx context.Context, peer peer.AddrInfo) error { + log.L().Debug("nodeinfo manager request one node info", zap.String("peer", peer.ID.Pretty())) + return dm.transmitter.UnicastOutbound(ctx, peer, &iotextypes.NodeInfoRequest{}) } // HandleNodeInfoRequest tell node info to peer -func (dm *DelegateManager) HandleNodeInfoRequest(ctx context.Context, peer peer.AddrInfo) error { - log.L().Debug("delegate manager tell node info", zap.Any("peer", peer.ID.Pretty())) +func (dm *InfoManager) HandleNodeInfoRequest(ctx context.Context, peer peer.AddrInfo) error { + log.L().Debug("nodeinfo manager tell node info", zap.Any("peer", peer.ID.Pretty())) req, err := dm.genNodeInfoMsg() if err != nil { return err @@ -202,13 +199,13 @@ func (dm *DelegateManager) HandleNodeInfoRequest(ctx context.Context, peer peer. return dm.transmitter.UnicastOutbound(ctx, peer, req) } -func (dm *DelegateManager) genNodeInfoMsg() (*iotextypes.ResponseNodeInfoMessage, error) { - req := &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ - Version: dm.myVersion, +func (dm *InfoManager) genNodeInfoMsg() (*iotextypes.NodeInfo, error) { + req := &iotextypes.NodeInfo{ + Info: &iotextypes.NodeInfoCore{ + Version: dm.version, Height: dm.chain.TipHeight(), Timestamp: timestamppb.Now(), - Address: dm.myAddress, + Address: dm.address, }, } // add sig for msg @@ -221,11 +218,11 @@ func (dm *DelegateManager) genNodeInfoMsg() (*iotextypes.ResponseNodeInfoMessage return req, nil } -func (dm *DelegateManager) isDelegate() bool { +func (dm *InfoManager) isDelegate() bool { // TODO whether i am delegate return false } -func hashNodeInfo(msg *iotextypes.NodeInfo) hash.Hash256 { +func hashNodeInfo(msg *iotextypes.NodeInfoCore) hash.Hash256 { return hash.Hash256b(byteutil.Must(proto.Marshal(msg))) } diff --git a/nodeinfo/manager_test.go b/nodeinfo/manager_test.go index 8133aaa53a..8d06566ee1 100644 --- a/nodeinfo/manager_test.go +++ b/nodeinfo/manager_test.go @@ -31,10 +31,9 @@ func TestNewDelegateManager(t *testing.T) { require.NoError(err) t.Run("disable_broadcast", func(t *testing.T) { - cfg := Config{true, 100 * time.Millisecond} - dm := NewDelegateManager(&cfg, tMock, hMock, privK) - require.Equal(cfg, dm.cfg) - require.Equal(map[string]Info{}, dm.nodeMap) + cfg := Config{false, 100 * time.Millisecond} + dm := NewInfoManager(&cfg, tMock, hMock, privK) + require.NotNil(dm.nodeMap) require.Equal(tMock, dm.transmitter) require.Equal(hMock, dm.chain) require.Equal(privK, dm.privKey) @@ -47,10 +46,9 @@ func TestNewDelegateManager(t *testing.T) { }) t.Run("enable_broadcast", func(t *testing.T) { - cfg := Config{false, 100 * time.Millisecond} - dm := NewDelegateManager(&cfg, tMock, hMock, privK) - require.Equal(cfg, dm.cfg) - require.Equal(map[string]Info{}, dm.nodeMap) + cfg := Config{true, 100 * time.Millisecond} + dm := NewInfoManager(&cfg, tMock, hMock, privK) + require.NotNil(dm.nodeMap) require.Equal(tMock, dm.transmitter) require.Equal(hMock, dm.chain) require.Equal(privK, dm.privKey) @@ -76,8 +74,8 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { require.NoError(err) t.Run("verify_pass", func(t *testing.T) { - msg := &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ + msg := &iotextypes.NodeInfo{ + Info: &iotextypes.NodeInfoCore{ Version: "v1.8.0", Height: 200, Timestamp: timestamppb.Now(), @@ -86,23 +84,25 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { } hash := hashNodeInfo(msg.Info) msg.Signature, _ = privKey.Sign(hash[:]) - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey) dm.HandleNodeInfo(context.Background(), "abc", msg) addr := msg.Info.Address - nodeGot := dm.nodeMap[addr] - require.Equal(msg.Info.Height, nodeGot.Height) - require.Equal(msg.Info.Version, nodeGot.Version) - require.Equal(msg.Info.Timestamp.AsTime().String(), nodeGot.Timestamp.String()) - require.Equal("abc", nodeGot.PeerID) + nodeGot, ok := dm.nodeMap.Get(addr) + require.True(ok) + nodeInfo := nodeGot.(Info) + require.Equal(msg.Info.Height, nodeInfo.Height) + require.Equal(msg.Info.Version, nodeInfo.Version) + require.Equal(msg.Info.Timestamp.AsTime().String(), nodeInfo.Timestamp.String()) + require.Equal("abc", nodeInfo.PeerID) m := dto.Metric{} - nodeDelegateHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) + _nodeInfoHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) require.Equal(msg.Info.Height, uint64(m.Gauge.GetValue())) }) t.Run("verify_fail", func(t *testing.T) { privKey2, _ := crypto.GenerateKey() - msg := &iotextypes.ResponseNodeInfoMessage{ - Info: &iotextypes.NodeInfo{ + msg := &iotextypes.NodeInfo{ + Info: &iotextypes.NodeInfoCore{ Version: "v1.8.0", Height: 200, Timestamp: timestamppb.Now(), @@ -110,13 +110,13 @@ func TestDelegateManager_HandleNodeInfo(t *testing.T) { }, Signature: []byte("xxxx"), } - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey) dm.HandleNodeInfo(context.Background(), "abc", msg) addr := msg.Info.Address - _, ok := dm.nodeMap[addr] + _, ok := dm.nodeMap.Get(addr) require.False(ok) m := dto.Metric{} - nodeDelegateHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) + _nodeInfoHeightGauge.WithLabelValues(addr, msg.Info.Version).Write(&m) require.Equal(uint64(0), uint64(m.Gauge.GetValue())) }) } @@ -131,7 +131,7 @@ func TestDelegateManager_BroadcastNodeInfo(t *testing.T) { require.NoError(err) t.Run("update_self", func(t *testing.T) { - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey) height := uint64(200) peerID, err := peer.IDFromString("12D3KooWF2fns5ZWKbPfx2U1wQDdxoTK2D6HC3ortbSAQYR4BQp4") require.NoError(err) @@ -141,11 +141,13 @@ func TestDelegateManager_BroadcastNodeInfo(t *testing.T) { err = dm.BroadcastNodeInfo(context.Background()) require.NoError(err) addr := privKey.PublicKey().Address().String() - nodeGot := dm.nodeMap[addr] - require.Equal(height, nodeGot.Height) - require.Equal(dm.myVersion, nodeGot.Version) - require.Equal(addr, nodeGot.Address) - require.Equal(peerID.Pretty(), nodeGot.PeerID) + nodeGot, ok := dm.nodeMap.Get(addr) + require.True(ok) + nodeInfo := nodeGot.(Info) + require.Equal(height, nodeInfo.Height) + require.Equal(dm.version, nodeInfo.Version) + require.Equal(addr, nodeInfo.Address) + require.Equal(peerID.Pretty(), nodeInfo.PeerID) }) } @@ -159,13 +161,13 @@ func TestDelegateManager_HandleNodeInfoRequest(t *testing.T) { require.NoError(err) t.Run("unicast", func(t *testing.T) { - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey) height := uint64(200) var sig []byte - message := &iotextypes.ResponseNodeInfoMessage{} + message := &iotextypes.NodeInfo{} hMock.EXPECT().TipHeight().Return(height).Times(1) tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_ context.Context, peerInfo peer.AddrInfo, msg proto.Message) error { - *message = *msg.(*iotextypes.ResponseNodeInfoMessage) + *message = *msg.(*iotextypes.NodeInfo) hash := hashNodeInfo(message.Info) sig, _ = dm.privKey.Sign(hash[:]) return nil @@ -173,8 +175,8 @@ func TestDelegateManager_HandleNodeInfoRequest(t *testing.T) { err := dm.HandleNodeInfoRequest(context.Background(), peer.AddrInfo{}) require.NoError(err) require.Equal(message.Info.Height, height) - require.Equal(message.Info.Version, dm.myVersion) - require.Equal(message.Info.Address, dm.myAddress) + require.Equal(message.Info.Version, dm.version) + require.Equal(message.Info.Address, dm.address) require.Equal(message.Signature, sig) }) } @@ -189,19 +191,19 @@ func TestDelegateManager_RequestSingleNodeInfoAsync(t *testing.T) { require.NoError(err) t.Run("request_single", func(t *testing.T) { - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey) var paramPeer peer.AddrInfo - var paramMsg iotextypes.RequestNodeInfoMessage + var paramMsg iotextypes.NodeInfoRequest peerID, err := peer.IDFromString("12D3KooWF2fns5ZWKbPfx2U1wQDdxoTK2D6HC3ortbSAQYR4BQp4") require.NoError(err) targetPeer := peer.AddrInfo{ID: peerID} tMock.EXPECT().UnicastOutbound(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(_ context.Context, p peer.AddrInfo, msg proto.Message) { paramPeer = p - paramMsg = *msg.(*iotextypes.RequestNodeInfoMessage) + paramMsg = *msg.(*iotextypes.NodeInfoRequest) }).Times(1) dm.RequestSingleNodeInfoAsync(context.Background(), targetPeer) require.Equal(targetPeer, paramPeer) - require.Equal(iotextypes.RequestNodeInfoMessage{}, paramMsg) + require.Equal(iotextypes.NodeInfoRequest{}, paramMsg) }) } @@ -214,7 +216,7 @@ func TestDelegateManager_GetNodeByAddr(t *testing.T) { privKey, err := crypto.GenerateKey() require.NoError(err) - dm := NewDelegateManager(&DefaultConfig, tMock, hMock, privKey) + dm := NewInfoManager(&DefaultConfig, tMock, hMock, privKey) dm.updateNode(&Info{Address: "1"}) dm.updateNode(&Info{Address: "2"}) diff --git a/test/mock/mock_dispatcher/mock_dispatcher.go b/test/mock/mock_dispatcher/mock_dispatcher.go index db5250dd19..c73a8c84fa 100644 --- a/test/mock/mock_dispatcher/mock_dispatcher.go +++ b/test/mock/mock_dispatcher/mock_dispatcher.go @@ -82,7 +82,7 @@ func (mr *MockSubscriberMockRecorder) HandleConsensusMsg(arg0 interface{}) *gomo } // HandleNodeInfoMsg mocks base method. -func (m *MockSubscriber) HandleNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.ResponseNodeInfoMessage) error { +func (m *MockSubscriber) HandleNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.NodeInfo) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "HandleNodeInfoMsg", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -96,7 +96,7 @@ func (mr *MockSubscriberMockRecorder) HandleNodeInfoMsg(arg0, arg1, arg2 interfa } // HandleRequestNodeInfoMsg mocks base method. -func (m *MockSubscriber) HandleRequestNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.RequestNodeInfoMessage) error { +func (m *MockSubscriber) HandleRequestNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.NodeInfoRequest) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "HandleRequestNodeInfoMsg", arg0, arg1, arg2) ret0, _ := ret[0].(error) From 5b4038e28d653d7eddcf41c6fa9cc2b611497836 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 2 Feb 2023 10:51:51 +0800 Subject: [PATCH 29/32] fix comments --- go.mod | 2 +- go.sum | 2 ++ nodeinfo/config.go | 2 ++ nodeinfo/manager.go | 17 +++++++---------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index db539b7522..fbb4e4fcf1 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/iotexproject/iotex-address v0.2.8 github.com/iotexproject/iotex-antenna-go/v2 v2.5.1 github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d - github.com/iotexproject/iotex-proto v0.5.12 + github.com/iotexproject/iotex-proto v0.5.13 github.com/libp2p/go-libp2p-core v0.8.5 github.com/mattn/go-sqlite3 v1.14.8 // indirect github.com/miguelmota/go-ethereum-hdwallet v0.1.1 diff --git a/go.sum b/go.sum index 4b24432935..24ce3dcc71 100644 --- a/go.sum +++ b/go.sum @@ -506,6 +506,8 @@ github.com/iotexproject/iotex-election v0.3.5-0.20210611041425-20ddf674363d/go.m github.com/iotexproject/iotex-proto v0.5.0/go.mod h1:Xg6REkv+nTZN+OC22xXIQuqKdTWWHwOAJEXCoMpDwtI= github.com/iotexproject/iotex-proto v0.5.12 h1:s65DbejTT/c5dBtlQykyPV4V7L6efDuOOGJiqu57LPw= github.com/iotexproject/iotex-proto v0.5.12/go.mod h1:6Xan740KoIFyw/ZztVpum5jac6Z++o1whMWDIY1SrQk= +github.com/iotexproject/iotex-proto v0.5.13 h1:4NzJWRoeH5z6To/2+t0rTZBzJ4WC+MoLHxAeesiuAnM= +github.com/iotexproject/iotex-proto v0.5.13/go.mod h1:G8u3b4zLUESnfeByVj6oqwnXFXNH4JLOWkwllqx8L80= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= diff --git a/nodeinfo/config.go b/nodeinfo/config.go index b5fdc98095..d05abc88e3 100644 --- a/nodeinfo/config.go +++ b/nodeinfo/config.go @@ -7,6 +7,8 @@ package nodeinfo import "time" +const _nodeMapSize = 1000 + // Config node config type Config struct { EnableBroadcastNodeInfo bool `yaml:"enableBroadcastNodeInfo"` diff --git a/nodeinfo/manager.go b/nodeinfo/manager.go index d88353159b..8df2f03c49 100644 --- a/nodeinfo/manager.go +++ b/nodeinfo/manager.go @@ -59,8 +59,6 @@ type ( } ) -const _nodeMapSizeLimit = 1000 - var _nodeInfoHeightGauge = prometheus.NewGaugeVec( prometheus.GaugeOpts{ Name: "iotex_node_info_height_gauge", @@ -76,7 +74,7 @@ func init() { // NewInfoManager new info manager func NewInfoManager(cfg *Config, t transmitter, h chain, privKey crypto.PrivateKey) *InfoManager { dm := &InfoManager{ - nodeMap: lru.New(_nodeMapSizeLimit), + nodeMap: lru.New(_nodeMapSize), transmitter: t, chain: h, privKey: privKey, @@ -85,14 +83,13 @@ func NewInfoManager(cfg *Config, t transmitter, h chain, privKey crypto.PrivateK } dm.broadcastTask = routine.NewRecurringTask(func() { - // delegates and nodes who are turned on will broadcast - if !cfg.EnableBroadcastNodeInfo && !dm.isDelegate() { + // delegates or nodes who are turned on will broadcast + if cfg.EnableBroadcastNodeInfo || dm.isDelegate() { + if err := dm.BroadcastNodeInfo(context.Background()); err != nil { + log.L().Error("nodeinfo manager broadcast node info failed", zap.Error(err)) + } + } else { log.L().Debug("nodeinfo manager general node disabled node info broadcast") - return - } - - if err := dm.BroadcastNodeInfo(context.Background()); err != nil { - log.L().Error("nodeinfo manager broadcast node info failed", zap.Error(err)) } }, cfg.BroadcastNodeInfoInterval) return dm From fd70cd1d35db183c60664025ec1cfdab92706f55 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 2 Feb 2023 11:42:25 +0800 Subject: [PATCH 30/32] update mock --- go.mod | 2 +- go.sum | 9 ++------ test/mock/mock_dispatcher/mock_dispatcher.go | 24 ++++++++++---------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 7edc58dba8..659a900b4f 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/ethereum/go-ethereum v1.10.21 github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a github.com/go-redis/redis/v8 v8.11.4 - github.com/golang/mock v1.6.0 + github.com/golang/mock v1.5.0 github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.4 github.com/gorilla/websocket v1.4.2 diff --git a/go.sum b/go.sum index df967dcadb..755e909c63 100644 --- a/go.sum +++ b/go.sum @@ -318,8 +318,8 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -1268,7 +1268,6 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.elastic.co/ecszap v1.0.0 h1:PdQkRUeraR3XHJ14T7JMa+ncU0XXrVrcEN/BoRa2nMI= @@ -1440,7 +1439,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1534,12 +1532,10 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1610,7 +1606,6 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190212162355-a5947ffaace3/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/test/mock/mock_dispatcher/mock_dispatcher.go b/test/mock/mock_dispatcher/mock_dispatcher.go index c73a8c84fa..d1377ac3ed 100644 --- a/test/mock/mock_dispatcher/mock_dispatcher.go +++ b/test/mock/mock_dispatcher/mock_dispatcher.go @@ -81,32 +81,32 @@ func (mr *MockSubscriberMockRecorder) HandleConsensusMsg(arg0 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleConsensusMsg", reflect.TypeOf((*MockSubscriber)(nil).HandleConsensusMsg), arg0) } -// HandleNodeInfoMsg mocks base method. -func (m *MockSubscriber) HandleNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.NodeInfo) error { +// HandleNodeInfo mocks base method. +func (m *MockSubscriber) HandleNodeInfo(arg0 context.Context, arg1 string, arg2 *iotextypes.NodeInfo) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HandleNodeInfoMsg", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "HandleNodeInfo", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } -// HandleNodeInfoMsg indicates an expected call of HandleNodeInfoMsg. -func (mr *MockSubscriberMockRecorder) HandleNodeInfoMsg(arg0, arg1, arg2 interface{}) *gomock.Call { +// HandleNodeInfo indicates an expected call of HandleNodeInfo. +func (mr *MockSubscriberMockRecorder) HandleNodeInfo(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleNodeInfoMsg", reflect.TypeOf((*MockSubscriber)(nil).HandleNodeInfoMsg), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleNodeInfo", reflect.TypeOf((*MockSubscriber)(nil).HandleNodeInfo), arg0, arg1, arg2) } -// HandleRequestNodeInfoMsg mocks base method. -func (m *MockSubscriber) HandleRequestNodeInfoMsg(arg0 context.Context, arg1 string, arg2 *iotextypes.NodeInfoRequest) error { +// HandleNodeInfoRequest mocks base method. +func (m *MockSubscriber) HandleNodeInfoRequest(arg0 context.Context, arg1 peer.AddrInfo, arg2 *iotextypes.NodeInfoRequest) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HandleRequestNodeInfoMsg", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "HandleNodeInfoRequest", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } -// HandleRequestNodeInfoMsg indicates an expected call of HandleRequestNodeInfoMsg. -func (mr *MockSubscriberMockRecorder) HandleRequestNodeInfoMsg(arg0, arg1, arg2 interface{}) *gomock.Call { +// HandleNodeInfoRequest indicates an expected call of HandleNodeInfoRequest. +func (mr *MockSubscriberMockRecorder) HandleNodeInfoRequest(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleRequestNodeInfoMsg", reflect.TypeOf((*MockSubscriber)(nil).HandleRequestNodeInfoMsg), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleNodeInfoRequest", reflect.TypeOf((*MockSubscriber)(nil).HandleNodeInfoRequest), arg0, arg1, arg2) } // HandleSyncRequest mocks base method. From 9947145c565ea049ccf1ccd835b56c844738667e Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 6 Feb 2023 11:22:58 +0800 Subject: [PATCH 31/32] move const var _nodeMapSize to config struct --- nodeinfo/config.go | 4 ++-- nodeinfo/manager.go | 2 +- nodeinfo/manager_test.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nodeinfo/config.go b/nodeinfo/config.go index d05abc88e3..d248079a38 100644 --- a/nodeinfo/config.go +++ b/nodeinfo/config.go @@ -7,16 +7,16 @@ package nodeinfo import "time" -const _nodeMapSize = 1000 - // Config node config type Config struct { EnableBroadcastNodeInfo bool `yaml:"enableBroadcastNodeInfo"` BroadcastNodeInfoInterval time.Duration `yaml:"broadcastNodeInfoInterval"` + NodeMapSize int `yaml:"nodeMapSize"` } // DefaultConfig is the default config var DefaultConfig = Config{ EnableBroadcastNodeInfo: false, BroadcastNodeInfoInterval: 5 * time.Minute, + NodeMapSize: 1000, } diff --git a/nodeinfo/manager.go b/nodeinfo/manager.go index 8df2f03c49..9b862ac2be 100644 --- a/nodeinfo/manager.go +++ b/nodeinfo/manager.go @@ -74,7 +74,7 @@ func init() { // NewInfoManager new info manager func NewInfoManager(cfg *Config, t transmitter, h chain, privKey crypto.PrivateKey) *InfoManager { dm := &InfoManager{ - nodeMap: lru.New(_nodeMapSize), + nodeMap: lru.New(cfg.NodeMapSize), transmitter: t, chain: h, privKey: privKey, diff --git a/nodeinfo/manager_test.go b/nodeinfo/manager_test.go index 8d06566ee1..103b15a79e 100644 --- a/nodeinfo/manager_test.go +++ b/nodeinfo/manager_test.go @@ -31,7 +31,7 @@ func TestNewDelegateManager(t *testing.T) { require.NoError(err) t.Run("disable_broadcast", func(t *testing.T) { - cfg := Config{false, 100 * time.Millisecond} + cfg := Config{false, 100 * time.Millisecond, 1000} dm := NewInfoManager(&cfg, tMock, hMock, privK) require.NotNil(dm.nodeMap) require.Equal(tMock, dm.transmitter) @@ -46,7 +46,7 @@ func TestNewDelegateManager(t *testing.T) { }) t.Run("enable_broadcast", func(t *testing.T) { - cfg := Config{true, 100 * time.Millisecond} + cfg := Config{true, 100 * time.Millisecond, 1000} dm := NewInfoManager(&cfg, tMock, hMock, privK) require.NotNil(dm.nodeMap) require.Equal(tMock, dm.transmitter) From 37fdaaa834cf077e2372c78d07a0c2570e1dcb4c Mon Sep 17 00:00:00 2001 From: dustinxie Date: Mon, 6 Feb 2023 09:59:45 -0800 Subject: [PATCH 32/32] Update manager.go --- nodeinfo/manager.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nodeinfo/manager.go b/nodeinfo/manager.go index 9b862ac2be..61cec9b932 100644 --- a/nodeinfo/manager.go +++ b/nodeinfo/manager.go @@ -48,10 +48,9 @@ type ( // InfoManager manage delegate node info InfoManager struct { - nodeMap *lru.Cache - version string - address string - + version string + address string + nodeMap *lru.Cache broadcastTask *routine.RecurringTask transmitter transmitter chain chain