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  // }