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

     1  package consensus
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  	"unsafe"
     9  
    10  	"SiaPrime/modules"
    11  	"SiaPrime/persist"
    12  	"SiaPrime/types"
    13  
    14  	"gitlab.com/NebulousLabs/bolt"
    15  )
    16  
    17  var (
    18  	// validateBlockParamsGot stores the parameters passed to the most recent call
    19  	// to mockBlockValidator.ValidateBlock.
    20  	validateBlockParamsGot validateBlockParams
    21  
    22  	mockValidBlock = types.Block{
    23  		Timestamp: 100,
    24  		ParentID:  mockParentID(),
    25  	}
    26  	mockInvalidBlock = types.Block{
    27  		Timestamp: 500,
    28  		ParentID:  mockParentID(),
    29  	}
    30  	// parentBlockSerialized is a mock serialized form of a processedBlock.
    31  	parentBlockSerialized = []byte{3, 2, 1}
    32  
    33  	parentBlockUnmarshaler = mockBlockMarshaler{
    34  		[]predefinedBlockUnmarshal{
    35  			{parentBlockSerialized, mockParent(), nil},
    36  		},
    37  	}
    38  
    39  	parentBlockHighTargetUnmarshaler = mockBlockMarshaler{
    40  		[]predefinedBlockUnmarshal{
    41  			{parentBlockSerialized, mockParentHighTarget(), nil},
    42  		},
    43  	}
    44  
    45  	parentBlockLowTargetUnmarshaler = mockBlockMarshaler{
    46  		[]predefinedBlockUnmarshal{
    47  			{parentBlockSerialized, mockParentLowTarget(), nil},
    48  		},
    49  	}
    50  
    51  	unmarshalFailedErr = errors.New("mock unmarshal failed")
    52  
    53  	failingBlockUnmarshaler = mockBlockMarshaler{
    54  		[]predefinedBlockUnmarshal{
    55  			{parentBlockSerialized, processedBlock{}, unmarshalFailedErr},
    56  		},
    57  	}
    58  
    59  	serializedParentBlockMap = []blockMapPair{
    60  		{mockValidBlock.ParentID[:], parentBlockSerialized},
    61  	}
    62  )
    63  
    64  type (
    65  	// mockDbBucket is an implementation of dbBucket for unit testing.
    66  	mockDbBucket struct {
    67  		values map[string][]byte
    68  	}
    69  
    70  	// mockDbTx is an implementation of dbTx for unit testing. It uses an
    71  	// in-memory key/value store to mock a database.
    72  	mockDbTx struct {
    73  		buckets map[string]dbBucket
    74  	}
    75  
    76  	// predefinedBlockUnmarshal is a predefined response from mockBlockMarshaler.
    77  	// It defines the unmarshaled processedBlock and error code that
    78  	// mockBlockMarshaler should return in response to an input serialized byte
    79  	// slice.
    80  	predefinedBlockUnmarshal struct {
    81  		serialized  []byte
    82  		unmarshaled processedBlock
    83  		err         error
    84  	}
    85  
    86  	// mockBlockMarshaler is an implementation of the encoding.GenericMarshaler
    87  	// interface for unit testing. It allows clients to specify mappings of
    88  	// serialized bytes into unmarshaled blocks.
    89  	mockBlockMarshaler struct {
    90  		p []predefinedBlockUnmarshal
    91  	}
    92  
    93  	// mockBlockRuleHelper is an implementation of the blockRuleHelper interface
    94  	// for unit testing.
    95  	mockBlockRuleHelper struct {
    96  		minTimestamp types.Timestamp
    97  	}
    98  
    99  	// mockBlockValidator is an implementation of the blockValidator interface for
   100  	// unit testing.
   101  	mockBlockValidator struct {
   102  		err error
   103  	}
   104  
   105  	// validateBlockParams stores the set of parameters passed to ValidateBlock.
   106  	validateBlockParams struct {
   107  		called       bool
   108  		b            types.Block
   109  		minTimestamp types.Timestamp
   110  		target       types.Target
   111  		height       types.BlockHeight
   112  	}
   113  
   114  	// blockMapPair represents a key-value pair in the mock block map.
   115  	blockMapPair struct {
   116  		key []byte
   117  		val []byte
   118  	}
   119  )
   120  
   121  // Get returns the value associated with a given key.
   122  func (bucket mockDbBucket) Get(key []byte) []byte {
   123  	return bucket.values[string(key)]
   124  }
   125  
   126  // Set adds a named value to a mockDbBucket.
   127  func (bucket mockDbBucket) Set(key []byte, value []byte) {
   128  	bucket.values[string(key)] = value
   129  }
   130  
   131  // Bucket returns a mock dbBucket object associated with the given bucket name.
   132  func (db mockDbTx) Bucket(name []byte) dbBucket {
   133  	return db.buckets[string(name)]
   134  }
   135  
   136  // Marshal is not implemented and panics if called.
   137  func (m mockBlockMarshaler) Marshal(interface{}) []byte {
   138  	panic("not implemented")
   139  }
   140  
   141  // Unmarshal unmarshals a byte slice into an object based on a pre-defined map
   142  // of deserialized objects.
   143  func (m mockBlockMarshaler) Unmarshal(b []byte, v interface{}) error {
   144  	for _, pu := range m.p {
   145  		if bytes.Equal(b[:], pu.serialized[:]) {
   146  			pv, ok := v.(*processedBlock)
   147  			if !ok {
   148  				panic("mockBlockMarshaler.Unmarshal expected v to be of type processedBlock")
   149  			}
   150  			*pv = pu.unmarshaled
   151  			return pu.err
   152  		}
   153  	}
   154  	panic("unmarshal failed: predefined unmarshal not found")
   155  }
   156  
   157  // AddPredefinedUnmarshal adds a predefinedBlockUnmarshal to mockBlockMarshaler.
   158  func (m *mockBlockMarshaler) AddPredefinedUnmarshal(u predefinedBlockUnmarshal) {
   159  	m.p = append(m.p, u)
   160  }
   161  
   162  // minimumValidChildTimestamp returns the minimum timestamp of pb that can be
   163  // considered a valid block.
   164  func (brh mockBlockRuleHelper) minimumValidChildTimestamp(blockMap dbBucket, pb *processedBlock) types.Timestamp {
   165  	return brh.minTimestamp
   166  }
   167  
   168  // ValidateBlock stores the parameters it receives and returns the mock error
   169  // defined by mockBlockValidator.err.
   170  func (bv mockBlockValidator) ValidateBlock(b types.Block, id types.BlockID, minTimestamp types.Timestamp, target types.Target, height types.BlockHeight, log *persist.Logger) error {
   171  	validateBlockParamsGot = validateBlockParams{true, b, minTimestamp, target, height}
   172  	return bv.err
   173  }
   174  
   175  // mockParentID returns a mock BlockID value.
   176  func mockParentID() (parentID types.BlockID) {
   177  	parentID[0] = 42
   178  	return parentID
   179  }
   180  
   181  // mockParent returns a mock processedBlock with its ChildTarget member
   182  // initialized to a dummy value.
   183  func mockParent() (parent processedBlock) {
   184  	var mockTarget types.Target
   185  	mockTarget[0] = 56
   186  	parent.ChildTarget = mockTarget
   187  	return parent
   188  }
   189  
   190  // mockParent returns a mock processedBlock with its ChildTarget member
   191  // initialized to a the maximum value.
   192  func mockParentHighTarget() (parent processedBlock) {
   193  	parent.ChildTarget = types.RootDepth
   194  	return parent
   195  }
   196  
   197  // mockParent returns a mock processedBlock with its ChildTarget member
   198  // initialized to the minimum value.
   199  func mockParentLowTarget() (parent processedBlock) {
   200  	return parent
   201  }
   202  
   203  // TestUnitValidateHeaderAndBlock runs a series of unit tests for validateHeaderAndBlock.
   204  func TestUnitValidateHeaderAndBlock(t *testing.T) {
   205  	var tests = []struct {
   206  		block                  types.Block
   207  		dosBlocks              map[types.BlockID]struct{}
   208  		blockMapPairs          []blockMapPair
   209  		earliestValidTimestamp types.Timestamp
   210  		marshaler              mockBlockMarshaler
   211  		useNilBlockMap         bool
   212  		validateBlockErr       error
   213  		errWant                error
   214  		msg                    string
   215  	}{
   216  		{
   217  			block:                  mockValidBlock,
   218  			dosBlocks:              make(map[types.BlockID]struct{}),
   219  			useNilBlockMap:         true,
   220  			earliestValidTimestamp: mockValidBlock.Timestamp,
   221  			marshaler:              parentBlockUnmarshaler,
   222  			errWant:                errNoBlockMap,
   223  			msg:                    "validateHeaderAndBlock should fail when no block map is found in the database",
   224  		},
   225  		{
   226  			block: mockValidBlock,
   227  			// Create a dosBlocks map where mockValidBlock is marked as a bad block.
   228  			dosBlocks: map[types.BlockID]struct{}{
   229  				mockValidBlock.ID(): {},
   230  			},
   231  			earliestValidTimestamp: mockValidBlock.Timestamp,
   232  			marshaler:              parentBlockUnmarshaler,
   233  			errWant:                errDoSBlock,
   234  			msg:                    "validateHeaderAndBlock should reject known bad blocks",
   235  		},
   236  		{
   237  			block:                  mockValidBlock,
   238  			dosBlocks:              make(map[types.BlockID]struct{}),
   239  			earliestValidTimestamp: mockValidBlock.Timestamp,
   240  			marshaler:              parentBlockUnmarshaler,
   241  			errWant:                errOrphan,
   242  			msg:                    "validateHeaderAndBlock should reject a block if its parent block does not appear in the block database",
   243  		},
   244  		{
   245  			block:                  mockValidBlock,
   246  			dosBlocks:              make(map[types.BlockID]struct{}),
   247  			blockMapPairs:          serializedParentBlockMap,
   248  			earliestValidTimestamp: mockValidBlock.Timestamp,
   249  			marshaler:              failingBlockUnmarshaler,
   250  			errWant:                unmarshalFailedErr,
   251  			msg:                    "validateHeaderAndBlock should fail when unmarshaling the parent block fails",
   252  		},
   253  		{
   254  			block:     mockInvalidBlock,
   255  			dosBlocks: make(map[types.BlockID]struct{}),
   256  			blockMapPairs: []blockMapPair{
   257  				{mockInvalidBlock.ParentID[:], parentBlockSerialized},
   258  			},
   259  			earliestValidTimestamp: mockInvalidBlock.Timestamp,
   260  			marshaler:              parentBlockUnmarshaler,
   261  			validateBlockErr:       errBadMinerPayouts,
   262  			errWant:                errBadMinerPayouts,
   263  			msg:                    "validateHeaderAndBlock should reject a block if ValidateBlock returns an error for the block",
   264  		},
   265  		{
   266  			block:                  mockValidBlock,
   267  			dosBlocks:              make(map[types.BlockID]struct{}),
   268  			blockMapPairs:          serializedParentBlockMap,
   269  			earliestValidTimestamp: mockValidBlock.Timestamp,
   270  			marshaler:              parentBlockUnmarshaler,
   271  			errWant:                nil,
   272  			msg:                    "validateHeaderAndBlock should accept a valid block",
   273  		},
   274  	}
   275  	for _, tt := range tests {
   276  		// Initialize the blockmap in the tx.
   277  		bucket := mockDbBucket{map[string][]byte{}}
   278  		for _, mapPair := range tt.blockMapPairs {
   279  			bucket.Set(mapPair.key, mapPair.val)
   280  		}
   281  		dbBucketMap := map[string]dbBucket{}
   282  		if tt.useNilBlockMap {
   283  			dbBucketMap[string(BlockMap)] = nil
   284  		} else {
   285  			dbBucketMap[string(BlockMap)] = bucket
   286  		}
   287  		tx := mockDbTx{dbBucketMap}
   288  
   289  		mockParent := mockParent()
   290  		cs := ConsensusSet{
   291  			dosBlocks: tt.dosBlocks,
   292  			marshaler: tt.marshaler,
   293  			blockRuleHelper: mockBlockRuleHelper{
   294  				minTimestamp: tt.earliestValidTimestamp,
   295  			},
   296  			blockValidator: mockBlockValidator{tt.validateBlockErr},
   297  		}
   298  		// Reset the stored parameters to ValidateBlock.
   299  		validateBlockParamsGot = validateBlockParams{}
   300  		_, err := cs.validateHeaderAndBlock(tx, tt.block, tt.block.ID())
   301  		if err != tt.errWant {
   302  			t.Errorf("%s: expected to fail with `%v', got: `%v'", tt.msg, tt.errWant, err)
   303  		}
   304  		if err == nil || validateBlockParamsGot.called {
   305  			if validateBlockParamsGot.b.ID() != tt.block.ID() {
   306  				t.Errorf("%s: incorrect parameter passed to ValidateBlock - got: %v, want: %v", tt.msg, validateBlockParamsGot.b, tt.block)
   307  			}
   308  			if validateBlockParamsGot.minTimestamp != tt.earliestValidTimestamp {
   309  				t.Errorf("%s: incorrect parameter passed to ValidateBlock - got: %v, want: %v", tt.msg, validateBlockParamsGot.minTimestamp, tt.earliestValidTimestamp)
   310  			}
   311  			if validateBlockParamsGot.target != mockParent.ChildTarget {
   312  				t.Errorf("%s: incorrect parameter passed to ValidateBlock - got: %v, want: %v", tt.msg, validateBlockParamsGot.target, mockParent.ChildTarget)
   313  			}
   314  		}
   315  	}
   316  }
   317  
   318  // TestCheckHeaderTarget probes the checkHeaderTarget function and checks that
   319  // the result matches the result of checkTarget.
   320  func TestCheckHeaderTarget(t *testing.T) {
   321  	var b types.Block
   322  	var h types.BlockHeader
   323  
   324  	tests := []struct {
   325  		target   types.Target
   326  		expected bool
   327  		msg      string
   328  	}{
   329  		{types.RootDepth, true, "checkHeaderTarget failed for a low target"},
   330  		{types.Target{}, false, "checkHeaderTarget passed for a high target"},
   331  		{types.Target(h.ID()), true, "checkHeaderTarget failed for a same target"},
   332  	}
   333  	for _, tt := range tests {
   334  		if checkHeaderTarget(h, tt.target) != tt.expected {
   335  			t.Error(tt.msg)
   336  		}
   337  		if checkHeaderTarget(h, tt.target) != checkTarget(b, b.ID(), tt.target) {
   338  			t.Errorf("checkHeaderTarget and checkTarget do not match for target %v", tt.target)
   339  		}
   340  	}
   341  }
   342  
   343  // TestUnitValidateHeader runs a series of unit tests for validateHeader.
   344  func TestUnitValidateHeader(t *testing.T) {
   345  	mockValidBlockID := mockValidBlock.ID()
   346  
   347  	var tests = []struct {
   348  		header                 types.BlockHeader
   349  		dosBlocks              map[types.BlockID]struct{}
   350  		blockMapPairs          []blockMapPair
   351  		earliestValidTimestamp types.Timestamp
   352  		marshaler              mockBlockMarshaler
   353  		useNilBlockMap         bool
   354  		errWant                error
   355  		msg                    string
   356  	}{
   357  		// Test that known dos blocks are rejected.
   358  		{
   359  			header: mockValidBlock.Header(),
   360  			// Create a dosBlocks map where mockValidBlock is marked as a bad block.
   361  			dosBlocks: map[types.BlockID]struct{}{
   362  				mockValidBlock.ID(): {},
   363  			},
   364  			blockMapPairs:          serializedParentBlockMap,
   365  			earliestValidTimestamp: mockValidBlock.Timestamp,
   366  			marshaler:              parentBlockUnmarshaler,
   367  			errWant:                errDoSBlock,
   368  			msg:                    "validateHeader should reject known bad blocks",
   369  		},
   370  		// Test that blocks are rejected if a block map doesn't exist.
   371  		{
   372  			header:                 mockValidBlock.Header(),
   373  			dosBlocks:              make(map[types.BlockID]struct{}),
   374  			blockMapPairs:          serializedParentBlockMap,
   375  			earliestValidTimestamp: mockValidBlock.Timestamp,
   376  			marshaler:              parentBlockUnmarshaler,
   377  			useNilBlockMap:         true,
   378  			errWant:                errNoBlockMap,
   379  			msg:                    "validateHeader should fail when no block map is found in the database",
   380  		},
   381  		// Test that known blocks are rejected.
   382  		{
   383  			header:                 mockValidBlock.Header(),
   384  			dosBlocks:              make(map[types.BlockID]struct{}),
   385  			blockMapPairs:          []blockMapPair{{mockValidBlockID[:], []byte{}}},
   386  			earliestValidTimestamp: mockValidBlock.Timestamp,
   387  			marshaler:              parentBlockUnmarshaler,
   388  			errWant:                modules.ErrBlockKnown,
   389  			msg:                    "validateHeader should fail when the block has been seen before",
   390  		},
   391  		// Test that blocks with unknown parents (orphans) are rejected.
   392  		{
   393  			header:                 mockValidBlock.Header(),
   394  			dosBlocks:              make(map[types.BlockID]struct{}),
   395  			earliestValidTimestamp: mockValidBlock.Timestamp,
   396  			marshaler:              parentBlockUnmarshaler,
   397  			errWant:                errOrphan,
   398  			msg:                    "validateHeader should reject a block if its parent block does not appear in the block database",
   399  		},
   400  		// Test that blocks whose parents don't unmarshal are rejected.
   401  		{
   402  			header:                 mockValidBlock.Header(),
   403  			dosBlocks:              make(map[types.BlockID]struct{}),
   404  			blockMapPairs:          serializedParentBlockMap,
   405  			earliestValidTimestamp: mockValidBlock.Timestamp,
   406  			marshaler:              failingBlockUnmarshaler,
   407  			errWant:                unmarshalFailedErr,
   408  			msg:                    "validateHeader should fail when unmarshaling the parent block fails",
   409  		},
   410  		// Test that blocks with too early of a timestamp are rejected.
   411  		{
   412  			header:                 mockValidBlock.Header(),
   413  			dosBlocks:              make(map[types.BlockID]struct{}),
   414  			blockMapPairs:          serializedParentBlockMap,
   415  			earliestValidTimestamp: mockValidBlock.Timestamp + 1,
   416  			marshaler:              parentBlockHighTargetUnmarshaler,
   417  			errWant:                errEarlyTimestamp,
   418  			msg:                    "validateHeader should fail when the header's timestamp is too early",
   419  		},
   420  		// Test that headers in the extreme future are rejected.
   421  		{
   422  			header: types.BlockHeader{
   423  				Timestamp: types.CurrentTimestamp() + types.ExtremeFutureThreshold + 2,
   424  				ParentID:  mockParentID(),
   425  			},
   426  			dosBlocks:     make(map[types.BlockID]struct{}),
   427  			blockMapPairs: serializedParentBlockMap,
   428  			marshaler:     parentBlockHighTargetUnmarshaler,
   429  			errWant:       errExtremeFutureTimestamp,
   430  			msg:           "validateHeader should fail when the header's timestamp is in the extreme future",
   431  		},
   432  		// Test that headers in the near future are not rejected.
   433  		{
   434  			header: types.BlockHeader{
   435  				Timestamp: types.CurrentTimestamp() + types.FutureThreshold + 2,
   436  				ParentID:  mockParentID(),
   437  			},
   438  			dosBlocks:     make(map[types.BlockID]struct{}),
   439  			blockMapPairs: serializedParentBlockMap,
   440  			marshaler:     parentBlockHighTargetUnmarshaler,
   441  			errWant:       nil,
   442  			msg:           "validateHeader should not reject headers whose timestamps are in the near future",
   443  		},
   444  		// Test that blocks with too large of a target are rejected.
   445  		{
   446  			header:                 mockValidBlock.Header(),
   447  			dosBlocks:              make(map[types.BlockID]struct{}),
   448  			blockMapPairs:          serializedParentBlockMap,
   449  			earliestValidTimestamp: mockValidBlock.Timestamp,
   450  			marshaler:              parentBlockLowTargetUnmarshaler,
   451  			errWant:                modules.ErrBlockUnsolved,
   452  			msg:                    "validateHeader should reject blocks with an insufficiently low target",
   453  		},
   454  		// Test that valid blocks are accepted.
   455  		{
   456  			header:                 mockValidBlock.Header(),
   457  			dosBlocks:              make(map[types.BlockID]struct{}),
   458  			blockMapPairs:          serializedParentBlockMap,
   459  			earliestValidTimestamp: mockValidBlock.Timestamp,
   460  			marshaler:              parentBlockHighTargetUnmarshaler,
   461  			errWant:                nil,
   462  			msg:                    "validateHeader should accept a valid block",
   463  		},
   464  	}
   465  	for _, tt := range tests {
   466  		// Initialize the blockmap in the tx.
   467  		bucket := mockDbBucket{map[string][]byte{}}
   468  		for _, mapPair := range tt.blockMapPairs {
   469  			bucket.Set(mapPair.key, mapPair.val)
   470  		}
   471  		dbBucketMap := map[string]dbBucket{}
   472  		if tt.useNilBlockMap {
   473  			dbBucketMap[string(BlockMap)] = nil
   474  		} else {
   475  			dbBucketMap[string(BlockMap)] = bucket
   476  		}
   477  		tx := mockDbTx{dbBucketMap}
   478  
   479  		cs := ConsensusSet{
   480  			dosBlocks: tt.dosBlocks,
   481  			marshaler: tt.marshaler,
   482  			blockRuleHelper: mockBlockRuleHelper{
   483  				minTimestamp: tt.earliestValidTimestamp,
   484  			},
   485  		}
   486  		err := cs.validateHeader(tx, tt.header)
   487  		if err != tt.errWant {
   488  			t.Errorf("%s: expected to fail with `%v', got: `%v'", tt.msg, tt.errWant, err)
   489  		}
   490  	}
   491  }
   492  
   493  // TestIntegrationDoSBlockHandling checks that saved bad blocks are correctly
   494  // ignored.
   495  func TestIntegrationDoSBlockHandling(t *testing.T) {
   496  	if testing.Short() {
   497  		t.SkipNow()
   498  	}
   499  	t.Parallel()
   500  	cst, err := createConsensusSetTester(t.Name())
   501  	if err != nil {
   502  		t.Fatal(err)
   503  	}
   504  	defer cst.Close()
   505  
   506  	// Mine a block that is valid except for containing a buried invalid
   507  	// transaction. The transaction has more siacoin inputs than outputs.
   508  	txnBuilder, err := cst.wallet.StartTransaction()
   509  	if err != nil {
   510  		t.Fatal(err)
   511  	}
   512  	err = txnBuilder.FundSiacoins(types.NewCurrency64(50))
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	txnSet, err := txnBuilder.Sign(true) // true sets the 'wholeTransaction' flag
   517  	if err != nil {
   518  		t.Fatal(err)
   519  	}
   520  
   521  	// Mine and submit the invalid block to the consensus set. The first time
   522  	// around, the complaint should be about the rule-breaking transaction.
   523  	block, target, err := cst.miner.BlockForWork()
   524  	if err != nil {
   525  		t.Fatal(err)
   526  	}
   527  	block.Transactions = append(block.Transactions, txnSet...)
   528  	dosBlock, _ := cst.miner.SolveBlock(block, target)
   529  	err = cst.cs.AcceptBlock(dosBlock)
   530  	if err != errSiacoinInputOutputMismatch {
   531  		t.Fatalf("expected %v, got %v", errSiacoinInputOutputMismatch, err)
   532  	}
   533  
   534  	// Submit the same block a second time. The complaint should be that the
   535  	// block is already known to be invalid.
   536  	err = cst.cs.AcceptBlock(dosBlock)
   537  	if err != errDoSBlock {
   538  		t.Fatalf("expected %v, got %v", errDoSBlock, err)
   539  	}
   540  }
   541  
   542  // TestBlockKnownHandling submits known blocks to the consensus set.
   543  func TestBlockKnownHandling(t *testing.T) {
   544  	if testing.Short() {
   545  		t.SkipNow()
   546  	}
   547  	t.Parallel()
   548  	cst, err := createConsensusSetTester(t.Name())
   549  	if err != nil {
   550  		t.Fatal(err)
   551  	}
   552  	defer cst.Close()
   553  
   554  	// Get a block destined to be stale.
   555  	block, target, err := cst.miner.BlockForWork()
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  	staleBlock, _ := cst.miner.SolveBlock(block, target)
   560  
   561  	// Add two new blocks to the consensus set to block the stale block.
   562  	block1, err := cst.miner.AddBlock()
   563  	if err != nil {
   564  		t.Fatal(err)
   565  	}
   566  	block2, err := cst.miner.AddBlock()
   567  	if err != nil {
   568  		t.Fatal(err)
   569  	}
   570  
   571  	// Submit the stale block.
   572  	err = cst.cs.AcceptBlock(staleBlock)
   573  	if err != nil && err != modules.ErrNonExtendingBlock {
   574  		t.Fatal(err)
   575  	}
   576  
   577  	// Submit all the blocks again, looking for a 'stale block' error.
   578  	err = cst.cs.AcceptBlock(block1)
   579  	if err == nil {
   580  		t.Fatal("expected an error upon submitting the block")
   581  	}
   582  	err = cst.cs.AcceptBlock(block2)
   583  	if err == nil {
   584  		t.Fatal("expected an error upon submitting the block")
   585  	}
   586  	err = cst.cs.AcceptBlock(staleBlock)
   587  	if err == nil {
   588  		t.Fatal("expected an error upon submitting the block")
   589  	}
   590  
   591  	// Try submitting the genesis block.
   592  	id, err := cst.cs.dbGetPath(0)
   593  	if err != nil {
   594  		t.Fatal(err)
   595  	}
   596  	genesisBlock, err := cst.cs.dbGetBlockMap(id)
   597  	if err != nil {
   598  		t.Fatal(err)
   599  	}
   600  	err = cst.cs.AcceptBlock(genesisBlock.Block)
   601  	if err == nil {
   602  		t.Fatal("expected an error upon submitting the block")
   603  	}
   604  }
   605  
   606  // TestOrphanHandling passes an orphan block to the consensus set.
   607  func TestOrphanHandling(t *testing.T) {
   608  	if testing.Short() {
   609  		t.SkipNow()
   610  	}
   611  	t.Parallel()
   612  	cst, err := createConsensusSetTester(t.Name())
   613  	if err != nil {
   614  		t.Fatal(err)
   615  	}
   616  	defer cst.Close()
   617  
   618  	// Try submitting an orphan block to the consensus set. The empty block can
   619  	// be used, because looking for a parent is one of the first checks the
   620  	// consensus set performs.
   621  	orphan := types.Block{}
   622  	err = cst.cs.AcceptBlock(orphan)
   623  	if err != errOrphan {
   624  		t.Fatalf("expected %v, got %v", errOrphan, err)
   625  	}
   626  	err = cst.cs.AcceptBlock(orphan)
   627  	if err != errOrphan {
   628  		t.Fatalf("expected %v, got %v", errOrphan, err)
   629  	}
   630  }
   631  
   632  // TestMissedTarget submits a block that does not meet the required target.
   633  func TestMissedTarget(t *testing.T) {
   634  	if testing.Short() {
   635  		t.SkipNow()
   636  	}
   637  	t.Parallel()
   638  	cst, err := createConsensusSetTester(t.Name())
   639  	if err != nil {
   640  		t.Fatal(err)
   641  	}
   642  	defer cst.Close()
   643  
   644  	// Mine a block that doesn't meet the target.
   645  	block, target, err := cst.miner.BlockForWork()
   646  	if err != nil {
   647  		t.Fatal(err)
   648  	}
   649  	for checkTarget(block, block.ID(), target) {
   650  		*(*uint64)(unsafe.Pointer(&block.Nonce)) += types.ASICHardforkFactor
   651  	}
   652  	if checkTarget(block, block.ID(), target) {
   653  		t.Fatal("unable to find a failing target")
   654  	}
   655  	err = cst.cs.AcceptBlock(block)
   656  	if err != modules.ErrBlockUnsolved {
   657  		t.Fatalf("expected %v, got %v", modules.ErrBlockUnsolved, err)
   658  	}
   659  }
   660  
   661  // TestMinerPayoutHandling checks that blocks with incorrect payouts are
   662  // rejected.
   663  func TestMinerPayoutHandling(t *testing.T) {
   664  	if testing.Short() {
   665  		t.SkipNow()
   666  	}
   667  	t.Parallel()
   668  	cst, err := createConsensusSetTester(t.Name())
   669  	if err != nil {
   670  		t.Fatal(err)
   671  	}
   672  	defer cst.Close()
   673  
   674  	// Create a block with the wrong miner payout structure - testing can be
   675  	// light here because there is heavier testing in the 'types' package,
   676  	// where the logic is defined.
   677  	block, target, err := cst.miner.BlockForWork()
   678  	if err != nil {
   679  		t.Fatal(err)
   680  	}
   681  	block.MinerPayouts = append(block.MinerPayouts, types.SiacoinOutput{Value: types.NewCurrency64(1)})
   682  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   683  	err = cst.cs.AcceptBlock(solvedBlock)
   684  	if err != errBadMinerPayouts {
   685  		t.Fatalf("expected %v, got %v", errBadMinerPayouts, err)
   686  	}
   687  }
   688  
   689  // TestEarlyTimestampHandling checks that blocks too far in the past are
   690  // rejected.
   691  func TestEarlyTimestampHandling(t *testing.T) {
   692  	if testing.Short() {
   693  		t.SkipNow()
   694  	}
   695  	t.Parallel()
   696  	cst, err := createConsensusSetTester(t.Name())
   697  	if err != nil {
   698  		t.Fatal(err)
   699  	}
   700  	defer cst.Close()
   701  	minTimestamp := types.CurrentTimestamp()
   702  	cst.cs.blockRuleHelper = mockBlockRuleHelper{
   703  		minTimestamp: minTimestamp,
   704  	}
   705  
   706  	// Submit a block with a timestamp in the past, before minTimestamp.
   707  	block, target, err := cst.miner.BlockForWork()
   708  	if err != nil {
   709  		t.Fatal(err)
   710  	}
   711  	block.Timestamp = minTimestamp - 1
   712  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   713  	err = cst.cs.AcceptBlock(solvedBlock)
   714  	if err != errEarlyTimestamp {
   715  		t.Fatalf("expected %v, got %v", errEarlyTimestamp, err)
   716  	}
   717  }
   718  
   719  // testFutureTimestampHandling checks that blocks in the future (but not
   720  // extreme future) are handled correctly.
   721  func TestFutureTimestampHandling(t *testing.T) {
   722  	if testing.Short() {
   723  		t.SkipNow()
   724  	}
   725  	t.Parallel()
   726  	cst, err := createConsensusSetTester(t.Name())
   727  	if err != nil {
   728  		t.Fatal(err)
   729  	}
   730  	defer cst.Close()
   731  
   732  	// Submit a block with a timestamp in the future, but not the extreme
   733  	// future.
   734  	block, target, err := cst.miner.BlockForWork()
   735  	if err != nil {
   736  		t.Fatal(err)
   737  	}
   738  	block.Timestamp = types.CurrentTimestamp() + 2 + types.FutureThreshold
   739  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   740  	err = cst.cs.AcceptBlock(solvedBlock)
   741  	if err != errFutureTimestamp {
   742  		t.Fatalf("expected %v, got %v", errFutureTimestamp, err)
   743  	}
   744  
   745  	// Poll the consensus set until the future block appears.
   746  	for i := 0; i < 30; i++ {
   747  		time.Sleep(time.Second * 3)
   748  		_, err = cst.cs.dbGetBlockMap(solvedBlock.ID())
   749  		if err == nil {
   750  			break
   751  		}
   752  	}
   753  	_, err = cst.cs.dbGetBlockMap(solvedBlock.ID())
   754  	if err != nil {
   755  		t.Errorf("Future block not added to consensus set.\nCurrent Timestamp %v\nFutureThreshold: %v\nBlock Timestamp %v\n", types.CurrentTimestamp(), types.FutureThreshold, block.Timestamp)
   756  	}
   757  }
   758  
   759  // TestExtremeFutureTimestampHandling checks that blocks in the extreme future
   760  // are rejected.
   761  func TestExtremeFutureTimestampHandling(t *testing.T) {
   762  	if testing.Short() {
   763  		t.SkipNow()
   764  	}
   765  	t.Parallel()
   766  	cst, err := createConsensusSetTester(t.Name())
   767  	if err != nil {
   768  		t.Fatal(err)
   769  	}
   770  	defer cst.Close()
   771  
   772  	// Submit a block with a timestamp in the extreme future.
   773  	block, target, err := cst.miner.BlockForWork()
   774  	if err != nil {
   775  		t.Fatal(err)
   776  	}
   777  	block.Timestamp = types.CurrentTimestamp() + 2 + types.ExtremeFutureThreshold
   778  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   779  	err = cst.cs.AcceptBlock(solvedBlock)
   780  	if err != errExtremeFutureTimestamp {
   781  		t.Fatalf("expected %v, got %v", errFutureTimestamp, err)
   782  	}
   783  }
   784  
   785  // TestBuriedBadTransaction tries submitting a block with a bad transaction
   786  // that is buried under good transactions.
   787  func TestBuriedBadTransaction(t *testing.T) {
   788  	if testing.Short() {
   789  		t.SkipNow()
   790  	}
   791  	t.Parallel()
   792  	cst, err := createConsensusSetTester(t.Name())
   793  	if err != nil {
   794  		t.Fatal(err)
   795  	}
   796  	defer cst.Close()
   797  	pb := cst.cs.dbCurrentProcessedBlock()
   798  
   799  	// Create a good transaction using the wallet.
   800  	txnValue := types.NewCurrency64(1200)
   801  	txnBuilder, err := cst.wallet.StartTransaction()
   802  	if err != nil {
   803  		t.Fatal(err)
   804  	}
   805  	err = txnBuilder.FundSiacoins(txnValue)
   806  	if err != nil {
   807  		t.Fatal(err)
   808  	}
   809  	txnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: txnValue})
   810  	txnSet, err := txnBuilder.Sign(true)
   811  	if err != nil {
   812  		t.Fatal(err)
   813  	}
   814  	err = cst.tpool.AcceptTransactionSet(txnSet)
   815  	if err != nil {
   816  		t.Fatal(err)
   817  	}
   818  
   819  	// Create a bad transaction
   820  	badTxn := types.Transaction{
   821  		SiacoinInputs: []types.SiacoinInput{{}},
   822  	}
   823  	txns := append(cst.tpool.TransactionList(), badTxn)
   824  
   825  	// Create a block with a buried bad transaction.
   826  	block := types.Block{
   827  		ParentID:     pb.Block.ID(),
   828  		Timestamp:    types.CurrentTimestamp(),
   829  		MinerPayouts: []types.SiacoinOutput{{Value: types.CalculateCoinbase(pb.Height + 1)}},
   830  		Transactions: txns,
   831  	}
   832  	block, _ = cst.miner.SolveBlock(block, pb.ChildTarget)
   833  	err = cst.cs.AcceptBlock(block)
   834  	if err == nil {
   835  		t.Error("buried transaction didn't cause an error")
   836  	}
   837  }
   838  
   839  // TestInconsistencyCheck puts the consensus set in to an inconsistent state
   840  // and makes sure that the santiy checks are triggering panics.
   841  func TestInconsistentCheck(t *testing.T) {
   842  	if testing.Short() {
   843  		t.SkipNow()
   844  	}
   845  	t.Parallel()
   846  	cst, err := createConsensusSetTester(t.Name())
   847  	if err != nil {
   848  		t.Fatal(err)
   849  	}
   850  
   851  	// Corrupt the consensus set by adding a new siafund output.
   852  	sfo := types.SiafundOutput{
   853  		Value: types.NewCurrency64(1),
   854  	}
   855  	cst.cs.dbAddSiafundOutput(types.SiafundOutputID{}, sfo)
   856  
   857  	// Catch a panic that should be caused by the inconsistency check after a
   858  	// block is mined.
   859  	defer func() {
   860  		r := recover()
   861  		if r == nil {
   862  			t.Fatalf("inconsistency panic not triggered by corrupted database")
   863  		}
   864  	}()
   865  	_, err = cst.miner.AddBlock()
   866  	if err != nil {
   867  		t.Fatal(err)
   868  	}
   869  }
   870  
   871  // COMPATv0.4.0
   872  //
   873  // This test checks that the hardfork scheduled for block 21,000 rolls through
   874  // smoothly.
   875  func TestTaxHardfork(t *testing.T) {
   876  	if testing.Short() {
   877  		t.SkipNow()
   878  	}
   879  	t.Parallel()
   880  	cst, err := createConsensusSetTester(t.Name())
   881  	if err != nil {
   882  		t.Fatal(err)
   883  	}
   884  	defer cst.Close()
   885  
   886  	// Create a file contract with a payout that is put into the blockchain
   887  	// before the hardfork block but expires after the hardfork block.
   888  	payout := types.NewCurrency64(400e6)
   889  	outputSize := types.PostTax(cst.cs.dbBlockHeight(), payout)
   890  	fc := types.FileContract{
   891  		WindowStart:        cst.cs.dbBlockHeight() + 12,
   892  		WindowEnd:          cst.cs.dbBlockHeight() + 14,
   893  		Payout:             payout,
   894  		ValidProofOutputs:  []types.SiacoinOutput{{Value: outputSize}},
   895  		MissedProofOutputs: []types.SiacoinOutput{{Value: outputSize}},
   896  		UnlockHash:         types.UnlockConditions{}.UnlockHash(), // The empty UC is anyone-can-spend
   897  	}
   898  
   899  	// Create and fund a transaction with a file contract.
   900  	txnBuilder, err := cst.wallet.StartTransaction()
   901  	if err != nil {
   902  		t.Fatal(err)
   903  	}
   904  	err = txnBuilder.FundSiacoins(payout)
   905  	if err != nil {
   906  		t.Fatal(err)
   907  	}
   908  	fcIndex := txnBuilder.AddFileContract(fc)
   909  	txnSet, err := txnBuilder.Sign(true)
   910  	if err != nil {
   911  		t.Fatal(err)
   912  	}
   913  	err = cst.tpool.AcceptTransactionSet(txnSet)
   914  	if err != nil {
   915  		t.Fatal(err)
   916  	}
   917  	_, err = cst.miner.AddBlock()
   918  	if err != nil {
   919  		t.Fatal(err)
   920  	}
   921  
   922  	// Check that the siafund pool was increased by the faulty float amount.
   923  	siafundPool := cst.cs.dbGetSiafundPool()
   924  	if !siafundPool.Equals64(15590e3) {
   925  		t.Fatal("siafund pool was not increased correctly")
   926  	}
   927  
   928  	// Mine blocks until the hardfork is reached.
   929  	for i := 0; i < 10; i++ {
   930  		_, err = cst.miner.AddBlock()
   931  		if err != nil {
   932  			t.Fatal(err)
   933  		}
   934  	}
   935  
   936  	// Submit a file contract revision and check that the payouts are able to
   937  	// be the same.
   938  	fcid := txnSet[len(txnSet)-1].FileContractID(fcIndex)
   939  	fcr := types.FileContractRevision{
   940  		ParentID:          fcid,
   941  		UnlockConditions:  types.UnlockConditions{},
   942  		NewRevisionNumber: 1,
   943  
   944  		NewFileSize:           1,
   945  		NewWindowStart:        cst.cs.dbBlockHeight() + 2,
   946  		NewWindowEnd:          cst.cs.dbBlockHeight() + 4,
   947  		NewValidProofOutputs:  fc.ValidProofOutputs,
   948  		NewMissedProofOutputs: fc.MissedProofOutputs,
   949  	}
   950  	txnBuilder, err = cst.wallet.StartTransaction()
   951  	if err != nil {
   952  		t.Fatal(err)
   953  	}
   954  	txnBuilder.AddFileContractRevision(fcr)
   955  	txnSet, err = txnBuilder.Sign(true)
   956  	if err != nil {
   957  		t.Fatal(err)
   958  	}
   959  	err = cst.tpool.AcceptTransactionSet(txnSet)
   960  	if err != nil {
   961  		t.Fatal(err)
   962  	}
   963  	_, err = cst.miner.AddBlock()
   964  	if err != nil {
   965  		t.Fatal(err)
   966  	}
   967  
   968  	// Mine blocks until the revision goes through, such that the sanity checks
   969  	// can be run.
   970  	for i := 0; i < 6; i++ {
   971  		_, err = cst.miner.AddBlock()
   972  		if err != nil {
   973  			t.Fatal(err)
   974  		}
   975  	}
   976  
   977  	// Check that the siafund pool did not change after the submitted revision.
   978  	siafundPool = cst.cs.dbGetSiafundPool()
   979  	if !siafundPool.Equals64(15590e3) {
   980  		t.Fatal("siafund pool was not increased correctly")
   981  	}
   982  }
   983  
   984  // mockGatewayDoesBroadcast implements modules.Gateway to mock the Broadcast
   985  // method.
   986  type mockGatewayDoesBroadcast struct {
   987  	modules.Gateway
   988  	broadcastCalled chan struct{}
   989  }
   990  
   991  // Broadcast is a mock implementation of modules.Gateway.Broadcast that
   992  // sends a sentinel value down a channel to signal it's been called.
   993  func (g *mockGatewayDoesBroadcast) Broadcast(name string, obj interface{}, peers []modules.Peer) {
   994  	g.Gateway.Broadcast(name, obj, peers)
   995  	g.broadcastCalled <- struct{}{}
   996  }
   997  
   998  // TestAcceptBlockBroadcasts tests that AcceptBlock broadcasts valid blocks and
   999  // that managedAcceptBlock does not.
  1000  func TestAcceptBlockBroadcasts(t *testing.T) {
  1001  	if testing.Short() {
  1002  		t.SkipNow()
  1003  	}
  1004  	t.Parallel()
  1005  	cst, err := blankConsensusSetTester(t.Name(), modules.ProdDependencies)
  1006  	if err != nil {
  1007  		t.Fatal(err)
  1008  	}
  1009  	defer cst.Close()
  1010  	mg := &mockGatewayDoesBroadcast{
  1011  		Gateway:         cst.cs.gateway,
  1012  		broadcastCalled: make(chan struct{}),
  1013  	}
  1014  	cst.cs.gateway = mg
  1015  
  1016  	// Test that Broadcast is called for valid blocks.
  1017  	b, _ := cst.miner.FindBlock()
  1018  	err = cst.cs.AcceptBlock(b)
  1019  	if err != nil {
  1020  		t.Fatal(err)
  1021  	}
  1022  	select {
  1023  	case <-mg.broadcastCalled:
  1024  	case <-time.After(10 * time.Millisecond):
  1025  		t.Error("expected AcceptBlock to broadcast a valid block")
  1026  	}
  1027  
  1028  	// Test that Broadcast is not called for invalid blocks.
  1029  	err = cst.cs.AcceptBlock(types.Block{})
  1030  	if err == nil {
  1031  		t.Fatal("expected AcceptBlock to error on an invalid block")
  1032  	}
  1033  	select {
  1034  	case <-mg.broadcastCalled:
  1035  		t.Error("AcceptBlock broadcasted an invalid block")
  1036  	case <-time.After(10 * time.Millisecond):
  1037  	}
  1038  
  1039  	// Test that Broadcast is not called in managedAcceptBlock.
  1040  	b, _ = cst.miner.FindBlock()
  1041  	_, err = cst.cs.managedAcceptBlocks([]types.Block{b})
  1042  	if err != nil {
  1043  		t.Fatal(err)
  1044  	}
  1045  	select {
  1046  	case <-mg.broadcastCalled:
  1047  		t.Errorf("managedAcceptBlock should not broadcast blocks")
  1048  	case <-time.After(10 * time.Millisecond):
  1049  	}
  1050  }
  1051  
  1052  // blockCountingSubscriber counts the number of blocks that get submitted to the
  1053  // subscriber, as well as the number of times that the subscriber has been given
  1054  // changes at all.
  1055  type blockCountingSubscriber struct {
  1056  	changes []modules.ConsensusChangeID
  1057  
  1058  	appliedBlocks  int
  1059  	revertedBlocks int
  1060  }
  1061  
  1062  // ProcessConsensusChange fills the subscription interface for the
  1063  // blockCountingSubscriber.
  1064  func (bcs *blockCountingSubscriber) ProcessConsensusChange(cc modules.ConsensusChange) {
  1065  	bcs.changes = append(bcs.changes, cc.ID)
  1066  	bcs.revertedBlocks += len(cc.RevertedBlocks)
  1067  	bcs.appliedBlocks += len(cc.AppliedBlocks)
  1068  }
  1069  
  1070  // TestChainedAcceptBlock creates series of blocks, some of which are valid,
  1071  // some invalid, and submits them to the consensus set, verifying that the
  1072  // consensus set updates correctly each time.
  1073  func TestChainedAcceptBlock(t *testing.T) {
  1074  	if testing.Short() {
  1075  		t.SkipNow()
  1076  	}
  1077  	t.Parallel()
  1078  	// Create a tester to send blocks in a batch to the other tester.
  1079  	cst, err := createConsensusSetTester(t.Name())
  1080  	if err != nil {
  1081  		t.Fatal(err)
  1082  	}
  1083  	defer cst.Close()
  1084  	cst2, err := blankConsensusSetTester(t.Name()+"2", modules.ProdDependencies)
  1085  	if err != nil {
  1086  		t.Fatal(err)
  1087  	}
  1088  	defer cst2.Close()
  1089  	// Subscribe a blockCountingSubscriber to cst2.
  1090  	var bcs blockCountingSubscriber
  1091  	cst2.cs.ConsensusSetSubscribe(&bcs, modules.ConsensusChangeBeginning, cst2.cs.tg.StopChan())
  1092  	if len(bcs.changes) != 1 || bcs.appliedBlocks != 1 || bcs.revertedBlocks != 0 {
  1093  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1094  	}
  1095  
  1096  	// Grab all of the blocks in cst, with the intention of giving them to cst2.
  1097  	var blocks []types.Block
  1098  	height := cst.cs.Height()
  1099  	for i := types.BlockHeight(0); i <= height; i++ {
  1100  		id, err := cst.cs.dbGetPath(i)
  1101  		if err != nil {
  1102  			t.Fatal(err)
  1103  		}
  1104  		pb, err := cst.cs.dbGetBlockMap(id)
  1105  		if err != nil {
  1106  			t.Fatal(err)
  1107  		}
  1108  		blocks = append(blocks, pb.Block)
  1109  	}
  1110  
  1111  	// Create a jumbling of the blocks, so that the set is not in order.
  1112  	jumble := make([]types.Block, len(blocks))
  1113  	jumble[0] = blocks[0]
  1114  	jumble[1] = blocks[2]
  1115  	jumble[2] = blocks[1]
  1116  	for i := 3; i < len(jumble); i++ {
  1117  		jumble[i] = blocks[i]
  1118  	}
  1119  	// Try to submit the blocks out-of-order, which would violate one of the
  1120  	// assumptions in managedAcceptBlocks.
  1121  	_, err = cst2.cs.managedAcceptBlocks(jumble)
  1122  	if err != errNonLinearChain {
  1123  		t.Fatal(err)
  1124  	}
  1125  	if cst2.cs.Height() != 0 {
  1126  		t.Fatal("blocks added even though the inputs were jumbled")
  1127  	}
  1128  	if len(bcs.changes) != 1 || bcs.appliedBlocks != 1 || bcs.revertedBlocks != 0 {
  1129  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1130  	}
  1131  
  1132  	// Tag an invalid block onto the end of blocks.
  1133  	block, err := cst.miner.AddBlock()
  1134  	if err != nil {
  1135  		t.Fatal(err)
  1136  	}
  1137  	// Adding an invalid transaction to make the block invalid.
  1138  	badBlock := block
  1139  	badBlock.Transactions = append(badBlock.Transactions, types.Transaction{
  1140  		SiacoinInputs: []types.SiacoinInput{{
  1141  			ParentID: types.SiacoinOutputID{1},
  1142  		}},
  1143  	})
  1144  	// Append the invalid transaction to the block.
  1145  	badBlocks := append(blocks, badBlock)
  1146  	// Submit the whole invalid set. Result should be that nothing is added.
  1147  	_, err = cst2.cs.managedAcceptBlocks(badBlocks)
  1148  	if err == nil {
  1149  		t.Fatal(err)
  1150  	}
  1151  	if cst2.cs.Height() != 0 {
  1152  		t.Log(cst2.cs.Height())
  1153  		t.Log(cst.cs.Height())
  1154  		t.Fatal("height is not correct, seems that blocks were added")
  1155  	}
  1156  	if bcs.appliedBlocks != 1 || bcs.revertedBlocks != 0 {
  1157  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1158  	}
  1159  
  1160  	// Try submitting the good blocks.
  1161  	_, err = cst2.cs.managedAcceptBlocks(blocks)
  1162  	if err != nil {
  1163  		t.Fatal(err)
  1164  	}
  1165  	if bcs.appliedBlocks != int(cst2.cs.Height()+1) || bcs.revertedBlocks != 0 {
  1166  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1167  	}
  1168  
  1169  	// Check that every change recorded in 'bcs' is also available in the
  1170  	// consensus set.
  1171  	for _, change := range bcs.changes {
  1172  		err := cst2.cs.db.Update(func(tx *bolt.Tx) error {
  1173  			_, exists := getEntry(tx, change)
  1174  			if !exists {
  1175  				t.Error("an entry was provided that doesn't exist")
  1176  			}
  1177  			return nil
  1178  		})
  1179  		if err != nil {
  1180  			t.Fatal(err)
  1181  		}
  1182  	}
  1183  }