github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/miner/blockmanager_test.go (about)

     1  package miner
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  	"unsafe"
     7  
     8  	"SiaPrime/crypto"
     9  	"SiaPrime/modules"
    10  	"SiaPrime/types"
    11  	"gitlab.com/NebulousLabs/fastrand"
    12  )
    13  
    14  // solveHeader takes a block header as input and returns a solved block header
    15  // as output.
    16  func solveHeader(header types.BlockHeader, target types.Target) types.BlockHeader {
    17  	// Solve the header.
    18  	for {
    19  		// Increment the nonce first to guarantee that a new header is formed
    20  		// - this helps check for pointer errors.
    21  		*(*uint64)(unsafe.Pointer(&header.Nonce)) += types.ASICHardforkFactor
    22  		id := crypto.HashObject(header)
    23  		if bytes.Compare(target[:], id[:]) >= 0 {
    24  			break
    25  		}
    26  	}
    27  	return header
    28  }
    29  
    30  // TestIntegrationHeaderForWork checks that header requesting, solving, and
    31  // submitting naively works.
    32  func TestIntegrationHeaderForWork(t *testing.T) {
    33  	if testing.Short() {
    34  		t.SkipNow()
    35  	}
    36  	mt, err := createMinerTester(t.Name())
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  
    41  	// Get a header and solve it.
    42  	header, target, err := mt.miner.HeaderForWork()
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	solvedHeader := solveHeader(header, target)
    47  	// Sanity check - header and solvedHeader should be different. (within the
    48  	// testing file, 'header' should always have a nonce of '0' and
    49  	// solvedHeader should never have a nonce of '0'.)
    50  	if header.Nonce == solvedHeader.Nonce {
    51  		t.Fatal("nonce memory is not independent")
    52  	}
    53  
    54  	// Submit the header.
    55  	err = mt.miner.SubmitHeader(solvedHeader)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  }
    60  
    61  // TestIntegrationHeaderForWorkUpdates checks that HeaderForWork starts
    62  // returning headers on the new block after a block has been submitted to the
    63  // consensus set.
    64  func TestIntegrationHeaderForWorkUpdates(t *testing.T) {
    65  	if testing.Short() {
    66  		t.SkipNow()
    67  	}
    68  	mt, err := createMinerTester(t.Name())
    69  	if err != nil {
    70  		t.Fatal(err)
    71  	}
    72  
    73  	// Get a header to advance into the header memory.
    74  	_, _, err = mt.miner.HeaderForWork()
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  
    79  	// Submit a block, which should trigger a header change.
    80  	_, err = mt.miner.AddBlock()
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	// Get a header to grind on.
    86  	header, target, err := mt.miner.HeaderForWork()
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	solvedHeader := solveHeader(header, target)
    91  
    92  	// Submit the header.
    93  	err = mt.miner.SubmitHeader(solvedHeader)
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	if !mt.cs.InCurrentPath(types.BlockID(crypto.HashObject(solvedHeader))) {
    98  		t.Error("header from solved block is not in the current path")
    99  	}
   100  }
   101  
   102  // TestIntegrationManyHeaders checks that requesting a full set of headers in a
   103  // row results in all unique headers, and that all of them can be reassembled
   104  // into valid blocks.
   105  func TestIntegrationManyHeaders(t *testing.T) {
   106  	if testing.Short() {
   107  		t.SkipNow()
   108  	}
   109  	mt, err := createMinerTester(t.Name())
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  
   114  	// Create a suite of headers for imaginary parallel mining.
   115  	solvedHeaders := make([]types.BlockHeader, HeaderMemory/BlockMemory*2)
   116  	for i := range solvedHeaders {
   117  		header, target, err := mt.miner.HeaderForWork()
   118  		if err != nil {
   119  			t.Fatal(err)
   120  		}
   121  		solvedHeaders[i] = solveHeader(header, target)
   122  	}
   123  
   124  	// Submit the headers randomly and make sure they are all considered valid.
   125  	for _, selection := range fastrand.Perm(len(solvedHeaders)) {
   126  		err = mt.miner.SubmitHeader(solvedHeaders[selection])
   127  		if err != nil && err != modules.ErrNonExtendingBlock {
   128  			t.Error(err)
   129  		}
   130  	}
   131  }
   132  
   133  // TestIntegrationHeaderBlockOverflow triggers a header overflow by requesting
   134  // a block that triggers the overflow.
   135  func TestIntegrationHeaderBlockOverflow(t *testing.T) {
   136  	if testing.Short() {
   137  		t.SkipNow()
   138  	}
   139  	mt, err := createMinerTester(t.Name())
   140  	if err != nil {
   141  		t.Fatal(err)
   142  	}
   143  
   144  	// Grab a header that will be overwritten.
   145  	header, target, err := mt.miner.HeaderForWork()
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	header = solveHeader(header, target)
   150  
   151  	// Mine blocks to wrap the memProgress around and wipe the old header.
   152  	for i := 0; i < BlockMemory; i++ {
   153  		_, err = mt.miner.AddBlock()
   154  		if err != nil {
   155  			t.Fatal(err)
   156  		}
   157  		// Grab a header to advance the mempool progress.
   158  		_, _, err = mt.miner.HeaderForWork()
   159  		if err != nil {
   160  			t.Fatal(err)
   161  		}
   162  	}
   163  
   164  	// Previous header should no longer be in memory.
   165  	err = mt.miner.SubmitHeader(header)
   166  	if err != errLateHeader {
   167  		t.Error(err)
   168  	}
   169  }
   170  
   171  // TestIntegrationHeaderRequestOverflow triggers a header overflow by
   172  // requesting a header that triggers overflow.
   173  func TestIntegrationHeaderRequestOverflow(t *testing.T) {
   174  	if testing.Short() {
   175  		t.SkipNow()
   176  	}
   177  	mt, err := createMinerTester(t.Name())
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  
   182  	// Grab a header that will be overwritten.
   183  	header, target, err := mt.miner.HeaderForWork()
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	header = solveHeader(header, target)
   188  
   189  	// Mine blocks to bring memProgress up to the edge. The number is chosen
   190  	// specifically so that the overflow happens during the requesting of 200
   191  	// headers.
   192  	for i := 0; i < BlockMemory-1; i++ {
   193  		_, err = mt.miner.AddBlock()
   194  		if err != nil {
   195  			t.Fatal(err)
   196  		}
   197  		// Grab a header to advance the mempool progress.
   198  		_, _, err = mt.miner.HeaderForWork()
   199  		if err != nil {
   200  			t.Fatal(err)
   201  		}
   202  	}
   203  
   204  	// Header should still be in memory.
   205  	err = mt.miner.SubmitHeader(header)
   206  	if err != modules.ErrNonExtendingBlock {
   207  		t.Error(err)
   208  	}
   209  
   210  	// Request headers until the overflow is achieved.
   211  	for i := 0; i < HeaderMemory/BlockMemory; i++ {
   212  		_, _, err = mt.miner.HeaderForWork()
   213  		if err != nil {
   214  			t.Fatal(err)
   215  		}
   216  	}
   217  
   218  	err = mt.miner.SubmitHeader(header)
   219  	if err != errLateHeader {
   220  		t.Error(err)
   221  	}
   222  }