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 }