github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/common/common.go (about) 1 package common 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "log" 8 "os" 9 "runtime" 10 "sync" 11 "sync/atomic" 12 "time" 13 14 "github.com/piotrnar/gocoin/lib/btc" 15 "github.com/piotrnar/gocoin/lib/chain" 16 "github.com/piotrnar/gocoin/lib/others/memory" 17 "github.com/piotrnar/gocoin/lib/others/sys" 18 "github.com/piotrnar/gocoin/lib/others/utils" 19 ) 20 21 const ( 22 Version = uint32(70015) 23 ) 24 25 var ( 26 Services uint64 = btc.SERVICE_SEGWIT | btc.SERVICE_NETWORK_LIMITED // It updates this value in InitConfig() 27 28 LogBuffer = new(bytes.Buffer) 29 Log *log.Logger = log.New(LogBuffer, "", 0) 30 31 BlockChain *chain.Chain 32 GenesisBlock *btc.Uint256 33 Magic [4]byte 34 Testnet bool 35 36 Last TheLastBlock 37 38 GocoinHomeDir string 39 StartTime time.Time 40 41 CounterMutex sync.Mutex 42 Counter map[string]uint64 = make(map[string]uint64) 43 44 busyLine int32 45 46 NetworkClosed sys.SyncBool 47 48 AverageBlockSize sys.SyncInt 49 avg_bsize_history []uint32 50 avg_bsize_idx int 51 avg_bsize_next uint32 52 avg_bsize_sum uint 53 54 allBalMinVal uint64 55 56 DropSlowestEvery time.Duration 57 BlockExpireEvery time.Duration 58 PingPeerEvery time.Duration 59 60 UserAgent string 61 62 ListenTCP bool 63 64 minFeePerKB, routeMinFeePerKB, minminFeePerKB uint64 65 maxMempoolSizeBytes, maxRejectedSizeBytes uint64 66 67 KillChan chan os.Signal = make(chan os.Signal) 68 69 SecretKey []byte // 32 bytes of secret key 70 PublicKey string 71 72 WalletON bool 73 WalletProgress uint32 // 0 for not / 1000 for max 74 WalletOnIn uint32 75 76 BlockChainSynchronized bool 77 78 lastTrustedBlock *btc.Uint256 79 LastTrustedBlockHeight uint32 80 81 Memory memory.Allocator 82 MemMutex sync.Mutex 83 84 NoCounters sys.SyncBool 85 86 SyncMaxCacheBytes sys.SyncInt 87 ) 88 89 type TheLastBlock struct { 90 sync.Mutex // use it for writing and reading from non-chain thread 91 Block *chain.BlockTreeNode 92 time.Time 93 ParseTill *chain.BlockTreeNode 94 ScriptFlags uint32 95 } 96 97 func (b *TheLastBlock) BlockHeight() (res uint32) { 98 b.Mutex.Lock() 99 res = b.Block.Height 100 b.Mutex.Unlock() 101 return 102 } 103 104 func CountSafe(k string) { 105 if !NoCounters.Get() { 106 CounterMutex.Lock() 107 Counter[k]++ 108 CounterMutex.Unlock() 109 } 110 } 111 112 func CountSafeAdd(k string, val uint64) { 113 if !NoCounters.Get() { 114 CounterMutex.Lock() 115 Counter[k] += val 116 CounterMutex.Unlock() 117 } 118 } 119 120 func CountSafeStore(k string, val uint64) { 121 if !NoCounters.Get() { 122 CounterMutex.Lock() 123 Counter[k] = val 124 CounterMutex.Unlock() 125 } 126 } 127 128 func CounterGet(k string) (val uint64) { 129 CounterMutex.Lock() 130 val = Counter[k] 131 CounterMutex.Unlock() 132 return 133 } 134 135 func Count(k string) { 136 if !NoCounters.Get() { 137 Counter[k]++ 138 } 139 } 140 141 func CountAdd(k string, val uint64) { 142 if !NoCounters.Get() { 143 Counter[k] += val 144 } 145 } 146 147 func Busy() { 148 var line int 149 _, _, line, _ = runtime.Caller(1) 150 atomic.StoreInt32(&busyLine, int32(line)) 151 } 152 153 func BusyIn() int { 154 return int(atomic.LoadInt32(&busyLine)) 155 } 156 157 func BytesToString(val uint64) string { 158 if val < 1e6 { 159 return fmt.Sprintf("%.1f KB", float64(val)/1e3) 160 } else if val < 1e9 { 161 return fmt.Sprintf("%.2f MB", float64(val)/1e6) 162 } 163 return fmt.Sprintf("%.2f GB", float64(val)/1e9) 164 } 165 166 //max 6 characters 167 func UintToString(num uint64) string { 168 if num < 1e5 { 169 return fmt.Sprint(num) + " " 170 } 171 if num < 10e6 { 172 return fmt.Sprintf("%.0f K", float64(num)/1e3) 173 } 174 if num < 10e7 { 175 return fmt.Sprintf("%.1f M", float64(num)/1e6) 176 } 177 if num < 10e9 { 178 return fmt.Sprintf("%.0f M", float64(num)/1e6) 179 } 180 if num < 10e10 { 181 return fmt.Sprintf("%.1f G", float64(num)/1e9) 182 } 183 if num < 10e12 { 184 return fmt.Sprintf("%.0f G", float64(num)/1e9) 185 } 186 if num < 10e13 { 187 return fmt.Sprintf("%.1f T", float64(num)/1e12) 188 } 189 if num < 10e15 { 190 return fmt.Sprintf("%.0f T", float64(num)/1e12) 191 } 192 if num < 10e16 { 193 return fmt.Sprintf("%.1f P", float64(num)/1e15) 194 } 195 if num < 10e18 { 196 return fmt.Sprintf("%.0f P", float64(num)/1e15) 197 } 198 return fmt.Sprintf("%.1f E", float64(num)/1e18) 199 } 200 201 func FloatToString(num float64) string { 202 if num > 1e24 { 203 return fmt.Sprintf("%.2f Y", num/1e24) 204 } 205 if num > 1e21 { 206 return fmt.Sprintf("%.2f Z", num/1e21) 207 } 208 if num > 1e18 { 209 return fmt.Sprintf("%.2f E", num/1e18) 210 } 211 if num > 1e15 { 212 return fmt.Sprintf("%.2f P", num/1e15) 213 } 214 if num > 1e12 { 215 return fmt.Sprintf("%.2f T", num/1e12) 216 } 217 if num > 1e9 { 218 return fmt.Sprintf("%.2f G", num/1e9) 219 } 220 if num > 1e6 { 221 return fmt.Sprintf("%.2f M", num/1e6) 222 } 223 if num > 1e3 { 224 return fmt.Sprintf("%.2f K", num/1e3) 225 } 226 return fmt.Sprintf("%.2f", num) 227 } 228 229 func HashrateToString(hr float64) string { 230 return FloatToString(hr) + "H/s" 231 } 232 233 // RecalcAverageBlockSize calculates the average blocks size over the last 2016 blocks. 234 // Only call from blockchain thread. 235 func RecalcAverageBlockSize() { 236 var le uint 237 var new_avg_size int 238 mutex_cfg.Lock() 239 AVG_BSIZE_SPAN := int(CFG.Stat.BSizeBlks) 240 mutex_cfg.Unlock() 241 n := BlockChain.LastBlock() 242 new_height := n.Height 243 if avg_bsize_next != 0 && n.Height == avg_bsize_next { 244 le = uint(n.BlockSize) 245 if len(avg_bsize_history) == AVG_BSIZE_SPAN { 246 if avg_bsize_idx >= AVG_BSIZE_SPAN { 247 avg_bsize_idx = 0 248 } 249 avg_bsize_sum -= uint(avg_bsize_history[avg_bsize_idx]) 250 avg_bsize_history[avg_bsize_idx] = uint32(le) 251 } else { 252 avg_bsize_history = append(avg_bsize_history, uint32(le)) 253 } 254 avg_bsize_idx++ 255 avg_bsize_sum += le 256 new_avg_size = int(avg_bsize_sum) / len(avg_bsize_history) 257 } else { 258 //println("Recalc avg_bsize @", new_height) 259 avg_bsize_history = make([]uint32, 0, AVG_BSIZE_SPAN) 260 avg_bsize_idx = 0 261 avg_bsize_sum = 0 262 for maxcnt := AVG_BSIZE_SPAN; maxcnt > 0 && n != nil; maxcnt-- { 263 le = uint(n.BlockSize) 264 avg_bsize_history = append(avg_bsize_history, uint32(le)) 265 avg_bsize_idx++ 266 avg_bsize_sum += le 267 n = n.Parent 268 } 269 hl := len(avg_bsize_history) 270 for i := 0; i < hl>>1; i++ { 271 avg_bsize_history[i], avg_bsize_history[hl-1-i] = avg_bsize_history[hl-1-i], avg_bsize_history[i] 272 } 273 274 if avg_bsize_sum == 0 || avg_bsize_idx == 0 { 275 new_avg_size = 204 276 } else { 277 new_avg_size = int(avg_bsize_sum) / avg_bsize_idx 278 } 279 } 280 AverageBlockSize.Store(new_avg_size) 281 avg_bsize_next = new_height + 1 282 } 283 284 func GetRawTx(BlockHeight uint32, txid *btc.Uint256) (data []byte, er error) { 285 data, er = BlockChain.GetRawTx(BlockHeight, txid) 286 if er != nil { 287 if Testnet { 288 data = utils.GetTestnetTxFromWeb(txid) 289 } else { 290 data = utils.GetTxFromWeb(txid) 291 } 292 if data != nil { 293 er = nil 294 } else { 295 er = errors.New("GetRawTx and GetTxFromWeb failed for " + txid.String()) 296 } 297 } 298 return 299 } 300 301 func WalletPendingTick() (res bool) { 302 mutex_cfg.Lock() 303 if WalletOnIn > 0 && BlockChainSynchronized { 304 WalletOnIn-- 305 res = WalletOnIn == 0 306 } 307 mutex_cfg.Unlock() 308 return 309 } 310 311 // Make sure to call it with mutex_cfg locked 312 func ApplyLTB(hash *btc.Uint256, height uint32) { 313 if height != 0 && LastTrustedBlockHeight > height { 314 return // Do not apply if older bock than the current one we have 315 } 316 lastTrustedBlock = hash 317 LastTrustedBlockHeight = height 318 319 if hash != nil && BlockChain != nil { 320 BlockChain.BlockIndexAccess.Lock() 321 node := BlockChain.BlockIndex[hash.BIdx()] 322 BlockChain.BlockIndexAccess.Unlock() 323 if node != nil { 324 LastTrustedBlockHeight = node.Height 325 for node != nil { 326 node.Trusted.Set() 327 node = node.Parent 328 } 329 } 330 } 331 } 332 333 // Make sure to call it with mutex_cfg locked 334 func ApplyLastTrustedBlock() { 335 ApplyLTB(btc.NewUint256FromString(CFG.LastTrustedBlock), 0) 336 } 337 338 func LastTrustedBlockMatch(h *btc.Uint256) (res bool) { 339 mutex_cfg.Lock() 340 res = lastTrustedBlock != nil && lastTrustedBlock.Equal(h) 341 mutex_cfg.Unlock() 342 return 343 } 344 345 func AcceptTx() (res bool) { 346 mutex_cfg.Lock() 347 res = CFG.TXPool.Enabled && BlockChainSynchronized 348 mutex_cfg.Unlock() 349 return 350 } 351 352 func UpdateScriptFlags(flags uint32) { 353 if flags == 0 { 354 // We pass timestamp of 0 to always use P2SH flag 355 flags = BlockChain.GetBlockFlags(Last.Block.Height, 0) 356 } 357 atomic.StoreUint32(&Last.ScriptFlags, flags) 358 } 359 360 func CurrentScriptFlags() uint32 { 361 return atomic.LoadUint32(&Last.ScriptFlags) 362 } 363 364 func MemUsed() (bts int, alcs int) { 365 MemMutex.Lock() 366 bts, alcs = Memory.Bytes, Memory.Allocs 367 MemMutex.Unlock() 368 return 369 }