github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/chains/cosmos/handlerCOSMOS.go (about)

     1  package cosmos
     2  
     3  import (
     4  
     5  	// "bytes"
     6  
     7  	"bufio"
     8  	"crypto/sha256"
     9  	b64 "encoding/base64"
    10  	"encoding/hex"
    11  	"encoding/json"
    12  	"errors"
    13  	"fmt"
    14  	"io"
    15  	"io/ioutil"
    16  	"net"
    17  	"net/http"
    18  	"os"
    19  	"runtime"
    20  	"strconv"
    21  	"strings"
    22  	"time"
    23  
    24  	"github.com/gogo/protobuf/proto"
    25  	lru "github.com/hashicorp/golang-lru"
    26  	log "github.com/sirupsen/logrus"
    27  	"github.com/supragya/TendermintConnector/chains"
    28  	"github.com/supragya/TendermintConnector/chains/cosmos/conn"
    29  	"github.com/supragya/TendermintConnector/chains/cosmos/crypto/ed25519"
    30  	"github.com/supragya/TendermintConnector/chains/cosmos/crypto/merkle"
    31  	"github.com/supragya/TendermintConnector/chains/cosmos/libs/bits"
    32  	flow "github.com/supragya/TendermintConnector/chains/cosmos/libs/flowrate"
    33  	tmmath "github.com/supragya/TendermintConnector/chains/cosmos/libs/math"
    34  	"github.com/supragya/TendermintConnector/chains/cosmos/libs/protoio"
    35  	"github.com/supragya/TendermintConnector/chains/cosmos/libs/timer"
    36  	tmcons "github.com/supragya/TendermintConnector/chains/cosmos/proto/tendermint/consensus"
    37  	tmp2p "github.com/supragya/TendermintConnector/chains/cosmos/proto/tendermint/p2p"
    38  	tmproto "github.com/supragya/TendermintConnector/chains/cosmos/proto/tendermint/types"
    39  	"github.com/supragya/TendermintConnector/marlin"
    40  	marlinTypes "github.com/supragya/TendermintConnector/types"
    41  )
    42  
    43  // ServicedTMCore is a string associated with each TM core handler
    44  // to decipher which handler is to be attached.
    45  var ServicedTMCore chains.NodeType = chains.NodeType{Version: "", Network: "cosmoshub-4", ProtocolVersionApp: "0", ProtocolVersionBlock: "11", ProtocolVersionP2p: "8"}
    46  
    47  // ---------------------- DATA CONNECT INTERFACE --------------------------------
    48  
    49  func RunDataConnect(peerAddr string,
    50  	marlinTo chan marlinTypes.MarlinMessage,
    51  	marlinFrom chan marlinTypes.MarlinMessage,
    52  	isConnectionOutgoing bool,
    53  	keyFile string,
    54  	listenPort int) {
    55  	log.Info("Starting cosmos Tendermint Core Handler - Vanilla Tendermint")
    56  
    57  	if keyFile != "" {
    58  		isKeyFileUsed = true
    59  		keyFileLocation = keyFile
    60  	}
    61  
    62  	for {
    63  		handler, err := createTMHandler(peerAddr, "0.0.0.0:0", marlinTo, marlinFrom, isConnectionOutgoing, listenPort, true)
    64  
    65  		if err != nil {
    66  			log.Error("Error encountered while creating TM Handler: ", err)
    67  			os.Exit(1)
    68  		}
    69  
    70  		if isConnectionOutgoing {
    71  			err = handler.dialPeer()
    72  		} else {
    73  			err = handler.acceptPeer()
    74  		}
    75  		if err != nil {
    76  			log.Error("Base Connection establishment with peer unsuccessful: ", err)
    77  			goto REATTEMPT_CONNECTION
    78  		}
    79  
    80  		err = handler.upgradeConnectionAndHandshake()
    81  		if err != nil {
    82  			log.Error("Error while upgrading connection and handshaking with peer: ", err)
    83  			goto REATTEMPT_CONNECTION
    84  		}
    85  
    86  		handler.beginServicing()
    87  
    88  		select {
    89  		case <-handler.signalConnError:
    90  			handler.signalShutSend <- struct{}{}
    91  			handler.signalShutRecv <- struct{}{}
    92  			handler.signalShutThroughput <- struct{}{}
    93  			goto REATTEMPT_CONNECTION
    94  		}
    95  
    96  	REATTEMPT_CONNECTION:
    97  		handler.baseConnection.Close()
    98  		handler.secretConnection.Close()
    99  		log.Info("Error encountered with connection to the peer. Attempting reconnect post 1 second.")
   100  		time.Sleep(1 * time.Second)
   101  	}
   102  }
   103  
   104  func (h *TendermintHandler) dialPeer() error {
   105  	var err error
   106  	h.baseConnection, err = net.DialTimeout("tcp", h.peerAddr, 2000*time.Millisecond)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  func (h *TendermintHandler) acceptPeer() error {
   115  
   116  	listener, err := net.Listen("tcp", "0.0.0.0:"+strconv.Itoa(h.listenPort))
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	log.Info("TMCore side listening for dials to ",
   122  		string(hex.EncodeToString(h.privateKey.PubKey().Address())), "@<SYSTEM-IP-ADDR>:", h.listenPort)
   123  
   124  	h.baseConnection, err = listener.Accept()
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	return nil
   130  }
   131  
   132  func (h *TendermintHandler) upgradeConnectionAndHandshake() error {
   133  	log.Info("Handshaking procedure")
   134  	var err error
   135  	h.secretConnection, err = conn.MakeSecretConnection(h.baseConnection, h.privateKey)
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	err = h.handshake()
   141  	if err != nil {
   142  		return err
   143  	}
   144  
   145  	log.Info("Established connection with TM peer [" +
   146  		string(hex.EncodeToString(h.secretConnection.RemotePubKey().Address())) +
   147  		"] a.k.a. " + h.peerNodeInfo.Moniker)
   148  	return nil
   149  }
   150  
   151  func (h *TendermintHandler) handshake() error {
   152  	var (
   153  		errc                              = make(chan error, 2)
   154  		ourNodeInfo tmp2p.DefaultNodeInfo = tmp2p.DefaultNodeInfo{
   155  			tmp2p.ProtocolVersion{App: 0, Block: 11, P2P: 8},
   156  			string(hex.EncodeToString(h.privateKey.PubKey().Address())),
   157  			"tcp://127.0.0.1:20026", //TODO Correct this - v0.2 prerelease
   158  			"cosmoshub-4",
   159  			"",
   160  			[]byte{channelBc, channelCsSt, channelCsDc, channelCsVo,
   161  				channelCsVs, channelMm, channelEv},
   162  			"marlin-tendermint-connector",
   163  			tmp2p.DefaultNodeInfoOther{"on", "tcp://0.0.0.0:26667"}, // TODO: Correct this - v0.2 prerelease
   164  		}
   165  	)
   166  
   167  	go func(errc chan<- error, c net.Conn) {
   168  		_, err := protoio.NewDelimitedWriter(c).WriteMsg(&ourNodeInfo)
   169  		if err != nil {
   170  			log.Error("Error encountered while sending handshake message ", err)
   171  		}
   172  		errc <- err
   173  	}(errc, h.secretConnection)
   174  
   175  	go func(errc chan<- error, c net.Conn) {
   176  		protoReader := protoio.NewDelimitedReader(c, 10240)
   177  		_, err := protoReader.ReadMsg(&h.peerNodeInfo)
   178  		if err != nil {
   179  			log.Error("Error encountered while recieving handshake message ", err)
   180  		}
   181  		errc <- err
   182  	}(errc, h.secretConnection)
   183  
   184  	for i := 0; i < cap(errc); i++ {
   185  		err := <-errc
   186  		if err != nil {
   187  			log.Error("Encountered error in handshake with TM core: ", err)
   188  			return err
   189  		}
   190  	}
   191  	return nil
   192  }
   193  
   194  func (h *TendermintHandler) beginServicing() error {
   195  	// Create a P2P Connection
   196  	h.p2pConnection = P2PConnection{
   197  		conn:            h.secretConnection,
   198  		bufConnReader:   bufio.NewReaderSize(h.secretConnection, 65535),
   199  		bufConnWriter:   bufio.NewWriterSize(h.secretConnection, 65535),
   200  		sendMonitor:     flow.New(0, 0),
   201  		recvMonitor:     flow.New(0, 0),
   202  		send:            make(chan struct{}, 1),
   203  		pong:            make(chan struct{}, 1),
   204  		doneSendRoutine: make(chan struct{}, 1),
   205  		quitSendRoutine: make(chan struct{}, 1),
   206  		quitRecvRoutine: make(chan struct{}, 1),
   207  		flushTimer:      timer.NewThrottleTimer("flush", 100*time.Millisecond),
   208  		pingTimer:       time.NewTicker(30 * time.Second),
   209  		pongTimeoutCh:   make(chan bool, 1),
   210  	}
   211  
   212  	// Start P2P Send and recieve routines + Status messages for message throughput
   213  	go h.sendRoutine()
   214  	go h.recvRoutine()
   215  	go h.throughput.presentThroughput(5, h.signalShutThroughput)
   216  
   217  	// Allow cosmosnet messages from marlin Relay
   218  	marlin.AllowServicedChainMessages(h.servicedChainId)
   219  	return nil
   220  }
   221  
   222  func (h *TendermintHandler) sendRoutine() {
   223  	protoWriter := protoio.NewDelimitedWriter(h.p2pConnection.bufConnWriter)
   224  	for {
   225  		var _n int
   226  		var err error
   227  		select {
   228  		case <-h.p2pConnection.pong:
   229  			// log.Info("Send Pong")
   230  			_n, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{}))
   231  			if err != nil {
   232  				log.Error("Failed to send PacketPong", "err", err)
   233  				h.flush()
   234  				h.signalConnError <- struct{}{}
   235  				return
   236  			}
   237  			h.p2pConnection.sendMonitor.Update(_n)
   238  			h.flush()
   239  
   240  		// Actual message packets from Marlin Relay (encoded in Marlin Tendermint Data Transfer Protocol v1)
   241  		case marlinMsg := <-h.marlinFrom:
   242  			switch marlinMsg.Channel {
   243  			case channelCsSt:
   244  				msgEncoded, err := h.getBytesFromMarlinMessage(&marlinMsg)
   245  				if err != nil {
   246  					log.Debug("Cannot get bytes from marlin to a valid Consensus Message: ", err)
   247  				}
   248  				msg, err := decodeMsg(msgEncoded)
   249  				if err != nil {
   250  					log.Debug("Cannot decode messages to CsSt: ", err)
   251  				}
   252  				switch msg.(type) {
   253  				case *NewRoundStepMessage:
   254  					for _, pkt := range marlinMsg.Packets {
   255  						_n, err := protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketMsg{
   256  							ChannelID: int32(channelCsSt),
   257  							EOF:       pkt.EOF == 1,
   258  							Data:      pkt.Bytes,
   259  						}))
   260  						if err != nil {
   261  							log.Error("Error occurred in sending data to TMCore: ", err)
   262  							// h.signalConnError <- struct{}{}
   263  						}
   264  						h.p2pConnection.sendMonitor.Update(int(_n))
   265  						err = h.p2pConnection.bufConnWriter.Flush()
   266  						if err != nil {
   267  							log.Error("Cannot flush buffer: ", err)
   268  						}
   269  					}
   270  				}
   271  			}
   272  		}
   273  	}
   274  }
   275  
   276  func (h *TendermintHandler) getBytesFromMarlinMessage(marlinMsg *marlinTypes.MarlinMessage) ([]byte, error) {
   277  	var databuf []byte
   278  	for _, pkt := range marlinMsg.Packets {
   279  		databuf = append(databuf, pkt.Bytes...)
   280  	}
   281  	return databuf, nil
   282  }
   283  
   284  func (h *TendermintHandler) flush() {
   285  	err := h.p2pConnection.bufConnWriter.Flush()
   286  	if err != nil {
   287  		log.Error("BufConnWriter flush failed", "err", err)
   288  	}
   289  }
   290  
   291  func (h *TendermintHandler) recvRoutine() {
   292  	log.Info("TMCore -> Connector Routine Started")
   293  	protoReader := protoio.NewDelimitedReader(h.p2pConnection.bufConnReader, 2000)
   294  
   295  FOR_LOOP:
   296  	for {
   297  		select {
   298  		case <-h.signalShutRecv:
   299  			log.Info("TMCore -> Connector Routine shutdown")
   300  			break FOR_LOOP
   301  		default:
   302  		}
   303  		h.p2pConnection.recvMonitor.Limit(20000, 5120000, true)
   304  
   305  		/*
   306  			Peek into bufConnReader for debugging
   307  
   308  			if numBytes := c.bufConnReader.Buffered(); numBytes > 0 {
   309  				bz, err := c.bufConnReader.Peek(cmn.MinInt(numBytes, 100))
   310  				if err == nil {
   311  					// return
   312  				} else {
   313  					log.Debug("Error peeking connection buffer ", "err ", err)
   314  					// return nil
   315  				}
   316  				log.Info("Peek connection buffer ", "numBytes ", numBytes, " bz ", bz)
   317  			}
   318  		*/
   319  
   320  		// Read packet type
   321  		var packet tmp2p.Packet
   322  		_n, err := protoReader.ReadMsg(&packet)
   323  
   324  		h.p2pConnection.recvMonitor.Update(int(_n))
   325  
   326  		// Unmarshalling test
   327  		if err != nil {
   328  			if err == io.EOF {
   329  				log.Error("TMCore -> Connector Connection is closed (likely by the other side) ", err)
   330  			} else {
   331  				log.Error("TMCore -> Connector Connection failed (reading byte): ", err)
   332  			}
   333  			h.signalConnError <- struct{}{}
   334  			break FOR_LOOP
   335  		}
   336  
   337  		switch pkt := packet.Sum.(type) {
   338  		case *tmp2p.Packet_PacketPing:
   339  			// TODO: prevent abuse, as they cause flush()'s.
   340  			// https://github.com/tendermint/tendermint/issues/1190
   341  			// log.Info("Receive Ping ", pkt)
   342  			select {
   343  			case h.p2pConnection.pong <- struct{}{}:
   344  			default:
   345  				// never block
   346  			}
   347  		case *tmp2p.Packet_PacketPong:
   348  			log.Info("Receive Pong")
   349  			select {
   350  			case h.p2pConnection.pongTimeoutCh <- false:
   351  			default:
   352  				// never block
   353  			}
   354  		case *tmp2p.Packet_PacketMsg:
   355  			var eof uint32 = 0
   356  			if pkt.PacketMsg.EOF {
   357  				eof = 1
   358  			}
   359  			h.channelBuffer[byte(pkt.PacketMsg.ChannelID)] = append(h.channelBuffer[byte(pkt.PacketMsg.ChannelID)],
   360  				marlinTypes.PacketMsg{
   361  					EOF:   eof,
   362  					Bytes: pkt.PacketMsg.Data,
   363  				})
   364  
   365  			// In case of incomplete message
   366  			if !pkt.PacketMsg.EOF {
   367  				log.Debug("TMCore -> Connector partial ", byte(pkt.PacketMsg.ChannelID))
   368  				break
   369  			}
   370  
   371  			// Reach here only in case message has EOF. At this point the previous
   372  			// messages are in h.channelBuffer[channel-idx]
   373  			switch byte(pkt.PacketMsg.ChannelID) {
   374  			case channelBc:
   375  				h.throughput.putInfo("from", "=BcMSG", 1)
   376  				log.Debug("TMCore -> Connector Blockhain is not serviced")
   377  				h.channelBuffer[channelBc] = h.channelBuffer[channelBc][:0]
   378  			case channelCsSt:
   379  				log.Debug("TMCore -> Connector CsSt servicing")
   380  				submessage, err := h.serviceConsensusStateMessage()
   381  				if err != nil {
   382  					log.Warning("Could not service consensus state message due to err: ", err)
   383  				}
   384  				h.throughput.putInfo("from", submessage, 1)
   385  				h.channelBuffer[channelCsSt] = h.channelBuffer[channelCsSt][:0]
   386  			case channelCsDc:
   387  				log.Debug("TMCore -> Connector CsDc servicing")
   388  				submessage, err := h.serviceConsensusDataMessage()
   389  				if err != nil {
   390  					log.Warning("Could not service consensus data message due to err: ", err)
   391  				}
   392  				h.throughput.putInfo("from", submessage, 1)
   393  				h.channelBuffer[channelCsDc] = h.channelBuffer[channelCsDc][:0]
   394  			case channelCsVo:
   395  				log.Debug("TMCore -> Connector CsDo servicing")
   396  				submessage, err := h.serviceConsensusVoteMessage()
   397  				if err != nil {
   398  					log.Warning("Could not service consensus vote message due to err: ", err)
   399  				}
   400  				h.throughput.putInfo("from", submessage, 1)
   401  				h.channelBuffer[channelCsVo] = h.channelBuffer[channelCsVo][:0]
   402  			case channelCsVs:
   403  				h.throughput.putInfo("from", "=CsVsVSB", 1)
   404  				log.Debug("TMCore -> Connector Consensus Vote Set Bits Channel is not serviced")
   405  				h.channelBuffer[channelCsVs] = h.channelBuffer[channelCsVs][:0]
   406  			case channelMm:
   407  				h.throughput.putInfo("from", "=MmMSG", 1)
   408  				log.Debug("TMCore -> Connector Mempool Channel is not serviced")
   409  				h.channelBuffer[channelMm] = h.channelBuffer[channelMm][:0]
   410  			case channelEv:
   411  				h.throughput.putInfo("from", "=EvMSG", 1)
   412  				log.Debug("TMCore -> Connector Evidence Channel is not serviced")
   413  				h.channelBuffer[channelEv] = h.channelBuffer[channelEv][:0]
   414  			default:
   415  				h.throughput.putInfo("from", "=UnkUNK", 1)
   416  				log.Warning("TMCore -> Connector Unknown ChannelID Message recieved: ", pkt.PacketMsg.ChannelID)
   417  				h.channelBuffer[byte(pkt.PacketMsg.ChannelID)] = h.channelBuffer[byte(pkt.PacketMsg.ChannelID)][:0]
   418  			}
   419  		}
   420  	}
   421  
   422  	// Cleanup
   423  	close(h.p2pConnection.pong)
   424  	for range h.p2pConnection.pong {
   425  		// Drain
   426  	}
   427  }
   428  
   429  func (h *TendermintHandler) getBytesFromChannelBuffer(chanbuf []marlinTypes.PacketMsg) []byte {
   430  	var databuf []byte
   431  	for _, pkt := range chanbuf {
   432  		databuf = append(databuf, pkt.Bytes...)
   433  	}
   434  	return databuf
   435  }
   436  
   437  func (h *TendermintHandler) serviceConsensusStateMessage() (string, error) {
   438  	ch := channelCsSt
   439  	msgBytes := h.getBytesFromChannelBuffer(h.channelBuffer[ch])
   440  	msg, err := decodeMsg(msgBytes)
   441  	if err != nil {
   442  		return "", err
   443  	}
   444  
   445  	switch msg.(type) {
   446  	case *NewRoundStepMessage:
   447  		message := marlinTypes.MarlinMessage{
   448  			ChainID: h.servicedChainId,
   449  			Channel: ch,
   450  			Packets: h.channelBuffer[ch],
   451  		}
   452  		// Send to marlin side
   453  		// select {
   454  		// case h.marlinTo <- message:
   455  		// default:
   456  		// 	log.Warning("Too many messages in channel marlinTo. Dropping oldest messages")
   457  		// 	_ = <-h.marlinTo
   458  		// 	h.marlinTo <- message
   459  		// }
   460  		// Reflect Back NRS message to get CsVoVOT messages
   461  		select {
   462  		case h.marlinFrom <- message:
   463  		default:
   464  			log.Warning("Too many messages in channel marlinFrom. Dropping oldest messages")
   465  			_ = <-h.marlinFrom
   466  			h.marlinFrom <- message
   467  		}
   468  		return "-CsStNRS", nil
   469  	case *Proposal:
   470  		return "-CsStPRO", nil
   471  	case *NewValidBlockMessage:
   472  		log.Debug("Found NewValidBlock, not servicing")
   473  		return "-CsStNVB", nil
   474  	case *HasVoteMessage:
   475  		log.Debug("Found HasVote, not servicing")
   476  		return "-CsStHVM", nil
   477  	case *VoteSetMaj23Message:
   478  		log.Debug("Found SetMaj23, not servicing")
   479  		return "-CsStM23", nil
   480  	default:
   481  		log.Warning("Unknown Consensus state message ", msg)
   482  		return "-CsStXXX", nil
   483  	}
   484  }
   485  
   486  func (h *TendermintHandler) serviceConsensusDataMessage() (string, error) {
   487  	ch := channelCsDc
   488  	msgBytes := h.getBytesFromChannelBuffer(h.channelBuffer[ch])
   489  	msg, err := decodeMsg(msgBytes)
   490  	if err != nil {
   491  		return "", err
   492  	}
   493  
   494  	switch msg.(type) {
   495  	case *ProposalMessage:
   496  		h.cahcedDcProposal = msg.(*ProposalMessage)
   497  		h.cachedDcProposalPacket = make([]marlinTypes.PacketMsg, 0)
   498  		for _, pkt := range h.channelBuffer[ch] {
   499  			h.cachedDcProposalPacket = append(h.cachedDcProposalPacket, pkt)
   500  		}
   501  		return "@CsDcPRO", nil
   502  	case *ProposalPOLMessage:
   503  		log.Debug("Found Proposal POL, not servicing")
   504  		return "-CsDcPOL", nil
   505  	case *BlockPartMessage:
   506  
   507  		if h.cahcedDcProposal == nil || msg.(*BlockPartMessage).Height != h.cahcedDcProposal.Proposal.Height || msg.(*BlockPartMessage).Round != h.cahcedDcProposal.Proposal.Round {
   508  			// log.Info("Cannot find the bpm match ", msg.(*BlockPartMessage).Height, msg.(*BlockPartMessage).Round)
   509  			return "-CsDcBPM", nil
   510  		}
   511  		// log.Info("Found the bpm match ", msg.(*BlockPartMessage).Height, msg.(*BlockPartMessage).Round)
   512  		message := marlinTypes.MarlinMessage{
   513  			ChainID:  h.servicedChainId,
   514  			Channel:  byte(0x90),
   515  			Packets:  h.cachedDcProposalPacket,
   516  			Packets2: h.channelBuffer[ch],
   517  		}
   518  
   519  		// log.Info("Sending an Ox90 message ", len(message.Packets), len(message.Packets2))
   520  		// Send to marlin side
   521  		select {
   522  		case h.marlinTo <- message:
   523  		default:
   524  			log.Warning("Too many messages in channel marlinTo. Dropping oldest messages")
   525  			_ = <-h.marlinTo
   526  			h.marlinTo <- message
   527  		}
   528  		log.Debug("Found BlockPart, not servicing")
   529  		return "+CsDcBPM", nil
   530  	default:
   531  		log.Warning("Unknown Consensus data message ", msg)
   532  		return "-CsDcXXX", nil
   533  	}
   534  }
   535  
   536  func (h *TendermintHandler) serviceConsensusVoteMessage() (string, error) {
   537  	ch := channelCsVo
   538  	msgBytes := h.getBytesFromChannelBuffer(h.channelBuffer[ch])
   539  	msg, err := decodeMsg(msgBytes)
   540  	if err != nil {
   541  		return "", err
   542  	}
   543  
   544  	switch msg.(type) {
   545  	case *VoteMessage:
   546  		message := marlinTypes.MarlinMessage{
   547  			ChainID: h.servicedChainId,
   548  			Channel: ch,
   549  			Packets: h.channelBuffer[ch],
   550  		}
   551  		// Send to marlin side
   552  		select {
   553  		case h.marlinTo <- message:
   554  		default:
   555  			log.Warning("Too many messages in channel marlinTo. Dropping oldest messages")
   556  			_ = <-h.marlinTo
   557  			h.marlinTo <- message
   558  		}
   559  		return "+CsVoVOT", nil
   560  	default:
   561  		log.Warning("Unknown Consensus vote message ", msg)
   562  		return "-CsVoXXX", nil
   563  	}
   564  }
   565  
   566  // ---------------------- KEY GENERATION INTERFACE -----------------------------
   567  
   568  var ServicedKeyFile string = "cosmos"
   569  var isKeyFileUsed, memoized bool
   570  var keyFileLocation string
   571  
   572  var privateKey ed25519.PrivKey
   573  
   574  func AsSha256(o interface{}) string {
   575  	h := sha256.New()
   576  	h.Write([]byte(fmt.Sprintf("%v", o)))
   577  
   578  	return fmt.Sprintf("%x", h.Sum(nil))
   579  }
   580  
   581  func GenerateKeyFile(fileLocation string) {
   582  	log.Info("Generating KeyPair for cosmoshub-4-mainnet")
   583  
   584  	privateKey := ed25519.GenPrivKey()
   585  	publicKey := privateKey.PubKey()
   586  
   587  	key := keyData{
   588  		Chain:      "cosmoshub-4-mainnet",
   589  		IdString:   string(hex.EncodeToString(publicKey.Address())),
   590  		PrivateKey: privateKey.Bytes(),
   591  		PublicKey:  publicKey.Bytes(),
   592  		Integrity:  "",
   593  	}
   594  
   595  	key.Integrity = AsSha256(key)
   596  
   597  	log.Info("ID for node after generating KeyPair: ", key.IdString)
   598  
   599  	encodedJson, err := json.MarshalIndent(&key, "", "    ")
   600  	if err != nil {
   601  		log.Error("Error generating KeyFile: ", err)
   602  	}
   603  	err = ioutil.WriteFile(fileLocation, encodedJson, 0644)
   604  	if err != nil {
   605  		log.Error("Error generating KeyFile: ", err)
   606  	}
   607  
   608  	log.Info("Successfully written keyfile ", fileLocation)
   609  }
   610  
   611  func VerifyKeyFile(fileLocation string) (bool, error) {
   612  	log.Info("Accessing disk to extract info from KeyFile: ", fileLocation)
   613  	jsonFile, err := os.Open(fileLocation)
   614  	// if we os.Open returns an error then handle it
   615  	if err != nil {
   616  		log.Error("Error accessing file KeyFile: ", fileLocation, " error: ", err, ". exiting application.")
   617  		os.Exit(1)
   618  	}
   619  	defer jsonFile.Close()
   620  
   621  	byteValue, err := ioutil.ReadAll(jsonFile)
   622  	if err != nil {
   623  		log.Error("Error decoding KeyFile: ", fileLocation, " error: ", err, ". exiting application.")
   624  		os.Exit(1)
   625  	}
   626  	var key keyData
   627  	json.Unmarshal(byteValue, &key)
   628  
   629  	integrity := key.Integrity
   630  	key.Integrity = ""
   631  
   632  	if key.Chain == "cosmoshub-4-mainnet" && integrity == AsSha256(key) {
   633  		log.Info("Integrity for KeyFile: ", fileLocation, " checked. Integrity OK.")
   634  		return true, nil
   635  	} else {
   636  		log.Error("Integrity for KeyFile: ", fileLocation, " checked. Integrity NOT OK.")
   637  		return false, nil
   638  	}
   639  }
   640  
   641  // ---------------------- COMMON UTILITIES ---------------------------------
   642  
   643  func createTMHandler(peerAddr string,
   644  	rpcAddr string,
   645  	marlinTo chan marlinTypes.MarlinMessage,
   646  	marlinFrom chan marlinTypes.MarlinMessage,
   647  	isConnectionOutgoing bool,
   648  	listenPort int,
   649  	isDataConnect bool) (TendermintHandler, error) {
   650  	chainId, ok := marlinTypes.ServicedChains["cosmoshub-4-mainnet"]
   651  	if !ok {
   652  		return TendermintHandler{}, errors.New("Cannot find cosmos in list of serviced chains by marlin connector")
   653  	}
   654  
   655  	privateKey := getPrivateKey()
   656  
   657  	vCache, err := lru.New2Q(500)
   658  	if err != nil {
   659  		return TendermintHandler{}, err
   660  	}
   661  
   662  	return TendermintHandler{
   663  		servicedChainId:      chainId,
   664  		listenPort:           listenPort,
   665  		isConnectionOutgoing: isConnectionOutgoing,
   666  		peerAddr:             peerAddr,
   667  		rpcAddr:              rpcAddr,
   668  		privateKey:           privateKey,
   669  		// codec:                amino.NewCodec(),
   670  		validatorCache: vCache,
   671  		marlinTo:       marlinTo,
   672  		marlinFrom:     marlinFrom,
   673  		channelBuffer:  make(map[byte][]marlinTypes.PacketMsg),
   674  		proposerCache:  make(map[int64]Validator),
   675  		throughput: throughPutData{
   676  			isDataConnect: isDataConnect,
   677  			toTMCore:      make(map[string]uint32),
   678  			fromTMCore:    make(map[string]uint32),
   679  			spam:          make(map[string]uint32),
   680  		},
   681  		signalConnError:      make(chan struct{}, 1),
   682  		signalShutSend:       make(chan struct{}, 1),
   683  		signalShutRecv:       make(chan struct{}, 1),
   684  		signalShutThroughput: make(chan struct{}, 1),
   685  	}, nil
   686  }
   687  
   688  func getPrivateKey() ed25519.PrivKey {
   689  	if !isKeyFileUsed {
   690  		return ed25519.GenPrivKey()
   691  	} else {
   692  		if !memoized {
   693  			valid, err := VerifyKeyFile(keyFileLocation)
   694  			if err != nil {
   695  				log.Error("Error verifying keyfile integrity: ", keyFileLocation)
   696  				os.Exit(1)
   697  			} else if !valid {
   698  				os.Exit(1)
   699  			}
   700  			log.Info("Accessing disk to extract info from KeyFile: ", keyFileLocation)
   701  			jsonFile, err := os.Open(keyFileLocation)
   702  			// if we os.Open returns an error then handle it
   703  			if err != nil {
   704  				log.Error("Error accessing file KeyFile: ", keyFileLocation, " error: ", err, ". exiting application.")
   705  				os.Exit(1)
   706  			}
   707  			defer jsonFile.Close()
   708  
   709  			byteValue, err := ioutil.ReadAll(jsonFile)
   710  			if err != nil {
   711  				log.Error("Error decoding KeyFile: ", keyFileLocation, " error: ", err, ". exiting application.")
   712  				os.Exit(1)
   713  			}
   714  			var key keyData
   715  			json.Unmarshal(byteValue, &key)
   716  			log.Info("Connector assumes for all connections henceforth the ID: ", key.IdString)
   717  			privateKey = key.PrivateKey
   718  			memoized = true
   719  		}
   720  		return privateKey
   721  	}
   722  }
   723  
   724  func (t *throughPutData) putInfo(direction string, key string, count uint32) {
   725  	t.mu.Lock()
   726  	switch direction {
   727  	case "to":
   728  		t.toTMCore[key] = t.toTMCore[key] + count
   729  	case "from":
   730  		t.fromTMCore[key] = t.fromTMCore[key] + count
   731  	case "spam":
   732  		t.spam[key] = t.spam[key] + count
   733  	}
   734  	t.mu.Unlock()
   735  }
   736  
   737  func (t *throughPutData) presentThroughput(sec time.Duration, shutdownCh chan struct{}) {
   738  	for {
   739  		time.Sleep(sec * time.Second)
   740  
   741  		select {
   742  		case <-shutdownCh:
   743  			return
   744  		default:
   745  		}
   746  		t.mu.Lock()
   747  		if t.isDataConnect {
   748  			log.Info(fmt.Sprintf("[DataConnect stats] To TMCore %v\tFrom TMCore %v", t.toTMCore, t.fromTMCore))
   749  		} else {
   750  			log.Info(fmt.Sprintf("[SpamFilter stats] Served %v", t.spam))
   751  		}
   752  		t.toTMCore = make(map[string]uint32)
   753  		t.fromTMCore = make(map[string]uint32)
   754  		t.spam = make(map[string]uint32)
   755  		t.mu.Unlock()
   756  	}
   757  }
   758  
   759  //-----------------------------------------------------------------------------
   760  // Messages
   761  
   762  // Message is a message that can be sent and received on the Reactor
   763  type Message interface {
   764  	// ValidateBasic() error // No restrictions
   765  }
   766  
   767  func decodeMsg(bz []byte) (msg Message, err error) {
   768  	pb := &tmcons.Message{}
   769  	if err = proto.Unmarshal(bz, pb); err != nil {
   770  		return msg, err
   771  	}
   772  
   773  	return MsgFromProto(pb)
   774  }
   775  
   776  // MsgFromProto takes a consensus proto message and returns the native go type
   777  func MsgFromProto(msg *tmcons.Message) (Message, error) {
   778  	if msg == nil {
   779  		return nil, errors.New("consensus: nil message")
   780  	}
   781  	var pb Message
   782  
   783  	switch msg := msg.Sum.(type) {
   784  	case *tmcons.Message_NewRoundStep:
   785  		rs, err := tmmath.SafeConvertUint8(int64(msg.NewRoundStep.Step))
   786  		// deny message based on possible overflow
   787  		if err != nil {
   788  			return nil, fmt.Errorf("denying message due to possible overflow: %w", err)
   789  		}
   790  		pb = &NewRoundStepMessage{
   791  			Height:                msg.NewRoundStep.Height,
   792  			Round:                 msg.NewRoundStep.Round,
   793  			Step:                  int8(rs),
   794  			SecondsSinceStartTime: msg.NewRoundStep.SecondsSinceStartTime,
   795  			LastCommitRound:       msg.NewRoundStep.LastCommitRound,
   796  		}
   797  	case *tmcons.Message_NewValidBlock:
   798  		pbPartSetHeader, err := PartSetHeaderFromProto(&msg.NewValidBlock.BlockPartSetHeader)
   799  		if err != nil {
   800  			return nil, fmt.Errorf("parts to proto error: %w", err)
   801  		}
   802  
   803  		pbBits := new(bits.BitArray)
   804  		pbBits.FromProto(msg.NewValidBlock.BlockParts)
   805  
   806  		pb = &NewValidBlockMessage{
   807  			Height:             msg.NewValidBlock.Height,
   808  			Round:              msg.NewValidBlock.Round,
   809  			BlockPartSetHeader: *pbPartSetHeader,
   810  			BlockParts:         pbBits,
   811  			IsCommit:           msg.NewValidBlock.IsCommit,
   812  		}
   813  	case *tmcons.Message_Proposal:
   814  		pbP, err := ProposalFromProto(&msg.Proposal.Proposal)
   815  		if err != nil {
   816  			return nil, fmt.Errorf("proposal msg to proto error: %w", err)
   817  		}
   818  
   819  		pb = &ProposalMessage{
   820  			Proposal: pbP,
   821  		}
   822  	case *tmcons.Message_ProposalPol:
   823  		pbBits := new(bits.BitArray)
   824  		pbBits.FromProto(&msg.ProposalPol.ProposalPol)
   825  		pb = &ProposalPOLMessage{
   826  			Height:           msg.ProposalPol.Height,
   827  			ProposalPOLRound: msg.ProposalPol.ProposalPolRound,
   828  			ProposalPOL:      pbBits,
   829  		}
   830  	case *tmcons.Message_BlockPart:
   831  		parts, err := PartFromProto(&msg.BlockPart.Part)
   832  		if err != nil {
   833  			return nil, fmt.Errorf("blockpart msg to proto error: %w", err)
   834  		}
   835  		pb = &BlockPartMessage{
   836  			Height: msg.BlockPart.Height,
   837  			Round:  msg.BlockPart.Round,
   838  			Part:   parts,
   839  		}
   840  	case *tmcons.Message_Vote:
   841  		vote, err := VoteFromProto(msg.Vote.Vote)
   842  		if err != nil {
   843  			return nil, fmt.Errorf("vote msg to proto error: %w", err)
   844  		}
   845  
   846  		pb = &VoteMessage{
   847  			Vote: vote,
   848  		}
   849  	case *tmcons.Message_HasVote:
   850  		pb = &HasVoteMessage{
   851  			Height: msg.HasVote.Height,
   852  			Round:  msg.HasVote.Round,
   853  			Type:   msg.HasVote.Type,
   854  			Index:  msg.HasVote.Index,
   855  		}
   856  	case *tmcons.Message_VoteSetMaj23:
   857  		bi, err := BlockIDFromProto(&msg.VoteSetMaj23.BlockID)
   858  		if err != nil {
   859  			return nil, fmt.Errorf("voteSetMaj23 msg to proto error: %w", err)
   860  		}
   861  		pb = &VoteSetMaj23Message{
   862  			Height:  msg.VoteSetMaj23.Height,
   863  			Round:   msg.VoteSetMaj23.Round,
   864  			Type:    msg.VoteSetMaj23.Type,
   865  			BlockID: *bi,
   866  		}
   867  	case *tmcons.Message_VoteSetBits:
   868  		bi, err := BlockIDFromProto(&msg.VoteSetBits.BlockID)
   869  		if err != nil {
   870  			return nil, fmt.Errorf("voteSetBits msg to proto error: %w", err)
   871  		}
   872  		bits := new(bits.BitArray)
   873  		bits.FromProto(&msg.VoteSetBits.Votes)
   874  
   875  		pb = &VoteSetBitsMessage{
   876  			Height:  msg.VoteSetBits.Height,
   877  			Round:   msg.VoteSetBits.Round,
   878  			Type:    msg.VoteSetBits.Type,
   879  			BlockID: *bi,
   880  			Votes:   bits,
   881  		}
   882  	default:
   883  		return nil, fmt.Errorf("consensus: message not recognized: %T", msg)
   884  	}
   885  
   886  	// if err := pb.ValidateBasic(); err != nil {
   887  	// 	return nil, err
   888  	// }
   889  
   890  	return pb, nil
   891  }
   892  
   893  // FromProto sets a protobuf PartSetHeader to the given pointer
   894  func PartSetHeaderFromProto(ppsh *tmproto.PartSetHeader) (*PartSetHeader, error) {
   895  	if ppsh == nil {
   896  		return nil, errors.New("nil PartSetHeader")
   897  	}
   898  	psh := new(PartSetHeader)
   899  	psh.Total = ppsh.Total
   900  	psh.Hash = ppsh.Hash
   901  
   902  	return psh, nil
   903  }
   904  
   905  // FromProto sets a protobuf BlockID to the given pointer.
   906  // It returns an error if the block id is invalid.
   907  func BlockIDFromProto(bID *tmproto.BlockID) (*BlockID, error) {
   908  	if bID == nil {
   909  		return nil, errors.New("nil BlockID")
   910  	}
   911  
   912  	blockID := new(BlockID)
   913  	ph, err := PartSetHeaderFromProto(&bID.PartSetHeader)
   914  	if err != nil {
   915  		return nil, err
   916  	}
   917  
   918  	blockID.PartSetHeader = *ph
   919  	blockID.Hash = bID.Hash
   920  
   921  	return blockID, nil
   922  }
   923  
   924  // FromProto sets a protobuf Proposal to the given pointer.
   925  // It returns an error if the proposal is invalid.
   926  func ProposalFromProto(pp *tmproto.Proposal) (*Proposal, error) {
   927  	if pp == nil {
   928  		return nil, errors.New("nil proposal")
   929  	}
   930  
   931  	p := new(Proposal)
   932  
   933  	blockID, err := BlockIDFromProto(&pp.BlockID)
   934  	if err != nil {
   935  		return nil, err
   936  	}
   937  
   938  	p.BlockID = *blockID
   939  	p.Type = pp.Type
   940  	p.Height = pp.Height
   941  	p.Round = pp.Round
   942  	p.POLRound = pp.PolRound
   943  	p.Timestamp = pp.Timestamp
   944  	p.Signature = pp.Signature
   945  
   946  	return p, nil
   947  }
   948  
   949  func PartFromProto(pb *tmproto.Part) (*Part, error) {
   950  	if pb == nil {
   951  		return nil, errors.New("nil part")
   952  	}
   953  
   954  	part := new(Part)
   955  	proof, err := merkle.ProofFromProto(&pb.Proof)
   956  	if err != nil {
   957  		return nil, err
   958  	}
   959  	part.Index = pb.Index
   960  	part.Bytes = pb.Bytes
   961  	part.Proof = *proof
   962  
   963  	return part, nil
   964  }
   965  
   966  // FromProto converts a proto generetad type to a handwritten type
   967  // return type, nil if everything converts safely, otherwise nil, error
   968  func VoteFromProto(pv *tmproto.Vote) (*Vote, error) {
   969  	if pv == nil {
   970  		return nil, errors.New("nil vote")
   971  	}
   972  
   973  	blockID, err := BlockIDFromProto(&pv.BlockID)
   974  	if err != nil {
   975  		return nil, err
   976  	}
   977  
   978  	vote := new(Vote)
   979  	vote.Type = pv.Type
   980  	vote.Height = pv.Height
   981  	vote.Round = pv.Round
   982  	vote.BlockID = *blockID
   983  	vote.Timestamp = pv.Timestamp
   984  	vote.ValidatorAddress = pv.ValidatorAddress
   985  	vote.ValidatorIndex = pv.ValidatorIndex
   986  	vote.Signature = pv.Signature
   987  
   988  	return vote, nil
   989  }
   990  
   991  //----------------------------------------
   992  // Packet
   993  
   994  // mustWrapPacket takes a packet kind (oneof) and wraps it in a tmp2p.Packet message.
   995  func mustWrapPacket(pb proto.Message) *tmp2p.Packet {
   996  	var msg tmp2p.Packet
   997  
   998  	switch pb := pb.(type) {
   999  	case *tmp2p.Packet: // already a packet
  1000  		msg = *pb
  1001  	case *tmp2p.PacketPing:
  1002  		msg = tmp2p.Packet{
  1003  			Sum: &tmp2p.Packet_PacketPing{
  1004  				PacketPing: pb,
  1005  			},
  1006  		}
  1007  	case *tmp2p.PacketPong:
  1008  		msg = tmp2p.Packet{
  1009  			Sum: &tmp2p.Packet_PacketPong{
  1010  				PacketPong: pb,
  1011  			},
  1012  		}
  1013  	case *tmp2p.PacketMsg:
  1014  		msg = tmp2p.Packet{
  1015  			Sum: &tmp2p.Packet_PacketMsg{
  1016  				PacketMsg: pb,
  1017  			},
  1018  		}
  1019  	default:
  1020  		panic(fmt.Errorf("unknown packet type %T", pb))
  1021  	}
  1022  
  1023  	return &msg
  1024  }
  1025  
  1026  // ---------------------- SPAM FILTER INTERFACE --------------------------------
  1027  
  1028  // RunSpamFilter serves as the entry point for a TM Core handler when serving as a spamfilter
  1029  func RunSpamFilter(rpcAddr string,
  1030  	marlinTo chan marlinTypes.MarlinMessage,
  1031  	marlinFrom chan marlinTypes.MarlinMessage) {
  1032  	log.Info("Starting Cosmoshub-4 Tendermint SpamFilter")
  1033  
  1034  	handler, err := createTMHandler("0.0.0.0:0", rpcAddr, marlinTo, marlinFrom, false, 0, false)
  1035  	if err != nil {
  1036  		log.Error("Error encountered while creating TM Handler: ", err)
  1037  		os.Exit(1)
  1038  	}
  1039  
  1040  	marlin.AllowServicedChainMessages(handler.servicedChainId)
  1041  
  1042  	coreCount := runtime.NumCPU()
  1043  	multiple := 2
  1044  	log.Info("Runtime found number of CPUs on machine to be ", coreCount, ". Hence, running ", multiple*coreCount, " spamfilter handlers.")
  1045  
  1046  	for i := 0; i < multiple*coreCount; i++ {
  1047  		go handler.beginServicingSpamFilter(i)
  1048  	}
  1049  
  1050  	handler.throughput.presentThroughput(5, handler.signalShutThroughput)
  1051  }
  1052  
  1053  func (h *TendermintHandler) beginServicingSpamFilter(id int) {
  1054  	log.Info("Running TM side spam filter handler ", id)
  1055  	// Blocking all except CsVoVOT
  1056  	for marlinMsg := range h.marlinFrom {
  1057  		switch marlinMsg.Channel {
  1058  		case channelBc:
  1059  			h.throughput.putInfo("spam", "-CsBc", 1)
  1060  			log.Debug("TMCore <-> Marlin Blockhain is not serviced")
  1061  			h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1062  		case channelCsSt:
  1063  			msgBytes := h.getBytesFromChannelBuffer(marlinMsg.Packets)
  1064  			msg, err := decodeMsg(msgBytes)
  1065  			if err != nil {
  1066  				h.throughput.putInfo("spam", "-CsStUNK", uint32(len(marlinMsg.Packets)))
  1067  				h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1068  			} else {
  1069  				switch msg.(type) {
  1070  				case *NewRoundStepMessage:
  1071  					h.throughput.putInfo("spam", "+CsStNRS", uint32(len(marlinMsg.Packets)))
  1072  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1073  				default:
  1074  					h.throughput.putInfo("spam", "-CsStUNK", uint32(len(marlinMsg.Packets)))
  1075  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1076  				}
  1077  			}
  1078  		case channelCsVo:
  1079  			// log.Info("consensus vote")
  1080  			msgBytes := h.getBytesFromChannelBuffer(marlinMsg.Packets)
  1081  			msg, err := decodeMsg(msgBytes)
  1082  			if err != nil {
  1083  				h.throughput.putInfo("spam", "-CsVoUNK", uint32(len(marlinMsg.Packets)))
  1084  				h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1085  			} else {
  1086  				switch msg.(type) {
  1087  				case *VoteMessage:
  1088  					if h.thoroughMessageCheck(msg) {
  1089  						h.marlinTo <- h.spamVerdictMessage(marlinMsg, true)
  1090  						h.throughput.putInfo("spam", "+CsVoVOT", uint32(len(marlinMsg.Packets)))
  1091  					} else {
  1092  						h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1093  						h.throughput.putInfo("spam", "-CsVoVOT", uint32(len(marlinMsg.Packets)))
  1094  					}
  1095  				default:
  1096  					h.throughput.putInfo("spam", "-CsVoUNK", uint32(len(marlinMsg.Packets)))
  1097  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1098  				}
  1099  			}
  1100  		case channelCsDc:
  1101  			msgBytes := h.getBytesFromChannelBuffer(marlinMsg.Packets)
  1102  			msg, err := decodeMsg(msgBytes)
  1103  			if err != nil {
  1104  				h.throughput.putInfo("spam", "-CsDcUNK(bare)", uint32(len(marlinMsg.Packets)))
  1105  				h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1106  			} else {
  1107  				switch msg.(type) {
  1108  				case *ProposalMessage:
  1109  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1110  					h.throughput.putInfo("spam", "-CsDcPRO(bare)", uint32(len(marlinMsg.Packets)))
  1111  				case *BlockPartMessage:
  1112  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1113  					h.throughput.putInfo("spam", "-CsDcBPM(bare)", uint32(len(marlinMsg.Packets)))
  1114  				default:
  1115  					h.throughput.putInfo("spam", "-CsVoUNK", uint32(len(marlinMsg.Packets)))
  1116  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1117  				}
  1118  			}
  1119  		case byte(0x90):
  1120  			// Special case: here the Proposal message comes bundled with a block part message
  1121  			// log.Info("0x90 channel -- ", len(marlinMsg.Packets), len(marlinMsg.Packets2))
  1122  			msgBytes := h.getBytesFromChannelBuffer(marlinMsg.Packets)
  1123  			msg, err := decodeMsg(msgBytes)
  1124  			if err != nil {
  1125  				h.throughput.putInfo("spam", "-CsDcUNK", uint32(len(marlinMsg.Packets)))
  1126  				h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1127  			}
  1128  			// log.Info("here ", msg)
  1129  			msgBytes2 := h.getBytesFromChannelBuffer(marlinMsg.Packets2)
  1130  			msg2, err := decodeMsg(msgBytes2)
  1131  			if err != nil {
  1132  				h.throughput.putInfo("spam", "-CsDcUNK", uint32(len(marlinMsg.Packets2)))
  1133  				h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1134  			}
  1135  			// log.Info("here2 ", msg2)
  1136  			switch msg.(type) {
  1137  			case *ProposalMessage:
  1138  				switch msg2.(type) {
  1139  				case *BlockPartMessage:
  1140  					pro := msg.(*ProposalMessage)
  1141  					bpm := msg2.(*BlockPartMessage)
  1142  
  1143  					if pro.Proposal.Height != bpm.Height || pro.Proposal.Round != bpm.Round {
  1144  						log.Info("PRO BPM height round mismatch")
  1145  						h.throughput.putInfo("spam", "-CsDcBPM", 1)
  1146  						h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1147  						break
  1148  					}
  1149  
  1150  					val, ok := h.getProposerAtHeight(pro.Proposal.Height)
  1151  					if !ok {
  1152  						log.Info("error getting proposer at height")
  1153  						h.throughput.putInfo("spam", "-CsDcBPM", 1)
  1154  						h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1155  						break
  1156  					}
  1157  
  1158  					p := pro.Proposal.ToProto()
  1159  					ok = val.PublicKey.VerifySignature(ProposalSignBytes("cosmoshub-4", p), pro.Proposal.Signature)
  1160  					if !ok {
  1161  						log.Info("PRO signature mismatch ", pro.Proposal.Height, pro.Proposal.Round, val.Address)
  1162  						h.throughput.putInfo("spam", "-CsDcBPM", 1)
  1163  						h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1164  						break
  1165  					}
  1166  
  1167  					err := bpm.Part.Proof.Verify(pro.Proposal.BlockID.PartSetHeader.Hash, bpm.Part.Bytes)
  1168  					if err != nil {
  1169  						log.Info("PRO BPM merkle verification error")
  1170  						h.throughput.putInfo("spam", "-CsDcBPM", 1)
  1171  						h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1172  						break
  1173  					}
  1174  
  1175  					h.throughput.putInfo("spam", "+CsDcBPM", 1)
  1176  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, true)
  1177  
  1178  				default:
  1179  					h.throughput.putInfo("spam", "-CsDcBPM", 1)
  1180  					h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1181  				}
  1182  			default:
  1183  				h.throughput.putInfo("spam", "-CsDcBPM", 1)
  1184  				h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1185  			}
  1186  
  1187  		case channelCsVs:
  1188  			h.throughput.putInfo("spam", "-CsVs", 1)
  1189  			h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1190  			log.Debug("TMCore <-> Marlin Consensensus Vote Set Bits Channel is not serviced")
  1191  		case channelMm:
  1192  			h.throughput.putInfo("spam", "-CsMm", 1)
  1193  			h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1194  			log.Debug("TMCore <-> Marlin Mempool Channel is not serviced")
  1195  		case channelEv:
  1196  			h.throughput.putInfo("spam", "-CsEv", 1)
  1197  			h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1198  			log.Debug("TMCore <-> MarlinEvidence Channel is not serviced")
  1199  		default:
  1200  			h.throughput.putInfo("spam", "-UnkUNK", 1)
  1201  			h.marlinTo <- h.spamVerdictMessage(marlinMsg, false)
  1202  		}
  1203  	}
  1204  }
  1205  
  1206  func (h *TendermintHandler) thoroughMessageCheck(msg Message) bool {
  1207  	switch msg.(type) {
  1208  	case *VoteMessage:
  1209  		if validator, ok := h.getValidators(msg.(*VoteMessage).Vote.Height); ok {
  1210  			vidx := msg.(*VoteMessage).Vote.ValidatorIndex
  1211  			vaddr := msg.(*VoteMessage).Vote.ValidatorAddress.String()
  1212  			if vidx >= int32(len(validator)) || vaddr != validator[vidx].Address ||
  1213  				!validator[vidx].PublicKey.VerifySignature(VoteSignBytes("cosmoshub-4", msg.(*VoteMessage).Vote.ToProto()), msg.(*VoteMessage).Vote.Signature) {
  1214  				return false
  1215  			}
  1216  			return true
  1217  		}
  1218  		return false
  1219  	case *BlockPartMessage:
  1220  		log.Info("Block part message: ", msg)
  1221  		// Cache hash verification, needs Proposal message support
  1222  		return false
  1223  	case *ProposalMessage:
  1224  		// log.Info("Block proposal message: ", msg)
  1225  		_, ok := h.getProposerAtHeight(msg.(ProposalMessage).Proposal.Height)
  1226  		if !ok {
  1227  			return false
  1228  		}
  1229  
  1230  		// if _, ok := h.getValidators(msg.(*ProposalMessage).Proposal.Height); ok {
  1231  		// 	// Check signature, add to map so that BPM messages can be verified
  1232  		// 	return true
  1233  		// }
  1234  		return false
  1235  	default:
  1236  		return false
  1237  	}
  1238  }
  1239  
  1240  func (h *TendermintHandler) getProposerAtHeight(height int64) (Validator, bool) {
  1241  	if val, ok := h.proposerCache[height]; ok {
  1242  		// Let clear some stuff from cache
  1243  		delete(h.proposerCache, height-10)
  1244  
  1245  		return val, true
  1246  	}
  1247  	// Find stuff from RPC
  1248  
  1249  	if validatorlist, ok := h.getValidators(height); ok {
  1250  		type ConsensusResponse struct {
  1251  			Result struct {
  1252  				RoundState struct {
  1253  					HeightRoundStep string `json:"height/round/step"`
  1254  					Proposer        struct {
  1255  						Address string `json:"address"`
  1256  						Index   int    `json:"index"`
  1257  					} `json:"proposer"`
  1258  				} `json:"round_state"`
  1259  			} `json:"result"`
  1260  		}
  1261  
  1262  		response, err := http.Get("http://" + h.rpcAddr + "/consensus_state")
  1263  		if err != nil {
  1264  			log.Error("Error while sending request to get blockchain status")
  1265  			return Validator{}, false
  1266  		}
  1267  
  1268  		bodyBytes, err := ioutil.ReadAll(response.Body)
  1269  		var jsonResult ConsensusResponse
  1270  		err = json.Unmarshal(bodyBytes, &jsonResult)
  1271  		if err != nil {
  1272  			log.Error("Undecodable response from rpc for next validator search")
  1273  			return Validator{}, false
  1274  		}
  1275  		response.Body.Close()
  1276  
  1277  		heightString := strings.Split(jsonResult.Result.RoundState.HeightRoundStep, "/")[0]
  1278  		heightFromResponse, err := strconv.ParseInt(heightString, 10, 64)
  1279  		if heightFromResponse != height {
  1280  			log.Error("Cannot find height match. Not newest proposal")
  1281  			return Validator{}, false
  1282  		}
  1283  
  1284  		candidateValidator := validatorlist[jsonResult.Result.RoundState.Proposer.Index]
  1285  		if strings.ToUpper(candidateValidator.Address) == jsonResult.Result.RoundState.Proposer.Address {
  1286  			return candidateValidator, true
  1287  		}
  1288  
  1289  		for _, val := range validatorlist {
  1290  			if strings.ToUpper(val.Address) == jsonResult.Result.RoundState.Proposer.Address {
  1291  				return val, true
  1292  			}
  1293  		}
  1294  
  1295  	}
  1296  	return Validator{}, false
  1297  }
  1298  
  1299  func (h *TendermintHandler) getValidators(height int64) ([]Validator, bool) {
  1300  	if height+10 < h.maxValidHeight {
  1301  		// Don't service messages too old
  1302  		return []Validator{}, false
  1303  	} else if h.validatorCache.Contains(height) {
  1304  		value, ok := h.validatorCache.Get(height)
  1305  		return value.([]Validator), ok
  1306  	} else {
  1307  		var validatorSet []Validator
  1308  		// log.Info("Asked about height: ", height)
  1309  		for i := 1; i < 3; i++ {
  1310  			// log.Info(len(validatorSet), height)
  1311  			response, err := http.Get("http://" + h.rpcAddr + "/validators?height=" + strconv.Itoa((int)(height)) + "&per_page=100&page=" + strconv.Itoa((int)(i)))
  1312  			if err != nil {
  1313  				log.Error("Error while sending request to get validators at height: ", height, " err: ", err)
  1314  				return []Validator{}, false
  1315  			} else {
  1316  				bodyBytes, err := ioutil.ReadAll(response.Body)
  1317  				if err != nil {
  1318  					log.Error("Error while parsing request to get validators at height: ", height, " err: ", err)
  1319  					return []Validator{}, false
  1320  				}
  1321  				var jsonResult map[string]interface{}
  1322  				json.Unmarshal(bodyBytes, &jsonResult)
  1323  				// verify interface for errors
  1324  				if _, errorFieldFound := jsonResult["error"]; errorFieldFound {
  1325  					return []Validator{}, false
  1326  				}
  1327  				validatorInfo := jsonResult["result"].(map[string]interface{})["validators"].([]interface{})
  1328  
  1329  				for _, v := range validatorInfo {
  1330  					if v.(map[string]interface{})["pub_key"].(map[string]interface{})["type"] != "tendermint/PubKeyEd25519" {
  1331  						log.Error("Not all keys of validators are tendermint/PubKeyEd25519. Cannot continue with this validator set from TMCore")
  1332  						return []Validator{}, false
  1333  					}
  1334  					decodedSlice, err := b64.StdEncoding.DecodeString(v.(map[string]interface{})["pub_key"].(map[string]interface{})["value"].(string))
  1335  					if err != nil {
  1336  						log.Error("Could not decode base64 pubkey")
  1337  						return []Validator{}, false
  1338  					}
  1339  					decodedArray := make(ed25519.PubKey, 32)
  1340  					// log.Info(decodedSlice[:32])
  1341  					for i := 0; i < 32; i++ {
  1342  						decodedArray[i] = decodedSlice[i]
  1343  					}
  1344  					validatorSet = append(validatorSet,
  1345  						Validator{
  1346  							PublicKey: decodedArray,
  1347  							Address:   v.(map[string]interface{})["address"].(string),
  1348  						})
  1349  				}
  1350  			}
  1351  			response.Body.Close()
  1352  		}
  1353  		// log.Info("ht ", height, " validator set ", len(validatorSet))
  1354  		h.validatorCache.Add(height, validatorSet)
  1355  
  1356  		h.maxValidHeight = height
  1357  		return validatorSet, true
  1358  	}
  1359  }
  1360  
  1361  func (h *TendermintHandler) spamVerdictMessage(msg marlinTypes.MarlinMessage, allow bool) marlinTypes.MarlinMessage {
  1362  	if allow {
  1363  		return marlinTypes.MarlinMessage{
  1364  			ChainID:  h.servicedChainId,
  1365  			Channel:  byte(0x01),
  1366  			PacketId: msg.PacketId,
  1367  		}
  1368  	} else {
  1369  		return marlinTypes.MarlinMessage{
  1370  			ChainID:  h.servicedChainId,
  1371  			Channel:  byte(0x00),
  1372  			PacketId: msg.PacketId,
  1373  		}
  1374  	}
  1375  }