// Get tx with given id from the balance folder, of from cache func tx_from_balance(txid *btc.Uint256, error_is_fatal bool) (tx *btc.Tx) { if tx = loadedTxs[txid.Hash]; tx != nil { return // we have it in cache already } fn := "balance/" + txid.String() + ".tx" buf, er := ioutil.ReadFile(fn) if er == nil && buf != nil { var th [32]byte btc.ShaHash(buf, th[:]) if txid.Hash == th { tx, _ = btc.NewTx(buf) if error_is_fatal && tx == nil { println("Transaction is corrupt:", txid.String()) cleanExit(1) } } else if error_is_fatal { println("Transaction file is corrupt:", txid.String()) cleanExit(1) } } else if error_is_fatal { println("Error reading transaction file:", fn) if er != nil { println(er.Error()) } cleanExit(1) } loadedTxs[txid.Hash] = tx // store it in the cache return }
// Handle incoming "tx" msg func (c *OneConnection) ParseTxNet(pl []byte) { if uint32(len(pl)) > atomic.LoadUint32(&common.CFG.TXPool.MaxTxSize) { common.CountSafe("TxRejectedBig") return } tx, le := btc.NewTx(pl) if tx == nil { c.DoS("TxRejectedBroken") return } if le != len(pl) { c.DoS("TxRejectedLenMismatch") return } if len(tx.TxIn) < 1 { c.Misbehave("TxRejectedNoInputs", 100) return } tx.SetHash(pl) NeedThisTx(tx.Hash, func() { // This body is called with a locked TxMutex tx.Raw = pl select { case NetTxs <- &TxRcvd{conn: c, tx: tx, raw: pl}: TransactionsPending[tx.Hash.BIdx()] = true default: common.CountSafe("TxRejectedFullQ") //println("NetTxsFULL") } }) }
func execute_test_tx(t *testing.T, tv *testvector) bool { if len(tv.inps) == 0 { t.Error("Vector has no inputs") return false } rd, er := hex.DecodeString(tv.tx) if er != nil { t.Error(er.Error()) return false } tx, _ := btc.NewTx(rd) if tx == nil { t.Error("Canot decode tx") return false } tx.Size = uint32(len(rd)) ha := btc.Sha2Sum(rd) tx.Hash = btc.NewUint256(ha[:]) if skip_broken_tests(tx) { return false } if !tx.IsCoinBase() { for i := range tx.TxIn { if tx.TxIn[i].Input.IsNull() { return false } } } oks := 0 for i := range tx.TxIn { var j int for j = range tv.inps { if bytes.Equal(tx.TxIn[i].Input.Hash[:], tv.inps[j].txid.Hash[:]) && tx.TxIn[i].Input.Vout == uint32(tv.inps[j].vout) { break } } if j >= len(tv.inps) { t.Error("Matching input not found") continue } pk, er := btc.DecodeScript(tv.inps[j].pkscr) if er != nil { t.Error(er.Error()) continue } var ss []byte if tv.inps[j].vout >= 0 { ss = tx.TxIn[i].ScriptSig } if VerifyTxScript(ss, pk, i, tx, tv.ver_flags) { oks++ } } return oks == len(tx.TxIn) }
// Handle incoming "tx" msg func (c *OneConnection) ParseTxNet(pl []byte) { tid := btc.NewSha2Hash(pl) NeedThisTx(tid, func() { // This body is called with a locked TxMutex if uint32(len(pl)) > atomic.LoadUint32(&common.CFG.TXPool.MaxTxSize) { common.CountSafe("TxTooBig") RejectTx(tid, len(pl), TX_REJECTED_TOO_BIG) return } tx, le := btc.NewTx(pl) if tx == nil { RejectTx(tid, len(pl), TX_REJECTED_FORMAT) c.DoS("TxBroken") return } if le != len(pl) { RejectTx(tid, len(pl), TX_REJECTED_LEN_MISMATCH) c.DoS("TxLenMismatch") return } if len(tx.TxIn) < 1 { RejectTx(tid, len(pl), TX_REJECTED_EMPTY_INPUT) c.DoS("TxNoInputs") return } tx.Hash = tid select { case NetTxs <- &TxRcvd{conn: c, tx: tx, raw: pl}: TransactionsPending[tid.BIdx()] = true default: common.CountSafe("NetTxsFULL") } }) }
func init() { rd, _ := hex.DecodeString("0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000") dummy_tx, _ := btc.NewTx(rd) dummy_tx.Size = uint32(len(rd)) ha := btc.Sha2Sum(rd) dummy_tx.Hash = btc.NewUint256(ha[:]) }
func output_utxo_tx_xml(w http.ResponseWriter, minedid, minedat string) { txid := btc.NewUint256FromString(minedid) if txid == nil { return } block_number, er := strconv.ParseUint(minedat, 10, 32) if er != nil { return } lck := new(usif.OneLock) lck.In.Add(1) lck.Out.Add(1) usif.LocksChan <- lck lck.In.Wait() w.Write([]byte("<tx>")) fmt.Fprint(w, "<id>", minedid, "</id>") if dat, er := common.BlockChain.GetRawTx(uint32(block_number), txid); er == nil { w.Write([]byte("<status>OK</status>")) w.Write([]byte(fmt.Sprint("<size>", len(dat), "</size>"))) tx, _ := btc.NewTx(dat) output_tx_xml(w, tx) } else { w.Write([]byte("<status>Not found</status>")) } w.Write([]byte("</tx>")) lck.Out.Done() }
func GetAverageFee() float64 { Last.Mutex.Lock() end := Last.Block Last.Mutex.Unlock() LockCfg() blocks := CFG.AverageFeeBlocks UnlockCfg() if blocks <= 0 { blocks = 1 // at leats one block } AverageFeeMutex.Lock() defer AverageFeeMutex.Unlock() if end.Height == averageFeeLastBlock && averageFeeLastCount == blocks { return AverageFee_SPB // we've already calculated for this block } averageFeeLastBlock = end.Height averageFeeLastCount = blocks AverageFeeBytes = 0 AverageFeeTotal = 0 for blocks > 0 { bl, _, e := BlockChain.Blocks.BlockGet(end.BlockHash) if e != nil { return 0 } block, e := btc.NewBlock(bl) if e != nil { return 0 } cbasetx, cbasetxlen := btc.NewTx(bl[block.TxOffset:]) for o := range cbasetx.TxOut { AverageFeeTotal += cbasetx.TxOut[o].Value } AverageFeeTotal -= btc.GetBlockReward(end.Height) AverageFeeBytes += uint64(len(bl) - block.TxOffset - cbasetxlen) /*do not count block header and conibase tx */ blocks-- end = end.Parent } if AverageFeeBytes == 0 { if AverageFeeTotal != 0 { panic("Impossible that miner gest a fee with no transactions in the block") } AverageFee_SPB = 0 } else { AverageFee_SPB = float64(AverageFeeTotal) / float64(AverageFeeBytes) } return AverageFee_SPB }
func BlocksMiner(bl []byte) (string, int) { for i, m := range MinerIds { if MinedBy(bl, m.Tag) { return m.Name, i } } bt, _ := btc.NewBlock(bl) cbtx, _ := btc.NewTx(bl[bt.TxOffset:]) adr := btc.NewAddrFromPkScript(cbtx.TxOut[0].Pk_script, Testnet) if adr != nil { return adr.String(), -1 } return "", -1 }
func raw_tx_from_file(fn string) *btc.Tx { dat := sys.GetRawData(fn) if dat == nil { fmt.Println("Cannot fetch raw transaction data") return nil } tx, txle := btc.NewTx(dat) if tx != nil { tx.SetHash(dat) if txle != len(dat) { fmt.Println("WARNING: Raw transaction length mismatch", txle, len(dat)) } } return tx }
func main() { load_dll() pkscript, _ := hex.DecodeString("76a9147d22f6c9cca35cb4071971fe442da58546aaeb5988ac") d, _ := hex.DecodeString("0100000002232e0afdd9bcad5e3ace8a19ab8ad0ed8cebd6213b098e36cdc8b25af1d5cd30010000006b483045022077768255f192427bd2841555cfc86fdb7332e18c5c530b3b6028cd034a339f9c022100b3876037f63559ca8a2766a86c8dc62d41c869abc539ab983ce8eccf448f117f012102a33ac1e78cd3ff49bde292da2efcf273509d0869fe81571dfb49528c8287a8fcffffffff2fc90cf473e6ce6177818f705f6e96c7ad42f921f23b660ea27f653346e6a8a9010000006a47304402206d5be8061f712fba560b9966e037f7c53cff377b0c15d8c62bd0a2bcb195048602200522601341cdf574e3a39ba0397d8fe5608e37fd46b3fda2684386207ca9bf69012102a33ac1e78cd3ff49bde292da2efcf273509d0869fe81571dfb49528c8287a8fcffffffff0200a86100000000001976a914ff8e92b694527dd77660f873eb3a86eda5ed459f88ac70110100000000001976a9147d22f6c9cca35cb4071971fe442da58546aaeb5988ac00000000") tx, _ := btc.NewTx(d) i := 0 flags := uint32(script.STANDARD_VERIFY_FLAGS) println(flags) res := script.VerifyTxScript(pkscript, i, tx, flags) println("Gocoin:", res) if use_consensus_lib { res = consensus_verify_script(pkscript, i, tx, flags) println("Consen:", res) } }
func raw_tx_from_file(fn string) *btc.Tx { d, er := ioutil.ReadFile(fn) if er != nil { fmt.Println(er.Error()) return nil } dat, er := hex.DecodeString(string(d)) if er != nil { fmt.Println("hex.DecodeString failed - assume binary transaction file") dat = d } tx, txle := btc.NewTx(dat) if tx != nil && txle != len(dat) { fmt.Println("WARNING: Raw transaction length mismatch", txle, len(dat)) } return tx }
func LoadRawTx(buf []byte) (s string) { txd, er := hex.DecodeString(string(buf)) if er != nil { txd = buf } // At this place we should have raw transaction in txd tx, le := btc.NewTx(txd) if tx == nil || le != len(txd) { s += fmt.Sprintln("Could not decode transaction file or it has some extra data") return } tx.SetHash(txd) network.TxMutex.Lock() defer network.TxMutex.Unlock() if _, ok := network.TransactionsToSend[tx.Hash.BIdx()]; ok { s += fmt.Sprintln("TxID", tx.Hash.String(), "was already in the pool") return } var missinginp bool var totinp, totout uint64 var sigops uint s, missinginp, totinp, totout, sigops, er = DecodeTxSops(tx) if er != nil { return } if missinginp { network.TransactionsToSend[tx.Hash.BIdx()] = &network.OneTxToSend{Tx: tx, Data: txd, Own: 2, Firstseen: time.Now(), Volume: totout, SigopsCost: sigops} } else { network.TransactionsToSend[tx.Hash.BIdx()] = &network.OneTxToSend{Tx: tx, Data: txd, Own: 1, Firstseen: time.Now(), Volume: totinp, Fee: totinp - totout, SigopsCost: sigops} } network.TransactionsToSendSize += uint64(len(txd)) s += fmt.Sprintln("Transaction added to the memory pool. Please double check its details above.") s += fmt.Sprintln("If it does what you intended, you can send it the network.\nUse TxID:", tx.Hash.String()) return }
func TestSighash(t *testing.T) { var arr [][]interface{} dat, er := ioutil.ReadFile("../test/sighash.json") if er != nil { println(er.Error()) return } r := bytes.NewBuffer(dat) d := json.NewDecoder(r) d.UseNumber() er = d.Decode(&arr) if er != nil { println(er.Error()) return } for i := range arr { if len(arr[i]) == 5 { tmp, _ := hex.DecodeString(arr[i][0].(string)) tx, _ := btc.NewTx(tmp) if tx == nil { t.Error("Cannot decode tx from text number", i) continue } tmp, _ = hex.DecodeString(arr[i][1].(string)) // script iidx, _ := arr[i][2].(json.Number).Int64() htype, _ := arr[i][3].(json.Number).Int64() got := tx.SignatureHash(tmp, int(iidx), int32(htype)) exp := btc.NewUint256FromString(arr[i][4].(string)) if !bytes.Equal(exp.Hash[:], got) { t.Error("SignatureHash mismatch at index", i) } } } }
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()) } }
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) }
// load the content of the "balance/" folder func load_balance(showbalance bool) { var unknownInputs, multisigInputs int f, e := os.Open("balance/unspent.txt") if e != nil { println(e.Error()) return } rd := bufio.NewReader(f) for { l, _, e := rd.ReadLine() if len(l) == 0 && e != nil { break } if l[64] == '-' { txid := btc.NewUint256FromString(string(l[:64])) rst := strings.SplitN(string(l[65:]), " ", 2) vout, _ := strconv.ParseUint(rst[0], 10, 32) uns := new(btc.TxPrevOut) copy(uns.Hash[:], txid.Hash[:]) uns.Vout = uint32(vout) lab := "" if len(rst) > 1 { lab = rst[1] } str := string(l) if sti := strings.Index(str, "_StealthC:"); sti != -1 { c, e := hex.DecodeString(str[sti+10 : sti+10+64]) if e != nil { fmt.Println("ERROR at stealth", txid.String(), vout, e.Error()) } else { // add a new key to the wallet sec := btc.DeriveNextPrivate(first_seed[:], c) is_stealth[len(priv_keys)] = true priv_keys = append(priv_keys, sec) labels = append(labels, lab) pub_key := btc.PublicFromPrivate(sec, true) publ_addrs = append(publ_addrs, btc.NewAddrFromPubkey(pub_key, AddrVerPubkey())) compressed_key = append(compressed_key, true) // stealth keys are always compressed } } if _, ok := loadedTxs[txid.Hash]; !ok { tf, _ := os.Open("balance/" + txid.String() + ".tx") if tf != nil { siz, _ := tf.Seek(0, os.SEEK_END) tf.Seek(0, os.SEEK_SET) buf := make([]byte, siz) tf.Read(buf) tf.Close() th := btc.Sha2Sum(buf) if bytes.Equal(th[:], txid.Hash[:]) { tx, _ := btc.NewTx(buf) if tx != nil { loadedTxs[txid.Hash] = tx } else { println("transaction is corrupt:", txid.String()) } } else { println("transaction file is corrupt:", txid.String()) os.Exit(1) } } else { println("transaction file not found:", txid.String()) os.Exit(1) } } // Sum up all the balance and check if we have private key for this input uo := UO(uns) add_it := true if !btc.IsP2SH(uo.Pk_script) { fnd := false for j := range publ_addrs { if publ_addrs[j].Owns(uo.Pk_script) { fnd = true break } } if !fnd { if *onlvalid { add_it = false } if showbalance { unknownInputs++ if *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "does not belong to your wallet (cannot sign it)") } } } } else { if *onlvalid { add_it = false } if *verbose { ss := uns.String() ss = ss[:8] + "..." + ss[len(ss)-12:] fmt.Println(ss, "belongs to a multisig address") } multisigInputs++ } if add_it { unspentOuts = append(unspentOuts, uns) unspentOutsLabel = append(unspentOutsLabel, lab) totBtc += UO(uns).Value } } } f.Close() fmt.Printf("You have %.8f BTC in %d unspent outputs. %d inputs are multisig type\n", float64(totBtc)/1e8, len(unspentOuts), multisigInputs) if showbalance { if unknownInputs > 0 { fmt.Printf("WARNING: Some inputs (%d) cannot be spent with this password (-v to print them)\n", unknownInputs) } } }
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) }