github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/uspv/msghandler.go (about)

     1  package uspv
     2  
     3  import (
     4  	"github.com/mit-dci/lit/logging"
     5  
     6  	"github.com/mit-dci/lit/btcutil/bloom"
     7  	"github.com/mit-dci/lit/lnutil"
     8  	"github.com/mit-dci/lit/wire"
     9  )
    10  
    11  func (s *SPVCon) incomingMessageHandler() {
    12  	for {
    13  		n, xm, _, err := wire.ReadMessageWithEncodingN(s.con, s.localVersion,
    14  			wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
    15  		if err != nil {
    16  			s.con.Close() // close the connection to prevent spam messages from crashing lit.
    17  			logging.Infof("ReadMessageWithEncodingN error.  Disconnecting from given peer. %s\n", err.Error())
    18  			if s.randomNodesOK { // if user wants to connect to localhost, let him do so
    19  				s.Connect("yes") // really any YupString here
    20  			} else {
    21  				s.con.Close()
    22  				return
    23  			}
    24  		}
    25  		s.RBytes += uint64(n)
    26  		//		logging.Infof("Got %d byte %s message\n", n, xm.Command())
    27  		switch m := xm.(type) {
    28  		case *wire.MsgVersion:
    29  			logging.Infof("Got version message.  Agent %s, version %d, at height %d\n",
    30  				m.UserAgent, m.ProtocolVersion, m.LastBlock)
    31  			s.remoteVersion = uint32(m.ProtocolVersion) // weird cast! bug?
    32  		case *wire.MsgVerAck:
    33  			logging.Infof("Got verack.  Whatever.\n")
    34  		case *wire.MsgAddr:
    35  			logging.Infof("got %d addresses.\n", len(m.AddrList))
    36  		case *wire.MsgPing:
    37  			// logging.Infof("Got a ping message.  We should pong back or they will kick us off.")
    38  			go s.PongBack(m.Nonce)
    39  		case *wire.MsgPong:
    40  			logging.Infof("Got a pong response. OK.\n")
    41  		case *wire.MsgBlock:
    42  			s.IngestBlock(m)
    43  		case *wire.MsgMerkleBlock:
    44  			s.IngestMerkleBlock(m)
    45  		case *wire.MsgHeaders: // concurrent because we keep asking for blocks
    46  			go s.HeaderHandler(m)
    47  		case *wire.MsgTx: // not concurrent! txs must be in order
    48  			s.TxHandler(m)
    49  		case *wire.MsgReject:
    50  			logging.Infof("Rejected! cmd: %s code: %s tx: %s reason: %s",
    51  				m.Cmd, m.Code.String(), m.Hash.String(), m.Reason)
    52  		case *wire.MsgInv:
    53  			s.InvHandler(m)
    54  		case *wire.MsgNotFound:
    55  			logging.Infof("Got not found response from remote:")
    56  			for i, thing := range m.InvList {
    57  				logging.Infof("\t%d) %s: %s", i, thing.Type, thing.Hash)
    58  			}
    59  		case *wire.MsgGetData:
    60  			s.GetDataHandler(m)
    61  
    62  		default:
    63  			if m != nil {
    64  				logging.Infof("Got unknown message type %s\n", m.Command())
    65  			} else {
    66  				logging.Errorf("Got nil message")
    67  			}
    68  		}
    69  	}
    70  }
    71  
    72  // this one seems kindof pointless?  could get ridf of it and let
    73  // functions call WriteMessageWithEncodingN themselves...
    74  func (s *SPVCon) outgoingMessageHandler() {
    75  	for {
    76  		msg := <-s.outMsgQueue
    77  		if msg == nil {
    78  			logging.Errorf("ERROR: nil message to outgoingMessageHandler\n")
    79  			continue
    80  		}
    81  		n, err := wire.WriteMessageWithEncodingN(s.con, msg, s.localVersion,
    82  			wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
    83  
    84  		if err != nil {
    85  			logging.Errorf("Write message error: %s", err.Error())
    86  		}
    87  		s.WBytes += uint64(n)
    88  	}
    89  }
    90  
    91  // fPositiveHandler monitors false positives and when it gets enough of them,
    92  func (s *SPVCon) fPositiveHandler() {
    93  	var fpAccumulator int32
    94  	for {
    95  		fpAccumulator += <-s.fPositives // blocks here
    96  		if fpAccumulator > 7 {
    97  			filt, err := s.GimmeFilter()
    98  			if err != nil {
    99  				logging.Errorf("Filter creation error: %s\n", err.Error())
   100  				logging.Errorf("uhoh, crashing filter handler")
   101  				return
   102  			}
   103  			// send filter
   104  			s.Refilter(filt)
   105  			logging.Infof("sent filter %x\n", filt.MsgFilterLoad().Filter)
   106  
   107  			// clear the channel
   108  		finClear:
   109  			for {
   110  				select {
   111  				case x := <-s.fPositives:
   112  					fpAccumulator += x
   113  				default:
   114  					break finClear
   115  				}
   116  			}
   117  
   118  			logging.Infof("reset %d false positives\n", fpAccumulator)
   119  			// reset accumulator
   120  			fpAccumulator = 0
   121  		}
   122  	}
   123  }
   124  
   125  // REORG TODO: how to detect reorgs and send them up to wallet layer
   126  
   127  // HeaderHandler ...
   128  func (s *SPVCon) HeaderHandler(m *wire.MsgHeaders) {
   129  	moar, err := s.IngestHeaders(m)
   130  	if err != nil {
   131  		logging.Errorf("Header error: %s\n", err.Error())
   132  		return
   133  	}
   134  	// more to get? if so, ask for them and return
   135  	if moar {
   136  		err = s.AskForHeaders()
   137  		if err != nil {
   138  			logging.Errorf("AskForHeaders error: %s", err.Error())
   139  		}
   140  		return
   141  	}
   142  	// no moar, done w/ headers, send filter and get blocks
   143  	if !s.HardMode { // don't send this in hardmode! that's the whole point
   144  		filt, err2 := s.GimmeFilter()
   145  		if err2 != nil {
   146  			logging.Errorf("AskForBlocks error: %s", err2.Error())
   147  			return
   148  		}
   149  		// send filter
   150  		s.SendFilter(filt)
   151  		logging.Infof("sent filter %x\n", filt.MsgFilterLoad().Filter)
   152  	}
   153  
   154  	err = s.AskForBlocks()
   155  	if err != nil {
   156  		logging.Errorf("AskForBlocks error: %s", err.Error())
   157  		return
   158  	}
   159  }
   160  
   161  // TxHandler takes in transaction messages that come in from either a request
   162  // after an inv message or after a merkle block message.
   163  func (s *SPVCon) TxHandler(tx *wire.MsgTx) {
   164  	logging.Infof("received msgtx %s\n", tx.TxHash().String())
   165  	// check if we have a height for this tx.
   166  	s.OKMutex.Lock()
   167  	height, ok := s.OKTxids[tx.TxHash()]
   168  	s.OKMutex.Unlock()
   169  	// if we don't have a height for this / it's not in the map, discard.
   170  	// currently CRASHES when this happens because I want to see if it ever does.
   171  	// it shouldn't if things are working properly.
   172  	if !ok {
   173  		logging.Errorf("Tx %s unknown, will not ingest\n", tx.TxHash().String())
   174  		panic("unknown tx")
   175  	}
   176  
   177  	// check for double spends ...?
   178  	//	allTxs, err := s.TS.GetAllTxs()
   179  	//	if err != nil {
   180  	//		logging.Errorf("Can't get txs from db: %s", err.Error())
   181  	//		return
   182  	//	}
   183  	//	dubs, err := CheckDoubleSpends(m, allTxs)
   184  	//	if err != nil {
   185  	//		logging.Errorf("CheckDoubleSpends error: %s", err.Error())
   186  	//		return
   187  	//	}
   188  	//	if len(dubs) > 0 {
   189  	//		for i, dub := range dubs {
   190  	//			logging.Infof("dub %d known tx %s and new tx %s are exclusive!!!\n",
   191  	//				i, dub.String(), m.TxSha().String())
   192  	//		}
   193  	//	}
   194  
   195  	// send txs up to wallit
   196  	if s.MatchTx(tx) {
   197  		s.TxUpToWallit <- lnutil.TxAndHeight{Tx: tx, Height: height}
   198  	}
   199  }
   200  
   201  // GetDataHandler responds to requests for tx data, which happen after
   202  // advertising our txs via an inv message
   203  func (s *SPVCon) GetDataHandler(m *wire.MsgGetData) {
   204  	logging.Infof("got GetData.  Contains:\n")
   205  	var sent int32
   206  	for i, thing := range m.InvList {
   207  		logging.Infof("\t%d)%s : %s",
   208  			i, thing.Type.String(), thing.Hash.String())
   209  
   210  		// I think we do the same thing for witTx or tx...
   211  		// I don't think they'll request non-witness anyway.
   212  		if thing.Type == wire.InvTypeWitnessTx || thing.Type == wire.InvTypeTx {
   213  			tx, ok := s.TxMap[thing.Hash]
   214  			if !ok || tx == nil {
   215  				logging.Infof("tx %s requested but we don't have it\n",
   216  					thing.Hash.String())
   217  				continue
   218  			}
   219  			s.outMsgQueue <- tx
   220  			sent++
   221  			continue
   222  		}
   223  		// didn't match, so it's not something we're responding to
   224  		logging.Infof("We only respond to tx requests, ignoring")
   225  	}
   226  	logging.Infof("sent %d of %d requested items", sent, len(m.InvList))
   227  }
   228  
   229  // InvHandler ...
   230  func (s *SPVCon) InvHandler(m *wire.MsgInv) {
   231  	logging.Infof("got inv.  Contains:\n")
   232  	for i, thing := range m.InvList {
   233  		logging.Infof("\t%d)%s : %s",
   234  			i, thing.Type.String(), thing.Hash.String())
   235  		if thing.Type == wire.InvTypeTx {
   236  			// ignore tx invs in ironman mode, or if we already have it
   237  			if !s.Ironman {
   238  				// new tx, OK it at 0 and request
   239  				// also request if we already have it; might have new witness?
   240  				// needed for confirmed channels...
   241  				s.OKTxid(&thing.Hash, 0) // unconfirmed
   242  				s.AskForTx(thing.Hash)
   243  			}
   244  		}
   245  		if thing.Type == wire.InvTypeBlock { // new block what to do?
   246  			select {
   247  			case <-s.inWaitState:
   248  				// start getting headers
   249  				logging.Infof("asking for headers due to inv block\n")
   250  				err := s.AskForHeaders()
   251  				if err != nil {
   252  					logging.Errorf("AskForHeaders error: %s", err.Error())
   253  				}
   254  			default:
   255  				// drop it as if its component particles had high thermal energies
   256  				logging.Infof("inv block but ignoring; not synced\n")
   257  			}
   258  		}
   259  	}
   260  }
   261  
   262  // PongBack ...
   263  func (s *SPVCon) PongBack(nonce uint64) {
   264  	mpong := wire.NewMsgPong(nonce)
   265  
   266  	s.outMsgQueue <- mpong
   267  	return
   268  }
   269  
   270  // SendFilter ...
   271  func (s *SPVCon) SendFilter(f *bloom.Filter) {
   272  	s.outMsgQueue <- f.MsgFilterLoad()
   273  
   274  	return
   275  }