github.com/NebulousLabs/Sia@v1.3.7/modules/consensus/accept_test.go (about)

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