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 }