Example #1
0
// testNewestShaEmpty ensures the NewestSha returns the values expected by
// the interface contract.
func testNewestShaEmpty(t *testing.T, db btcdb.Db) {
	sha, height, err := db.NewestSha()
	if err != nil {
		t.Errorf("NewestSha error %v", err)
	}
	if !sha.IsEqual(&zeroHash) {
		t.Errorf("NewestSha wrong hash got: %s, want %s", sha, &zeroHash)

	}
	if height != -1 {
		t.Errorf("NewestSha wrong height got: %d, want %d", height, -1)
	}
}
func testFetchRangeHeight(t *testing.T, db btcdb.Db, blocks []*btcutil.Block) {

	var testincrement int64 = 50
	var testcnt int64 = 100

	shanames := make([]*btcwire.ShaHash, len(blocks))

	nBlocks := int64(len(blocks))

	for i := range blocks {
		blockSha, err := blocks[i].Sha()
		if err != nil {
			t.Errorf("FetchRangeHeight: unexpected failure computing block sah %v", err)
		}
		shanames[i] = blockSha
	}

	for startheight := int64(0); startheight < nBlocks; startheight += testincrement {
		endheight := startheight + testcnt

		if endheight > nBlocks {
			endheight = btcdb.AllShas
		}

		shalist, err := db.FetchHeightRange(startheight, endheight)
		if err != nil {
			t.Errorf("FetchRangeHeight: unexpected failure looking up shas %v", err)
		}

		if endheight == btcdb.AllShas {
			if int64(len(shalist)) != nBlocks-startheight {
				t.Errorf("FetchRangeHeight: expected A %v shas, got %v", nBlocks-startheight, len(shalist))
			}
		} else {
			if int64(len(shalist)) != testcnt {
				t.Errorf("FetchRangeHeight: expected %v shas, got %v", testcnt, len(shalist))
			}
		}

		for i := range shalist {
			sha0 := *shanames[int64(i)+startheight]
			sha1 := shalist[i]
			if sha0 != sha1 {
				t.Errorf("FetchRangeHeight: mismatch sha at %v requested range %v %v: %v %v ", int64(i)+startheight, startheight, endheight, sha0, sha1)
			}
		}
	}

}
Example #3
0
func testIterator(t *testing.T, db btcdb.Db, shas []btcwire.ShaHash,
	sync string) {

	// Iterate over the whole list of shas.
	iter, err := db.NewIterateBlocks()
	if err != nil {
		t.Errorf("failed to create iterated blocks")
		return
	}

	// Skip the genesis block.
	_ = iter.NextRow()

	i := 0
	for ; iter.NextRow(); i++ {
		key, pver, buf, err := iter.Row()
		if err != nil {
			t.Errorf("iter.NextRow() failed: %v (%s)", err, sync)
			break
		}
		if i >= len(shas) {
			t.Errorf("iterator returned more shas than "+
				"expected - %d (%s)", i, sync)
			break
		}
		if !key.IsEqual(&shas[i]) {
			t.Errorf("iterator test: %dth sha doesn't match (%s)",
				i, sync)
		}
		if !bytes.Equal(zeroBlock, buf) {
			t.Errorf("iterator test: %d buf incorrect (%s)", i,
				sync)
		}
		if pver != 1 {
			t.Errorf("iterator: %dth pver is %d and not 1 (%s)",
				i, pver, sync)
		}
	}
	if i < len(shas) {
		t.Errorf("iterator got no rows on %dth loop, should have %d "+
			"(%s)", i, len(shas), sync)
	}
	if _, _, _, err = iter.Row(); err == nil {
		t.Errorf("done iterator didn't return failure")
	}
	iter.Close()
}
Example #4
0
func testNewestSha(t *testing.T, db btcdb.Db, expSha btcwire.ShaHash,
	expBlk int64, situation string) {

	newestsha, blkid, err := db.NewestSha()
	if err != nil {
		t.Errorf("NewestSha failed %v (%s)", err, situation)
		return
	}
	if blkid != expBlk {
		t.Errorf("NewestSha blkid is %d not %d (%s)", blkid, expBlk,
			situation)
	}
	if !newestsha.IsEqual(&expSha) {
		t.Errorf("Newestsha isn't the last sha we inserted %v %v (%s)",
			newestsha, &expSha, situation)
	}
}
Example #5
0
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
}
Example #6
0
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
}
Example #7
0
func getSha(db btcdb.Db, str string) (btcwire.ShaHash, error) {
	argtype, idx, sha, err := parsesha(str)
	if err != nil {
		log.Warnf("unable to decode [%v] %v", str, err)
		return btcwire.ShaHash{}, err
	}

	switch argtype {
	case ArgSha:
		// nothing to do
	case ArgHeight:
		sha, err = db.FetchBlockShaByHeight(idx)
		if err != nil {
			return btcwire.ShaHash{}, err
		}
	}
	if sha == nil {
		fmt.Printf("wtf sha is nil but err is %v", err)
	}
	return *sha, nil
}
Example #8
0
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
}
Example #9
0
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
}
Example #10
0
func FindSender(txIns []*btcwire.TxIn, btcdb btcdb.Db) (Address, error) {
	inputs := make(map[string]int64)

	for _, txIn := range txIns {
		op := txIn.PreviousOutpoint
		hash := op.Hash
		index := op.Index
		transactions, err := btcdb.FetchTxBySha(&hash)
		if err != nil {
			return Address{}, err
		}
		// TODO: During initial sync unconfirmed transactions might be picked up
		// We should prevent that from showing up but this is a work around
		// When a transaction is not in the database yet
		if len(transactions) == 0 {
			continue
		}

		previousOutput := transactions[0].Tx.TxOut[index]

		// The largest contributor receives the Mastercoins, so add multiple address values together
		address, _ := GetAddrs(previousOutput.PkScript)
		inputs[address[0].Addr] += previousOutput.Value
	}

	// Decide which input has the most value so we know who is sending this transaction
	var highest int64
	var highestAddress string

	for k, v := range inputs {
		if v > highest {
			highest = v
			highestAddress = k
		}
	}
	return Address{Addr: highestAddress}, nil
}
Example #11
0
// 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
}
Example #12
0
// chainSetup is used to create a new db and chain instance with the genesis
// block already inserted.  In addition to the new chain instnce, it returns
// a teardown function the caller should invoke when done testing to clean up.
func chainSetup(dbName string) (*btcchain.BlockChain, func(), error) {
	if !isSupportedDbType(testDbType) {
		return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
	}

	// Handle memory database specially since it doesn't need the disk
	// specific handling.
	var db btcdb.Db
	var teardown func()
	if testDbType == "memdb" {
		ndb, err := btcdb.CreateDB(testDbType)
		if err != nil {
			return nil, nil, fmt.Errorf("error creating db: %v", err)
		}
		db = ndb

		// Setup a teardown function for cleaning up.  This function is
		// returned to the caller to be invoked when it is done testing.
		teardown = func() {
			db.Close()
		}
	} else {
		// Create the root directory for test databases.
		if !fileExists(testDbRoot) {
			if err := os.MkdirAll(testDbRoot, 0700); err != nil {
				err := fmt.Errorf("unable to create test db "+
					"root: %v", err)
				return nil, nil, err
			}
		}

		// Create a new database to store the accepted blocks into.
		dbPath := filepath.Join(testDbRoot, dbName)
		_ = os.RemoveAll(dbPath)
		ndb, err := btcdb.CreateDB(testDbType, dbPath)
		if err != nil {
			return nil, nil, fmt.Errorf("error creating db: %v", err)
		}
		db = ndb

		// Setup a teardown function for cleaning up.  This function is
		// returned to the caller to be invoked when it is done testing.
		teardown = func() {
			dbVersionPath := filepath.Join(testDbRoot, dbName+".ver")
			db.Sync()
			db.Close()
			os.RemoveAll(dbPath)
			os.Remove(dbVersionPath)
			os.RemoveAll(testDbRoot)
		}
	}

	// Insert the main network genesis block.  This is part of the initial
	// database setup.
	genesisBlock := btcutil.NewBlock(&btcwire.GenesisBlock)
	_, err := db.InsertBlock(genesisBlock)
	if err != nil {
		teardown()
		err := fmt.Errorf("failed to insert genesis block: %v", err)
		return nil, nil, err
	}

	chain := btcchain.New(db, btcwire.MainNet, nil)
	return chain, teardown, nil
}
Example #13
0
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
}
Example #14
0
func search(log btclog.Logger, db btcdb.Db) map[string][]*rData {
	// Setup signal handler
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)

	// Potential optimisation: keep the bloom filter between runs
	filter := dablooms.NewScalingBloom(bloomSize, bloomRate, "blockchainr_bloom.bin")
	if filter == nil {
		log.Warn("dablooms.NewScalingBloom failed")
		return nil
	}

	potentialValues := make(stringSet)
	rMap := make(map[string][]*rData)

	_, maxHeigth, err := db.NewestSha()
	if err != nil {
		log.Warnf("db NewestSha failed: %v", err)
		return nil
	}

	for step := 1; step <= 2; step++ {
		lastTime := time.Now()
		lastSig := int64(0)
		sigCounter := int64(0)
		matches := int64(0)
		ticker := time.Tick(tickFreq * time.Second)

		signatures := getSignatures(maxHeigth, log, db)
		for rd := range signatures {
			select {
			case s := <-signalChan:
				log.Infof("Step %v - signal %v - %v sigs in %.2fs, %v matches, %v total, block %v of %v",
					step, s, sigCounter-lastSig, time.Since(lastTime).Seconds(),
					matches, sigCounter, rd.H, maxHeigth)

				if s == syscall.SIGINT || s == syscall.SIGTERM {
					return rMap
				}

			case <-ticker:
				log.Infof("Step %v - %v sigs in %.2fs, %v matches, %v total, block %v of %v",
					step, sigCounter-lastSig, time.Since(lastTime).Seconds(),
					matches, sigCounter, rd.H, maxHeigth)
				lastTime = time.Now()
				lastSig = sigCounter

			default:
				break
			}

			// Potential optimisation: store in potentialValues also the block
			// height, and if step 2 finds the same h first, it's a bloom
			// false positive
			if step == 1 {
				b := rd.sig.R.Bytes()
				if filter.Check(b) {
					matches++
					potentialValues.Add(rd.sig.R.String())
				} else {
					if !filter.Add(b, 1) {
						log.Warn("Add failed (?)")
					}
				}
			} else if step == 2 {
				if potentialValues.Contains(rd.sig.R.String()) {
					matches++
					rMap[rd.sig.R.String()] = append(rMap[rd.sig.R.String()], rd)
				}
			}
			sigCounter++
		}

		if *memprofile != "" {
			f, err := os.Create(fmt.Sprintf("%s.%d", *memprofile, step))
			if err != nil {
				log.Warnf("open memprofile failed: %v", err)
				return nil
			}
			pprof.WriteHeapProfile(f)
			f.Close()
		}

		log.Infof("Step %v done - %v signatures processed - %v matches",
			step, sigCounter, matches)
	}
	return rMap
}
Example #15
0
func testFetch(t *testing.T, db btcdb.Db, shas []btcwire.ShaHash,
	sync string) {

	// Test the newest sha is what we expect and call it twice to ensure
	// caching is working working properly.
	numShas := int64(len(shas))
	newestSha := shas[numShas-1]
	newestBlockID := int64(numShas)
	testNewestSha(t, db, newestSha, newestBlockID, sync)
	testNewestSha(t, db, newestSha, newestBlockID, sync+" cached")

	for i, sha := range shas {
		// Add one for genesis block skew.
		i = i + 1

		// Ensure the sha exists in the db as expected.
		if !db.ExistsSha(&sha) {
			t.Errorf("testSha %d doesn't exists (%s)", i, sync)
			break
		}

		// Fetch the sha from the db and ensure all fields are expected
		// values.
		buf, pver, idx, err := sqlite3.FetchSha(db, &sha)
		if err != nil {
			t.Errorf("Failed to fetch testSha %d (%s)", i, sync)
		}
		if !bytes.Equal(zeroBlock, buf) {
			t.Errorf("testSha %d incorrect block return (%s)", i,
				sync)
		}
		if pver != 1 {
			t.Errorf("pver is %d and not 1 for testSha %d (%s)",
				pver, i, sync)
		}
		if idx != int64(i) {
			t.Errorf("index isn't as expected %d vs %d (%s)",
				idx, i, sync)
		}

		// Fetch the sha by index and ensure it matches.
		tsha, err := db.FetchBlockShaByHeight(int64(i))
		if err != nil {
			t.Errorf("can't fetch sha at index %d: %v", i, err)
			continue
		}
		if !tsha.IsEqual(&sha) {
			t.Errorf("sha for index %d isn't shas[%d]", i, i)
		}
	}

	endBlockID := numShas + 1
	midBlockID := endBlockID / 2
	fetchIdxTests := []fetchIdxTest{
		// All shas.
		{1, btcdb.AllShas, shas, "fetch all shas"},

		//// All shas using known bounds.
		{1, endBlockID, shas, "fetch all shas2"},

		// Partial list starting at beginning.
		{1, midBlockID, shas[:midBlockID-1], "fetch first half"},

		// Partial list ending at end.
		{midBlockID, endBlockID, shas[midBlockID-1 : endBlockID-1],
			"fetch second half"},

		// Nonexistent off the end.
		{endBlockID, endBlockID * 2, []btcwire.ShaHash{},
			"fetch nonexistent"},
	}

	for _, test := range fetchIdxTests {
		t.Logf("numSha: %d - Fetch from %d to %d\n", numShas, test.start, test.end)
		if shalist, err := db.FetchHeightRange(test.start, test.end); err == nil {
			compareArray(t, shalist, test.exp, test.test, sync)
		} else {
			t.Errorf("failed to fetch index range for %s (%s)",
				test.test, sync)
		}
	}

	// Try and fetch nonexistent sha.
	if db.ExistsSha(&badSha) {
		t.Errorf("nonexistent sha exists (%s)!", sync)
	}
	_, _, _, err := sqlite3.FetchSha(db, &badSha)
	if err == nil {
		t.Errorf("Success when fetching a bad sha! (%s)", sync)
	}
	// XXX if not check to see it is the right value?

	testIterator(t, db, shas, sync)
}