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  }