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  }