github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/_deprecated_chains/irisnet/handlerIrisnet.go (about) 1 package irisnet 2 3 import ( 4 "bufio" 5 // "bytes" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "os" 11 "reflect" 12 "runtime" 13 "strconv" 14 "time" 15 "encoding/hex" 16 "encoding/json" 17 b64 "encoding/base64" 18 "net/http" 19 "io/ioutil" 20 21 log "github.com/sirupsen/logrus" 22 "github.com/hashicorp/golang-lru" 23 "github.com/supragya/TendermintConnector/chains" 24 "github.com/supragya/TendermintConnector/chains/irisnet/conn" 25 cmn "github.com/supragya/TendermintConnector/chains/irisnet/libs/common" 26 flow "github.com/supragya/TendermintConnector/chains/irisnet/libs/flowrate" 27 marlinTypes "github.com/supragya/TendermintConnector/types" 28 amino "github.com/tendermint/go-amino" 29 "github.com/tendermint/tendermint/crypto/ed25519" 30 31 // Protocols 32 "github.com/supragya/TendermintConnector/marlin" 33 ) 34 35 // ServicedTMCore is a string associated with each TM core handler 36 // to decipher which handler is to be attached. 37 var ServicedTMCore chains.NodeType = chains.NodeType{Version: "0.32.2", Network: "irishub", ProtocolVersionApp: "2", ProtocolVersionBlock: "9", ProtocolVersionP2p: "5"} 38 39 // ---------------------- DATA CONNECT INTERFACE -------------------------------- 40 41 func RunDataConnect(peerAddr string, 42 marlinTo chan marlinTypes.MarlinMessage, 43 marlinFrom chan marlinTypes.MarlinMessage, 44 isConnectionOutgoing bool, 45 keyFile string, 46 listenPort int) { 47 log.Info("Starting Irisnet Tendermint Core Handler - 0.16.3-d83fc038-2-mainnet") 48 49 if keyFile != "" { 50 isKeyFileUsed = true 51 keyFileLocation = keyFile 52 } 53 54 for { 55 handler, err := createTMHandler(peerAddr, "0.0.0.0:0", marlinTo, marlinFrom, isConnectionOutgoing, listenPort, true) 56 57 if err != nil { 58 log.Error("Error encountered while creating TM Handler: ", err) 59 os.Exit(1) 60 } 61 62 if isConnectionOutgoing { 63 err = handler.dialPeer() 64 } else { 65 err = handler.acceptPeer() 66 } 67 if err != nil { 68 log.Error("Base Connection establishment with peer unsuccessful: ", err) 69 goto REATTEMPT_CONNECTION 70 } 71 72 err = handler.upgradeConnectionAndHandshake() 73 if err != nil { 74 log.Error("Error while upgrading connection and handshaking with peer: ", err) 75 goto REATTEMPT_CONNECTION 76 } 77 78 handler.beginServicing() 79 80 select { 81 case <-handler.signalConnError: 82 handler.signalShutSend <- struct{}{} 83 handler.signalShutRecv <- struct{}{} 84 handler.signalShutThroughput <- struct{}{} 85 goto REATTEMPT_CONNECTION 86 } 87 88 REATTEMPT_CONNECTION: 89 handler.baseConnection.Close() 90 handler.secretConnection.Close() 91 log.Info("Error encountered with connection to the peer. Attempting reconnect post 1 second.") 92 time.Sleep(1 * time.Second) 93 } 94 } 95 96 func (h *TendermintHandler) dialPeer() error { 97 var err error 98 h.baseConnection, err = net.DialTimeout("tcp", h.peerAddr, 2000*time.Millisecond) 99 if err != nil { 100 return err 101 } 102 103 return nil 104 } 105 106 func (h *TendermintHandler) acceptPeer() error { 107 log.Info("TMCore side listening for dials to ", 108 string(hex.EncodeToString(h.privateKey.PubKey().Address())), "@<SYSTEM-IP-ADDR>:", h.listenPort) 109 110 listener, err := net.Listen("tcp", "0.0.0.0:"+strconv.Itoa(h.listenPort)) 111 if err != nil { 112 return err 113 } 114 115 h.baseConnection, err = listener.Accept() 116 if err != nil { 117 return err 118 } 119 120 return nil 121 } 122 123 func (h *TendermintHandler) upgradeConnectionAndHandshake() error { 124 var err error 125 h.secretConnection, err = conn.MakeSecretConnection(h.baseConnection, h.privateKey) 126 if err != nil { 127 return err 128 } 129 130 err = h.handshake() 131 if err != nil { 132 return err 133 } 134 135 log.Info("Established connection with TM peer [" + 136 string(hex.EncodeToString(h.secretConnection.RemotePubKey().Address())) + 137 "] a.k.a. " + h.peerNodeInfo.Moniker) 138 return nil 139 } 140 141 func (h *TendermintHandler) handshake() error { 142 var ( 143 errc = make(chan error, 2) 144 ourNodeInfo DefaultNodeInfo = DefaultNodeInfo{ 145 ProtocolVersion{App: 2, Block: 9, P2P: 5}, 146 string(hex.EncodeToString(h.privateKey.PubKey().Address())), 147 "tcp://127.0.0.1:20006", //TODO Correct this - v0.2 prerelease 148 "irishub", 149 "0.32.2", 150 []byte{channelBc, channelCsSt, channelCsDc, channelCsVo, 151 channelCsVs, channelMm, channelEv}, 152 "marlin-tendermint-connector", 153 DefaultNodeInfoOther{"on", "tcp://0.0.0.0:26667"}, // TODO: Correct this - v0.2 prerelease 154 } 155 ) 156 157 go func(errc chan<- error, c net.Conn) { 158 _, err := h.codec.MarshalBinaryLengthPrefixedWriter(c, ourNodeInfo) 159 if err != nil { 160 log.Error("Error encountered while sending handshake message") 161 } 162 errc <- err 163 }(errc, h.secretConnection) 164 go func(errc chan<- error, c net.Conn) { 165 _, err := h.codec.UnmarshalBinaryLengthPrefixedReader( 166 c, 167 &h.peerNodeInfo, 168 int64(10240), // 10KB MaxNodeInfoSize() 169 ) 170 if err != nil { 171 log.Error("Error encountered while recieving handshake message") 172 } 173 errc <- err 174 }(errc, h.secretConnection) 175 176 for i := 0; i < cap(errc); i++ { 177 err := <-errc 178 if err != nil { 179 log.Error("Encountered error in handshake with TM core: ", err) 180 return err 181 } 182 } 183 return nil 184 } 185 186 func (h *TendermintHandler) beginServicing() error { 187 // Register Messages 188 RegisterPacket(h.codec) 189 RegisterConsensusMessages(h.codec) 190 191 // Create a P2P Connection 192 h.p2pConnection = P2PConnection{ 193 conn: h.secretConnection, 194 bufConnReader: bufio.NewReaderSize(h.secretConnection, 65535), 195 bufConnWriter: bufio.NewWriterSize(h.secretConnection, 65535), 196 sendMonitor: flow.New(0, 0), 197 recvMonitor: flow.New(0, 0), 198 send: make(chan struct{}, 1), 199 pong: make(chan struct{}, 1), 200 doneSendRoutine: make(chan struct{}, 1), 201 quitSendRoutine: make(chan struct{}, 1), 202 quitRecvRoutine: make(chan struct{}, 1), 203 flushTimer: cmn.NewThrottleTimer("flush", 100*time.Millisecond), 204 pingTimer: time.NewTicker(30 * time.Second), 205 pongTimeoutCh: make(chan bool, 1), 206 } 207 208 // Start P2P Send and recieve routines + Status messages for message throughput 209 go h.sendRoutine() 210 go h.recvRoutine() 211 go h.throughput.presentThroughput(5, h.signalShutThroughput) 212 213 // Allow Irisnet messages from marlin Relay 214 marlin.AllowServicedChainMessages(h.servicedChainId) 215 return nil 216 } 217 218 func (h *TendermintHandler) sendRoutine() { 219 log.Info("TMCore <- Connector Routine Started") 220 221 for { 222 SELECTION: 223 select { 224 case <-h.p2pConnection.pingTimer.C: // Send PING messages to TMCore 225 _n, err := h.codec.MarshalBinaryLengthPrefixedWriter(h.p2pConnection.bufConnWriter, PacketPing{}) 226 if err != nil { 227 break SELECTION 228 } 229 h.p2pConnection.sendMonitor.Update(int(_n)) 230 h.p2pConnection.pongTimer = time.AfterFunc(60*time.Second, func() { 231 select { 232 case h.p2pConnection.pongTimeoutCh <- true: 233 default: 234 } 235 }) 236 237 err = h.p2pConnection.bufConnWriter.Flush() 238 if err != nil { 239 log.Error("Cannot flush buffer PingTimer: ", err) 240 h.signalConnError <- struct{}{} 241 } 242 243 case <-h.p2pConnection.pong: // Send PONG messages to TMCore 244 _n, err := h.codec.MarshalBinaryLengthPrefixedWriter(h.p2pConnection.bufConnWriter, PacketPong{}) 245 if err != nil { 246 log.Error("Cannot send Pong message: ", err) 247 break SELECTION 248 } 249 h.p2pConnection.sendMonitor.Update(int(_n)) 250 err = h.p2pConnection.bufConnWriter.Flush() 251 if err != nil { 252 log.Error("Cannot flush buffer: ", err) 253 h.signalConnError <- struct{}{} 254 } 255 256 case timeout := <-h.p2pConnection.pongTimeoutCh: // Check if PONG messages are received in time 257 if timeout { 258 log.Error("Pong timeout, TM Core did not reply in time!") 259 h.p2pConnection.stopPongTimer() 260 h.signalConnError <- struct{}{} 261 } else { 262 h.p2pConnection.stopPongTimer() 263 } 264 265 case <-h.signalShutSend: // Signal to Shut down sendRoutine 266 log.Info("node <- Connector Routine shutdown") 267 h.p2pConnection.stopPongTimer() 268 close(h.p2pConnection.doneSendRoutine) 269 return 270 271 case marlinMsg := <-h.marlinFrom: // Actual message packets from Marlin Relay (encoded in Marlin Tendermint Data Transfer Protocol v1) 272 switch marlinMsg.Channel { 273 case channelCsSt: 274 msg, err:= h.decodeConsensusMsgFromChannelBuffer(marlinMsg.Packets) 275 if err != nil { 276 log.Debug("Cannot decode message recieved from marlin to a valid Consensus Message: ", err) 277 } else { 278 switch msg.(type) { 279 case *NewRoundStepMessage: 280 for _, pkt := range marlinMsg.Packets { 281 _n, err := h.codec.MarshalBinaryLengthPrefixedWriter( 282 h.p2pConnection.bufConnWriter, 283 PacketMsg{ 284 ChannelID: byte(pkt.ChannelID), 285 EOF: byte(pkt.EOF), 286 Bytes: pkt.Bytes, 287 }) 288 if err != nil { 289 log.Error("Error occurred in sending data to TMCore: ", err) 290 h.signalConnError <- struct{}{} 291 } 292 h.p2pConnection.sendMonitor.Update(int(_n)) 293 err = h.p2pConnection.bufConnWriter.Flush() 294 if err != nil { 295 log.Error("Cannot flush buffer: ", err) 296 h.signalConnError <- struct{}{} 297 } 298 } 299 h.throughput.putInfo("to", "+CsStNRS", uint32(len(marlinMsg.Packets))) 300 default: 301 h.throughput.putInfo("to", "-CsStUNK", uint32(len(marlinMsg.Packets))) 302 } 303 } 304 case channelCsVo: 305 msg, err:= h.decodeConsensusMsgFromChannelBuffer(marlinMsg.Packets) 306 if err != nil { 307 log.Debug("Cannot decode message recieved from marlin to a valid Consensus Message: ", err) 308 } else { 309 switch msg.(type) { 310 case *VoteMessage: 311 for _, pkt := range marlinMsg.Packets { 312 _n, err := h.codec.MarshalBinaryLengthPrefixedWriter( 313 h.p2pConnection.bufConnWriter, 314 PacketMsg{ 315 ChannelID: byte(pkt.ChannelID), 316 EOF: byte(pkt.EOF), 317 Bytes: pkt.Bytes, 318 }) 319 if err != nil { 320 log.Error("Error occurred in sending data to TMCore: ", err) 321 h.signalConnError <- struct{}{} 322 } 323 h.p2pConnection.sendMonitor.Update(int(_n)) 324 err = h.p2pConnection.bufConnWriter.Flush() 325 if err != nil { 326 log.Error("Cannot flush buffer: ", err) 327 h.signalConnError <- struct{}{} 328 } 329 } 330 h.throughput.putInfo("to", "+CsVoVOT", uint32(len(marlinMsg.Packets))) 331 default: 332 h.throughput.putInfo("to", "-CsVoUNK", uint32(len(marlinMsg.Packets))) 333 } 334 } 335 case channelCsDc: 336 msg, err:= h.decodeConsensusMsgFromChannelBuffer(marlinMsg.Packets) 337 if err != nil { 338 log.Debug("Cannot decode message recieved from marlin to a valid Consensus Message: ", err) 339 } else { 340 switch msg.(type) { 341 case *ProposalMessage: 342 for _, pkt := range marlinMsg.Packets { 343 _n, err := h.codec.MarshalBinaryLengthPrefixedWriter( 344 h.p2pConnection.bufConnWriter, 345 PacketMsg{ 346 ChannelID: byte(pkt.ChannelID), 347 EOF: byte(pkt.EOF), 348 Bytes: pkt.Bytes, 349 }) 350 if err != nil { 351 log.Error("Error occurred in sending data to TMCore: ", err) 352 h.signalConnError <- struct{}{} 353 } 354 h.p2pConnection.sendMonitor.Update(int(_n)) 355 err = h.p2pConnection.bufConnWriter.Flush() 356 if err != nil { 357 log.Error("Cannot flush buffer: ", err) 358 h.signalConnError <- struct{}{} 359 } 360 } 361 h.throughput.putInfo("to", "+CsDcPRP", uint32(len(marlinMsg.Packets))) 362 case *ProposalPOLMessage: 363 // Not serviced 364 case *BlockPartMessage: 365 for _, pkt := range marlinMsg.Packets { 366 _n, err := h.codec.MarshalBinaryLengthPrefixedWriter( 367 h.p2pConnection.bufConnWriter, 368 PacketMsg{ 369 ChannelID: byte(pkt.ChannelID), 370 EOF: byte(pkt.EOF), 371 Bytes: pkt.Bytes, 372 }) 373 if err != nil { 374 log.Error("Error occurred in sending data to TMCore: ", err) 375 h.signalConnError <- struct{}{} 376 } 377 h.p2pConnection.sendMonitor.Update(int(_n)) 378 err = h.p2pConnection.bufConnWriter.Flush() 379 if err != nil { 380 log.Error("Cannot flush buffer: ", err) 381 h.signalConnError <- struct{}{} 382 } 383 } 384 h.throughput.putInfo("to", "+CsDcBPM", uint32(len(marlinMsg.Packets))) 385 default: 386 h.throughput.putInfo("to", "-CsDcUNK", uint32(len(marlinMsg.Packets))) 387 } 388 } 389 default: 390 h.throughput.putInfo("to", "-UnkUNK", uint32(len(marlinMsg.Packets))) 391 log.Debug("TMCore <- connector Not servicing undecipherable channel ", marlinMsg.Channel) 392 } 393 } 394 } 395 } 396 397 func (h *TendermintHandler) recvRoutine() { 398 log.Info("TMCore -> Connector Routine Started") 399 400 FOR_LOOP: 401 for { 402 select { 403 case <-h.signalShutRecv: 404 log.Info("TMCore -> Connector Routine shutdown") 405 break FOR_LOOP 406 default: 407 } 408 h.p2pConnection.recvMonitor.Limit(20000, 5120000, true) 409 410 /* 411 Peek into bufConnReader for debugging 412 413 if numBytes := c.bufConnReader.Buffered(); numBytes > 0 { 414 bz, err := c.bufConnReader.Peek(cmn.MinInt(numBytes, 100)) 415 if err == nil { 416 // return 417 } else { 418 log.Debug("Error peeking connection buffer ", "err ", err) 419 // return nil 420 } 421 log.Info("Peek connection buffer ", "numBytes ", numBytes, " bz ", bz) 422 } 423 */ 424 425 // Read packet type 426 var packet Packet 427 _n, err := h.codec.UnmarshalBinaryLengthPrefixedReader( 428 h.p2pConnection.bufConnReader, 429 &packet, 430 int64(20000)) 431 432 h.p2pConnection.recvMonitor.Update(int(_n)) 433 434 // Unmarshalling test 435 if err != nil { 436 if err == io.EOF { 437 log.Error("TMCore -> Connector Connection is closed (likely by the other side)") 438 } else { 439 log.Error("TMCore -> Connector Connection failed (reading byte): ", err) 440 } 441 h.signalConnError <- struct{}{} 442 break FOR_LOOP 443 } 444 445 // Read more depending on packet type. 446 switch pkt := packet.(type) { 447 case PacketPing: // Received PING messages from TMCore 448 select { 449 case h.p2pConnection.pong <- PacketPong{}: 450 default: 451 } 452 453 case PacketPong: // Received PONG messages from TMCore 454 select { 455 case h.p2pConnection.pongTimeoutCh <- false: 456 default: 457 } 458 459 case PacketMsg: // Actual message packets from TMCore 460 switch pkt.ChannelID { 461 case channelBc: 462 h.throughput.putInfo("from", "=BcMSG", 1) 463 log.Debug("TMCore -> Connector Blockhain is not serviced") 464 case channelCsSt: 465 h.channelBuffer[channelCsSt] = append(h.channelBuffer[channelCsSt], 466 marlinTypes.PacketMsg{ 467 ChannelID: uint32(pkt.ChannelID), 468 EOF: uint32(pkt.EOF), 469 Bytes: pkt.Bytes, 470 }) 471 472 if pkt.EOF == byte(0x01) { 473 msg, err := h.decodeConsensusMsgFromChannelBuffer(h.channelBuffer[channelCsSt]) 474 if err != nil { 475 log.Error("Cannot decode message recieved from TMCore to a valid Consensus Message: ", err) 476 } else { 477 message := marlinTypes.MarlinMessage{ 478 ChainID: h.servicedChainId, 479 Channel: channelCsSt, 480 Packets: h.channelBuffer[channelCsSt], 481 } 482 483 switch msg.(type) { 484 // Only NRS is sent forward 485 case *NewRoundStepMessage: 486 select { 487 case h.marlinTo <- message: 488 default: 489 log.Warning("Too many messages in channel marlinTo. Dropping oldest messages") 490 _ = <-h.marlinTo 491 h.marlinTo <- message 492 } 493 select { 494 case h.marlinFrom <- message: 495 default: 496 log.Warning("Too many messages in channel marlinFrom. Dropping oldest messages") 497 _ = <-h.marlinFrom 498 h.marlinFrom <- message 499 } 500 h.throughput.putInfo("from", "+CsStNRS", uint32(len(h.channelBuffer[channelCsSt]))) 501 case *NewValidBlockMessage: 502 // h.throughput.putInfo("from", "=CsStNVB", uint32(len(h.channelBuffer[channelCsSt]))) 503 case *HasVoteMessage: 504 // h.throughput.putInfo("from", "=CsStHVM", uint32(len(h.channelBuffer[channelCsSt]))) 505 case *VoteSetMaj23Message: 506 // h.throughput.putInfo("from", "=CsStM23", uint32(len(h.channelBuffer[channelCsSt]))) 507 default: 508 h.throughput.putInfo("from", "-CsStUNK", uint32(len(h.channelBuffer[channelCsSt]))) 509 } 510 } 511 h.channelBuffer[channelCsSt] = h.channelBuffer[channelCsSt][:0] 512 } 513 case channelCsDc: 514 h.channelBuffer[channelCsDc] = append(h.channelBuffer[channelCsDc], 515 marlinTypes.PacketMsg{ 516 ChannelID: uint32(pkt.ChannelID), 517 EOF: uint32(pkt.EOF), 518 Bytes: pkt.Bytes, 519 }) 520 if pkt.EOF == byte(0x01) { 521 msg, err := h.decodeConsensusMsgFromChannelBuffer(h.channelBuffer[channelCsDc]) 522 if err != nil { 523 log.Error("Cannot decode message recieved from TMCore to a valid Consensus Message: ", err) 524 } else { 525 message := marlinTypes.MarlinMessage{ 526 ChainID: h.servicedChainId, 527 Channel: channelCsDc, 528 Packets: h.channelBuffer[channelCsDc], 529 } 530 531 switch msg.(type) { 532 case *ProposalMessage: 533 select { 534 case h.marlinTo <- message: 535 default: 536 log.Warning("Too many messages in channel marlinTo. Dropping oldest messages") 537 _ = <-h.marlinTo 538 h.marlinTo <- message 539 } 540 h.throughput.putInfo("from", "+CsDcPRP", uint32(len(h.channelBuffer[channelCsDc]))) 541 case *ProposalPOLMessage: 542 // Not serviced 543 case *BlockPartMessage: 544 select { 545 case h.marlinTo <- message: 546 default: 547 log.Warning("Too many messages in channel marlinTo. Dropping oldest messages") 548 _ = <-h.marlinTo 549 h.marlinTo <- message 550 } 551 h.throughput.putInfo("from", "+CsDcBPM", uint32(len(h.channelBuffer[channelCsDc]))) 552 default: 553 h.throughput.putInfo("from", "-CsDcMSG", uint32(len(h.channelBuffer[channelCsDc]))) 554 } 555 } 556 h.channelBuffer[channelCsDc] = h.channelBuffer[channelCsDc][:0] 557 558 } 559 case channelCsVo: 560 h.channelBuffer[channelCsVo] = append(h.channelBuffer[channelCsVo], 561 marlinTypes.PacketMsg{ 562 ChannelID: uint32(pkt.ChannelID), 563 EOF: uint32(pkt.EOF), 564 Bytes: pkt.Bytes, 565 }) 566 if pkt.EOF == byte(0x01) { 567 msg, err := h.decodeConsensusMsgFromChannelBuffer(h.channelBuffer[channelCsVo]) 568 if err != nil { 569 log.Error("Cannot decode message recieved from TMCore to a valid Consensus Message: ", err) 570 } else { 571 message := marlinTypes.MarlinMessage{ 572 ChainID: h.servicedChainId, 573 Channel: channelCsVo, 574 Packets: h.channelBuffer[channelCsVo], 575 } 576 577 switch msg.(type) { 578 case *VoteMessage: 579 select { 580 case h.marlinTo <- message: 581 default: 582 log.Warning("Too many messages in channel marlinTo. Dropping oldest messages") 583 _ = <-h.marlinTo 584 h.marlinTo <- message 585 } 586 h.throughput.putInfo("from", "+CsVoVOT", uint32(len(h.channelBuffer[channelCsVo]))) 587 default: 588 h.throughput.putInfo("from", "-CsVoVOT", uint32(len(h.channelBuffer[channelCsVo]))) 589 } 590 } 591 h.channelBuffer[channelCsVo] = h.channelBuffer[channelCsVo][:0] 592 } 593 case channelCsVs: 594 h.throughput.putInfo("from", "=CsVsVSB", 1) 595 log.Debug("TMCore -> Connector Consensensus Vote Set Bits Channel is not serviced") 596 case channelMm: 597 h.throughput.putInfo("from", "=MmMSG", 1) 598 log.Debug("TMCore -> Connector Mempool Channel is not serviced") 599 case channelEv: 600 h.throughput.putInfo("from", "=EvMSG", 1) 601 log.Debug("TMCore -> Connector Evidence Channel is not serviced") 602 default: 603 h.throughput.putInfo("from", "=UnkUNK", 1) 604 log.Warning("TMCore -> Connector Unknown ChannelID Message recieved: ", pkt.ChannelID) 605 } 606 607 default: 608 log.Error("TMCore -> Connector Unknown message type ", reflect.TypeOf(packet)) 609 log.Error("TMCore -> Connector Connection failed: ", err) 610 h.signalConnError <- struct{}{} 611 break FOR_LOOP 612 } 613 } 614 615 // Cleanup 616 close(h.p2pConnection.pong) 617 for range h.p2pConnection.pong { 618 // Drain 619 } 620 } 621 622 func (h *TendermintHandler) decodeConsensusMsgFromChannelBuffer(chanbuf []marlinTypes.PacketMsg) (ConsensusMessage, error) { 623 var databuf []byte 624 var msg ConsensusMessage 625 var err error 626 for _, pkt := range chanbuf { 627 databuf = append(databuf, pkt.Bytes...) 628 } 629 if len(databuf) > 1048576 { 630 return msg, errors.New("Message is larger than 1MB. Cannot decode") 631 } 632 err = h.codec.UnmarshalBinaryBare(databuf, &msg) 633 return msg, err 634 } 635 636 func (c *P2PConnection) stopPongTimer() { 637 if c.pongTimer != nil { 638 _ = c.pongTimer.Stop() 639 c.pongTimer = nil 640 } 641 } 642 643 // ---------------------- SPAM FILTER INTERFACE -------------------------------- 644 645 // RunSpamFilter serves as the entry point for a TM Core handler when serving as a spamfilter 646 func RunSpamFilter(rpcAddr string, 647 marlinTo chan marlinTypes.MarlinMessage, 648 marlinFrom chan marlinTypes.MarlinMessage) { 649 log.Info("Starting Irisnet Tendermint SpamFilter - 0.16.3-d83fc038-2-mainnet") 650 651 handler, err := createTMHandler("0.0.0.0:0", rpcAddr, marlinTo, marlinFrom, false, 0, false) 652 if err != nil { 653 log.Error("Error encountered while creating TM Handler: ", err) 654 os.Exit(1) 655 } 656 657 marlin.AllowServicedChainMessages(handler.servicedChainId) 658 659 RegisterPacket(handler.codec) 660 RegisterConsensusMessages(handler.codec) 661 662 coreCount := runtime.NumCPU() 663 multiple := 2 664 log.Info("Runtime found number of CPUs on machine to be ", coreCount, ". Hence, running ", multiple*coreCount, " spamfilter handlers.") 665 666 for i := 0; i < multiple*coreCount; i++ { 667 go handler.beginServicingSpamFilter(i) 668 } 669 670 handler.throughput.presentThroughput(5, handler.signalShutThroughput) 671 } 672 673 func (h *TendermintHandler) beginServicingSpamFilter(id int) { 674 log.Info("Running TM side spam filter handler ", id) 675 // Register Messages 676 677 // TODO - SpamFilter never has to consult RPC server currently - since only CsSt+ is supported, write for that. v0.2 prerelease 678 679 for marlinMsg := range h.marlinFrom { 680 switch marlinMsg.Channel { 681 case channelBc: 682 h.throughput.putInfo("spam", "-CsBc", 1) 683 log.Debug("TMCore <-> Marlin Blockhain is not serviced") 684 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 685 case channelCsSt: 686 msg, err := h.decodeConsensusMsgFromChannelBuffer(marlinMsg.Packets) 687 if err != nil { 688 h.throughput.putInfo("spam", "-CsStUNK", uint32(len(marlinMsg.Packets))) 689 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 690 } else { 691 switch msg.(type) { 692 case *NewRoundStepMessage: 693 h.throughput.putInfo("spam", "+CsStNRS", uint32(len(marlinMsg.Packets))) 694 h.marlinTo <- h.spamVerdictMessage(marlinMsg, true) 695 default: 696 h.throughput.putInfo("spam", "-CsStUNK", uint32(len(marlinMsg.Packets))) 697 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 698 } 699 } 700 case channelCsVo: 701 msg, err := h.decodeConsensusMsgFromChannelBuffer(marlinMsg.Packets) 702 if err != nil { 703 h.throughput.putInfo("spam", "-CsVoUNK", uint32(len(marlinMsg.Packets))) 704 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 705 } else { 706 switch msg.(type) { 707 case *VoteMessage: 708 if h.thoroughMessageCheck(msg) { 709 h.marlinTo <- h.spamVerdictMessage(marlinMsg, true) 710 h.throughput.putInfo("spam", "+CsVoVOT", uint32(len(marlinMsg.Packets))) 711 } else { 712 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 713 h.throughput.putInfo("spam", "-CsVoVOT", uint32(len(marlinMsg.Packets))) 714 } 715 default: 716 h.throughput.putInfo("spam", "-CsVoUNK", uint32(len(marlinMsg.Packets))) 717 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 718 } 719 } 720 case channelCsDc: 721 msg, err := h.decodeConsensusMsgFromChannelBuffer(marlinMsg.Packets) 722 if err != nil { 723 h.throughput.putInfo("spam", "-CsDcUNK", uint32(len(marlinMsg.Packets))) 724 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 725 } else { 726 switch msg.(type) { 727 case *ProposalMessage: 728 if h.thoroughMessageCheck(msg) { 729 h.marlinTo <- h.spamVerdictMessage(marlinMsg, true) 730 h.throughput.putInfo("spam", "+CsDcPRO", uint32(len(marlinMsg.Packets))) 731 } else { 732 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 733 h.throughput.putInfo("spam", "-CsDcPRO", uint32(len(marlinMsg.Packets))) 734 } 735 case *BlockPartMessage: 736 if h.thoroughMessageCheck(msg) { 737 h.marlinTo <- h.spamVerdictMessage(marlinMsg, true) 738 h.throughput.putInfo("spam", "+CsDcBPM", uint32(len(marlinMsg.Packets))) 739 } else { 740 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 741 h.throughput.putInfo("spam", "-CsDcBPM", uint32(len(marlinMsg.Packets))) 742 } 743 default: 744 h.throughput.putInfo("spam", "-CsVoUNK", uint32(len(marlinMsg.Packets))) 745 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 746 } 747 } 748 case channelCsVs: 749 h.throughput.putInfo("spam", "-CsVs", 1) 750 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 751 log.Debug("TMCore <-> Marlin Consensensus Vote Set Bits Channel is not serviced") 752 case channelMm: 753 h.throughput.putInfo("spam", "-CsMm", 1) 754 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 755 log.Debug("TMCore <-> Marlin Mempool Channel is not serviced") 756 case channelEv: 757 h.throughput.putInfo("spam", "-CsEv", 1) 758 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 759 log.Debug("TMCore <-> MarlinEvidence Channel is not serviced") 760 default: 761 h.throughput.putInfo("spam", "-UnkUNK", 1) 762 h.marlinTo <- h.spamVerdictMessage(marlinMsg, false) 763 } 764 } 765 } 766 767 func (h *TendermintHandler) thoroughMessageCheck(msg ConsensusMessage) bool { 768 switch msg.(type) { 769 case *VoteMessage: 770 if validator, ok := h.getValidators(msg.(*VoteMessage).Vote.Height); ok { 771 vidx := msg.(*VoteMessage).Vote.ValidatorIndex 772 vaddr := msg.(*VoteMessage).Vote.ValidatorAddress.String() 773 if vidx >= len(validator) || vaddr != validator[vidx].Address || 774 !validator[vidx].PublicKey.VerifyBytes(msg.(*VoteMessage).Vote.SignBytes("irishub", h.codec), msg.(*VoteMessage).Vote.Signature) { 775 return false 776 } 777 return true 778 } 779 return false 780 case *BlockPartMessage: 781 // Cache hash verification, needs Proposal message support 782 return false 783 case *ProposalMessage: 784 // if _, ok := h.getValidators(msg.(*ProposalMessage).Proposal.Height); ok { 785 // // Check signature, add to map so that BPM messages can be verified 786 // return true 787 // } 788 return false 789 default: 790 return false 791 } 792 } 793 794 func (vote *Vote) SignBytes(chainID string, cdc *amino.Codec) []byte { 795 bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainID, vote)) 796 if err != nil { 797 panic(err) 798 } 799 return bz 800 } 801 802 func (h *TendermintHandler) getValidators(height int64) ([]Validator, bool) { 803 if height+10 < h.maxValidHeight { 804 // Don't service messages too old 805 return []Validator{}, false 806 } else if h.validatorCache.Contains(height) { 807 value, ok := h.validatorCache.Get(height) 808 return value.([]Validator), ok 809 } else { 810 // log.Info("Asked about height: ", height) 811 response, err := http.Get("http://"+h.rpcAddr+"/validators?height="+strconv.Itoa((int)(height))) 812 defer response.Body.Close() 813 if err != nil { 814 log.Error("Error while sending request to get validators at height: ", height, " err: ", err) 815 return []Validator{}, false 816 } else { 817 bodyBytes, err := ioutil.ReadAll(response.Body) 818 if err != nil { 819 log.Error("Error while parsing request to get validators at height: ", height, " err: ", err) 820 return []Validator{}, false 821 } 822 var jsonResult map[string]interface{} 823 json.Unmarshal(bodyBytes, &jsonResult) 824 // verify interface for errors 825 if _, errorFieldFound := jsonResult["error"]; errorFieldFound { 826 return []Validator{}, false 827 } 828 validatorInfo := jsonResult["result"].(map[string]interface{})["validators"].([]interface{}) 829 830 var validatorSet []Validator 831 for _, v := range(validatorInfo) { 832 if v.(map[string]interface{})["pub_key"].(map[string]interface{})["type"] != "tendermint/PubKeyEd25519" { 833 log.Error("Not all keys of validators are tendermint/PubKeyEd25519. Cannot continue with this validator set from TMCore") 834 return []Validator{}, false 835 } 836 decodedSlice, err := b64.StdEncoding.DecodeString(v.(map[string]interface{})["pub_key"].(map[string]interface{})["value"].(string)) 837 if err != nil { 838 return []Validator{}, false 839 } 840 var decodedArray [32]byte 841 copy(decodedArray[:], decodedSlice[:32]) 842 validatorSet = append(validatorSet, 843 Validator{ 844 PublicKey: ed25519.PubKeyEd25519(decodedArray), 845 Address: v.(map[string]interface{})["address"].(string), 846 }) 847 } 848 h.validatorCache.Add(height, validatorSet) 849 850 h.maxValidHeight = height 851 return validatorSet, true 852 } 853 } 854 } 855 856 func (h *TendermintHandler) spamVerdictMessage(msg marlinTypes.MarlinMessage, allow bool) marlinTypes.MarlinMessage { 857 if allow { 858 return marlinTypes.MarlinMessage{ 859 ChainID: h.servicedChainId, 860 Channel: byte(0x01), 861 PacketId: msg.PacketId, 862 } 863 } else { 864 return marlinTypes.MarlinMessage{ 865 ChainID: h.servicedChainId, 866 Channel: byte(0x00), 867 PacketId: msg.PacketId, 868 } 869 } 870 } 871 872 // ---------------------- KEY GENERATION INTERFACE ----------------------------- 873 874 var ServicedKeyFile string = "irisnet" 875 var isKeyFileUsed, memoized bool 876 var keyFileLocation string 877 var privateKey ed25519.PrivKeyEd25519 878 879 func GenerateKeyFile(fileLocation string) { 880 log.Info("Generating KeyPair for irisnet-0.16.3-mainnet") 881 882 privateKey := ed25519.GenPrivKey() 883 publicKey := privateKey.PubKey() 884 885 key := keyData{ 886 Chain: "irisnet-0.16.3-mainnet", 887 IdString: string(hex.EncodeToString(publicKey.Address())), 888 PrivateKeyString: string(hex.EncodeToString(privateKey[:])), 889 PublicKeyString: string(hex.EncodeToString(publicKey.Bytes())), 890 PrivateKey: privateKey, 891 PublicKey: publicKey.(ed25519.PubKeyEd25519), 892 } 893 894 log.Info("ID for node after generating KeyPair: ", key.IdString) 895 896 encodedJson, err := json.MarshalIndent(&key, "", " ") 897 if err != nil { 898 log.Error("Error generating KeyFile: ", err) 899 } 900 err = ioutil.WriteFile(fileLocation, encodedJson, 0644) 901 if err != nil { 902 log.Error("Error generating KeyFile: ", err) 903 } 904 905 log.Info("Successfully written keyfile ", fileLocation) 906 } 907 908 func VerifyKeyFile(fileLocation string) (bool, error) { 909 log.Info("Accessing disk to extract info from KeyFile: ", fileLocation) 910 jsonFile, err := os.Open(fileLocation) 911 // if we os.Open returns an error then handle it 912 if err != nil { 913 log.Error("Error accessing file KeyFile: ", fileLocation, " error: ", err, ". exiting application.") 914 os.Exit(1) 915 } 916 defer jsonFile.Close() 917 918 byteValue, err := ioutil.ReadAll(jsonFile) 919 if err != nil { 920 log.Error("Error decoding KeyFile: ", fileLocation, " error: ", err, ". exiting application.") 921 os.Exit(1) 922 } 923 var key keyData 924 json.Unmarshal(byteValue, &key) 925 926 // TODO Check these conditions, add more checks - v0.2 prerelease 927 if key.Chain == "irisnet-0.16.3-mainnet" && string(hex.EncodeToString(key.PrivateKey[:])) == key.PrivateKeyString { 928 log.Info("Integrity for KeyFile: ", fileLocation, " checked. Integrity OK.") 929 return true, nil 930 } else { 931 log.Error("Integrity for KeyFile: ", fileLocation, " checked. Integrity NOT OK.") 932 return false, nil 933 } 934 } 935 936 func getPrivateKey() ed25519.PrivKeyEd25519 { 937 if !isKeyFileUsed { 938 return ed25519.GenPrivKey() 939 } else { 940 if !memoized { 941 valid, err := VerifyKeyFile(keyFileLocation) 942 if err != nil { 943 log.Error("Error verifying keyfile integrity: ", keyFileLocation) 944 os.Exit(1) 945 } else if !valid { 946 os.Exit(1) 947 } 948 log.Info("Accessing disk to extract info from KeyFile: ", keyFileLocation) 949 jsonFile, err := os.Open(keyFileLocation) 950 // if we os.Open returns an error then handle it 951 if err != nil { 952 log.Error("Error accessing file KeyFile: ", keyFileLocation, " error: ", err, ". exiting application.") 953 os.Exit(1) 954 } 955 defer jsonFile.Close() 956 957 byteValue, err := ioutil.ReadAll(jsonFile) 958 if err != nil { 959 log.Error("Error decoding KeyFile: ", keyFileLocation, " error: ", err, ". exiting application.") 960 os.Exit(1) 961 } 962 var key keyData 963 json.Unmarshal(byteValue, &key) 964 log.Info("Connector assumes for all connections henceforth the ID: ", key.IdString) 965 privateKey = key.PrivateKey 966 memoized = true 967 } 968 return privateKey 969 } 970 } 971 972 // ---------------------- COMMON UTILITIES --------------------------------- 973 974 975 func createTMHandler(peerAddr string, 976 rpcAddr string, 977 marlinTo chan marlinTypes.MarlinMessage, 978 marlinFrom chan marlinTypes.MarlinMessage, 979 isConnectionOutgoing bool, 980 listenPort int, 981 isDataConnect bool) (TendermintHandler, error) { 982 chainId, ok := marlinTypes.ServicedChains["irisnet-0.16.3-mainnet"] 983 if !ok { 984 return TendermintHandler{}, errors.New("Cannot find irisnet-0.16.3-mainnet in list of serviced chains by marlin connector") 985 } 986 987 privateKey := getPrivateKey() 988 989 vCache, err := lru.New2Q(500) 990 if err != nil { 991 return TendermintHandler{}, err 992 } 993 994 return TendermintHandler{ 995 servicedChainId: chainId, 996 listenPort: listenPort, 997 isConnectionOutgoing: isConnectionOutgoing, 998 peerAddr: peerAddr, 999 rpcAddr: rpcAddr, 1000 privateKey: privateKey, 1001 codec: amino.NewCodec(), 1002 validatorCache: vCache, 1003 marlinTo: marlinTo, 1004 marlinFrom: marlinFrom, 1005 channelBuffer: make(map[byte][]marlinTypes.PacketMsg), 1006 throughput: throughPutData{ 1007 isDataConnect: isDataConnect, 1008 toTMCore: make(map[string]uint32), 1009 fromTMCore: make(map[string]uint32), 1010 spam: make(map[string]uint32), 1011 }, 1012 signalConnError: make(chan struct{}, 1), 1013 signalShutSend: make(chan struct{}, 1), 1014 signalShutRecv: make(chan struct{}, 1), 1015 signalShutThroughput: make(chan struct{}, 1), 1016 }, nil 1017 } 1018 1019 func (t *throughPutData) putInfo(direction string, key string, count uint32) { 1020 t.mu.Lock() 1021 switch direction { 1022 case "to": 1023 t.toTMCore[key] = t.toTMCore[key] + count 1024 case "from": 1025 t.fromTMCore[key] = t.fromTMCore[key] + count 1026 case "spam": 1027 t.spam[key] = t.spam[key] + count 1028 } 1029 t.mu.Unlock() 1030 } 1031 1032 func (t *throughPutData) presentThroughput(sec time.Duration, shutdownCh chan struct{}) { 1033 for { 1034 time.Sleep(sec * time.Second) 1035 1036 select { 1037 case <-shutdownCh: 1038 return 1039 default: 1040 } 1041 t.mu.Lock() 1042 if t.isDataConnect { 1043 log.Info(fmt.Sprintf("[DataConnect stats] To TMCore %v\tFrom TMCore %v", t.toTMCore, t.fromTMCore)) 1044 } else { 1045 log.Info(fmt.Sprintf("[SpamFilter stats] Served %v", t.spam)) 1046 } 1047 t.toTMCore = make(map[string]uint32) 1048 t.fromTMCore = make(map[string]uint32) 1049 t.spam = make(map[string]uint32) 1050 t.mu.Unlock() 1051 } 1052 } 1053 1054 1055 // --- EXTRAS 1056 1057 1058 // Canonical* wraps the structs in types for amino encoding them for use in SignBytes / the Signable interface. 1059 // TimeFormat is used for generating the sigs 1060 // const TimeFormat = time.RFC3339Nano 1061 1062 type CanonicalBlockID struct { 1063 Hash cmn.HexBytes 1064 PartsHeader CanonicalPartSetHeader 1065 } 1066 1067 type CanonicalPartSetHeader struct { 1068 Hash cmn.HexBytes 1069 Total int 1070 } 1071 1072 type CanonicalProposal struct { 1073 Type byte // type alias for byte 1074 Height int64 `binary:"fixed64"` 1075 Round int64 `binary:"fixed64"` 1076 POLRound int64 `binary:"fixed64"` 1077 BlockID CanonicalBlockID 1078 Timestamp time.Time 1079 ChainID string 1080 } 1081 1082 type CanonicalVote struct { 1083 Type byte // type alias for byte 1084 Height int64 `binary:"fixed64"` 1085 Round int64 `binary:"fixed64"` 1086 BlockID CanonicalBlockID 1087 Timestamp time.Time 1088 ChainID string 1089 } 1090 1091 //----------------------------------- 1092 // Canonicalize the structs 1093 1094 func CanonicalizeBlockID(blockID BlockID) CanonicalBlockID { 1095 return CanonicalBlockID{ 1096 Hash: blockID.Hash, 1097 PartsHeader: CanonicalizePartSetHeader(blockID.PartsHeader), 1098 } 1099 } 1100 1101 func CanonicalizePartSetHeader(psh PartSetHeader) CanonicalPartSetHeader { 1102 return CanonicalPartSetHeader{ 1103 psh.Hash, 1104 psh.Total, 1105 } 1106 } 1107 1108 func CanonicalizeProposal(chainID string, proposal *Proposal) CanonicalProposal { 1109 return CanonicalProposal{ 1110 Type: byte(0x20), 1111 Height: proposal.Height, 1112 Round: int64(proposal.Round), // cast int->int64 to make amino encode it fixed64 (does not work for int) 1113 POLRound: int64(proposal.POLRound), 1114 BlockID: CanonicalizeBlockID(proposal.BlockID), 1115 Timestamp: proposal.Timestamp, 1116 ChainID: chainID, 1117 } 1118 } 1119 1120 func CanonicalizeVote(chainID string, vote *Vote) CanonicalVote { 1121 return CanonicalVote{ 1122 Type: vote.Type, 1123 Height: vote.Height, 1124 Round: int64(vote.Round), // cast int->int64 to make amino encode it fixed64 (does not work for int) 1125 Timestamp: vote.Timestamp, 1126 BlockID: CanonicalizeBlockID(vote.BlockID), 1127 ChainID: chainID, 1128 } 1129 } 1130 1131 // // CanonicalTime can be used to stringify time in a canonical way. 1132 // func CanonicalTime(t time.Time) string { 1133 // // Note that sending time over amino resets it to 1134 // // local time, we need to force UTC here, so the 1135 // // signatures match 1136 // return tmtime.Canonical(t).Format(TimeFormat) 1137 // }