github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/modules/consensus/accept_test.go (about)

     1  package consensus
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/Synthesix/Sia/modules"
    10  	"github.com/Synthesix/Sia/persist"
    11  	"github.com/Synthesix/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 := cst.wallet.StartTransaction()
   508  	err = txnBuilder.FundSiacoins(types.NewCurrency64(50))
   509  	if err != nil {
   510  		t.Fatal(err)
   511  	}
   512  	txnSet, err := txnBuilder.Sign(true) // true sets the 'wholeTransaction' flag
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  
   517  	// Mine and submit the invalid block to the consensus set. The first time
   518  	// around, the complaint should be about the rule-breaking transaction.
   519  	block, target, err := cst.miner.BlockForWork()
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  	block.Transactions = append(block.Transactions, txnSet...)
   524  	dosBlock, _ := cst.miner.SolveBlock(block, target)
   525  	err = cst.cs.AcceptBlock(dosBlock)
   526  	if err != errSiacoinInputOutputMismatch {
   527  		t.Fatalf("expected %v, got %v", errSiacoinInputOutputMismatch, err)
   528  	}
   529  
   530  	// Submit the same block a second time. The complaint should be that the
   531  	// block is already known to be invalid.
   532  	err = cst.cs.AcceptBlock(dosBlock)
   533  	if err != errDoSBlock {
   534  		t.Fatalf("expected %v, got %v", errDoSBlock, err)
   535  	}
   536  }
   537  
   538  // TestBlockKnownHandling submits known blocks to the consensus set.
   539  func TestBlockKnownHandling(t *testing.T) {
   540  	if testing.Short() {
   541  		t.SkipNow()
   542  	}
   543  	t.Parallel()
   544  	cst, err := createConsensusSetTester(t.Name())
   545  	if err != nil {
   546  		t.Fatal(err)
   547  	}
   548  	defer cst.Close()
   549  
   550  	// Get a block destined to be stale.
   551  	block, target, err := cst.miner.BlockForWork()
   552  	if err != nil {
   553  		t.Fatal(err)
   554  	}
   555  	staleBlock, _ := cst.miner.SolveBlock(block, target)
   556  
   557  	// Add two new blocks to the consensus set to block the stale block.
   558  	block1, err := cst.miner.AddBlock()
   559  	if err != nil {
   560  		t.Fatal(err)
   561  	}
   562  	block2, err := cst.miner.AddBlock()
   563  	if err != nil {
   564  		t.Fatal(err)
   565  	}
   566  
   567  	// Submit the stale block.
   568  	err = cst.cs.AcceptBlock(staleBlock)
   569  	if err != nil && err != modules.ErrNonExtendingBlock {
   570  		t.Fatal(err)
   571  	}
   572  
   573  	// Submit all the blocks again, looking for a 'stale block' error.
   574  	err = cst.cs.AcceptBlock(block1)
   575  	if err == nil {
   576  		t.Fatal("expected an error upon submitting the block")
   577  	}
   578  	err = cst.cs.AcceptBlock(block2)
   579  	if err == nil {
   580  		t.Fatal("expected an error upon submitting the block")
   581  	}
   582  	err = cst.cs.AcceptBlock(staleBlock)
   583  	if err == nil {
   584  		t.Fatal("expected an error upon submitting the block")
   585  	}
   586  
   587  	// Try submitting the genesis block.
   588  	id, err := cst.cs.dbGetPath(0)
   589  	if err != nil {
   590  		t.Fatal(err)
   591  	}
   592  	genesisBlock, err := cst.cs.dbGetBlockMap(id)
   593  	if err != nil {
   594  		t.Fatal(err)
   595  	}
   596  	err = cst.cs.AcceptBlock(genesisBlock.Block)
   597  	if err == nil {
   598  		t.Fatal("expected an error upon submitting the block")
   599  	}
   600  }
   601  
   602  // TestOrphanHandling passes an orphan block to the consensus set.
   603  func TestOrphanHandling(t *testing.T) {
   604  	if testing.Short() {
   605  		t.SkipNow()
   606  	}
   607  	t.Parallel()
   608  	cst, err := createConsensusSetTester(t.Name())
   609  	if err != nil {
   610  		t.Fatal(err)
   611  	}
   612  	defer cst.Close()
   613  
   614  	// Try submitting an orphan block to the consensus set. The empty block can
   615  	// be used, because looking for a parent is one of the first checks the
   616  	// consensus set performs.
   617  	orphan := types.Block{}
   618  	err = cst.cs.AcceptBlock(orphan)
   619  	if err != errOrphan {
   620  		t.Fatalf("expected %v, got %v", errOrphan, err)
   621  	}
   622  	err = cst.cs.AcceptBlock(orphan)
   623  	if err != errOrphan {
   624  		t.Fatalf("expected %v, got %v", errOrphan, err)
   625  	}
   626  }
   627  
   628  // TestMissedTarget submits a block that does not meet the required target.
   629  func TestMissedTarget(t *testing.T) {
   630  	if testing.Short() {
   631  		t.SkipNow()
   632  	}
   633  	t.Parallel()
   634  	cst, err := createConsensusSetTester(t.Name())
   635  	if err != nil {
   636  		t.Fatal(err)
   637  	}
   638  	defer cst.Close()
   639  
   640  	// Mine a block that doesn't meet the target.
   641  	block, target, err := cst.miner.BlockForWork()
   642  	if err != nil {
   643  		t.Fatal(err)
   644  	}
   645  	for checkTarget(block, block.ID(), target) && block.Nonce[0] != 255 {
   646  		block.Nonce[0]++
   647  	}
   648  	if checkTarget(block, block.ID(), target) {
   649  		t.Fatal("unable to find a failing target")
   650  	}
   651  	err = cst.cs.AcceptBlock(block)
   652  	if err != modules.ErrBlockUnsolved {
   653  		t.Fatalf("expected %v, got %v", modules.ErrBlockUnsolved, err)
   654  	}
   655  }
   656  
   657  // TestMinerPayoutHandling checks that blocks with incorrect payouts are
   658  // rejected.
   659  func TestMinerPayoutHandling(t *testing.T) {
   660  	if testing.Short() {
   661  		t.SkipNow()
   662  	}
   663  	t.Parallel()
   664  	cst, err := createConsensusSetTester(t.Name())
   665  	if err != nil {
   666  		t.Fatal(err)
   667  	}
   668  	defer cst.Close()
   669  
   670  	// Create a block with the wrong miner payout structure - testing can be
   671  	// light here because there is heavier testing in the 'types' package,
   672  	// where the logic is defined.
   673  	block, target, err := cst.miner.BlockForWork()
   674  	if err != nil {
   675  		t.Fatal(err)
   676  	}
   677  	block.MinerPayouts = append(block.MinerPayouts, types.SiacoinOutput{Value: types.NewCurrency64(1)})
   678  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   679  	err = cst.cs.AcceptBlock(solvedBlock)
   680  	if err != errBadMinerPayouts {
   681  		t.Fatalf("expected %v, got %v", errBadMinerPayouts, err)
   682  	}
   683  }
   684  
   685  // TestEarlyTimestampHandling checks that blocks too far in the past are
   686  // rejected.
   687  func TestEarlyTimestampHandling(t *testing.T) {
   688  	if testing.Short() {
   689  		t.SkipNow()
   690  	}
   691  	t.Parallel()
   692  	cst, err := createConsensusSetTester(t.Name())
   693  	if err != nil {
   694  		t.Fatal(err)
   695  	}
   696  	defer cst.Close()
   697  	minTimestamp := types.CurrentTimestamp()
   698  	cst.cs.blockRuleHelper = mockBlockRuleHelper{
   699  		minTimestamp: minTimestamp,
   700  	}
   701  
   702  	// Submit a block with a timestamp in the past, before minTimestamp.
   703  	block, target, err := cst.miner.BlockForWork()
   704  	if err != nil {
   705  		t.Fatal(err)
   706  	}
   707  	block.Timestamp = minTimestamp - 1
   708  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   709  	err = cst.cs.AcceptBlock(solvedBlock)
   710  	if err != errEarlyTimestamp {
   711  		t.Fatalf("expected %v, got %v", errEarlyTimestamp, err)
   712  	}
   713  }
   714  
   715  // testFutureTimestampHandling checks that blocks in the future (but not
   716  // extreme future) are handled correctly.
   717  func TestFutureTimestampHandling(t *testing.T) {
   718  	if testing.Short() {
   719  		t.SkipNow()
   720  	}
   721  	t.Parallel()
   722  	cst, err := createConsensusSetTester(t.Name())
   723  	if err != nil {
   724  		t.Fatal(err)
   725  	}
   726  	defer cst.Close()
   727  
   728  	// Submit a block with a timestamp in the future, but not the extreme
   729  	// future.
   730  	block, target, err := cst.miner.BlockForWork()
   731  	if err != nil {
   732  		t.Fatal(err)
   733  	}
   734  	block.Timestamp = types.CurrentTimestamp() + 2 + types.FutureThreshold
   735  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   736  	err = cst.cs.AcceptBlock(solvedBlock)
   737  	if err != errFutureTimestamp {
   738  		t.Fatalf("expected %v, got %v", errFutureTimestamp, err)
   739  	}
   740  
   741  	// Poll the consensus set until the future block appears.
   742  	for i := 0; i < 30; i++ {
   743  		time.Sleep(time.Second * 3)
   744  		_, err = cst.cs.dbGetBlockMap(solvedBlock.ID())
   745  		if err == nil {
   746  			break
   747  		}
   748  	}
   749  	_, err = cst.cs.dbGetBlockMap(solvedBlock.ID())
   750  	if err != nil {
   751  		t.Errorf("Future block not added to consensus set.\nCurrent Timestamp %v\nFutureThreshold: %v\nBlock Timestamp %v\n", types.CurrentTimestamp(), types.FutureThreshold, block.Timestamp)
   752  	}
   753  }
   754  
   755  // TestExtremeFutureTimestampHandling checks that blocks in the extreme future
   756  // are rejected.
   757  func TestExtremeFutureTimestampHandling(t *testing.T) {
   758  	if testing.Short() {
   759  		t.SkipNow()
   760  	}
   761  	t.Parallel()
   762  	cst, err := createConsensusSetTester(t.Name())
   763  	if err != nil {
   764  		t.Fatal(err)
   765  	}
   766  	defer cst.Close()
   767  
   768  	// Submit a block with a timestamp in the extreme future.
   769  	block, target, err := cst.miner.BlockForWork()
   770  	if err != nil {
   771  		t.Fatal(err)
   772  	}
   773  	block.Timestamp = types.CurrentTimestamp() + 2 + types.ExtremeFutureThreshold
   774  	solvedBlock, _ := cst.miner.SolveBlock(block, target)
   775  	err = cst.cs.AcceptBlock(solvedBlock)
   776  	if err != errExtremeFutureTimestamp {
   777  		t.Fatalf("expected %v, got %v", errFutureTimestamp, err)
   778  	}
   779  }
   780  
   781  // TestBuriedBadTransaction tries submitting a block with a bad transaction
   782  // that is buried under good transactions.
   783  func TestBuriedBadTransaction(t *testing.T) {
   784  	if testing.Short() {
   785  		t.SkipNow()
   786  	}
   787  	t.Parallel()
   788  	cst, err := createConsensusSetTester(t.Name())
   789  	if err != nil {
   790  		t.Fatal(err)
   791  	}
   792  	defer cst.Close()
   793  	pb := cst.cs.dbCurrentProcessedBlock()
   794  
   795  	// Create a good transaction using the wallet.
   796  	txnValue := types.NewCurrency64(1200)
   797  	txnBuilder := cst.wallet.StartTransaction()
   798  	err = txnBuilder.FundSiacoins(txnValue)
   799  	if err != nil {
   800  		t.Fatal(err)
   801  	}
   802  	txnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: txnValue})
   803  	txnSet, err := txnBuilder.Sign(true)
   804  	if err != nil {
   805  		t.Fatal(err)
   806  	}
   807  	err = cst.tpool.AcceptTransactionSet(txnSet)
   808  	if err != nil {
   809  		t.Fatal(err)
   810  	}
   811  
   812  	// Create a bad transaction
   813  	badTxn := types.Transaction{
   814  		SiacoinInputs: []types.SiacoinInput{{}},
   815  	}
   816  	txns := append(cst.tpool.TransactionList(), badTxn)
   817  
   818  	// Create a block with a buried bad transaction.
   819  	block := types.Block{
   820  		ParentID:     pb.Block.ID(),
   821  		Timestamp:    types.CurrentTimestamp(),
   822  		MinerPayouts: []types.SiacoinOutput{{Value: types.CalculateCoinbase(pb.Height + 1)}},
   823  		Transactions: txns,
   824  	}
   825  	block, _ = cst.miner.SolveBlock(block, pb.ChildTarget)
   826  	err = cst.cs.AcceptBlock(block)
   827  	if err == nil {
   828  		t.Error("buried transaction didn't cause an error")
   829  	}
   830  }
   831  
   832  // TestInconsistencyCheck puts the consensus set in to an inconsistent state
   833  // and makes sure that the santiy checks are triggering panics.
   834  func TestInconsistentCheck(t *testing.T) {
   835  	if testing.Short() {
   836  		t.SkipNow()
   837  	}
   838  	t.Parallel()
   839  	cst, err := createConsensusSetTester(t.Name())
   840  	if err != nil {
   841  		t.Fatal(err)
   842  	}
   843  
   844  	// Corrupt the consensus set by adding a new siafund output.
   845  	sfo := types.SiafundOutput{
   846  		Value: types.NewCurrency64(1),
   847  	}
   848  	cst.cs.dbAddSiafundOutput(types.SiafundOutputID{}, sfo)
   849  
   850  	// Catch a panic that should be caused by the inconsistency check after a
   851  	// block is mined.
   852  	defer func() {
   853  		r := recover()
   854  		if r == nil {
   855  			t.Fatalf("inconsistency panic not triggered by corrupted database")
   856  		}
   857  	}()
   858  	_, err = cst.miner.AddBlock()
   859  	if err != nil {
   860  		t.Fatal(err)
   861  	}
   862  }
   863  
   864  // COMPATv0.4.0
   865  //
   866  // This test checks that the hardfork scheduled for block 21,000 rolls through
   867  // smoothly.
   868  func TestTaxHardfork(t *testing.T) {
   869  	if testing.Short() {
   870  		t.SkipNow()
   871  	}
   872  	t.Parallel()
   873  	cst, err := createConsensusSetTester(t.Name())
   874  	if err != nil {
   875  		t.Fatal(err)
   876  	}
   877  	defer cst.Close()
   878  
   879  	// Create a file contract with a payout that is put into the blockchain
   880  	// before the hardfork block but expires after the hardfork block.
   881  	payout := types.NewCurrency64(400e6)
   882  	outputSize := types.PostTax(cst.cs.dbBlockHeight(), payout)
   883  	fc := types.FileContract{
   884  		WindowStart:        cst.cs.dbBlockHeight() + 12,
   885  		WindowEnd:          cst.cs.dbBlockHeight() + 14,
   886  		Payout:             payout,
   887  		ValidProofOutputs:  []types.SiacoinOutput{{Value: outputSize}},
   888  		MissedProofOutputs: []types.SiacoinOutput{{Value: outputSize}},
   889  		UnlockHash:         types.UnlockConditions{}.UnlockHash(), // The empty UC is anyone-can-spend
   890  	}
   891  
   892  	// Create and fund a transaction with a file contract.
   893  	txnBuilder := cst.wallet.StartTransaction()
   894  	err = txnBuilder.FundSiacoins(payout)
   895  	if err != nil {
   896  		t.Fatal(err)
   897  	}
   898  	fcIndex := txnBuilder.AddFileContract(fc)
   899  	txnSet, err := txnBuilder.Sign(true)
   900  	if err != nil {
   901  		t.Fatal(err)
   902  	}
   903  	err = cst.tpool.AcceptTransactionSet(txnSet)
   904  	if err != nil {
   905  		t.Fatal(err)
   906  	}
   907  	_, err = cst.miner.AddBlock()
   908  	if err != nil {
   909  		t.Fatal(err)
   910  	}
   911  
   912  	// Check that the siafund pool was increased by the faulty float amount.
   913  	siafundPool := cst.cs.dbGetSiafundPool()
   914  	if !siafundPool.Equals64(15590e3) {
   915  		t.Fatal("siafund pool was not increased correctly")
   916  	}
   917  
   918  	// Mine blocks until the hardfork is reached.
   919  	for i := 0; i < 10; i++ {
   920  		_, err = cst.miner.AddBlock()
   921  		if err != nil {
   922  			t.Fatal(err)
   923  		}
   924  	}
   925  
   926  	// Submit a file contract revision and check that the payouts are able to
   927  	// be the same.
   928  	fcid := txnSet[len(txnSet)-1].FileContractID(fcIndex)
   929  	fcr := types.FileContractRevision{
   930  		ParentID:          fcid,
   931  		UnlockConditions:  types.UnlockConditions{},
   932  		NewRevisionNumber: 1,
   933  
   934  		NewFileSize:           1,
   935  		NewWindowStart:        cst.cs.dbBlockHeight() + 2,
   936  		NewWindowEnd:          cst.cs.dbBlockHeight() + 4,
   937  		NewValidProofOutputs:  fc.ValidProofOutputs,
   938  		NewMissedProofOutputs: fc.MissedProofOutputs,
   939  	}
   940  	txnBuilder = cst.wallet.StartTransaction()
   941  	txnBuilder.AddFileContractRevision(fcr)
   942  	txnSet, err = txnBuilder.Sign(true)
   943  	if err != nil {
   944  		t.Fatal(err)
   945  	}
   946  	err = cst.tpool.AcceptTransactionSet(txnSet)
   947  	if err != nil {
   948  		t.Fatal(err)
   949  	}
   950  	_, err = cst.miner.AddBlock()
   951  	if err != nil {
   952  		t.Fatal(err)
   953  	}
   954  
   955  	// Mine blocks until the revision goes through, such that the sanity checks
   956  	// can be run.
   957  	for i := 0; i < 6; i++ {
   958  		_, err = cst.miner.AddBlock()
   959  		if err != nil {
   960  			t.Fatal(err)
   961  		}
   962  	}
   963  
   964  	// Check that the siafund pool did not change after the submitted revision.
   965  	siafundPool = cst.cs.dbGetSiafundPool()
   966  	if !siafundPool.Equals64(15590e3) {
   967  		t.Fatal("siafund pool was not increased correctly")
   968  	}
   969  }
   970  
   971  // mockGatewayDoesBroadcast implements modules.Gateway to mock the Broadcast
   972  // method.
   973  type mockGatewayDoesBroadcast struct {
   974  	modules.Gateway
   975  	broadcastCalled chan struct{}
   976  }
   977  
   978  // Broadcast is a mock implementation of modules.Gateway.Broadcast that
   979  // sends a sentinel value down a channel to signal it's been called.
   980  func (g *mockGatewayDoesBroadcast) Broadcast(name string, obj interface{}, peers []modules.Peer) {
   981  	g.Gateway.Broadcast(name, obj, peers)
   982  	g.broadcastCalled <- struct{}{}
   983  }
   984  
   985  // TestAcceptBlockBroadcasts tests that AcceptBlock broadcasts valid blocks and
   986  // that managedAcceptBlock does not.
   987  func TestAcceptBlockBroadcasts(t *testing.T) {
   988  	if testing.Short() {
   989  		t.SkipNow()
   990  	}
   991  	t.Parallel()
   992  	cst, err := blankConsensusSetTester(t.Name())
   993  	if err != nil {
   994  		t.Fatal(err)
   995  	}
   996  	defer cst.Close()
   997  	mg := &mockGatewayDoesBroadcast{
   998  		Gateway:         cst.cs.gateway,
   999  		broadcastCalled: make(chan struct{}),
  1000  	}
  1001  	cst.cs.gateway = mg
  1002  
  1003  	// Test that Broadcast is called for valid blocks.
  1004  	b, _ := cst.miner.FindBlock()
  1005  	err = cst.cs.AcceptBlock(b)
  1006  	if err != nil {
  1007  		t.Fatal(err)
  1008  	}
  1009  	select {
  1010  	case <-mg.broadcastCalled:
  1011  	case <-time.After(10 * time.Millisecond):
  1012  		t.Error("expected AcceptBlock to broadcast a valid block")
  1013  	}
  1014  
  1015  	// Test that Broadcast is not called for invalid blocks.
  1016  	err = cst.cs.AcceptBlock(types.Block{})
  1017  	if err == nil {
  1018  		t.Fatal("expected AcceptBlock to error on an invalid block")
  1019  	}
  1020  	select {
  1021  	case <-mg.broadcastCalled:
  1022  		t.Error("AcceptBlock broadcasted an invalid block")
  1023  	case <-time.After(10 * time.Millisecond):
  1024  	}
  1025  
  1026  	// Test that Broadcast is not called in managedAcceptBlock.
  1027  	b, _ = cst.miner.FindBlock()
  1028  	_, err = cst.cs.managedAcceptBlocks([]types.Block{b})
  1029  	if err != nil {
  1030  		t.Fatal(err)
  1031  	}
  1032  	select {
  1033  	case <-mg.broadcastCalled:
  1034  		t.Errorf("managedAcceptBlock should not broadcast blocks")
  1035  	case <-time.After(10 * time.Millisecond):
  1036  	}
  1037  }
  1038  
  1039  // blockCountingSubscriber counts the number of blocks that get submitted to the
  1040  // subscriber, as well as the number of times that the subscriber has been given
  1041  // changes at all.
  1042  type blockCountingSubscriber struct {
  1043  	changes []modules.ConsensusChangeID
  1044  
  1045  	appliedBlocks  int
  1046  	revertedBlocks int
  1047  }
  1048  
  1049  // ProcessConsensusChange fills the subscription interface for the
  1050  // blockCountingSubscriber.
  1051  func (bcs *blockCountingSubscriber) ProcessConsensusChange(cc modules.ConsensusChange) {
  1052  	bcs.changes = append(bcs.changes, cc.ID)
  1053  	bcs.revertedBlocks += len(cc.RevertedBlocks)
  1054  	bcs.appliedBlocks += len(cc.AppliedBlocks)
  1055  }
  1056  
  1057  // TestChainedAcceptBlock creates series of blocks, some of which are valid,
  1058  // some invalid, and submits them to the consensus set, verifying that the
  1059  // consensus set updates correctly each time.
  1060  func TestChainedAcceptBlock(t *testing.T) {
  1061  	if testing.Short() {
  1062  		t.SkipNow()
  1063  	}
  1064  	t.Parallel()
  1065  	// Create a tester to send blocks in a batch to the other tester.
  1066  	cst, err := createConsensusSetTester(t.Name())
  1067  	if err != nil {
  1068  		t.Fatal(err)
  1069  	}
  1070  	defer cst.Close()
  1071  	cst2, err := blankConsensusSetTester(t.Name() + "2")
  1072  	if err != nil {
  1073  		t.Fatal(err)
  1074  	}
  1075  	defer cst2.Close()
  1076  	// Subscribe a blockCountingSubscriber to cst2.
  1077  	var bcs blockCountingSubscriber
  1078  	cst2.cs.ConsensusSetSubscribe(&bcs, modules.ConsensusChangeBeginning, cst2.cs.tg.StopChan())
  1079  	if len(bcs.changes) != 1 || bcs.appliedBlocks != 1 || bcs.revertedBlocks != 0 {
  1080  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1081  	}
  1082  
  1083  	// Grab all of the blocks in cst, with the intention of giving them to cst2.
  1084  	var blocks []types.Block
  1085  	height := cst.cs.Height()
  1086  	for i := types.BlockHeight(0); i <= height; i++ {
  1087  		id, err := cst.cs.dbGetPath(i)
  1088  		if err != nil {
  1089  			t.Fatal(err)
  1090  		}
  1091  		pb, err := cst.cs.dbGetBlockMap(id)
  1092  		if err != nil {
  1093  			t.Fatal(err)
  1094  		}
  1095  		blocks = append(blocks, pb.Block)
  1096  	}
  1097  
  1098  	// Create a jumbling of the blocks, so that the set is not in order.
  1099  	jumble := make([]types.Block, len(blocks))
  1100  	jumble[0] = blocks[0]
  1101  	jumble[1] = blocks[2]
  1102  	jumble[2] = blocks[1]
  1103  	for i := 3; i < len(jumble); i++ {
  1104  		jumble[i] = blocks[i]
  1105  	}
  1106  	// Try to submit the blocks out-of-order, which would violate one of the
  1107  	// assumptions in managedAcceptBlocks.
  1108  	_, err = cst2.cs.managedAcceptBlocks(jumble)
  1109  	if err != errNonLinearChain {
  1110  		t.Fatal(err)
  1111  	}
  1112  	if cst2.cs.Height() != 0 {
  1113  		t.Fatal("blocks added even though the inputs were jumbled")
  1114  	}
  1115  	if len(bcs.changes) != 1 || bcs.appliedBlocks != 1 || bcs.revertedBlocks != 0 {
  1116  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1117  	}
  1118  
  1119  	// Tag an invalid block onto the end of blocks.
  1120  	block, err := cst.miner.AddBlock()
  1121  	if err != nil {
  1122  		t.Fatal(err)
  1123  	}
  1124  	// Adding an invalid transaction to make the block invalid.
  1125  	badBlock := block
  1126  	badBlock.Transactions = append(badBlock.Transactions, types.Transaction{
  1127  		SiacoinInputs: []types.SiacoinInput{{
  1128  			ParentID: types.SiacoinOutputID{1},
  1129  		}},
  1130  	})
  1131  	// Append the invalid transaction to the block.
  1132  	badBlocks := append(blocks, badBlock)
  1133  	// Submit the whole invalid set. Result should be that nothing is added.
  1134  	_, err = cst2.cs.managedAcceptBlocks(badBlocks)
  1135  	if err == nil {
  1136  		t.Fatal(err)
  1137  	}
  1138  	if cst2.cs.Height() != 0 {
  1139  		t.Log(cst2.cs.Height())
  1140  		t.Log(cst.cs.Height())
  1141  		t.Fatal("height is not correct, seems that blocks were added")
  1142  	}
  1143  	if bcs.appliedBlocks != 1 || bcs.revertedBlocks != 0 {
  1144  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1145  	}
  1146  
  1147  	// Try submitting the good blocks.
  1148  	_, err = cst2.cs.managedAcceptBlocks(blocks)
  1149  	if err != nil {
  1150  		t.Fatal(err)
  1151  	}
  1152  	if bcs.appliedBlocks != int(cst2.cs.Height()+1) || bcs.revertedBlocks != 0 {
  1153  		t.Error("consensus changes do not seem to be getting passed to subscribers correctly")
  1154  	}
  1155  
  1156  	// Check that every change recorded in 'bcs' is also available in the
  1157  	// consensus set.
  1158  	for _, change := range bcs.changes {
  1159  		err := cst2.cs.db.Update(func(tx *bolt.Tx) error {
  1160  			_, exists := getEntry(tx, change)
  1161  			if !exists {
  1162  				t.Error("an entry was provided that doesn't exist")
  1163  			}
  1164  			return nil
  1165  		})
  1166  		if err != nil {
  1167  			t.Fatal(err)
  1168  		}
  1169  	}
  1170  }