// This function is called from a net conn thread func netBlockReceived(conn *OneConnection, b []byte) { bl, e := btc.NewBlock(b) if e != nil { conn.DoS("BrokenBlock") println("NewBlock:", e.Error()) return } idx := bl.Hash.BIdx() MutexRcv.Lock() if rb, got := ReceivedBlocks[idx]; got { rb.Cnt++ MutexRcv.Unlock() common.CountSafe("BlockSameRcvd") return } orb := &OneReceivedBlock{Time: time.Now()} if bip, ok := conn.GetBlockInProgress[idx]; ok { orb.TmDownload = orb.Time.Sub(bip.start) conn.Mutex.Lock() delete(conn.GetBlockInProgress, idx) conn.Mutex.Unlock() } else { common.CountSafe("UnxpectedBlockRcvd") } ReceivedBlocks[idx] = orb MutexRcv.Unlock() NetBlocks <- &BlockRcvd{Conn: conn, Block: bl} }
func (c *one_net_conn) headers(d []byte) { var hdr [81]byte b := bytes.NewReader(d) cnt, er := btc.ReadVLen(b) if er != nil { return } if cnt == 0 /*|| LastBlock.node.Height>=10e3*/ { SetAllHeadersDone(true) return } for i := uint64(0); i < cnt; i++ { if _, er = b.Read(hdr[:]); er != nil { return } if hdr[80] != 0 { fmt.Println(LastBlock.node.Height, "Unexpected value of txn_count") continue } bl, er := btc.NewBlock(hdr[:]) if er == nil { er = chkblock(bl) if er != nil { fmt.Println(er.Error()) os.Exit(1) } } else { fmt.Println(LastBlock.node.Height, er.Error()) } } //fmt.Println("Height:", LastBlock.node.Height) }
func (ch *Chain) ParseTillBlock(end *BlockTreeNode) { var b []byte var er error var trusted bool prv := time.Now().UnixNano() for !AbortNow && ch.BlockTreeEnd != end { cur := time.Now().UnixNano() if cur-prv >= 10e9 { fmt.Println("ParseTillBlock ...", ch.BlockTreeEnd.Height, "/", end.Height) prv = cur } nxt := ch.BlockTreeEnd.FindPathTo(end) if nxt == nil { break } b, trusted, er = ch.Blocks.BlockGet(nxt.BlockHash) if er != nil { panic("Db.BlockGet(): " + er.Error()) } bl, er := btc.NewBlock(b) if er != nil { ch.DeleteBranch(nxt) break } er = bl.BuildTxList() if er != nil { ch.DeleteBranch(nxt) break } bl.Trusted = trusted changes, er := ch.ProcessBlockTransactions(bl, nxt.Height, end.Height) if er != nil { println("ProcessBlockTransactions", nxt.Height, er.Error()) ch.DeleteBranch(nxt) break } if !trusted { ch.Blocks.BlockTrusted(bl.Hash.Hash[:]) } ch.Unspent.CommitBlockTxs(changes, bl.Hash.Hash[:]) ch.BlockTreeEnd = nxt } if !AbortNow && ch.BlockTreeEnd != end { end, _ = ch.BlockTreeRoot.FindFarthestNode() fmt.Println("ParseTillBlock failed - now go to", end.Height) ch.MoveToBlock(end) } ch.Unspent.Sync() ch.Save() }
func GetchBlockForBIP152(hash *btc.Uint256) (crec *chain.BlckCachRec) { crec, _, _ = common.BlockChain.Blocks.BlockGetExt(hash) if crec == nil { fmt.Println("BlockGetExt failed for", hash.String()) return } if crec.Block == nil { crec.Block, _ = btc.NewBlock(crec.Data) if crec.Block == nil { fmt.Println("SendCmpctBlk: btc.NewBlock() failed for", hash.String()) return } } if len(crec.Block.Txs) == 0 { if crec.Block.BuildTxList() != nil { fmt.Println("SendCmpctBlk: bl.BuildTxList() failed for", hash.String()) return } } if len(crec.BIP152) != 24 { crec.BIP152 = make([]byte, 24) copy(crec.BIP152[:8], crec.Data[48:56]) // set the nonce to 8 middle-bytes of block's merkle_root sha := sha256.New() sha.Write(crec.Data[:80]) sha.Write(crec.BIP152[:8]) copy(crec.BIP152[8:24], sha.Sum(nil)[0:16]) } return }
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 (ch *Chain) UndoLastBlock() { fmt.Println("Undo block", ch.BlockTreeEnd.Height, ch.BlockTreeEnd.BlockHash.String(), ch.BlockTreeEnd.BlockSize>>10, "KB") raw, _, _ := ch.Blocks.BlockGet(ch.BlockTreeEnd.BlockHash) bl, _ := btc.NewBlock(raw) bl.BuildTxList() ch.Unspent.UndoBlockTxs(bl, ch.BlockTreeEnd.Parent.BlockHash.Hash[:]) ch.BlockTreeEnd = ch.BlockTreeEnd.Parent }
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 defrag_db() { if (usif.DefragBlocksDB & 1) != 0 { qdb.SetDefragPercent(1) fmt.Print("Defragmenting UTXO database") for { if !common.BlockChain.Unspent.Idle() { break } fmt.Print(".") } fmt.Println("done") } if (usif.DefragBlocksDB & 2) != 0 { fmt.Println("Creating empty database in", common.GocoinHomeDir+"defrag", "...") os.RemoveAll(common.GocoinHomeDir + "defrag") defragdb := chain.NewBlockDB(common.GocoinHomeDir + "defrag") fmt.Println("Defragmenting the database...") blk := common.BlockChain.BlockTreeRoot for { blk = blk.FindPathTo(common.BlockChain.BlockTreeEnd) if blk == nil { fmt.Println("Database defragmenting finished successfully") fmt.Println("To use the new DB, move the two new files to a parent directory and restart the client") break } if (blk.Height & 0xff) == 0 { fmt.Printf("%d / %d blocks written (%d%%)\r", blk.Height, common.BlockChain.BlockTreeEnd.Height, 100*blk.Height/common.BlockChain.BlockTreeEnd.Height) } bl, trusted, er := common.BlockChain.Blocks.BlockGet(blk.BlockHash) if er != nil { fmt.Println("FATAL ERROR during BlockGet:", er.Error()) break } nbl, er := btc.NewBlock(bl) if er != nil { fmt.Println("FATAL ERROR during NewBlock:", er.Error()) break } nbl.Trusted = trusted defragdb.BlockAdd(blk.Height, nbl) } defragdb.Sync() defragdb.Close() } }
func (c *OneConnection) ProcessNewHeader(hdr []byte) (int, *OneBlockToGet) { var ok bool var b2g *OneBlockToGet bl, _ := btc.NewBlock(hdr) c.Mutex.Lock() c.InvStore(MSG_BLOCK, bl.Hash.Hash[:]) c.Mutex.Unlock() if _, ok = ReceivedBlocks[bl.Hash.BIdx()]; ok { common.CountSafe("HeaderOld") //fmt.Println("", i, bl.Hash.String(), "-already received") return PH_STATUS_OLD, nil } if b2g, ok = BlocksToGet[bl.Hash.BIdx()]; ok { common.CountSafe("HeaderFresh") //fmt.Println(c.PeerAddr.Ip(), "block", bl.Hash.String(), " not new but get it") return PH_STATUS_FRESH, b2g } common.CountSafe("HeaderNew") //fmt.Println("", i, bl.Hash.String(), " - NEW!") common.BlockChain.BlockIndexAccess.Lock() defer common.BlockChain.BlockIndexAccess.Unlock() if er, dos, _ := common.BlockChain.PreCheckBlock(bl); er != nil { common.CountSafe("PreCheckBlockFail") //println("PreCheckBlock err", dos, er.Error()) if dos { return PH_STATUS_FATAL, nil } else { return PH_STATUS_ERROR, nil } } node := common.BlockChain.AcceptHeader(bl) b2g = &OneBlockToGet{Started: c.LastMsgTime, Block: bl, BlockTreeNode: node, InProgress: 0} AddB2G(b2g) LastCommitedHeader = node return PH_STATUS_NEW, b2g }
func (c *one_net_conn) block(d []byte) { BlocksMutex.Lock() defer BlocksMutex.Unlock() h := btc.NewSha2Hash(d[:80]) c.Lock() c.last_blk_rcvd = time.Now() c.Unlock() bip := BlocksInProgress[h.Hash] if bip == nil || !bip.Conns[c.id] { COUNTER("UNEX") //fmt.Println(h.String(), "- already received", bip) return } delete(bip.Conns, c.id) c.Lock() c.inprogress-- c.Unlock() atomic.AddUint64(&DlBytesDownloaded, uint64(len(d))) blocksize_update(len(d)) bl, er := btc.NewBlock(d) if er != nil { fmt.Println(c.peerip, "-", er.Error()) c.setbroken(true) return } bl.BuildTxList() if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) { fmt.Println(c.peerip, " - MerkleRoot mismatch at block", bip.Height) c.setbroken(true) return } BlocksCachedSize += uint(len(d)) BlocksCached[bip.Height] = bl delete(BlocksToGet, bip.Height) delete(BlocksInProgress, h.Hash) //fmt.Println(" got block", height) }
func (ch *Chain) GetRawTx(BlockHeight uint32, txid *btc.Uint256) (data []byte, er error) { // Find the block with the indicated Height in the main tree ch.BlockIndexAccess.Lock() n := ch.BlockTreeEnd if n.Height < BlockHeight { println(n.Height, BlockHeight) ch.BlockIndexAccess.Unlock() er = errors.New("GetRawTx: block height too big") return } for n.Height > BlockHeight { n = n.Parent } ch.BlockIndexAccess.Unlock() bd, _, e := ch.Blocks.BlockGet(n.BlockHash) if e != nil { er = errors.New("GetRawTx: block not in the database") return } bl, e := btc.NewBlock(bd) if e != nil { er = errors.New("GetRawTx: NewBlock failed") return } e = bl.BuildTxList() if e != nil { er = errors.New("GetRawTx: BuildTxList failed") return } // Find the transaction we need and store it in the file for i := range bl.Txs { if bl.Txs[i].Hash.Equal(txid) { data = bl.Txs[i].Serialize() return } } er = errors.New("GetRawTx: BuildTxList failed") return }
func GetRawTransaction(BlockHeight uint32, txid *btc.Uint256, txf io.Writer) bool { // Find the block with the indicated Height in the main tree common.BlockChain.BlockIndexAccess.Lock() n := common.Last.Block if n.Height < BlockHeight { println(n.Height, BlockHeight) common.BlockChain.BlockIndexAccess.Unlock() panic("This should not happen") } for n.Height > BlockHeight { n = n.Parent } common.BlockChain.BlockIndexAccess.Unlock() bd, _, e := common.BlockChain.Blocks.BlockGet(n.BlockHash) if e != nil { println("BlockGet", n.BlockHash.String(), BlockHeight, e.Error()) println("This should not happen - please, report a bug.") println("You can probably fix it by launching the client with -rescan") os.Exit(1) } bl, e := btc.NewBlock(bd) if e != nil { println("NewBlock: ", e.Error()) os.Exit(1) } e = bl.BuildTxList() if e != nil { println("BuildTxList:", e.Error()) os.Exit(1) } // Find the transaction we need and store it in the file for i := range bl.Txs { if bl.Txs[i].Hash.Equal(txid) { txf.Write(bl.Txs[i].Serialize()) return true } } return false }
func dump_block(s string) { h := btc.NewUint256FromString(s) if h == nil { println("Specify block's hash") return } crec, _, er := common.BlockChain.Blocks.BlockGetExt(btc.NewUint256(h.Hash[:])) if er != nil { println(er.Error()) return } ioutil.WriteFile(h.String()+".bin", crec.Data, 0700) if crec.Block == nil { crec.Block, _ = btc.NewBlock(crec.Data) } if crec.Block.OldData == nil { crec.Block.BuildTxList() } ioutil.WriteFile(h.String()+".old", crec.Block.OldData, 0700) fmt.Println("Block saved") }
func verify_block(blk []byte, sl one_idx_rec, off int) { bl, er := btc.NewBlock(blk) if er != nil { println("verify_block at off", off, er.Error()) return } if !bytes.Equal(bl.Hash.Hash[:], sl.Hash()) { println("verify_block at off", off, "Header invalid") return } er = bl.BuildTxList() if er != nil { println("verify_block at off", off, er.Error()) return } merk, _ := btc.GetMerkle(bl.Txs) if !bytes.Equal(bl.MerkleRoot(), merk) { println("verify_block at off", off, "Payload invalid") 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) }
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 (c *OneConnection) ProcessGetData(pl []byte) { var notfound []byte //println(c.PeerAddr.Ip(), "getdata") b := bytes.NewReader(pl) cnt, e := btc.ReadVLen(b) if e != nil { println("ProcessGetData:", e.Error(), c.PeerAddr.Ip()) return } for i := 0; i < int(cnt); i++ { var typ uint32 var h [36]byte n, _ := b.Read(h[:]) if n != 36 { println("ProcessGetData: pl too short", c.PeerAddr.Ip()) return } typ = binary.LittleEndian.Uint32(h[:4]) c.Mutex.Lock() c.InvStore(typ, h[4:36]) c.Mutex.Unlock() common.CountSafe(fmt.Sprintf("GetdataType-%x", typ)) if typ == MSG_BLOCK || typ == MSG_WITNESS_BLOCK { crec, _, er := common.BlockChain.Blocks.BlockGetExt(btc.NewUint256(h[4:])) //bl, _, er := common.BlockChain.Blocks.BlockGet(btc.NewUint256(h[4:])) if er == nil { bl := crec.Data if typ == MSG_BLOCK { // remove witness data from the block if crec.Block == nil { crec.Block, _ = btc.NewBlock(bl) } if crec.Block.OldData == nil { crec.Block.BuildTxList() } //println("block size", len(crec.Data), "->", len(bl)) bl = crec.Block.OldData } c.SendRawMsg("block", bl) } else { notfound = append(notfound, h[:]...) } } else if typ == MSG_TX || typ == MSG_WITNESS_TX { // transaction TxMutex.Lock() if tx, ok := TransactionsToSend[btc.NewUint256(h[4:]).BIdx()]; ok && tx.Blocked == 0 { tx.SentCnt++ tx.Lastsent = time.Now() TxMutex.Unlock() if tx.SegWit == nil || typ == MSG_WITNESS_TX { c.SendRawMsg("tx", tx.Data) } else { c.SendRawMsg("tx", tx.Serialize()) } } else { TxMutex.Unlock() notfound = append(notfound, h[:]...) } } else if typ == MSG_CMPCT_BLOCK { c.SendCmpctBlk(btc.NewUint256(h[4:])) } else { if common.DebugLevel > 0 { println("getdata for type", typ, "not supported yet") } if typ > 0 && typ <= 3 /*3 is a filtered block(we dont support it)*/ { notfound = append(notfound, h[:]...) } } } if len(notfound) > 0 { buf := new(bytes.Buffer) btc.WriteVlen(buf, uint64(len(notfound)/36)) buf.Write(notfound) c.SendRawMsg("notfound", buf.Bytes()) } }
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 (c *one_net_conn) block(d []byte) { atomic.AddUint64(&DlBytesDownloaded, uint64(len(d))) BlocksMutex.Lock() defer BlocksMutex.Unlock() h := btc.NewSha2Hash(d[:80]) c.Lock() c.last_blk_rcvd = time.Now() c.Unlock() bip := BlocksInProgress[h.Hash] if bip == nil || !bip.Conns[c.id] { COUNTER("BNOT") //fmt.Println(h.String(), "- already received", bip) return } //fmt.Println(h.String(), "- new", bip.Height) COUNTER("BYES") delete(bip.Conns, c.id) c.Lock() c.inprogress-- c.Unlock() blocksize_update(len(d)) bl, er := btc.NewBlock(d) if er != nil { fmt.Println(c.Ip(), "-", er.Error()) c.setbroken(true) return } bl.BuildTxList() if !bytes.Equal(btc.GetMerkel(bl.Txs), bl.MerkleRoot()) { fmt.Println(c.Ip(), " - MerkleRoot mismatch at block", bip.Height) c.setbroken(true) return } delete(BlocksToGet, bip.Height) delete(BlocksInProgress, h.Hash) if len(BlocksInProgress) == 0 { EmptyInProgressCnt++ } //println("got-", bip.Height, BlocksComplete+1) if BlocksComplete+1 == bip.Height { BlocksComplete++ BlockQueue <- bl for { bl = BlocksCached[BlocksComplete+1] if bl == nil { break } BlocksComplete++ delete(BlocksCached, BlocksComplete) BlocksCachedSize -= uint64(len(bl.Raw)) BlockQueue <- bl } } else { BlocksCached[bip.Height] = bl BlocksCachedSize += uint64(len(d)) } }
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 SubmitBlock(cmd *RpcCommand, resp *RpcResponse, b []byte) { var bd []byte var er error switch uu := cmd.Params.(type) { case []interface{}: if len(uu) < 1 { resp.Error = RpcError{Code: -1, Message: "empty params array"} return } bd, er = hex.DecodeString(uu[0].(string)) if er != nil { resp.Error = RpcError{Code: -3, Message: er.Error()} return } default: resp.Error = RpcError{Code: -2, Message: "incorrect params type"} return } bs := new(BlockSubmited) bs.Block, er = btc.NewBlock(bd) if er != nil { resp.Error = RpcError{Code: -4, Message: er.Error()} return } network.MutexRcv.Lock() network.ReceivedBlocks[bs.Block.Hash.BIdx()] = &network.OneReceivedBlock{TmStart: time.Now()} network.MutexRcv.Unlock() println("new block", bs.Block.Hash.String(), "len", len(bd), "- submitting...") bs.Done.Add(1) RpcBlocks <- bs bs.Done.Wait() if bs.Error != "" { //resp.Error = RpcError{Code: -10, Message: bs.Error} idx := strings.Index(bs.Error, "- RPC_Result:") if idx == -1 { resp.Result = "inconclusive" } else { resp.Result = bs.Error[idx+13:] } println("submiting block error:", bs.Error) println("submiting block result:", resp.Result.(string)) print("time_now:", time.Now().Unix()) print(" cur_block_ts:", bs.Block.BlockTime()) print(" last_given_now:", last_given_time) print(" last_given_min:", last_given_mintime) common.Last.Mutex.Lock() print(" prev_block_ts:", common.Last.Block.Timestamp()) common.Last.Mutex.Unlock() println() return } // cress check with bitcoind... if false { bitcoind_result := process_rpc(b) json.Unmarshal(bitcoind_result, &resp) switch cmd.Params.(type) { case string: println("\007Block rejected by bitcoind:", resp.Result.(string)) ioutil.WriteFile(fmt.Sprint(bs.Block.Height, "-", bs.Block.Hash.String()), bd, 0777) default: println("submiting block verified OK", bs.Error) } } }
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 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 } tot_blocks++ tot_blocks_len += len(bl) diff += btc.GetDifficulty(block.Bits()) if common.MinedByUs(bl) { 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) } 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 import_blockchain(dir string) { BlockDatabase := blockdb.NewBlockDB(dir, Magic) chain := chain.NewChain(GocoinHomeDir, GenesisBlock, false) var bl *btc.Block var er error var dat []byte var totbytes, perbytes uint64 chain.DoNotSync = true fmt.Println("Be patient while importing Satoshi's database... ") start := time.Now().UnixNano() prv := start for { now := time.Now().UnixNano() if now-prv >= 10e9 { stat(now-start, now-prv, totbytes, perbytes, chain.BlockTreeEnd.Height) prv = now // show progress each 10 seconds perbytes = 0 } dat, er = BlockDatabase.FetchNextBlock() if dat == nil || er != nil { println("END of DB file") break } bl, er = btc.NewBlock(dat[:]) if er != nil { println("Block inconsistent:", er.Error()) break } bl.Trusted = Trust er, _, _ = chain.CheckBlock(bl) if er != nil { if er.Error() != "Genesis" { println("CheckBlock failed:", er.Error()) os.Exit(1) // Such a thing should not happen, so let's better abort here. } continue } er = chain.AcceptBlock(bl) if er != nil { println("AcceptBlock failed:", er.Error()) os.Exit(1) // Such a thing should not happen, so let's better abort here. } totbytes += uint64(len(bl.Raw)) perbytes += uint64(len(bl.Raw)) } stop := time.Now().UnixNano() stat(stop-start, stop-prv, totbytes, perbytes, chain.BlockTreeEnd.Height) fmt.Println("Satoshi's database import finished in", (stop-start)/1e9, "seconds") fmt.Println("Now saving the new database...") chain.Save() chain.Close() fmt.Println("Database saved. No more imports should be needed.") }
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()) } }