func p_blocks(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } blks := load_template("blocks.html") onerow := load_template("blocks_row.html") common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() for cnt := uint32(0); end != nil && cnt < atomic.LoadUint32(&common.CFG.WebUI.ShowBlocks); cnt++ { bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return } block, e := btc.NewBlock(bl) if e != nil { return } cbasetx, _ := btc.NewTx(bl[block.TxOffset:]) s := onerow s = strings.Replace(s, "{BLOCK_NUMBER}", fmt.Sprint(end.Height), 1) s = strings.Replace(s, "{BLOCK_TIMESTAMP}", time.Unix(int64(block.BlockTime()), 0).Format("Mon 15:04:05"), 1) s = strings.Replace(s, "{BLOCK_HASH}", end.BlockHash.String(), 1) s = strings.Replace(s, "{BLOCK_TXS}", fmt.Sprint(block.TxCount), 1) s = strings.Replace(s, "{BLOCK_SIZE}", fmt.Sprintf("%.1f", float64(len(bl))/1000), 1) var rew uint64 for o := range cbasetx.TxOut { rew += cbasetx.TxOut[o].Value } s = strings.Replace(s, "<!--BLOCK_VERSION-->", fmt.Sprint(block.Version()), 1) s = strings.Replace(s, "{BLOCK_REWARD}", fmt.Sprintf("%.2f", float64(rew)/1e8), 1) mi, _ := common.TxMiner(cbasetx) if len(mi) > 10 { mi = mi[:10] } s = strings.Replace(s, "{BLOCK_MINER}", mi, 1) network.MutexRcv.Lock() rb := network.ReceivedBlocks[end.BlockHash.BIdx()] network.MutexRcv.Unlock() if rb.TmDownload != 0 { s = strings.Replace(s, "{TIME_TO_DOWNLOAD}", fmt.Sprint(int(rb.TmDownload/time.Millisecond)), 1) } else { s = strings.Replace(s, "{TIME_TO_DOWNLOAD}", "", 1) } if rb.TmAccept != 0 { s = strings.Replace(s, "{TIME_TO_ACCEPT}", fmt.Sprint(int(rb.TmAccept/time.Millisecond)), 1) } else { s = strings.Replace(s, "{TIME_TO_ACCEPT}", "", 1) } if rb.Cnt != 0 { s = strings.Replace(s, "{WASTED_BLOCKS}", fmt.Sprint(rb.Cnt), 1) } else { s = strings.Replace(s, "{WASTED_BLOCKS}", "", 1) } s = strings.Replace(s, "{TIME_RECEIVED}", rb.Time.Format("15:04:05"), 1) blks = templ_add(blks, "<!--BLOCK_ROW-->", s) end = end.Parent } write_html_head(w, r) w.Write([]byte(blks)) write_html_tail(w) }
func do_mining(s string) { var totbtc, hrs uint64 if s != "" { hrs, _ = strconv.ParseUint(s, 10, 64) } if hrs == 0 { hrs = uint64(common.CFG.MiningStatHours) } fmt.Println("Looking back", hrs, "hours...") lim := uint32(time.Now().Add(-time.Hour * time.Duration(hrs)).Unix()) common.Last.Mutex.Lock() bte := common.Last.Block end := bte common.Last.Mutex.Unlock() cnt, diff := 0, float64(0) tot_blocks, tot_blocks_len := 0, 0 bip100_voting := make(map[string]uint) bip100x := regexp.MustCompile("/BV{0,1}[0-9]+[M]{0,1}/") for end.Timestamp() >= lim { bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { println(cnt, e.Error()) return } block, e := btc.NewBlock(bl) if e != nil { println("btc.NewBlock failed", e.Error()) return } bt, _ := btc.NewBlock(bl) cbasetx, cbtxlen := btc.NewTx(bl[bt.TxOffset:]) tot_blocks++ tot_blocks_len += len(bl) diff += btc.GetDifficulty(block.Bits()) common.LockCfg() if common.CFG.Beeps.MinerID != "" && bytes.Contains(bl[bt.TxOffset:bt.TxOffset+cbtxlen], []byte(common.CFG.Beeps.MinerID)) { block.BuildTxList() totbtc += block.Txs[0].TxOut[0].Value cnt++ fmt.Printf("%4d) %6d %s %s %5.2f => %5.2f BTC total, %d txs, %.1f KB\n", cnt, end.Height, end.BlockHash.String(), time.Unix(int64(end.Timestamp()), 0).Format("2006-01-02 15:04:05"), float64(block.Txs[0].TxOut[0].Value)/1e8, float64(totbtc)/1e8, len(block.Txs), float64(len(bl))/1e3) } common.UnlockCfg() res := bip100x.Find(cbasetx.TxIn[0].ScriptSig) if res != nil { bip100_voting[string(res)]++ nimer, _ := common.TxMiner(cbasetx) fmt.Println(" block", end.Height, "by", nimer, "voting", string(res), " total:", bip100_voting[string(res)]) } end = end.Parent } if tot_blocks == 0 { fmt.Println("There are no blocks from the last", hrs, "hour(s)") return } diff /= float64(tot_blocks) common.LockCfg() if common.CFG.Beeps.MinerID != "" { fmt.Printf("%.8f BTC mined by %s, in %d blocks for the last %d hours\n", float64(totbtc)/1e8, common.CFG.Beeps.MinerID, cnt, hrs) } common.UnlockCfg() if cnt > 0 { fmt.Printf("Projected weekly income : %.0f BTC, estimated hashrate : %s\n", 7*24*float64(totbtc)/float64(hrs)/1e8, common.HashrateToString(float64(cnt)/float64(6*hrs)*diff*7158278.826667)) } bph := float64(tot_blocks) / float64(hrs) fmt.Printf("Total network hashrate : %s @ average diff %.0f (%.2f bph)\n", common.HashrateToString(bph/6*diff*7158278.826667), diff, bph) fmt.Printf("Average block size was %.1f KB, next difficulty change in %d blocks\n", float64(tot_blocks_len/tot_blocks)/1e3, 2016-bte.Height%2016) }
func json_blocks(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } type one_block struct { Height uint32 Timestamp uint32 Hash string TxCnt int Size int Version uint32 Reward uint64 Miner string FeeSPB float64 Received uint32 TimePre, TimeDl, TimeVer, TimeQue int WasteCnt uint MissedCnt int FromConID uint32 Sigops int MinFeeKSPB uint64 NonWitnessSize int } var blks []*one_block common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() for cnt := uint32(0); end != nil && cnt < atomic.LoadUint32(&common.CFG.WebUI.ShowBlocks); cnt++ { bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return } block, e := btc.NewBlock(bl) if e != nil { return } b := new(one_block) b.Height = end.Height b.Timestamp = block.BlockTime() b.Hash = end.BlockHash.String() b.TxCnt = block.TxCount b.Size = len(bl) b.Version = block.Version() cbasetx, cbaselen := btc.NewTx(bl[block.TxOffset:]) for o := range cbasetx.TxOut { b.Reward += cbasetx.TxOut[o].Value } b.Miner, _ = common.TxMiner(cbasetx) if len(bl)-block.TxOffset-cbaselen != 0 { b.FeeSPB = float64(b.Reward-btc.GetBlockReward(end.Height)) / float64(len(bl)-block.TxOffset-cbaselen) } common.BlockChain.BlockIndexAccess.Lock() node := common.BlockChain.BlockIndex[end.BlockHash.BIdx()] common.BlockChain.BlockIndexAccess.Unlock() network.MutexRcv.Lock() rb := network.ReceivedBlocks[end.BlockHash.BIdx()] network.MutexRcv.Unlock() b.Received = uint32(rb.TmStart.Unix()) b.Sigops = int(node.SigopsCost) if rb.TmPreproc.IsZero() { b.TimePre = -1 } else { b.TimePre = int(rb.TmPreproc.Sub(rb.TmStart) / time.Millisecond) } if rb.TmDownload.IsZero() { b.TimeDl = -1 } else { b.TimeDl = int(rb.TmDownload.Sub(rb.TmStart) / time.Millisecond) } if rb.TmQueue.IsZero() { b.TimeQue = -1 } else { b.TimeQue = int(rb.TmQueue.Sub(rb.TmStart) / time.Millisecond) } if rb.TmAccepted.IsZero() { b.TimeVer = -1 } else { b.TimeVer = int(rb.TmAccepted.Sub(rb.TmStart) / time.Millisecond) } b.WasteCnt = rb.Cnt b.MissedCnt = rb.TxMissing b.FromConID = rb.FromConID b.MinFeeKSPB = rb.MinFeeKSPB b.NonWitnessSize = rb.NonWitnessSize blks = append(blks, b) end = end.Parent } bx, er := json.Marshal(blks) if er == nil { w.Header()["Content-Type"] = []string{"application/json"} w.Write(bx) } else { println(er.Error()) } }
func p_miners(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } common.ReloadMiners() m := make(map[string]omv, 20) var om omv cnt := 0 common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() var lastts int64 var diff float64 var totbts uint64 var totfees uint64 current_mid := -1 now := time.Now().Unix() common.LockCfg() minerid := common.CFG.Beeps.MinerID common.UnlockCfg() next_diff_change := 2016 - end.Height%2016 block_versions := make(map[uint32]uint) // bip100 bip100_voting := make(map[string]uint) //var bip100, bip100v uint64 bip100x := regexp.MustCompile("/BV{0,1}[0-9]+[M]{0,1}/") //bip100rx := regexp.MustCompile("/B[0-9]+[M]{0,1}/") for ; end != nil; cnt++ { if now-int64(end.Timestamp()) > int64(common.CFG.MiningStatHours)*3600 { break } lastts = int64(end.Timestamp()) bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return } block, e := btc.NewBlock(bl) cbasetx, _ := btc.NewTx(bl[block.TxOffset:]) block_versions[binary.LittleEndian.Uint32(bl[0:4])]++ diff += btc.GetDifficulty(end.Bits()) miner, mid := common.TxMiner(cbasetx) if mid == -1 { miner = "<i>" + miner + "</i>" } om = m[miner] om.cnt++ om.bts += uint64(len(bl)) om.mid = mid // Blocks reward var rew uint64 for o := range cbasetx.TxOut { rew += cbasetx.TxOut[o].Value } om.fees += rew - btc.GetBlockReward(end.Height) // bip-100 res := bip100x.Find(cbasetx.TxIn[0].ScriptSig) if res != nil { bip100_voting[string(res)]++ } m[miner] = om if mid != -1 && current_mid == -1 && minerid == string(common.MinerIds[mid].Tag) { current_mid = mid } totbts += uint64(len(bl)) end = end.Parent } if cnt == 0 { write_html_head(w, r) w.Write([]byte(fmt.Sprint("No blocks in last ", common.CFG.MiningStatHours, " hours"))) write_html_tail(w) return } srt := make(onemiernstat, len(m)) i := 0 for k, v := range m { srt[i].name = k srt[i].omv = v i++ } sort.Sort(srt) mnrs := load_template("miners.html") onerow := load_template("miners_row.html") diff /= float64(cnt) bph := float64(cnt) / float64(common.CFG.MiningStatHours) hrate := bph / 6 * diff * 7158278.826667 mnrs = strings.Replace(mnrs, "{MINING_HOURS}", fmt.Sprint(common.CFG.MiningStatHours), 1) mnrs = strings.Replace(mnrs, "{BLOCKS_COUNT}", fmt.Sprint(cnt), 1) mnrs = strings.Replace(mnrs, "{FIRST_BLOCK_TIME}", time.Unix(lastts, 0).Format("2006-01-02 15:04:05"), 1) mnrs = strings.Replace(mnrs, "{AVG_BLOCKS_PER_HOUR}", fmt.Sprintf("%.2f", bph), 1) mnrs = strings.Replace(mnrs, "{AVG_DIFFICULTY}", common.NumberToString(diff), 1) mnrs = strings.Replace(mnrs, "{AVG_HASHDATE}", common.HashrateToString(hrate), 1) mnrs = strings.Replace(mnrs, "{AVG_BLOCKSIZE}", fmt.Sprintf("%.1fKB", float64(totbts)/float64(cnt)/1000), 1) mnrs = strings.Replace(mnrs, "{DIFF_CHANGE_IN}", fmt.Sprint(next_diff_change), 1) mnrs = strings.Replace(mnrs, "{MINER_MON_IDX}", fmt.Sprint(current_mid), 1) for i := range srt { s := onerow s = strings.Replace(s, "{MINER_NAME}", srt[i].name, 1) s = strings.Replace(s, "{BLOCK_COUNT}", fmt.Sprint(srt[i].cnt), 1) s = strings.Replace(s, "{TOTAL_PERCENT}", fmt.Sprintf("%.0f", 100*float64(srt[i].cnt)/float64(cnt)), 1) s = strings.Replace(s, "{MINER_HASHRATE}", common.HashrateToString(hrate*float64(srt[i].cnt)/float64(cnt)), 1) s = strings.Replace(s, "{AVG_BLOCK_SIZE}", fmt.Sprintf("%.1fKB", float64(srt[i].bts)/float64(srt[i].cnt)/1000), 1) s = strings.Replace(s, "{MINER_ID}", fmt.Sprint(srt[i].mid), -1) s = strings.Replace(s, "<!--TOTAL_FEES-->", btc.UintToBtc(srt[i].fees), -1) s = strings.Replace(s, "<!--FEE_PER_BYTE-->", fmt.Sprint(srt[i].fees/srt[i].bts), -1) mnrs = templ_add(mnrs, "<!--MINER_ROW-->", s) totfees += srt[i].fees } mnrs = strings.Replace(mnrs, "<!--TOTAL_MINING_FEES-->", btc.UintToBtc(totfees), 1) mnrs = strings.Replace(mnrs, "<!--AVERAGE_FEE_PER_BYTE-->", fmt.Sprint(totfees/totbts), 1) var bv string for k, v := range block_versions { if bv != "" { bv += ", " } bv += fmt.Sprintf("%d (%d%%) x <b>v%d</b>", v, 100*int(v)/cnt, k) } mnrs = strings.Replace(mnrs, "<!--BLOCK_VERSIONS-->", bv, 1) // bip100 bv = "" for k, v := range bip100_voting { if bv != "" { bv += " + " } bv += fmt.Sprintf("%sx%d", k, v) } mnrs = strings.Replace(mnrs, "<!--BLOCKSIZE_VOTES-->", bv, 1) write_html_head(w, r) w.Write([]byte(mnrs)) write_html_tail(w) }
func json_blocks(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } type one_block struct { Height uint32 Timestamp uint32 Hash string TxCnt int Size int Version uint32 Reward uint64 Miner string Received uint32 TimeDl, TimeVer int WasteCnt uint } var blks []*one_block common.Last.Mutex.Lock() end := common.Last.Block common.Last.Mutex.Unlock() for cnt := uint32(0); end != nil && cnt < atomic.LoadUint32(&common.CFG.WebUI.ShowBlocks); cnt++ { bl, _, e := common.BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return } block, e := btc.NewBlock(bl) if e != nil { return } b := new(one_block) b.Height = end.Height b.Timestamp = block.BlockTime() b.Hash = end.BlockHash.String() b.TxCnt = block.TxCount b.Size = len(bl) b.Version = block.Version() cbasetx, _ := btc.NewTx(bl[block.TxOffset:]) for o := range cbasetx.TxOut { b.Reward += cbasetx.TxOut[o].Value } b.Miner, _ = common.TxMiner(cbasetx) network.MutexRcv.Lock() rb := network.ReceivedBlocks[end.BlockHash.BIdx()] network.MutexRcv.Unlock() b.Received = uint32(rb.Time.Unix()) if rb.TmDownload != 0 { b.TimeDl = int(rb.TmDownload / time.Millisecond) } else { b.TimeDl = -1 } if rb.TmAccept != 0 { b.TimeVer = int(rb.TmAccept / time.Millisecond) } else { b.TimeVer = -1 } b.WasteCnt = rb.Cnt blks = append(blks, b) end = end.Parent } bx, er := json.Marshal(blks) if er == nil { w.Header()["Content-Type"] = []string{"application/json"} w.Write(bx) } else { println(er.Error()) } }