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() }
// 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>=150e3*/ { 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) 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 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 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_REWARD}", fmt.Sprintf("%.2f", float64(rew)/1e8), 1) mi, _ := common.BlocksMiner(bl) 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) } blks = templ_add(blks, "<!--BLOCK_ROW-->", s) end = end.Parent } write_html_head(w, r) w.Write([]byte(blks)) write_html_tail(w) }
func import_blockchain(dir string) { trust := !textui.AskYesNo("Do you want to verify scripts while importing (will be slow)?") BlockDatabase := blockdb.NewBlockDB(dir, common.Magic) chain := chain.NewChain(common.GocoinHomeDir, common.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.Sync() chain.Save() chain.Close() fmt.Println("Database saved. No more imports should be needed.") fmt.Println("It is advised to close and restart the node now, to free some mem.") }
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 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) }