github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/network/tick.go (about) 1 package network 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/binary" 7 "encoding/hex" 8 "fmt" 9 "math/rand" 10 "net" 11 "os" 12 "runtime/debug" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/piotrnar/gocoin/client/common" 18 "github.com/piotrnar/gocoin/client/network/peersdb" 19 "github.com/piotrnar/gocoin/lib/btc" 20 "github.com/piotrnar/gocoin/lib/others/sys" 21 ) 22 23 var ( 24 TCPServerStarted bool 25 next_drop_peer time.Time 26 next_clean_hammers time.Time 27 28 NextConnectFriends time.Time = time.Now() 29 AuthPubkeys [][]byte 30 SpecialAgents []string 31 SpecialIPs [][4]byte 32 FriendsAccess sync.Mutex 33 34 GetMPInProgressTicket = make(chan bool, 1) 35 GetMPInProgressConnID sys.SyncInt 36 ) 37 38 // call with unlocked c.Mutex 39 func (c *OneConnection) ExpireHeadersAndGetData(now *time.Time, curr_ping_cnt uint64) { 40 var disconnect string 41 42 c.Mutex.Lock() 43 /*if c.X.Debug { 44 println(c.ConnID, "- ExpireHeadersAndGetData", curr_ping_cnt, c.X.GetHeadersSentAtPingCnt, c.X.GetHeadersInProgress, len(c.GetBlockInProgress)) 45 }*/ 46 47 if c.X.GetHeadersInProgress { 48 var err string 49 if curr_ping_cnt > c.X.GetHeadersSentAtPingCnt { 50 err = "GetHeadersPong" 51 } else if now != nil && now.After(c.X.GetHeadersTimeOutAt) { 52 err = "GetHeadersTimeout" 53 } 54 if err != "" { 55 // GetHeaders timeout accured 56 c.X.GetHeadersInProgress = false 57 c.X.LastHeadersEmpty = true 58 c.X.AllHeadersReceived = true 59 common.CountSafe(err) 60 disconnect = err 61 } 62 } 63 c.Mutex.Unlock() 64 65 // never lock network.MutexRcv within (*OneConnection).Mutex as it can cause a deadlock 66 MutexRcv.Lock() 67 c.Mutex.Lock() 68 for k, v := range c.GetBlockInProgress { 69 if curr_ping_cnt > v.SentAtPingCnt { 70 common.CountSafe("BlockInprogNotfound") 71 c.cntInc("BlockNotFound") 72 } else if now != nil && now.After(v.start.Add(5*time.Minute)) { 73 common.CountSafe("BlockInprogTimeout") 74 c.cntInc("BlockTimeout") 75 } else { 76 continue 77 } 78 c.X.BlocksExpired++ 79 delete(c.GetBlockInProgress, k) 80 if bip, ok := BlocksToGet[k]; ok { 81 bip.InProgress-- 82 } 83 if now == nil { 84 disconnect = "BlockDlPongExp" 85 } else { 86 disconnect = "BlockDlTimeout" 87 } 88 } 89 c.Mutex.Unlock() 90 MutexRcv.Unlock() 91 92 if disconnect != "" { 93 if c.X.IsSpecial { 94 common.CountSafe("Spec" + disconnect) 95 c.cntInc(disconnect) 96 } else { 97 c.Disconnect(true, disconnect) 98 } 99 } 100 } 101 102 // Call this once a minute 103 func (c *OneConnection) Maintanence(now time.Time) { 104 // Expire GetBlockInProgress after five minutes, if they are not in BlocksToGet 105 c.ExpireHeadersAndGetData(&now, 0) 106 107 // Expire BlocksReceived after two days 108 c.Mutex.Lock() 109 if len(c.blocksreceived) > 0 { 110 var i int 111 for i = 0; i < len(c.blocksreceived); i++ { 112 if c.blocksreceived[i].Add(common.GetDuration(&common.BlockExpireEvery)).After(now) { 113 break 114 } 115 common.CountSafe("BlksRcvdExpired") 116 } 117 if i > 0 { 118 //println(c.ConnID, "expire", i, "block(s)") 119 c.blocksreceived = c.blocksreceived[i:] 120 } 121 } 122 c.Mutex.Unlock() 123 } 124 125 func (c *OneConnection) Tick(now time.Time) { 126 c.Mutex.Lock() 127 c.X.Ticks++ 128 if common.NoCounters.Get() && len(c.counters) > 0 { 129 c.counters = make(map[string]uint64) // reset all the counters 130 } 131 c.Mutex.Unlock() 132 133 if !c.X.VersionReceived { 134 // Wait only certain amount of time for the version message 135 if c.X.ConnectedAt.Add(VersionMsgTimeout).Before(now) { 136 c.Disconnect(true, "VersionTimeout") 137 common.CountSafe("NetVersionTout") 138 return 139 } 140 // Until we receive version message, do nothing more. 141 return 142 } 143 144 var new_sec bool 145 if tck := now.Unix(); c.lastSec != tck { 146 // these opertions will only be done once a second 147 new_sec = true // keep this for later (to try a ping) 148 c.lastSec = tck 149 150 // If we have not received any data for some time, disconnect 151 if now.Sub(c.X.LastDataGot) > NoDataTimeout { 152 c.Disconnect(true, "NoDataTimeout") 153 common.CountSafe("NetNoDataTout") 154 return 155 } 156 157 if len(c.GetMP) > 0 && common.GetBool(&common.BlockChainSynchronized) { 158 // See if to send "getmp" command 159 select { 160 case GetMPInProgressTicket <- true: 161 // ticket received - check for the request... 162 GetMPInProgressConnID.Store(int(c.ConnID)) 163 if c.SendGetMP() != nil { 164 // SendGetMP() failed - clear the global flag/channel 165 <-GetMPInProgressTicket 166 <-c.GetMP 167 } 168 default: 169 // failed to get the ticket - just do nothing 170 } 171 } 172 173 // Tick the recent transactions counter 174 if now.After(c.txsNxt) { 175 c.Mutex.Lock() 176 if len(c.txsCha) == cap(c.txsCha) { 177 tmp := <-c.txsCha 178 c.X.TxsReceived -= tmp 179 } 180 c.txsCha <- c.txsCur 181 c.txsCur = 0 182 c.txsNxt = c.txsNxt.Add(TxsCounterPeriod) 183 c.Mutex.Unlock() 184 } 185 186 if mfpb := common.MinFeePerKB(); mfpb != c.X.LastMinFeePerKByte { 187 c.X.LastMinFeePerKByte = mfpb 188 if c.Node.Version >= 70013 { 189 c.SendFeeFilter() 190 } 191 } 192 193 if now.After(c.nextMaintanence) { 194 c.Maintanence(now) 195 c.nextMaintanence = now.Add(MAINTANENCE_PERIOD) 196 } 197 198 // Ask node for new addresses...? 199 if !c.X.OurGetAddrDone && peersdb.PeerDB.Count() < peersdb.MinPeersInDB { 200 common.CountSafe("AddrsWanted") 201 c.SendRawMsg("getaddr", nil) 202 c.X.OurGetAddrDone = true 203 } 204 } 205 206 c.Mutex.Lock() 207 if c.HasNetworkService() && !c.X.GetHeadersInProgress && !c.X.AllHeadersReceived && len(c.GetBlockInProgress) == 0 { 208 c.Mutex.Unlock() 209 c.sendGetHeaders() 210 return // new headers requested 211 } 212 213 if c.X.AllHeadersReceived { 214 if !c.X.GetBlocksDataNow && now.After(c.nextGetData) { 215 c.X.GetBlocksDataNow = true 216 } 217 if c.X.GetBlocksDataNow && len(c.GetBlockInProgress) <= c.keepBlocksOver { 218 c.X.GetBlocksDataNow = false 219 c.Mutex.Unlock() 220 c.GetBlockData() 221 return // block data requested 222 } 223 } 224 c.Mutex.Unlock() 225 226 if new_sec { // nothing requested - free to ping.. 227 c.TryPing(now) 228 } 229 } 230 231 func DoNetwork(ad *peersdb.PeerAddr) { 232 conn := NewConnection(ad) 233 Mutex_net.Lock() 234 if _, ok := OpenCons[ad.UniqID()]; ok { 235 common.CountSafe("ConnectingAgain") 236 Mutex_net.Unlock() 237 return 238 } 239 if ad.Friend || ad.Manual { 240 conn.MutexSetBool(&conn.X.IsSpecial, true) 241 } 242 OpenCons[ad.UniqID()] = conn 243 OutConsActive++ 244 Mutex_net.Unlock() 245 go func() { 246 var con net.Conn 247 var e error 248 con_done := make(chan bool, 1) 249 250 go func(addr string) { 251 // we do net.Dial() in paralell routine, so we can abort quickly upon request 252 con, e = net.DialTimeout("tcp4", addr, TCPDialTimeout) 253 con_done <- true 254 }(fmt.Sprintf("%d.%d.%d.%d:%d", ad.Ip4[0], ad.Ip4[1], ad.Ip4[2], ad.Ip4[3], ad.Port)) 255 256 for { 257 select { 258 case <-con_done: 259 if e == nil { 260 Mutex_net.Lock() 261 conn.Conn = con 262 conn.X.ConnectedAt = time.Now() 263 Mutex_net.Unlock() 264 conn.Run() 265 } else { 266 conn.dead = true 267 } 268 case <-time.After(10 * time.Millisecond): 269 if !conn.IsBroken() { 270 continue 271 } 272 } 273 break 274 } 275 276 Mutex_net.Lock() 277 delete(OpenCons, ad.UniqID()) 278 OutConsActive-- 279 Mutex_net.Unlock() 280 if conn.dead { 281 ad.Dead() 282 } else { 283 ad.Save() 284 } 285 }() 286 } 287 288 // TCP server 289 func tcp_server() { 290 var ad net.TCPAddr 291 ad.IP = net.ParseIP(common.CFG.Net.BindToIF) 292 if ad.IP == nil { 293 println("Check config value of Net.BindToIF - binding to any...") 294 ad.IP = net.IPv4(0, 0, 0, 0) 295 } 296 ad.Port = int(common.DefaultTcpPort()) 297 298 lis, e := net.ListenTCP("tcp4", &ad) 299 if e != nil { 300 println("ListenTCP", e.Error()) 301 return 302 } 303 defer lis.Close() 304 305 //fmt.Println("TCP server started at", ad.String()) 306 307 for common.IsListenTCP() { 308 //common.CountSafe("NetServerLoops") 309 Mutex_net.Lock() 310 ica := InConsActive 311 Mutex_net.Unlock() 312 if ica < common.GetUint32(&common.CFG.Net.MaxInCons) { 313 lis.SetDeadline(time.Now().Add(100 * time.Millisecond)) 314 tc, e := lis.AcceptTCP() 315 if e == nil && common.IsListenTCP() { 316 var terminate bool 317 318 // set port to default, for incomming connections 319 ad, e := peersdb.NewIncommingConnection(tc.RemoteAddr().String(), true) 320 if e == nil { 321 //println("incomming connection from", ad.Ip(), tc.RemoteAddr().String()) 322 // Hammering protection 323 HammeringMutex.Lock() 324 if rd := RecentlyDisconencted[ad.NetAddr.Ip4]; rd != nil { 325 rd.Count++ 326 terminate = rd.Count > HammeringMaxAllowedCount 327 } 328 HammeringMutex.Unlock() 329 330 if terminate { 331 common.CountSafe("BanHammerIn") 332 ad.Ban("HammerIn") 333 } else { 334 // Incoming IP passed all the initial checks - talk to it 335 conn := NewConnection(ad) 336 conn.X.ConnectedAt = time.Now() 337 conn.X.Incomming = true 338 conn.Conn = tc 339 Mutex_net.Lock() 340 if _, ok := OpenCons[ad.UniqID()]; ok { 341 //fmt.Println(ad.Ip(), "already connected") 342 common.CountSafe("SameIpReconnect") 343 Mutex_net.Unlock() 344 terminate = true 345 } else { 346 OpenCons[ad.UniqID()] = conn 347 InConsActive++ 348 Mutex_net.Unlock() 349 go func() { 350 conn.Run() 351 Mutex_net.Lock() 352 delete(OpenCons, ad.UniqID()) 353 InConsActive-- 354 Mutex_net.Unlock() 355 }() 356 } 357 } 358 } else { 359 common.CountSafe("InConnDenied") 360 terminate = true 361 } 362 363 // had any error occured - close the TCP connection 364 if terminate { 365 tc.Close() 366 } 367 } 368 } else { 369 time.Sleep(1e8) 370 } 371 } 372 Mutex_net.Lock() 373 for _, c := range OpenCons { 374 if c.X.Incomming { 375 c.Disconnect(false, "CloseAllIn") 376 } 377 } 378 TCPServerStarted = false 379 Mutex_net.Unlock() 380 //fmt.Println("TCP server stopped") 381 } 382 383 var friends_pubkey_cache map[string][]byte 384 385 func ConnectFriends() { 386 common.CountSafe("ConnectFriends") 387 388 f, _ := os.Open(common.GocoinHomeDir + "friends.txt") 389 if f == nil { 390 return 391 } 392 defer f.Close() 393 394 var auth_pubkeys [][]byte 395 var special_agents []string 396 var special_ips [][4]byte 397 var addrs_to_connect []*peersdb.PeerAddr 398 friend_ids := make(map[uint64]bool) 399 400 new_pubkey_cache := make(map[string][]byte) 401 rd := bufio.NewReader(f) 402 if rd != nil { 403 for { 404 ln, _, er := rd.ReadLine() 405 if er != nil { 406 break 407 } 408 lns := strings.Trim(string(ln), " \r\n\t") 409 if len(lns) == 0 || lns[0] == '#' { 410 continue 411 } 412 ls := strings.SplitN(lns, " ", 2) 413 if len(ls[0]) > 1 { 414 var done bool 415 switch ls[0][0] { 416 case '@': 417 var pk []byte 418 pks := ls[0][1:] 419 if friends_pubkey_cache != nil { 420 pk = friends_pubkey_cache[pks] 421 //println(" - from cache:", len(pk)) 422 } 423 if pk == nil { 424 pk = btc.Decodeb58(pks) 425 } 426 if len(pk) == 33 { 427 new_pubkey_cache[pks] = pk 428 auth_pubkeys = append(auth_pubkeys, pk) 429 //println("Using Auth Key:", hex.EncodeToString(pk)) 430 } else { 431 println(pks, "is not a valid Auth Key. Check your friends.txt file") 432 } 433 434 case '+': 435 if ad, _ := peersdb.NewAddrFromString(ls[0][1:], false); ad != nil { 436 special_ips = append(special_ips, ad.Ip4) 437 } 438 439 case '*': 440 special_agents = append(special_agents, ls[0][1:]) 441 442 } 443 if done { 444 continue 445 } 446 } 447 if peersdb.ConnectOnly != "" { 448 // Do not connect to friends in single connection mode 449 continue 450 } 451 ad, _ := peersdb.NewAddrFromString(ls[0], false) 452 if ad != nil { 453 //println(" Trying to connect", ad.Ip()) 454 addrs_to_connect = append(addrs_to_connect, ad) 455 continue 456 } 457 } 458 } 459 if len(new_pubkey_cache) > 0 { 460 friends_pubkey_cache = new_pubkey_cache 461 } else { 462 friends_pubkey_cache = nil 463 } 464 FriendsAccess.Lock() 465 AuthPubkeys = auth_pubkeys 466 SpecialAgents = special_agents 467 SpecialIPs = special_ips 468 FriendsAccess.Unlock() 469 470 for _, ad := range addrs_to_connect { 471 Mutex_net.Lock() 472 curr := OpenCons[ad.UniqID()] 473 Mutex_net.Unlock() 474 if curr == nil { 475 ad.Friend = true 476 DoNetwork(ad) 477 } else { 478 curr.Mutex.Lock() 479 curr.PeerAddr.Friend = true 480 curr.X.IsSpecial = true 481 curr.Mutex.Unlock() 482 } 483 friend_ids[ad.UniqID()] = true 484 } 485 486 // Unmark those that are not longer friends 487 Mutex_net.Lock() 488 for _, v := range OpenCons { 489 v.Lock() 490 if v.PeerAddr.Friend && !friend_ids[v.PeerAddr.UniqID()] { 491 v.PeerAddr.Friend = false 492 if !v.PeerAddr.Manual { 493 v.X.IsSpecial = false 494 } 495 } 496 v.Unlock() 497 } 498 Mutex_net.Unlock() 499 } 500 501 func NetworkTick() { 502 if common.IsListenTCP() { 503 if !TCPServerStarted { 504 TCPServerStarted = true 505 go tcp_server() 506 } 507 } 508 509 now := time.Now() 510 511 // Push GetHeaders if not in progress 512 Mutex_net.Lock() 513 var cnt_headers_in_progress int 514 var max_headers_got_cnt int 515 var _v *OneConnection 516 for _, v := range OpenCons { 517 v.Mutex.Lock() // TODO: Sometimes it might hang here - check why!! 518 if !v.X.AllHeadersReceived || v.X.GetHeadersInProgress { 519 cnt_headers_in_progress++ 520 } else if !v.X.LastHeadersEmpty { 521 if _v == nil || v.X.TotalNewHeadersCount > max_headers_got_cnt { 522 max_headers_got_cnt = v.X.TotalNewHeadersCount 523 _v = v 524 } 525 } 526 v.Mutex.Unlock() 527 } 528 conn_cnt := OutConsActive 529 Mutex_net.Unlock() 530 531 if cnt_headers_in_progress == 0 { 532 if _v != nil { 533 common.CountSafe("GetHeadersPush") 534 /*println("No headers_in_progress, so take it from", _v.ConnID, 535 _v.X.TotalNewHeadersCount, _v.X.LastHeadersEmpty)*/ 536 _v.Mutex.Lock() 537 if _v.X.Debug { 538 println(_v.ConnID, "- GetHeadersPush") 539 } 540 _v.X.AllHeadersReceived = false 541 _v.Mutex.Unlock() 542 } else { 543 common.CountSafe("GetHeadersNone") 544 } 545 } 546 547 if common.CFG.DropPeers.DropEachMinutes != 0 { 548 if next_drop_peer.IsZero() { 549 next_drop_peer = now.Add(common.GetDuration(&common.DropSlowestEvery)) 550 } else if now.After(next_drop_peer) { 551 if drop_worst_peer() { 552 next_drop_peer = now.Add(common.GetDuration(&common.DropSlowestEvery)) 553 } else { 554 // If no peer dropped this time, try again sooner 555 next_drop_peer = now.Add(common.GetDuration(&common.DropSlowestEvery) >> 2) 556 } 557 } 558 } 559 560 // hammering protection - expire recently disconnected, but not more often than once a minute 561 if next_clean_hammers.IsZero() { 562 next_clean_hammers = now.Add(HammeringExpirePeriod) 563 } else if now.After(next_clean_hammers) { 564 HammeringMutex.Lock() 565 for k, t := range RecentlyDisconencted { 566 if now.Sub(t.Time) >= HammeringMinReconnect { 567 delete(RecentlyDisconencted, k) 568 } 569 } 570 HammeringMutex.Unlock() 571 next_clean_hammers = now.Add(HammeringExpirePeriod) 572 } 573 574 // Connect friends 575 Mutex_net.Lock() 576 if now.After(NextConnectFriends) { 577 Mutex_net.Unlock() 578 ConnectFriends() 579 Mutex_net.Lock() 580 NextConnectFriends = now.Add(15 * time.Minute) 581 } 582 Mutex_net.Unlock() 583 584 if conn_cnt < common.GetUint32(&common.CFG.Net.MaxOutCons) { 585 // First we will choose up to 128 peers that we have seen alive - do not sort them 586 adrs := peersdb.GetRecentPeers(128, false, func(ad *peersdb.PeerAddr) bool { 587 return ad.Banned != 0 || !ad.SeenAlive || (ad.Services&btc.SERVICE_SEGWIT) == 0 || ConnectionActive(ad) 588 }) 589 // now fetch another 32 never tried peers (this time sorted) 590 new_cnt := int(32) 591 if len(adrs) > new_cnt { 592 new_cnt = len(adrs) 593 } 594 adrs2 := peersdb.GetRecentPeers(uint(new_cnt), true, func(ad *peersdb.PeerAddr) bool { 595 return ad.Banned != 0 || ad.SeenAlive || (ad.Services&btc.SERVICE_SEGWIT) == 0 // ignore those that have been seen alive 596 }) 597 adrs = append(adrs, adrs2...) 598 // Now we should have 128 peers known to be alive and 32 never tried ones 599 // ... giving us 20% chance of selecting a never tried one. 600 if len(adrs) != 0 { 601 ad := adrs[rand.Int31n(int32(len(adrs)))] 602 //print("chosen ", ad.String(), "\n> ") 603 DoNetwork(ad) 604 } 605 } 606 607 if expireTxsNow { 608 ExpireTxs() 609 } else if now.After(lastTxsExpire.Add(time.Minute)) { 610 expireTxsNow = true 611 } 612 } 613 614 func (c *OneConnection) SendFeeFilter() { 615 var pl [8]byte 616 binary.LittleEndian.PutUint64(pl[:], c.X.LastMinFeePerKByte) 617 c.SendRawMsg("feefilter", pl[:]) 618 } 619 620 // GetMPDone should be called upon receiving "getmpdone" message or when the peer disconnects. 621 func (c *OneConnection) GetMPDone(pl []byte) { 622 if len(c.GetMP) == 0 { 623 return 624 } 625 if len(GetMPInProgressTicket) == 0 { 626 // This will happen when our chain is not yet synchronized and we are disconnecting a peer which have sent "authack" 627 return 628 } 629 630 if GetMPInProgressConnID.Get() != int(c.ConnID) { 631 if len(pl) < 1 { 632 <-c.GetMP 633 } else { 634 println("PEER", c.ConnID, "MISBEHAVE: Sent getmpdone but ticket", GetMPInProgressConnID.Get(), "held elsewere") 635 } 636 return 637 } 638 639 // the ticket is ours 640 if len(pl) < 1 || pl[0] == 0 { 641 <-c.GetMP 642 } else if c.SendGetMP() != nil { 643 <-c.GetMP 644 } else { 645 return 646 } 647 648 if len(GetMPInProgressTicket) == 0 { 649 // TODO: remove it at some point (should not be happening) 650 println("ERROR: GetMPDone() exiting without a ticket (will hang)") 651 } 652 <-GetMPInProgressTicket 653 } 654 655 // Run starts a process that handles communication with a single peer. 656 func (c *OneConnection) Run() { 657 defer func() { 658 if r := recover(); r != nil { 659 err, ok := r.(error) 660 if !ok { 661 err = fmt.Errorf("pkg: %v", r) 662 } 663 fmt.Println() 664 fmt.Println() 665 fmt.Println("********************** THIS SHOULD NOT HAPPEN **********************") 666 fmt.Println("Please report by sending email to piotr@gocoin.pl") 667 fmt.Println("or by logging new issue at https://github.com/piotrnar/gocoin/issues") 668 fmt.Println() 669 fmt.Println("Make sure to include the data below:") 670 fmt.Println() 671 fmt.Println(err.Error()) 672 fmt.Println(string(debug.Stack())) 673 fmt.Println() 674 fmt.Println("The node will likely malfunction now - it is advised to restart it.") 675 fmt.Println("************************ END OF REPORT ****************************") 676 } 677 }() 678 679 c.writing_thread_push = make(chan bool, 1) 680 681 c.SendVersion() 682 683 c.Mutex.Lock() 684 now := time.Now() 685 c.X.LastDataGot = now 686 c.nextMaintanence = now.Add(time.Minute) 687 c.LastPingSent = now.Add(5*time.Second - common.GetDuration(&common.PingPeerEvery)) // do first ping ~5 seconds from now 688 689 c.txsNxt = now.Add(TxsCounterPeriod) 690 c.txsCha = make(chan int, TxsCounterBufLen) 691 692 c.Mutex.Unlock() 693 694 next_tick := now 695 next_invs := now 696 697 c.writing_thread_done.Add(1) 698 go c.writing_thread() 699 700 for !c.IsBroken() { 701 cmd, read_tried := c.FetchMessage() 702 703 now = time.Now() 704 if c.X.VersionReceived && (c.sendInvsNow.Get() || now.After(next_invs)) { 705 c.SendInvs() 706 next_invs = now.Add(InvsFlushPeriod) 707 } 708 709 if now.After(next_tick) { 710 c.Tick(now) 711 next_tick = now.Add(PeerTickPeriod) 712 } 713 714 if cmd == nil { 715 if c.unfinished_getdata != nil && !c.SendingPaused() { 716 common.CountSafe("GetDataRestored") 717 tmp := c.unfinished_getdata.Bytes() 718 //println(c.ConnID, "restoring getdata for", len(tmp)/36, "invs") 719 c.unfinished_getdata = nil 720 c.processGetData(bytes.NewReader(tmp)) 721 } 722 723 if !read_tried { 724 // it will end up here if we did not even try to read anything because of BW limit 725 time.Sleep(10 * time.Millisecond) 726 } 727 continue 728 } 729 730 if c.X.VersionReceived { 731 c.PeerAddr.Alive() 732 } 733 734 if cmd.cmd == "version" { 735 if c.X.VersionReceived { 736 //println("VersionAgain from", c.ConnID, c.PeerAddr.Ip(), c.Node.Agent) 737 c.Misbehave("VersionAgain", 1000/10) 738 continue 739 } 740 er := c.HandleVersion(cmd.pl) 741 if er != nil { 742 //println("version msg error:", er.Error()) 743 c.DoS("Ver" + er.Error()) 744 break 745 } 746 if common.FLAG.Log { 747 f, _ := os.OpenFile("conn_log.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660) 748 if f != nil { 749 fmt.Fprintf(f, "%s: New connection. ID:%d Incomming:%t Addr:%s Version:%d Services:0x%x Agent:%s\n", 750 time.Now().Format("2006-01-02 15:04:05"), c.ConnID, c.X.Incomming, 751 c.PeerAddr.Ip(), c.Node.Version, c.Node.Services, c.Node.Agent) 752 f.Close() 753 } 754 } 755 c.X.LastMinFeePerKByte = common.MinFeePerKB() 756 757 if c.X.IsGocoin { 758 c.SendAuth() 759 } 760 761 if c.Node.Version >= 70012 && c.HasNetworkService() { 762 c.SendRawMsg("sendheaders", nil) 763 if c.Node.Version >= 70013 { 764 if c.X.LastMinFeePerKByte != 0 { 765 c.SendFeeFilter() 766 } 767 if c.Node.Version >= 70014 && common.GetBool(&common.CFG.TXPool.Enabled) { 768 if (c.Node.Services & btc.SERVICE_SEGWIT) == 0 { 769 // if the node does not support segwit, request compact blocks 770 // only if we have not achieved the segwit enforcement moment 771 if common.BlockChain.Consensus.Enforce_SEGWIT == 0 || 772 common.Last.BlockHeight() < common.BlockChain.Consensus.Enforce_SEGWIT { 773 c.SendRawMsg("sendcmpct", []byte{0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 774 } 775 } else { 776 c.SendRawMsg("sendcmpct", []byte{0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) 777 } 778 } 779 } 780 } 781 c.PeerAddr.Services = c.Node.Services 782 c.PeerAddr.NodeAgent = c.Node.Agent 783 c.PeerAddr.Alive() 784 785 if common.IsListenTCP() { 786 c.SendOwnAddr() 787 } 788 continue 789 } 790 791 switch cmd.cmd { 792 case "inv": 793 c.ProcessInv(cmd.pl) 794 795 case "tx": 796 if common.AcceptTx() { 797 c.ParseTxNet(cmd.pl) 798 } 799 800 case "addr": 801 c.ParseAddr(cmd.pl) 802 803 case "block": //block received 804 netBlockReceived(c, cmd.pl) 805 c.MutexSetBool(&c.X.GetBlocksDataNow, true) // ask for more blocks during next tick 806 807 case "getblocks": 808 c.GetBlocks(cmd.pl) 809 810 case "getdata": 811 c.ProcessGetData(cmd.pl) 812 813 case "getaddr": 814 if !c.X.GetAddrDone { 815 c.HandleGetaddr() 816 c.X.GetAddrDone = true 817 } else { 818 c.Mutex.Lock() 819 c.cntInc("SecondGetAddr") 820 c.Mutex.Unlock() 821 if c.Misbehave("SecondGetAddr", 1000/20) { 822 break 823 } 824 } 825 826 case "ping": 827 re := make([]byte, len(cmd.pl)) 828 copy(re, cmd.pl) 829 c.SendRawMsg("pong", re) 830 831 case "pong": 832 c.HandlePong(cmd.pl) 833 834 case "getheaders": 835 c.GetHeaders(cmd.pl) 836 837 case "notfound": 838 common.CountSafe("NotFound") 839 840 case "headers": 841 if c.HandleHeaders(cmd.pl) > 0 { 842 c.sendGetHeaders() 843 } 844 845 case "sendheaders": 846 c.Mutex.Lock() 847 c.Node.SendHeaders = true 848 c.Mutex.Unlock() 849 850 case "feefilter": 851 if len(cmd.pl) >= 8 { 852 c.X.MinFeeSPKB = int64(binary.LittleEndian.Uint64(cmd.pl[:8])) 853 //println(c.PeerAddr.Ip(), c.Node.Agent, "feefilter", c.X.MinFeeSPKB) 854 } 855 856 case "sendcmpct": 857 if len(cmd.pl) >= 9 { 858 version := binary.LittleEndian.Uint64(cmd.pl[1:9]) 859 c.Mutex.Lock() 860 if version > c.Node.SendCmpctVer { 861 //println(c.ConnID, "sendcmpct", cmd.pl[0]) 862 c.Node.SendCmpctVer = version 863 c.Node.HighBandwidth = cmd.pl[0] == 1 864 } else { 865 c.cntInc(fmt.Sprint("SendCmpctV", version)) 866 } 867 c.Mutex.Unlock() 868 } else { 869 common.CountSafe("SendCmpctErr") 870 if len(cmd.pl) != 5 { 871 println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "sendcmpct", hex.EncodeToString(cmd.pl)) 872 } 873 } 874 875 case "cmpctblock": 876 if common.GetBool(&common.BlockChainSynchronized) { 877 c.ProcessCmpctBlock(cmd.pl) 878 } 879 880 case "getblocktxn": 881 c.ProcessGetBlockTxn(cmd.pl) 882 //println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "getblocktxn", hex.EncodeToString(cmd.pl)) 883 884 case "blocktxn": 885 c.ProcessBlockTxn(cmd.pl) 886 //println(c.ConnID, c.PeerAddr.Ip(), c.Node.Agent, "blocktxn", hex.EncodeToString(cmd.pl)) 887 888 case "getmp": 889 if c.X.Authorized { 890 c.ProcessGetMP(cmd.pl) 891 } 892 893 case "auth": 894 c.AuthRvcd(cmd.pl) 895 896 case "authack": 897 c.Mutex.Lock() 898 c.X.AuthAckGot = true 899 c.Mutex.Unlock() 900 if len(cmd.pl) > 0 { 901 // if there is payload, the first byte says if the node is synchronized 902 c.X.ChainSynchronized = cmd.pl[0] != 0 903 } 904 if c.X.ChainSynchronized { 905 c.GetMPNow() // No point in asking non-synched nodes for their mempool 906 } 907 908 case "getmpdone": 909 c.GetMPDone(cmd.pl) 910 911 case "filterload", "filteradd", "filterclear", "merkleblock": 912 c.DoS("SPV") 913 914 default: 915 } 916 } 917 918 c.GetMPDone(nil) // release the ticket, if kept 919 920 c.Conn.SetWriteDeadline(time.Now()) // this should cause c.Conn.Write() to terminate 921 c.writing_thread_done.Wait() 922 923 c.Mutex.Lock() 924 MutexRcv.Lock() 925 for k := range c.GetBlockInProgress { 926 if rec, ok := BlocksToGet[k]; ok { 927 rec.InProgress-- 928 } 929 } 930 MutexRcv.Unlock() 931 932 ban := c.banit 933 c.Mutex.Unlock() 934 935 if c.PeerAddr.Friend || c.X.Authorized { 936 common.CountSafe(fmt.Sprint("FDisconnect-", ban)) 937 } else { 938 if ban { 939 c.PeerAddr.Ban(c.ban_reason) 940 common.CountSafe("PeersBanned") 941 } else if c.X.Incomming && !c.MutexGetBool(&c.X.IsSpecial) { 942 var rd *RecentlyDisconenctedType 943 HammeringMutex.Lock() 944 rd = RecentlyDisconencted[c.PeerAddr.NetAddr.Ip4] 945 if rd == nil { 946 rd = &RecentlyDisconenctedType{Time: time.Now(), Count: 1} 947 } 948 rd.Why = c.why_disconnected 949 RecentlyDisconencted[c.PeerAddr.NetAddr.Ip4] = rd 950 HammeringMutex.Unlock() 951 } 952 } 953 c.Conn.Close() 954 } 955 956 func init() { 957 rand.Seed(time.Now().UnixNano()) 958 }