github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/blockchain/common_test.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package blockchain_test
     7  
     8  import (
     9  	"compress/bzip2"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  
    17  	"github.com/dashpay/godash/blockchain"
    18  	"github.com/dashpay/godash/chaincfg"
    19  	"github.com/dashpay/godash/database"
    20  	_ "github.com/dashpay/godash/database/ffldb"
    21  	"github.com/dashpay/godash/wire"
    22  )
    23  
    24  const (
    25  	// testDbType is the database backend type to use for the tests.
    26  	testDbType = "ffldb"
    27  
    28  	// testDbRoot is the root directory used to create all test databases.
    29  	testDbRoot = "testdbs"
    30  
    31  	// blockDataNet is the expected network in the test block data.
    32  	blockDataNet = wire.MainNet
    33  )
    34  
    35  // filesExists returns whether or not the named file or directory exists.
    36  func fileExists(name string) bool {
    37  	if _, err := os.Stat(name); err != nil {
    38  		if os.IsNotExist(err) {
    39  			return false
    40  		}
    41  	}
    42  	return true
    43  }
    44  
    45  // isSupportedDbType returns whether or not the passed database type is
    46  // currently supported.
    47  func isSupportedDbType(dbType string) bool {
    48  	supportedDrivers := database.SupportedDrivers()
    49  	for _, driver := range supportedDrivers {
    50  		if dbType == driver {
    51  			return true
    52  		}
    53  	}
    54  
    55  	return false
    56  }
    57  
    58  // chainSetup is used to create a new db and chain instance with the genesis
    59  // block already inserted.  In addition to the new chain instnce, it returns
    60  // a teardown function the caller should invoke when done testing to clean up.
    61  func chainSetup(dbName string) (*blockchain.BlockChain, func(), error) {
    62  	if !isSupportedDbType(testDbType) {
    63  		return nil, nil, fmt.Errorf("unsupported db type %v", testDbType)
    64  	}
    65  
    66  	// Handle memory database specially since it doesn't need the disk
    67  	// specific handling.
    68  	var db database.DB
    69  	var teardown func()
    70  	if testDbType == "memdb" {
    71  		ndb, err := database.Create(testDbType)
    72  		if err != nil {
    73  			return nil, nil, fmt.Errorf("error creating db: %v", err)
    74  		}
    75  		db = ndb
    76  
    77  		// Setup a teardown function for cleaning up.  This function is
    78  		// returned to the caller to be invoked when it is done testing.
    79  		teardown = func() {
    80  			db.Close()
    81  		}
    82  	} else {
    83  		// Create the root directory for test databases.
    84  		if !fileExists(testDbRoot) {
    85  			if err := os.MkdirAll(testDbRoot, 0700); err != nil {
    86  				err := fmt.Errorf("unable to create test db "+
    87  					"root: %v", err)
    88  				return nil, nil, err
    89  			}
    90  		}
    91  
    92  		// Create a new database to store the accepted blocks into.
    93  		dbPath := filepath.Join(testDbRoot, dbName)
    94  		_ = os.RemoveAll(dbPath)
    95  		ndb, err := database.Create(testDbType, dbPath, blockDataNet)
    96  		if err != nil {
    97  			return nil, nil, fmt.Errorf("error creating db: %v", err)
    98  		}
    99  		db = ndb
   100  
   101  		// Setup a teardown function for cleaning up.  This function is
   102  		// returned to the caller to be invoked when it is done testing.
   103  		teardown = func() {
   104  			db.Close()
   105  			os.RemoveAll(dbPath)
   106  			os.RemoveAll(testDbRoot)
   107  		}
   108  	}
   109  
   110  	// Create the main chain instance.
   111  	chain, err := blockchain.New(&blockchain.Config{
   112  		DB:          db,
   113  		ChainParams: &chaincfg.MainNetParams,
   114  		TimeSource:  blockchain.NewMedianTime(),
   115  	})
   116  	if err != nil {
   117  		teardown()
   118  		err := fmt.Errorf("failed to create chain instance: %v", err)
   119  		return nil, nil, err
   120  	}
   121  	return chain, teardown, nil
   122  }
   123  
   124  // loadUtxoView returns a utxo view loaded from a file.
   125  func loadUtxoView(filename string) (*blockchain.UtxoViewpoint, error) {
   126  	// The utxostore file format is:
   127  	// <tx hash><serialized utxo len><serialized utxo>
   128  	//
   129  	// The serialized utxo len is a little endian uint32 and the serialized
   130  	// utxo uses the format described in chainio.go.
   131  
   132  	filename = filepath.Join("testdata", filename)
   133  	fi, err := os.Open(filename)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	// Choose read based on whether the file is compressed or not.
   139  	var r io.Reader
   140  	if strings.HasSuffix(filename, ".bz2") {
   141  		r = bzip2.NewReader(fi)
   142  	} else {
   143  		r = fi
   144  	}
   145  	defer fi.Close()
   146  
   147  	view := blockchain.NewUtxoViewpoint()
   148  	for {
   149  		// Hash of the utxo entry.
   150  		var hash wire.ShaHash
   151  		_, err := io.ReadAtLeast(r, hash[:], len(hash[:]))
   152  		if err != nil {
   153  			// Expected EOF at the right offset.
   154  			if err == io.EOF {
   155  				break
   156  			}
   157  			return nil, err
   158  		}
   159  
   160  		// Num of serialize utxo entry bytes.
   161  		var numBytes uint32
   162  		err = binary.Read(r, binary.LittleEndian, &numBytes)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  
   167  		// Serialized utxo entry.
   168  		serialized := make([]byte, numBytes)
   169  		_, err = io.ReadAtLeast(r, serialized, int(numBytes))
   170  		if err != nil {
   171  			return nil, err
   172  		}
   173  
   174  		// Deserialize it and add it to the view.
   175  		utxoEntry, err := blockchain.TstDeserializeUtxoEntry(serialized)
   176  		if err != nil {
   177  			return nil, err
   178  		}
   179  		view.Entries()[hash] = utxoEntry
   180  	}
   181  
   182  	return view, nil
   183  }