gitlab.com/jokerrs1/Sia@v1.3.2/modules/miner/blockmanager_test.go (about)

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