github.com/aergoio/aergo@v1.3.1/polaris/client/polarisconnect.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package client 7 8 import ( 9 "bufio" 10 "errors" 11 "fmt" 12 "github.com/aergoio/aergo/p2p/p2pkey" 13 "github.com/aergoio/aergo/p2p/v030" 14 "github.com/aergoio/aergo/polaris/common" 15 "github.com/libp2p/go-libp2p-core/network" 16 "sync" 17 18 "github.com/aergoio/aergo-actor/actor" 19 "github.com/aergoio/aergo-lib/log" 20 "github.com/aergoio/aergo/config" 21 "github.com/aergoio/aergo/message" 22 "github.com/aergoio/aergo/p2p/p2pcommon" 23 "github.com/aergoio/aergo/p2p/p2putil" 24 "github.com/aergoio/aergo/pkg/component" 25 "github.com/aergoio/aergo/types" 26 ) 27 28 var ErrTooLowVersion = errors.New("aergosvr version is too low") 29 30 // PeerMapService is 31 type PolarisConnectSvc struct { 32 *component.BaseComponent 33 34 PrivateChain bool 35 36 mapServers []p2pcommon.PeerMeta 37 exposeself bool 38 39 ntc p2pcommon.NTContainer 40 nt p2pcommon.NetworkTransport 41 42 rwmutex *sync.RWMutex 43 } 44 45 func NewPolarisConnectSvc(cfg *config.P2PConfig, ntc p2pcommon.NTContainer) *PolarisConnectSvc { 46 pcs := &PolarisConnectSvc{ 47 rwmutex: &sync.RWMutex{}, 48 exposeself: cfg.NPExposeSelf, 49 } 50 pcs.BaseComponent = component.NewBaseComponent(message.MapSvc, pcs, log.NewLogger("pcs")) 51 52 // init 53 pcs.ntc = ntc 54 pcs.initSvc(cfg) 55 // TODO need more pretty way to get chainID 56 57 return pcs 58 } 59 60 func (pcs *PolarisConnectSvc) initSvc(cfg *config.P2PConfig) { 61 pcs.PrivateChain = !pcs.ntc.ChainID().PublicNet 62 if cfg.NPUsePolaris { 63 // private network does not use public polaris 64 if !pcs.PrivateChain { 65 servers := make([]string, 0) 66 // add hardcoded built-in servers if net is ONE net. 67 if *pcs.ntc.ChainID() == common.ONEMainNet { 68 pcs.Logger.Info().Msg("chain is ONE Mainnet so use default polaris for mainnet") 69 servers = common.MainnetMapServer 70 } else if *pcs.ntc.ChainID() == common.ONETestNet { 71 pcs.Logger.Info().Msg("chain is ONE Testnet so use default polaris for testnet") 72 servers = common.TestnetMapServer 73 } else { 74 pcs.Logger.Info().Msg("chain is custom public network so only custom polaris in configuration file will be used") 75 } 76 77 for _, addrStr := range servers { 78 meta, err := p2putil.FromMultiAddrString(addrStr) 79 if err != nil { 80 pcs.Logger.Info().Str("addr_str", addrStr).Msg("invalid polaris server address in base setting ") 81 continue 82 } 83 pcs.mapServers = append(pcs.mapServers, meta) 84 } 85 } else { 86 pcs.Logger.Info().Msg("chain is private so only using polaris in config file") 87 } 88 // append custom polarises set in configuration file 89 for _, addrStr := range cfg.NPAddPolarises { 90 meta, err := p2putil.FromMultiAddrString(addrStr) 91 if err != nil { 92 pcs.Logger.Info().Str("addr_str", addrStr).Msg("invalid polaris server address in config file ") 93 continue 94 } 95 pcs.mapServers = append(pcs.mapServers, meta) 96 } 97 98 if len(pcs.mapServers) == 0 { 99 pcs.Logger.Warn().Msg("using Polaris is enabled but no active polaris server found. node discovery by polaris will not works well") 100 } else { 101 pcs.Logger.Info().Array("polarises", p2putil.NewLogPeerMetasMarshaller(pcs.mapServers, 10)).Msg("using Polaris") 102 } 103 } else { 104 pcs.Logger.Info().Msg("node discovery by Polaris is disabled by configuration.") 105 } 106 } 107 108 func (pcs *PolarisConnectSvc) BeforeStart() {} 109 110 func (pcs *PolarisConnectSvc) AfterStart() { 111 pcs.nt = pcs.ntc.GetNetworkTransport() 112 pcs.nt.AddStreamHandler(common.PolarisPingSub, pcs.onPing) 113 114 } 115 116 func (pcs *PolarisConnectSvc) BeforeStop() { 117 pcs.nt.RemoveStreamHandler(common.PolarisPingSub) 118 } 119 120 func (pcs *PolarisConnectSvc) Statistics() *map[string]interface{} { 121 return nil 122 //dummy := make(map[string]interface{}) 123 //return &dummy 124 } 125 126 func (pcs *PolarisConnectSvc) Receive(context actor.Context) { 127 rawMsg := context.Message() 128 switch msg := rawMsg.(type) { 129 case *message.MapQueryMsg: 130 pcs.Hub().Tell(message.P2PSvc, pcs.queryPeers(msg)) 131 default: 132 // pcs.Logger.Debug().Interface("msg", msg) // TODO: temporal code for resolve compile error 133 } 134 } 135 136 func (pcs *PolarisConnectSvc) queryPeers(msg *message.MapQueryMsg) *message.MapQueryRsp { 137 succ := 0 138 resultPeers := make([]*types.PeerAddress, 0, msg.Count) 139 for _, meta := range pcs.mapServers { 140 addrs, err := pcs.connectAndQuery(meta, msg.BestBlock.Hash, msg.BestBlock.Header.BlockNo) 141 if err != nil { 142 if err == ErrTooLowVersion { 143 pcs.Logger.Error().Err(err).Str("polarisID", p2putil.ShortForm(meta.ID)).Msg("Polaris responded this aergosvr is too low, check and upgrade aergosvr") 144 } else { 145 pcs.Logger.Warn().Err(err).Str("polarisID", p2putil.ShortForm(meta.ID)).Msg("failed to get peer addresses") 146 } 147 continue 148 } 149 // FIXME delete duplicated peers 150 resultPeers = append(resultPeers, addrs...) 151 succ++ 152 } 153 err := error(nil) 154 if succ == 0 { 155 err = fmt.Errorf("all servers of polaris are down") 156 } 157 pcs.Logger.Debug().Int("peer_cnt", len(resultPeers)).Msg("Got map response and send back") 158 resp := &message.MapQueryRsp{Peers: resultPeers, Err: err} 159 return resp 160 } 161 162 func (pcs *PolarisConnectSvc) connectAndQuery(mapServerMeta p2pcommon.PeerMeta, bestHash []byte, bestHeight uint64) ([]*types.PeerAddress, error) { 163 s, err := pcs.nt.GetOrCreateStreamWithTTL(mapServerMeta, common.PolarisConnectionTTL, common.PolarisMapSub) 164 if err != nil { 165 return nil, err 166 } 167 defer s.Close() 168 169 peerID := s.Conn().RemotePeer() 170 if peerID != mapServerMeta.ID { 171 return nil, fmt.Errorf("internal error peerid mismatch, exp %s, actual %s", mapServerMeta.ID.Pretty(), peerID.Pretty()) 172 } 173 pcs.Logger.Debug().Str("polarisID", peerID.String()).Msg("Sending map query") 174 175 rw := v030.NewV030ReadWriter(bufio.NewReader(s), bufio.NewWriter(s), nil) 176 177 peerAddress := pcs.ntc.SelfMeta().ToPeerAddress() 178 chainBytes, _ := pcs.ntc.ChainID().Bytes() 179 peerStatus := &types.Status{Sender: &peerAddress, BestBlockHash: bestHash, BestHeight: bestHeight, ChainID: chainBytes, 180 Version: p2pkey.NodeVersion()} 181 182 return pcs.queryToPolaris(mapServerMeta, rw, peerStatus) 183 } 184 185 func (pcs *PolarisConnectSvc) queryToPolaris(mapServerMeta p2pcommon.PeerMeta, rw p2pcommon.MsgReadWriter, peerStatus *types.Status) ([]*types.PeerAddress, error) { 186 // receive input 187 err := pcs.sendRequest(peerStatus, mapServerMeta, pcs.exposeself, 100, rw) 188 if err != nil { 189 return nil, err 190 } 191 _, resp, err := pcs.readResponse(mapServerMeta, rw) 192 if err != nil { 193 return nil, err 194 } 195 switch resp.Status { 196 case types.ResultStatus_OK: 197 return resp.Addresses, nil 198 case types.ResultStatus_FAILED_PRECONDITION: 199 if resp.Message == common.TooOldVersionMsg { 200 return nil, ErrTooLowVersion 201 } else { 202 return nil, fmt.Errorf("remote error %s", resp.Status.String()) 203 } 204 default: 205 return nil, fmt.Errorf("remote error %s", resp.Status.String()) 206 } 207 } 208 209 func (pcs *PolarisConnectSvc) sendRequest(status *types.Status, mapServerMeta p2pcommon.PeerMeta, register bool, size int, wt p2pcommon.MsgReadWriter) error { 210 msgID := p2pcommon.NewMsgID() 211 queryReq := &types.MapQuery{Status: status, Size: int32(size), AddMe: register, Excludes: [][]byte{[]byte(mapServerMeta.ID)}} 212 bytes, err := p2putil.MarshalMessageBody(queryReq) 213 if err != nil { 214 return err 215 } 216 reqMsg := common.NewPolarisMessage(msgID, common.MapQuery, bytes) 217 218 return wt.WriteMsg(reqMsg) 219 } 220 221 // tryAddPeer will do check connecting peer and add. it will return peer meta information received from 222 // remote peer setup some 223 func (pcs *PolarisConnectSvc) readResponse(mapServerMeta p2pcommon.PeerMeta, rd p2pcommon.MsgReadWriter) (p2pcommon.Message, *types.MapResponse, error) { 224 data, err := rd.ReadMsg() 225 if err != nil { 226 return nil, nil, err 227 } 228 queryResp := &types.MapResponse{} 229 err = p2putil.UnmarshalMessageBody(data.Payload(), queryResp) 230 if err != nil { 231 return data, nil, err 232 } 233 pcs.Logger.Debug().Str(p2putil.LogPeerID, mapServerMeta.ID.String()).Int("peer_cnt", len(queryResp.Addresses)).Msg("Received map query response") 234 235 return data, queryResp, nil 236 } 237 238 func (pcs *PolarisConnectSvc) onPing(s network.Stream) { 239 peerID := s.Conn().RemotePeer() 240 pcs.Logger.Debug().Str("polarisID", peerID.String()).Msg("Received ping from polaris (maybe)") 241 242 rw := v030.NewV030ReadWriter(bufio.NewReader(s), bufio.NewWriter(s), nil) 243 defer s.Close() 244 245 req, err := rw.ReadMsg() 246 if err != nil { 247 return 248 } 249 pingReq := &types.Ping{} 250 err = p2putil.UnmarshalMessageBody(req.Payload(), pingReq) 251 if err != nil { 252 return 253 } 254 // TODO: check if sender is known polaris or peer and it not, ban or write to blacklist . 255 pingResp := &types.Ping{} 256 bytes, err := p2putil.MarshalMessageBody(pingResp) 257 if err != nil { 258 return 259 } 260 msgID := p2pcommon.NewMsgID() 261 respMsg := common.NewPolarisRespMessage(msgID, req.ID(), p2pcommon.PingResponse, bytes) 262 err = rw.WriteMsg(respMsg) 263 if err != nil { 264 return 265 } 266 }