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

     1  // Copyright (c) 2013-2014 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  	"io"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/dashpay/godash/blockchain"
    18  	"github.com/dashpay/godash/wire"
    19  	"github.com/dashpay/godashutil"
    20  )
    21  
    22  // TestReorganization loads a set of test blocks which force a chain
    23  // reorganization to test the block chain handling code.
    24  // The test blocks were originally from a post on the bitcoin talk forums:
    25  // https://bitcointalk.org/index.php?topic=46370.msg577556#msg577556
    26  func TestReorganization(t *testing.T) {
    27  	// Intentionally load the side chain blocks out of order to ensure
    28  	// orphans are handled properly along with chain reorganization.
    29  	testFiles := []string{
    30  		"blk_0_to_4.dat.bz2",
    31  		"blk_4A.dat.bz2",
    32  		"blk_5A.dat.bz2",
    33  		"blk_3A.dat.bz2",
    34  	}
    35  
    36  	var blocks []*godashutil.Block
    37  	for _, file := range testFiles {
    38  		blockTmp, err := loadBlocks(file)
    39  		if err != nil {
    40  			t.Errorf("Error loading file: %v\n", err)
    41  		}
    42  		for _, block := range blockTmp {
    43  			blocks = append(blocks, block)
    44  		}
    45  	}
    46  
    47  	t.Logf("Number of blocks: %v\n", len(blocks))
    48  
    49  	// Create a new database and chain instance to run tests against.
    50  	chain, teardownFunc, err := chainSetup("reorg")
    51  	if err != nil {
    52  		t.Errorf("Failed to setup chain instance: %v", err)
    53  		return
    54  	}
    55  	defer teardownFunc()
    56  
    57  	// Since we're not dealing with the real block chain, disable
    58  	// checkpoints and set the coinbase maturity to 1.
    59  	chain.DisableCheckpoints(true)
    60  	blockchain.TstSetCoinbaseMaturity(1)
    61  
    62  	expectedOrphans := map[int]struct{}{5: {}, 6: {}}
    63  	for i := 1; i < len(blocks); i++ {
    64  		isOrphan, err := chain.ProcessBlock(blocks[i], blockchain.BFNone)
    65  		if err != nil {
    66  			t.Errorf("ProcessBlock fail on block %v: %v\n", i, err)
    67  			return
    68  		}
    69  		if _, ok := expectedOrphans[i]; !ok && isOrphan {
    70  			t.Errorf("ProcessBlock incorrectly returned block %v "+
    71  				"is an orphan\n", i)
    72  		}
    73  	}
    74  
    75  	return
    76  }
    77  
    78  // loadBlocks reads files containing bitcoin block data (gzipped but otherwise
    79  // in the format bitcoind writes) from disk and returns them as an array of
    80  // godashutil.Block.  This is largely borrowed from the test code in btcdb.
    81  func loadBlocks(filename string) (blocks []*godashutil.Block, err error) {
    82  	filename = filepath.Join("testdata/", filename)
    83  
    84  	var network = wire.MainNet
    85  	var dr io.Reader
    86  	var fi io.ReadCloser
    87  
    88  	fi, err = os.Open(filename)
    89  	if err != nil {
    90  		return
    91  	}
    92  
    93  	if strings.HasSuffix(filename, ".bz2") {
    94  		dr = bzip2.NewReader(fi)
    95  	} else {
    96  		dr = fi
    97  	}
    98  	defer fi.Close()
    99  
   100  	var block *godashutil.Block
   101  
   102  	err = nil
   103  	for height := int64(1); err == nil; height++ {
   104  		var rintbuf uint32
   105  		err = binary.Read(dr, binary.LittleEndian, &rintbuf)
   106  		if err == io.EOF {
   107  			// hit end of file at expected offset: no warning
   108  			height--
   109  			err = nil
   110  			break
   111  		}
   112  		if err != nil {
   113  			break
   114  		}
   115  		if rintbuf != uint32(network) {
   116  			break
   117  		}
   118  		err = binary.Read(dr, binary.LittleEndian, &rintbuf)
   119  		blocklen := rintbuf
   120  
   121  		rbytes := make([]byte, blocklen)
   122  
   123  		// read block
   124  		dr.Read(rbytes)
   125  
   126  		block, err = godashutil.NewBlockFromBytes(rbytes)
   127  		if err != nil {
   128  			return
   129  		}
   130  		blocks = append(blocks, block)
   131  	}
   132  
   133  	return
   134  }