func set_miner(p string) { if p == "" { common.ReloadMiners() fmt.Println("Specify MinerID string or one of the numberic values:") for i := range common.MinerIds { fmt.Printf("%3d - %s %s\n", i, common.MinerIds[i].Name, hex.EncodeToString(common.MinerIds[i].Tag)) } return } if p == "off" { common.LockCfg() common.CFG.Beeps.MinerID = "" common.UnlockCfg() fmt.Printf("Mining monitor disabled\n") return } v, e := strconv.ParseUint(p, 10, 32) common.LockCfg() if e != nil { common.CFG.Beeps.MinerID = p } else if int(v) < len(common.MinerIds) { common.CFG.Beeps.MinerID = string(common.MinerIds[v].Tag) } else { fmt.Println("The number is too big. Max is", len(common.MinerIds)-1) } fmt.Printf("Current miner ID: '%s'\n", common.CFG.Beeps.MinerID) common.UnlockCfg() }
func NetworkTick() { if common.IsListenTCP() { if !TCPServerStarted { TCPServerStarted = true go tcp_server() } } Mutex_net.Lock() conn_cnt := OutConsActive Mutex_net.Unlock() if next_drop_slowest.IsZero() { next_drop_slowest = time.Now().Add(DropSlowestEvery) } else if conn_cnt >= atomic.LoadUint32(&common.CFG.Net.MaxOutCons) { // Having max number of outgoing connections, check to drop the slowest one if time.Now().After(next_drop_slowest) { drop_slowest_peer() next_drop_slowest = time.Now().Add(DropSlowestEvery) } } // hammering protection - expire recently disconnected if next_clean_hammers.IsZero() { next_clean_hammers = time.Now().Add(HammeringMinReconnect) } else if time.Now().After(next_clean_hammers) { HammeringMutex.Lock() for k, t := range RecentlyDisconencted { if time.Now().Sub(t) >= HammeringMinReconnect { delete(RecentlyDisconencted, k) } } HammeringMutex.Unlock() ExpireCachedBlocks() next_clean_hammers = time.Now().Add(HammeringMinReconnect) } for conn_cnt < atomic.LoadUint32(&common.CFG.Net.MaxOutCons) { adrs := peersdb.GetBestPeers(16, ConnectionActive) if len(adrs) == 0 { common.LockCfg() if common.CFG.ConnectOnly == "" && common.DebugLevel > 0 { println("no new peers", len(OpenCons), conn_cnt) } common.UnlockCfg() break } DoNetwork(adrs[rand.Int31n(int32(len(adrs)))]) Mutex_net.Lock() conn_cnt = OutConsActive Mutex_net.Unlock() } }
func p_home(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } // The handler also gets called for /favicon.ico if r.URL.Path != "/" { http.NotFound(w, r) } s := load_template("home.html") wallet.BalanceMutex.Lock() if len(wallet.MyBalance) > 0 { wal := load_template("home_wal.html") wal = strings.Replace(wal, "{TOTAL_BTC}", fmt.Sprintf("%.8f", float64(wallet.LastBalance)/1e8), 1) wal = strings.Replace(wal, "{UNSPENT_OUTS}", fmt.Sprint(len(wallet.MyBalance)), 1) s = strings.Replace(s, "<!--WALLET-->", wal, 1) } else { if wallet.MyWallet == nil { s = strings.Replace(s, "<!--WALLET-->", "You have no wallet", 1) } else { s = strings.Replace(s, "<!--WALLET-->", "Your balance is <b>zero</b>", 1) } } wallet.BalanceMutex.Unlock() s = strings.Replace(s, "<--NETWORK_HASHRATE-->", usif.GetNetworkHashRate(), 1) common.LockCfg() dat, _ := json.Marshal(&common.CFG) common.UnlockCfg() s = strings.Replace(s, "{CONFIG_FILE}", strings.Replace(string(dat), ",\"", ", \"", -1), 1) write_html_head(w, r) w.Write([]byte(s)) write_html_tail(w) }
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("%dx%d", v, 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 p_cfg(w http.ResponseWriter, r *http.Request) { if !ipchecker(r) { return } common.LockCfg() defer common.UnlockCfg() if r.Method == "POST" { if len(r.Form["configjson"]) > 0 { e := json.Unmarshal([]byte(r.Form["configjson"][0]), &common.CFG) if e == nil { common.Reset() } if len(r.Form["save"]) > 0 { common.SaveConfig() } http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["walletdata"]) > 0 && len(r.Form["walletfname"]) > 0 { fn := r.Form["walletfname"][0] if fn != "" { fn = common.CFG.Walletdir + string(os.PathSeparator) + fn ioutil.WriteFile(fn, []byte(r.Form["walletdata"][0]), 0660) wallet.LoadWallet(fn) } http.Redirect(w, r, "/wal", http.StatusFound) return } if len(r.Form["shutdown"]) > 0 { usif.Exit_now = true w.Write([]byte("Your node should shut down soon")) return } return } // for any other GET we need a matching session-id if !checksid(r) { new_session_id(w) return } if len(r.Form["txponoff"]) > 0 { common.CFG.TXPool.Enabled = !common.CFG.TXPool.Enabled http.Redirect(w, r, "txs", http.StatusFound) return } if len(r.Form["txronoff"]) > 0 { common.CFG.TXRoute.Enabled = !common.CFG.TXRoute.Enabled http.Redirect(w, r, "txs", http.StatusFound) return } if len(r.Form["lonoff"]) > 0 { common.SetListenTCP(!common.IsListenTCP(), true) http.Redirect(w, r, "net", http.StatusFound) return } if len(r.Form["drop"]) > 0 { network.DropPeer(r.Form["drop"][0]) http.Redirect(w, r, "net", http.StatusFound) return } if len(r.Form["savecfg"]) > 0 { dat, _ := json.Marshal(&common.CFG) if dat != nil { ioutil.WriteFile(common.ConfigFile, dat, 0660) } http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["beepblock"]) > 0 { common.CFG.Beeps.NewBlock = !common.CFG.Beeps.NewBlock http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["freemem"]) > 0 { sys.FreeMem() http.Redirect(w, r, "/", http.StatusFound) return } if len(r.Form["mid"]) > 0 { v, e := strconv.ParseUint(r.Form["mid"][0], 10, 32) if e == nil && v < uint64(len(common.MinerIds)) { common.CFG.Beeps.MinerID = string(common.MinerIds[v].Tag) } else { common.CFG.Beeps.MinerID = "" } http.Redirect(w, r, "miners", http.StatusFound) return } }
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) }