github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/usif/textui/network.go (about)

     1  package textui
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"sort"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/piotrnar/gocoin/client/common"
    12  	"github.com/piotrnar/gocoin/client/network"
    13  	"github.com/piotrnar/gocoin/client/network/peersdb"
    14  )
    15  
    16  type SortedKeys []struct {
    17  	Key    uint64
    18  	ConnID uint32
    19  }
    20  
    21  func (sk SortedKeys) Len() int {
    22  	return len(sk)
    23  }
    24  
    25  func (sk SortedKeys) Less(a, b int) bool {
    26  	return sk[a].ConnID < sk[b].ConnID
    27  }
    28  
    29  func (sk SortedKeys) Swap(a, b int) {
    30  	sk[a], sk[b] = sk[b], sk[a]
    31  }
    32  
    33  func net_drop(par string) {
    34  	conid, e := strconv.ParseUint(par, 10, 32)
    35  	if e != nil {
    36  		println(e.Error())
    37  		return
    38  	}
    39  	network.DropPeer(uint32(conid))
    40  }
    41  
    42  func node_info(par string) {
    43  	conid, e := strconv.ParseUint(par, 10, 32)
    44  	if e != nil {
    45  		return
    46  	}
    47  
    48  	var r *network.ConnInfo
    49  
    50  	network.Mutex_net.Lock()
    51  
    52  	for _, v := range network.OpenCons {
    53  		if uint32(conid) == v.ConnID {
    54  			r = new(network.ConnInfo)
    55  			v.GetStats(r)
    56  			break
    57  		}
    58  	}
    59  	network.Mutex_net.Unlock()
    60  
    61  	if r == nil {
    62  		return
    63  	}
    64  
    65  	fmt.Printf("Connection ID %d:\n", r.ID)
    66  	if r.Incomming {
    67  		fmt.Println("Coming from", r.PeerIp)
    68  	} else {
    69  		fmt.Println("Going to", r.PeerIp)
    70  	}
    71  	if !r.ConnectedAt.IsZero() {
    72  		fmt.Println("Connected at", r.ConnectedAt.Format("2006-01-02 15:04:05"))
    73  		if r.Version != 0 {
    74  			fmt.Println("Node Version:", r.Version, "/ Services:", fmt.Sprintf("0x%x", r.Services))
    75  			fmt.Println("User Agent:", r.Agent)
    76  			fmt.Println("Chain Height:", r.Height)
    77  			fmt.Printf("Reported IP: %d.%d.%d.%d\n", byte(r.ReportedIp4>>24), byte(r.ReportedIp4>>16),
    78  				byte(r.ReportedIp4>>8), byte(r.ReportedIp4))
    79  			fmt.Println("SendHeaders:", r.SendHeaders)
    80  		}
    81  		fmt.Println("Invs Done:", r.InvsDone)
    82  		fmt.Println("Last data got:", time.Since(r.LastDataGot).String())
    83  		fmt.Println("Last data sent:", time.Since(r.LastSent).String())
    84  		fmt.Println("Last command received:", r.LastCmdRcvd, " ", r.LastBtsRcvd, "bytes")
    85  		fmt.Println("Last command sent:", r.LastCmdSent, " ", r.LastBtsSent, "bytes")
    86  		fmt.Print("Invs  Recieved:", r.InvsRecieved, "  Pending:", r.InvsToSend, "\n")
    87  		fmt.Print("Bytes to send:", r.BytesToSend, " (", r.MaxSentBufSize, " max)\n")
    88  		fmt.Print("BlockInProgress:", r.BlocksInProgress, "  GetHeadersInProgress:", r.GetHeadersInProgress, "\n")
    89  		fmt.Println("GetBlocksDataNow:", r.GetBlocksDataNow)
    90  		fmt.Println("AllHeadersReceived:", r.AllHeadersReceived)
    91  		fmt.Println("Total Received:", r.BytesReceived, " /  Sent:", r.BytesSent)
    92  		mts := make(map[string]bool)
    93  		var had bool
    94  		for k, v := range r.Counters {
    95  			if len(k) > 5 && strings.HasPrefix(k, "rbts_") || strings.HasPrefix(k, "sbts_") ||
    96  				strings.HasPrefix(k, "rcvd_") || strings.HasPrefix(k, "sent_") {
    97  				mts[k[5:]] = true
    98  			} else {
    99  				fmt.Print(k, ":", v, "  ")
   100  				had = true
   101  			}
   102  		}
   103  		if had {
   104  			fmt.Println()
   105  		}
   106  		mms := make([]string, 0, len(mts))
   107  		for k := range mts {
   108  			mms = append(mms, k)
   109  		}
   110  		sort.Strings(mms)
   111  		for _, msg := range mms {
   112  			fmt.Printf("\t%-12s      R:[%8d | %10s]     S:[%8d | %10s]\n", msg,
   113  				r.Counters["rcvd_"+msg], common.BytesToString(r.Counters["rbts_"+msg]),
   114  				r.Counters["sent_"+msg], common.BytesToString(r.Counters["sbts_"+msg]))
   115  		}
   116  	} else {
   117  		fmt.Println("Not yet connected")
   118  	}
   119  }
   120  
   121  func net_conn(par string) {
   122  	ad, er := peersdb.NewAddrFromString(par, false)
   123  	if er != nil {
   124  		fmt.Println(par, er.Error())
   125  		return
   126  	}
   127  	fmt.Println("Connecting to", ad.Ip())
   128  	ad.Manual = true
   129  	network.DoNetwork(ad)
   130  }
   131  
   132  func net_stats(par string) {
   133  	if par == "bw" {
   134  		common.PrintBWStats()
   135  		return
   136  	} else if par != "" {
   137  		node_info(par)
   138  		return
   139  	}
   140  
   141  	network.Mutex_net.Lock()
   142  	fmt.Printf("%d active net connections, %d outgoing\n", len(network.OpenCons), network.OutConsActive)
   143  	srt := make(SortedKeys, len(network.OpenCons))
   144  	cnt := 0
   145  	for k, v := range network.OpenCons {
   146  		srt[cnt].Key = k
   147  		srt[cnt].ConnID = v.ConnID
   148  		cnt++
   149  	}
   150  	sort.Sort(srt)
   151  	for idx := range srt {
   152  		v := network.OpenCons[srt[idx].Key]
   153  		v.Mutex.Lock()
   154  		fmt.Printf("%8d) ", v.ConnID)
   155  
   156  		if v.X.Incomming {
   157  			fmt.Print("<- ")
   158  		} else {
   159  			fmt.Print(" ->")
   160  		}
   161  		fmt.Printf(" %21s %5dms", v.PeerAddr.Ip(), v.GetAveragePing())
   162  		//fmt.Printf(" %7d : %-16s %7d : %-16s", v.X.LastBtsRcvd, v.X.LastCmdRcvd, v.X.LastBtsSent, v.X.LastCmdSent)
   163  		fmt.Printf(" %10s %10s", common.BytesToString(v.X.BytesReceived), common.BytesToString(v.X.BytesSent))
   164  		if len(v.GetBlockInProgress) != 0 {
   165  			fmt.Printf(" %4d", len(v.GetBlockInProgress))
   166  		} else {
   167  			fmt.Print("     ")
   168  		}
   169  		fmt.Print("  ", v.Node.Agent)
   170  		if v.X.IsSpecial {
   171  			fmt.Print(" F")
   172  		}
   173  
   174  		if b2s := v.BytesToSent(); b2s > 0 {
   175  			fmt.Print("  ", b2s)
   176  		}
   177  		v.Mutex.Unlock()
   178  		fmt.Println()
   179  	}
   180  
   181  	if network.ExternalAddrLen() > 0 {
   182  		fmt.Print("External addresses:")
   183  		network.ExternalIpMutex.Lock()
   184  		for ip, cnt := range network.ExternalIp4 {
   185  			fmt.Printf(" %d.%d.%d.%d(%d)", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip), cnt)
   186  		}
   187  		network.ExternalIpMutex.Unlock()
   188  		fmt.Println()
   189  	} else {
   190  		fmt.Println("No known external address")
   191  	}
   192  
   193  	network.Mutex_net.Unlock()
   194  
   195  	fmt.Println("GetMPInProgress:", len(network.GetMPInProgressTicket) != 0)
   196  
   197  	common.PrintBWStats()
   198  }
   199  
   200  func net_rd(par string) {
   201  	network.HammeringMutex.Lock()
   202  	srt := make([]string, len(network.RecentlyDisconencted))
   203  	var idx int
   204  	for ip, rd := range network.RecentlyDisconencted {
   205  		srt[idx] = fmt.Sprintf("%31d %16s %3d %16s - %s", rd.Time.UnixNano(),
   206  			fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]), rd.Count,
   207  			time.Since(rd.Time).String(), rd.Why)
   208  		idx++
   209  	}
   210  	sort.Strings(srt)
   211  	network.HammeringMutex.Unlock()
   212  	fmt.Println("Recently disconencted incoming connections:")
   213  	for _, s := range srt {
   214  		fmt.Println(s[32:])
   215  	}
   216  	fmt.Println("Baned if", network.HammeringMaxAllowedCount+1, "conections (within", network.HammeringMinReconnect,
   217  		"...", network.HammeringMinReconnect+network.HammeringExpirePeriod, "in between)")
   218  }
   219  
   220  func net_friends(par string) {
   221  	network.FriendsAccess.Lock()
   222  	for _, pk := range network.AuthPubkeys {
   223  		fmt.Println("Pubkey", hex.EncodeToString(pk))
   224  	}
   225  	for _, ua := range network.SpecialAgents {
   226  		fmt.Println("Agent Prefix", ua)
   227  	}
   228  	for _, p := range network.SpecialIPs {
   229  		fmt.Println("IP ", fmt.Sprintf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]))
   230  	}
   231  	network.FriendsAccess.Unlock()
   232  }
   233  
   234  func print_fetch_counters() {
   235  	network.MutexRcv.Lock()
   236  	defer network.MutexRcv.Unlock()
   237  	fmt.Print("\t")
   238  	fmt.Print("NoBlocksToGet:", network.Fetch.NoBlocksToGet)
   239  	fmt.Print(",  HasBlocksExpired:", network.Fetch.HasBlocksExpired)
   240  	fmt.Print(",  MaxCountInProgress:", network.Fetch.MaxCountInProgress)
   241  	fmt.Print("\n\t")
   242  	fmt.Print("MaxBytesInProgress:", network.Fetch.MaxBytesInProgress)
   243  	fmt.Print(",  NoWitness:", network.Fetch.NoWitness)
   244  	fmt.Print(",  Nothing:", network.Fetch.Nothing)
   245  	fmt.Print("\n\t")
   246  	fmt.Print("ReachEndOfLoop:", network.Fetch.ReachEndOfLoop)
   247  	fmt.Print(",  ReachMaxCnt:", network.Fetch.ReachMaxCnt)
   248  	fmt.Print(",  ReachMaxData:", network.Fetch.ReachMaxData)
   249  	fmt.Print("\n\tBlksCntMax   ")
   250  	for i, v := range network.Fetch.BlksCntMax {
   251  		if v != 0 {
   252  			fmt.Print("  x", i, ":", v)
   253  		}
   254  	}
   255  	fmt.Println()
   256  }
   257  
   258  func sync_stats(par string) {
   259  	common.Last.Mutex.Lock()
   260  	lb := common.Last.Block.Height
   261  	common.Last.Mutex.Unlock()
   262  
   263  	network.MutexRcv.Lock()
   264  	li2get := network.LowestIndexToBlocksToGet
   265  	network.MutexRcv.Unlock()
   266  
   267  	network.CachedBlocksMutex.Lock()
   268  	lencb := len(network.CachedBlocks)
   269  	network.CachedBlocksMutex.Unlock()
   270  
   271  	fmt.Printf("@%d\tReady: %d   InCacheCnt: %d   Avg.Bl.Size: %d   EmptyCache: %d\n",
   272  		lb, li2get-lb-1, lencb,
   273  		common.AverageBlockSize.Get(), network.Fetch.CacheEmpty)
   274  	tot := common.DlBytesTotal
   275  	if tot > 0 {
   276  		wst := network.Fetch.BlockBytesWasted
   277  		fmt.Printf("\tWasted %d blocks carrying %d / %dMB, which was %.2f%% of total DL bandwidth\n",
   278  			network.Fetch.BlockSameRcvd, wst>>20, tot>>20, 100*float64(wst)/float64(tot))
   279  	}
   280  
   281  	if strings.Contains(par, "c") {
   282  		var lowest_cached_height, highest_cached_height uint32
   283  		var ready_cached_cnt uint32
   284  		var cached_ready_bytes int
   285  		m := make(map[uint32]*network.BlockRcvd)
   286  		for _, b := range network.CachedBlocks {
   287  			bh := b.BlockTreeNode.Height
   288  			m[bh] = b
   289  			if lowest_cached_height == 0 {
   290  				lowest_cached_height, highest_cached_height = bh, bh
   291  			} else if b.BlockTreeNode.Height < lowest_cached_height {
   292  				lowest_cached_height = bh
   293  			} else if bh > highest_cached_height {
   294  				highest_cached_height = bh
   295  			}
   296  		}
   297  		for {
   298  			if b, ok := m[lb+ready_cached_cnt+1]; ok {
   299  				ready_cached_cnt++
   300  				cached_ready_bytes += b.Size
   301  			} else {
   302  				break
   303  			}
   304  		}
   305  		fmt.Printf("\tCache Ready: %d:%dMB   Used: %d:%dMB   Limit: %dMB   Max Used: %d%%\n",
   306  			ready_cached_cnt, cached_ready_bytes>>20, lencb, network.CachedBlocksBytes.Get()>>20,
   307  			common.SyncMaxCacheBytes.Get()>>20,
   308  			100*network.MaxCachedBlocksSize.Get()/common.SyncMaxCacheBytes.Get())
   309  	} else {
   310  		fmt.Printf("\tCache Used: %d:%dMB   Limit: %dMB   Max Used: %d%%\n",
   311  			lencb, network.CachedBlocksBytes.Get()>>20, common.SyncMaxCacheBytes.Get()>>20,
   312  			100*network.MaxCachedBlocksSize.Get()/common.SyncMaxCacheBytes.Get())
   313  	}
   314  
   315  	if strings.Contains(par, "x") {
   316  		var bip_cnt, ip_min, ip_max uint32
   317  		network.MutexRcv.Lock()
   318  		for _, bip := range network.BlocksToGet {
   319  			if bip.InProgress > 0 {
   320  				if ip_min == 0 {
   321  					ip_min = bip.BlockTreeNode.Height
   322  					ip_max = ip_min
   323  				} else if bip.BlockTreeNode.Height < ip_min {
   324  					ip_min = bip.BlockTreeNode.Height
   325  				} else if bip.BlockTreeNode.Height > ip_max {
   326  					ip_max = bip.BlockTreeNode.Height
   327  				}
   328  				bip_cnt++
   329  			}
   330  		}
   331  		network.MutexRcv.Unlock()
   332  		fmt.Printf("\tIn Progress: %d, starting from %d, up to %d (%d)\n",
   333  			bip_cnt, ip_min, ip_max, ip_max-ip_min)
   334  	}
   335  
   336  	if d := network.Fetc.HeightD; d != 0 {
   337  		a := network.Fetc.HeightA
   338  		if siz := d - a; siz > 0 {
   339  			b := network.Fetc.HeightB
   340  			c := network.Fetc.HeightC
   341  			fil := b - a
   342  			fmt.Printf("\tLast Fetch from %d:%d to %d:%d -> BTG:%d (ready %d%% of %d)\n", a, b, d, c,
   343  				network.Fetc.B2G, 100*fil/siz, siz)
   344  		}
   345  	}
   346  
   347  	max_blocks_at_once := common.GetUint32(&common.CFG.Net.MaxBlockAtOnce)
   348  	fmt.Print("\t")
   349  	for i := uint32(0); i < max_blocks_at_once; i++ {
   350  		cnt := network.Fetc.C[i]
   351  		if cnt == 0 {
   352  			fmt.Printf("  C%d:-", i)
   353  		} else {
   354  			fmt.Printf("  C%d:%d", i, cnt)
   355  		}
   356  	}
   357  	fmt.Println()
   358  
   359  	print_fetch_counters()
   360  	if strings.Contains(par, "r") {
   361  		common.CountSafeStore("BlocksUnderflowCount", 0)
   362  		println("Error counter set to 0")
   363  	}
   364  }
   365  
   366  func init() {
   367  	newUi("net n", false, net_stats, "Show network statistics. Specify ID to see its details.")
   368  	newUi("drop", false, net_drop, "Disconenct from node with a given IP")
   369  	newUi("conn", false, net_conn, "Connect to the given node (specify IP and optionally a port)")
   370  	newUi("rd", false, net_rd, "Show recently disconnected incoming connections")
   371  	newUi("friends", false, net_friends, "Show current friends settings")
   372  	newUi("ss", true, sync_stats, "Show chain sync statistics. Add charecter 'c' (cache), 'x' (in progress) or 'r' (reset couter)")
   373  }