func verifyChain(db btcdb.Db, level, depth int32) error { _, curheight64, err := db.NewestSha() if err != nil { rpcsLog.Errorf("Verify is unable to fetch current block "+ "height: %v", err) } curheight := int32(curheight64) if depth > curheight { depth = curheight } for height := curheight; height > (curheight - depth); height-- { // Level 0 just looks up the block. sha, err := db.FetchBlockShaByHeight(int64(height)) if err != nil { rpcsLog.Errorf("Verify is unable to fetch block at "+ "height %d: %v", height, err) return err } block, err := db.FetchBlockBySha(sha) if err != nil { rpcsLog.Errorf("Verify is unable to fetch block at "+ "sha %v height %d: %v", sha, height, err) return err } // Level 1 does basic chain sanity checks. if level > 0 { err := btcchain.CheckBlockSanity(block, activeNetParams.powLimit) if err != nil { rpcsLog.Errorf("Verify is unable to "+ "validate block at sha %v height "+ "%d: %v", sha, height, err) return err } } } rpcsLog.Infof("Chain verify completed successfully") return nil }
func DumpBlock(db btcdb.Db, height int64, fo io.Writer, rflag bool, fflag bool, tflag bool) error { sha, err := db.FetchBlockShaByHeight(height) if err != nil { return err } blk, err := db.FetchBlockBySha(sha) if err != nil { log.Warnf("Failed to fetch block %v, err %v", sha, err) return err } rblk, err := blk.Bytes() blkid := blk.Height() if rflag { log.Infof("Block %v depth %v %v", sha, blkid, spew.Sdump(rblk)) } mblk := blk.MsgBlock() if fflag { log.Infof("Block %v depth %v %v", sha, blkid, spew.Sdump(mblk)) } if tflag { log.Infof("Num transactions %v", len(mblk.Transactions)) for i, tx := range mblk.Transactions { txsha, err := tx.TxSha() if err != nil { continue } log.Infof("tx %v: %v", i, &txsha) } } if fo != nil { // generate and write header values binary.Write(fo, binary.LittleEndian, uint32(btcwire.MainNet)) binary.Write(fo, binary.LittleEndian, uint32(len(rblk))) // write block fo.Write(rblk) } return nil }
func fetch(db btcdb.Db, rd *rData) error { sha, err := db.FetchBlockShaByHeight(rd.in.H) if err != nil { return fmt.Errorf("failed FetchBlockShaByHeight(%v): %v\n", rd.in.H, err) } blk, err := db.FetchBlockBySha(sha) if err != nil { return fmt.Errorf("failed FetchBlockBySha(%v) - h %v: %v\n", sha, rd.in.H, err) } tx := blk.Transactions()[rd.in.Tx] rd.blkSha = sha rd.blk = blk rd.tx = tx rd.txInIndex = rd.in.TxIn rd.txIn = tx.MsgTx().TxIn[rd.in.TxIn] txPrevList, err := db.FetchTxBySha(&rd.txIn.PreviousOutPoint.Hash) if err != nil { return fmt.Errorf("failed FetchTxBySha(%v) - h %v: %v\n", rd.txIn.PreviousOutPoint.Hash, rd.in.H, err) } if len(txPrevList) != 1 { return fmt.Errorf("not single FetchTxBySha(%v) - h %v: %v\n", rd.txIn.PreviousOutPoint.Hash, rd.in.H, len(txPrevList)) } blkPrev, err := db.FetchBlockBySha(txPrevList[0].BlkSha) if err != nil { return fmt.Errorf("failed prev FetchBlockBySha(%v) - h %v: %v\n", txPrevList[0].BlkSha, rd.in.H, err) } rd.txPrev = txPrevList[0] rd.txPrevOutIndex = rd.txIn.PreviousOutPoint.Index rd.txPrevOut = rd.txPrev.Tx.TxOut[rd.txPrevOutIndex] rd.blkPrev = blkPrev return nil }
func getHeight(db btcdb.Db, str string) (int64, error) { argtype, idx, sha, err := parsesha(str) if err != nil { log.Warnf("unable to decode [%v] %v", str, err) return 0, err } switch argtype { case ArgSha: // nothing to do blk, err := db.FetchBlockBySha(sha) if err != nil { log.Warnf("unable to locate block sha %v err %v", sha, err) return 0, err } idx = blk.Height() case ArgHeight: } return idx, nil }
// findCandidates searches the chain backwards for checkpoint candidates and // returns a slice of found candidates, if any. It also stops searching for // candidates at the last checkpoint that is already hard coded into btcchain // since there is no point in finding candidates before already existing // checkpoints. func findCandidates(db btcdb.Db, latestHash *btcwire.ShaHash) ([]*btcchain.Checkpoint, error) { // Start with the latest block of the main chain. block, err := db.FetchBlockBySha(latestHash) if err != nil { return nil, err } // Setup chain and get the latest checkpoint. Ignore notifications // since they aren't needed for this util. chain := btcchain.New(db, activeNetwork, nil) latestCheckpoint := chain.LatestCheckpoint() if latestCheckpoint == nil { return nil, fmt.Errorf("unable to retrieve latest checkpoint") } // The latest known block must be at least the last known checkpoint // plus required checkpoint confirmations. checkpointConfirmations := int64(btcchain.CheckpointConfirmations) requiredHeight := latestCheckpoint.Height + checkpointConfirmations if block.Height() < requiredHeight { return nil, fmt.Errorf("the block database is only at height "+ "%d which is less than the latest checkpoint height "+ "of %d plus required confirmations of %d", block.Height(), latestCheckpoint.Height, checkpointConfirmations) } // Indeterminate progress setup. numBlocksToTest := block.Height() - requiredHeight progressInterval := (numBlocksToTest / 100) + 1 // min 1 fmt.Print("Searching for candidates") defer fmt.Println() // Loop backwards through the chain to find checkpoint candidates. var candidates []*btcchain.Checkpoint numTested := int64(0) for len(candidates) < cfg.NumCandidates && block.Height() > requiredHeight { // Display progress. if numTested%progressInterval == 0 { fmt.Print(".") } // Determine if this block is a checkpoint candidate. isCandidate, err := chain.IsCheckpointCandidate(block) if err != nil { return nil, err } // All checks passed, so this node seems like a reasonable // checkpoint candidate. if isCandidate { candidateHash, err := block.Sha() if err != nil { return nil, err } checkpoint := btcchain.Checkpoint{ Height: block.Height(), Hash: candidateHash, } candidates = append(candidates, &checkpoint) } prevHash := &block.MsgBlock().Header.PrevBlock block, err = db.FetchBlockBySha(prevHash) if err != nil { return nil, err } numTested++ } return candidates, nil }
func getSignatures(maxHeigth int64, log btclog.Logger, db btcdb.Db) chan *rData { heigthChan := make(chan int64) blockChan := make(chan *btcutil.Block) sigChan := make(chan *rData) go func() { for h := int64(0); h < maxHeigth; h++ { heigthChan <- h } close(heigthChan) }() var blockWg sync.WaitGroup for i := 0; i <= 10; i++ { blockWg.Add(1) go func() { for h := range heigthChan { sha, err := db.FetchBlockShaByHeight(h) if err != nil { log.Warnf("failed FetchBlockShaByHeight(%v): %v", h, err) return } blk, err := db.FetchBlockBySha(sha) if err != nil { log.Warnf("failed FetchBlockBySha(%v) - h %v: %v", sha, h, err) return } blockChan <- blk } blockWg.Done() }() } go func() { blockWg.Wait() close(blockChan) }() var sigWg sync.WaitGroup for i := 0; i <= 10; i++ { sigWg.Add(1) go func() { for blk := range blockChan { mblk := blk.MsgBlock() for i, tx := range mblk.Transactions { if btcchain.IsCoinBase(btcutil.NewTx(tx)) { continue } for t, txin := range tx.TxIn { dataSlice, err := btcscript.PushedData(txin.SignatureScript) if err != nil { continue } for d, data := range dataSlice { signature, err := btcec.ParseSignature(data, btcec.S256()) if err != nil { continue } sigChan <- &rData{ sig: signature, H: blk.Height(), Tx: i, TxIn: t, Data: d, } } } } } sigWg.Done() }() } go func() { sigWg.Wait() close(sigChan) }() return sigChan }