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

     1  package webui
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"time"
     7  
     8  	//	"bytes"
     9  	//	"regexp"
    10  	"encoding/binary"
    11  	"encoding/json"
    12  	"net/http"
    13  
    14  	"github.com/piotrnar/gocoin/client/common"
    15  	"github.com/piotrnar/gocoin/lib/btc"
    16  )
    17  
    18  type OneMinedBlock struct {
    19  	Height  uint32
    20  	Version uint32
    21  	Length  int
    22  	Fees    uint64
    23  	Strings string
    24  }
    25  
    26  type omv struct {
    27  	unknown_miner bool
    28  	bts           uint64
    29  	fees          uint64
    30  	blocks        []OneMinedBlock
    31  	//ebad_cnt int
    32  	//nya_cnt int
    33  }
    34  
    35  type onemiernstat []struct {
    36  	name string
    37  	omv
    38  }
    39  
    40  func (x onemiernstat) Len() int {
    41  	return len(x)
    42  }
    43  
    44  func (x onemiernstat) Less(i, j int) bool {
    45  	if len(x[i].blocks) == len(x[j].blocks) {
    46  		return x[i].name < x[j].name // Same numbers: sort by name
    47  	}
    48  	return len(x[i].blocks) > len(x[j].blocks)
    49  }
    50  
    51  func (x onemiernstat) Swap(i, j int) {
    52  	x[i], x[j] = x[j], x[i]
    53  }
    54  
    55  func p_miners(w http.ResponseWriter, r *http.Request) {
    56  	if !ipchecker(r) {
    57  		return
    58  	}
    59  
    60  	write_html_head(w, r)
    61  	w.Write([]byte(load_template("miners.html")))
    62  	write_html_tail(w)
    63  }
    64  
    65  func json_blkver(w http.ResponseWriter, r *http.Request) {
    66  	if !ipchecker(r) {
    67  		return
    68  	}
    69  
    70  	w.Header()["Content-Type"] = []string{"application/json"}
    71  
    72  	common.Last.Mutex.Lock()
    73  	end := common.Last.Block
    74  	common.Last.Mutex.Unlock()
    75  
    76  	w.Write([]byte("["))
    77  	if end != nil {
    78  		max_cnt := 2 * 2016 //common.BlockChain.Consensus.Window
    79  		for {
    80  			w.Write([]byte(fmt.Sprint("[", end.Height, ",", binary.LittleEndian.Uint32(end.BlockHeader[0:4]), "]")))
    81  			end = end.Parent
    82  			if end == nil || max_cnt <= 1 {
    83  				break
    84  			}
    85  			max_cnt--
    86  			w.Write([]byte(","))
    87  		}
    88  	}
    89  	w.Write([]byte("]"))
    90  }
    91  
    92  func json_miners(w http.ResponseWriter, r *http.Request) {
    93  	if !ipchecker(r) {
    94  		return
    95  	}
    96  
    97  	type one_miner_row struct {
    98  		Unknown               bool
    99  		Name                  string
   100  		Blocks                int
   101  		TotalFees, TotalBytes uint64
   102  		MinedBlocks           []OneMinedBlock
   103  		//BUcnt, NYAcnt int
   104  	}
   105  
   106  	type the_mining_stats struct {
   107  		MiningStatHours  uint
   108  		BlockCount       uint
   109  		FirstBlockTime   int64
   110  		AvgBlocksPerHour float64
   111  		AvgDifficulty    float64
   112  		AvgHashrate      float64
   113  		NextDiffChange   uint32
   114  		Miners           []one_miner_row
   115  	}
   116  
   117  	common.ReloadMiners()
   118  
   119  	m := make(map[string]omv, 20)
   120  	var om omv
   121  	cnt := uint(0)
   122  	common.Last.Mutex.Lock()
   123  	end := common.Last.Block
   124  	common.Last.Mutex.Unlock()
   125  	var lastts int64
   126  	var diff float64
   127  	now := time.Now().Unix()
   128  
   129  	next_diff_change := 2016 - end.Height%2016
   130  
   131  	//eb_ad_x := regexp.MustCompile("/EB[0-9]+/AD[0-9]+/")
   132  
   133  	for ; end != nil; cnt++ {
   134  		if now-int64(end.Timestamp()) > int64(common.CFG.Stat.MiningHrs)*3600 {
   135  			break
   136  		}
   137  		lastts = int64(end.Timestamp())
   138  		bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash)
   139  		if e != nil {
   140  			break
   141  		}
   142  
   143  		block, e := btc.NewBlock(bl)
   144  		if e != nil {
   145  			break
   146  		}
   147  
   148  		cbasetx, _ := btc.NewTx(bl[block.TxOffset:])
   149  
   150  		strs := string(cbasetx.TxIn[0].ScriptSig)
   151  
   152  		diff += btc.GetDifficulty(end.Bits())
   153  		miner, mid := common.TxMiner(cbasetx)
   154  		om = m[miner]
   155  		om.bts += uint64(len(bl))
   156  		om.unknown_miner = (mid == -1)
   157  
   158  		// Blocks reward
   159  		var rew uint64
   160  		for o := range cbasetx.TxOut {
   161  			rew += cbasetx.TxOut[o].Value
   162  		}
   163  		fees := rew - btc.GetBlockReward(end.Height)
   164  		if int64(fees) > 0 { // solution for a possibility of a miner not claiming the reward (see block #501726)
   165  			om.fees += fees
   166  		}
   167  		om.blocks = append(om.blocks, OneMinedBlock{Height: end.Height,
   168  			Version: block.Version(), Length: len(bl), Fees: fees, Strings: strs})
   169  
   170  		/*if eb_ad_x.Find(cbasetx.TxIn[0].ScriptSig) != nil {
   171  			om.ebad_cnt++
   172  		}
   173  
   174  		if bytes.Index(cbasetx.TxIn[0].ScriptSig, []byte("/NYA/")) != -1 {
   175  			om.nya_cnt++
   176  		}*/
   177  
   178  		m[miner] = om
   179  
   180  		end = end.Parent
   181  	}
   182  
   183  	if cnt == 0 {
   184  		w.Write([]byte("{}"))
   185  		return
   186  	}
   187  
   188  	srt := make(onemiernstat, len(m))
   189  	i := 0
   190  	for k, v := range m {
   191  		srt[i].name = k
   192  		srt[i].omv = v
   193  		i++
   194  	}
   195  	sort.Sort(srt)
   196  
   197  	var stats the_mining_stats
   198  
   199  	diff /= float64(cnt)
   200  	bph := float64(cnt) / float64(common.CFG.Stat.MiningHrs)
   201  	hrate := bph / 6 * diff * 7158278.826667
   202  
   203  	stats.MiningStatHours = common.CFG.Stat.MiningHrs
   204  	stats.BlockCount = cnt
   205  	stats.FirstBlockTime = lastts
   206  	stats.AvgBlocksPerHour = bph
   207  	stats.AvgDifficulty = diff
   208  	stats.AvgHashrate = hrate
   209  	stats.NextDiffChange = next_diff_change
   210  
   211  	stats.Miners = make([]one_miner_row, len(srt))
   212  	for i := range srt {
   213  		stats.Miners[i].Unknown = srt[i].unknown_miner
   214  		stats.Miners[i].Name = srt[i].name
   215  		stats.Miners[i].Blocks = len(srt[i].blocks)
   216  		stats.Miners[i].TotalFees = srt[i].fees
   217  		stats.Miners[i].TotalBytes = srt[i].bts
   218  		stats.Miners[i].MinedBlocks = srt[i].blocks
   219  		//stats.Miners[i].BUcnt = srt[i].ebad_cnt
   220  		//stats.Miners[i].NYAcnt = srt[i].nya_cnt
   221  	}
   222  
   223  	bx, er := json.Marshal(stats)
   224  	if er == nil {
   225  		w.Header()["Content-Type"] = []string{"application/json"}
   226  		w.Write(bx)
   227  	} else {
   228  		println(er.Error())
   229  	}
   230  
   231  }