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