func TestAcceptBlockBroadcasts(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := blankConsensusSetTester(t.Name(), modules.ProdDependencies)
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	mg := &mockGatewayDoesBroadcast{
		Gateway:         cst.cs.gateway,
		broadcastCalled: make(chan struct{}),
	}
	cst.cs.gateway = mg
	b, _ := cst.miner.FindBlock()
	err = cst.cs.AcceptBlock(b)
	if err != nil {
		t.Fatal(err)
	}
	select {
	case <-mg.broadcastCalled:
	case <-time.After(10 * time.Millisecond):
		t.Error("expected AcceptBlock to broadcast a valid block")
	}
	err = cst.cs.AcceptBlock(types.Block{})
	if err == nil {
		t.Fatal("expected AcceptBlock to error on an invalid block")
	}
	select {
	case <-mg.broadcastCalled:
		t.Error("AcceptBlock broadcasted an invalid block")
	case <-time.After(10 * time.Millisecond):
	}
	b, _ = cst.miner.FindBlock()
	_, err = cst.cs.managedAcceptBlocks([]types.Block{b})
	if err != nil {
		t.Fatal(err)
	}
	select {
	case <-mg.broadcastCalled:
		t.Errorf("managedAcceptBlock should not broadcast blocks")
	case <-time.After(10 * time.Millisecond):
	}
}
TestAcceptBlockBroadcasts tests that AcceptBlock broadcasts valid blocks and
that managedAcceptBlock does not.
package consensus
import (
	"bytes"
	"errors"
	"testing"
	"time"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/persist"
	"github.com/NebulousLabs/Sia/types"
	"github.com/coreos/bbolt"
)
var (
	validateBlockParamsGot validateBlockParams
	mockValidBlock = types.Block{
		Timestamp: 100,
		ParentID:  mockParentID(),
	}
	mockInvalidBlock = types.Block{
		Timestamp: 500,
		ParentID:  mockParentID(),
	}
	parentBlockSerialized = []byte{3, 2, 1}
	parentBlockUnmarshaler = mockBlockMarshaler{
		[]predefinedBlockUnmarshal{
			{parentBlockSerialized, mockParent(), nil},
		},
	}
	parentBlockHighTargetUnmarshaler = mockBlockMarshaler{
		[]predefinedBlockUnmarshal{
			{parentBlockSerialized, mockParentHighTarget(), nil},
		},
	}
	parentBlockLowTargetUnmarshaler = mockBlockMarshaler{
		[]predefinedBlockUnmarshal{
			{parentBlockSerialized, mockParentLowTarget(), nil},
		},
	}
	unmarshalFailedErr = errors.New("mock unmarshal failed")
	failingBlockUnmarshaler = mockBlockMarshaler{
		[]predefinedBlockUnmarshal{
			{parentBlockSerialized, processedBlock{}, unmarshalFailedErr},
		},
	}
	serializedParentBlockMap = []blockMapPair{
		{mockValidBlock.ParentID[:], parentBlockSerialized},
	}
)
type (
	mockDbBucket struct {
		values map[string][]byte
	}
	mockDbTx struct {
		buckets map[string]dbBucket
	}
	predefinedBlockUnmarshal struct {
		serialized  []byte
		unmarshaled processedBlock
		err         error
	}
	mockBlockMarshaler struct {
		p []predefinedBlockUnmarshal
	}
	mockBlockRuleHelper struct {
		minTimestamp types.Timestamp
	}
	mockBlockValidator struct {
		err error
	}
	validateBlockParams struct {
		called       bool
		b            types.Block
		minTimestamp types.Timestamp
		target       types.Target
		height       types.BlockHeight
	}
	blockMapPair struct {
		key []byte
		val []byte
	}
)
func (bucket mockDbBucket) Get(key []byte) []byte {
	return bucket.values[string(key)]
}
func (bucket mockDbBucket) Set(key []byte, value []byte) {
	bucket.values[string(key)] = value
}
func (db mockDbTx) Bucket(name []byte) dbBucket {
	return db.buckets[string(name)]
}
func (m mockBlockMarshaler) Marshal(interface{}) []byte {
	panic("not implemented")
}
func (m mockBlockMarshaler) Unmarshal(b []byte, v interface{}) error {
	for _, pu := range m.p {
		if bytes.Equal(b[:], pu.serialized[:]) {
			pv, ok := v.(*processedBlock)
			if !ok {
				panic("mockBlockMarshaler.Unmarshal expected v to be of type processedBlock")
			}
			*pv = pu.unmarshaled
			return pu.err
		}
	}
	panic("unmarshal failed: predefined unmarshal not found")
}
func (m *mockBlockMarshaler) AddPredefinedUnmarshal(u predefinedBlockUnmarshal) {
	m.p = append(m.p, u)
}
func (brh mockBlockRuleHelper) minimumValidChildTimestamp(blockMap dbBucket, pb *processedBlock) types.Timestamp {
	return brh.minTimestamp
}
func (bv mockBlockValidator) ValidateBlock(b types.Block, id types.BlockID, minTimestamp types.Timestamp, target types.Target, height types.BlockHeight, log *persist.Logger) error {
	validateBlockParamsGot = validateBlockParams{true, b, minTimestamp, target, height}
	return bv.err
}
func mockParentID() (parentID types.BlockID) {
	parentID[0] = 42
	return parentID
}
func mockParent() (parent processedBlock) {
	var mockTarget types.Target
	mockTarget[0] = 56
	parent.ChildTarget = mockTarget
	return parent
}
func mockParentHighTarget() (parent processedBlock) {
	parent.ChildTarget = types.RootDepth
	return parent
}
func mockParentLowTarget() (parent processedBlock) {
	return parent
}
func TestUnitValidateHeaderAndBlock(t *testing.T) {
	var tests = []struct {
		block                  types.Block
		dosBlocks              map[types.BlockID]struct{}
		blockMapPairs          []blockMapPair
		earliestValidTimestamp types.Timestamp
		marshaler              mockBlockMarshaler
		useNilBlockMap         bool
		validateBlockErr       error
		errWant                error
		msg                    string
	}{
		{
			block:                  mockValidBlock,
			dosBlocks:              make(map[types.BlockID]struct{}),
			useNilBlockMap:         true,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                errNoBlockMap,
			msg:                    "validateHeaderAndBlock should fail when no block map is found in the database",
		},
		{
			block: mockValidBlock,
			dosBlocks: map[types.BlockID]struct{}{
				mockValidBlock.ID(): {},
			},
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                errDoSBlock,
			msg:                    "validateHeaderAndBlock should reject known bad blocks",
		},
		{
			block:                  mockValidBlock,
			dosBlocks:              make(map[types.BlockID]struct{}),
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                errOrphan,
			msg:                    "validateHeaderAndBlock should reject a block if its parent block does not appear in the block database",
		},
		{
			block:                  mockValidBlock,
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              failingBlockUnmarshaler,
			errWant:                unmarshalFailedErr,
			msg:                    "validateHeaderAndBlock should fail when unmarshaling the parent block fails",
		},
		{
			block:     mockInvalidBlock,
			dosBlocks: make(map[types.BlockID]struct{}),
			blockMapPairs: []blockMapPair{
				{mockInvalidBlock.ParentID[:], parentBlockSerialized},
			},
			earliestValidTimestamp: mockInvalidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			validateBlockErr:       errBadMinerPayouts,
			errWant:                errBadMinerPayouts,
			msg:                    "validateHeaderAndBlock should reject a block if ValidateBlock returns an error for the block",
		},
		{
			block:                  mockValidBlock,
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                nil,
			msg:                    "validateHeaderAndBlock should accept a valid block",
		},
	}
	for _, tt := range tests {
		bucket := mockDbBucket{map[string][]byte{}}
		for _, mapPair := range tt.blockMapPairs {
			bucket.Set(mapPair.key, mapPair.val)
		}
		dbBucketMap := map[string]dbBucket{}
		if tt.useNilBlockMap {
			dbBucketMap[string(BlockMap)] = nil
		} else {
			dbBucketMap[string(BlockMap)] = bucket
		}
		tx := mockDbTx{dbBucketMap}
		mockParent := mockParent()
		cs := ConsensusSet{
			dosBlocks: tt.dosBlocks,
			marshaler: tt.marshaler,
			blockRuleHelper: mockBlockRuleHelper{
				minTimestamp: tt.earliestValidTimestamp,
			},
			blockValidator: mockBlockValidator{tt.validateBlockErr},
		}
		validateBlockParamsGot = validateBlockParams{}
		_, err := cs.validateHeaderAndBlock(tx, tt.block, tt.block.ID())
		if err != tt.errWant {
			t.Errorf("%s: expected to fail with `%v', got: `%v'", tt.msg, tt.errWant, err)
		}
		if err == nil || validateBlockParamsGot.called {
			if validateBlockParamsGot.b.ID() != tt.block.ID() {
				t.Errorf("%s: incorrect parameter passed to ValidateBlock - got: %v, want: %v", tt.msg, validateBlockParamsGot.b, tt.block)
			}
			if validateBlockParamsGot.minTimestamp != tt.earliestValidTimestamp {
				t.Errorf("%s: incorrect parameter passed to ValidateBlock - got: %v, want: %v", tt.msg, validateBlockParamsGot.minTimestamp, tt.earliestValidTimestamp)
			}
			if validateBlockParamsGot.target != mockParent.ChildTarget {
				t.Errorf("%s: incorrect parameter passed to ValidateBlock - got: %v, want: %v", tt.msg, validateBlockParamsGot.target, mockParent.ChildTarget)
			}
		}
	}
}
func TestCheckHeaderTarget(t *testing.T) {
	var b types.Block
	var h types.BlockHeader
	tests := []struct {
		target   types.Target
		expected bool
		msg      string
	}{
		{types.RootDepth, true, "checkHeaderTarget failed for a low target"},
		{types.Target{}, false, "checkHeaderTarget passed for a high target"},
		{types.Target(h.ID()), true, "checkHeaderTarget failed for a same target"},
	}
	for _, tt := range tests {
		if checkHeaderTarget(h, tt.target) != tt.expected {
			t.Error(tt.msg)
		}
		if checkHeaderTarget(h, tt.target) != checkTarget(b, b.ID(), tt.target) {
			t.Errorf("checkHeaderTarget and checkTarget do not match for target %v", tt.target)
		}
	}
}
func TestUnitValidateHeader(t *testing.T) {
	mockValidBlockID := mockValidBlock.ID()
	var tests = []struct {
		header                 types.BlockHeader
		dosBlocks              map[types.BlockID]struct{}
		blockMapPairs          []blockMapPair
		earliestValidTimestamp types.Timestamp
		marshaler              mockBlockMarshaler
		useNilBlockMap         bool
		errWant                error
		msg                    string
	}{
		{
			header: mockValidBlock.Header(),
			dosBlocks: map[types.BlockID]struct{}{
				mockValidBlock.ID(): {},
			},
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                errDoSBlock,
			msg:                    "validateHeader should reject known bad blocks",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			useNilBlockMap:         true,
			errWant:                errNoBlockMap,
			msg:                    "validateHeader should fail when no block map is found in the database",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          []blockMapPair{{mockValidBlockID[:], []byte{}}},
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                modules.ErrBlockKnown,
			msg:                    "validateHeader should fail when the block has been seen before",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockUnmarshaler,
			errWant:                errOrphan,
			msg:                    "validateHeader should reject a block if its parent block does not appear in the block database",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              failingBlockUnmarshaler,
			errWant:                unmarshalFailedErr,
			msg:                    "validateHeader should fail when unmarshaling the parent block fails",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp + 1,
			marshaler:              parentBlockHighTargetUnmarshaler,
			errWant:                errEarlyTimestamp,
			msg:                    "validateHeader should fail when the header's timestamp is too early",
		},
		{
			header: types.BlockHeader{
				Timestamp: types.CurrentTimestamp() + types.ExtremeFutureThreshold + 2,
				ParentID:  mockParentID(),
			},
			dosBlocks:     make(map[types.BlockID]struct{}),
			blockMapPairs: serializedParentBlockMap,
			marshaler:     parentBlockHighTargetUnmarshaler,
			errWant:       errExtremeFutureTimestamp,
			msg:           "validateHeader should fail when the header's timestamp is in the extreme future",
		},
		{
			header: types.BlockHeader{
				Timestamp: types.CurrentTimestamp() + types.FutureThreshold + 2,
				ParentID:  mockParentID(),
			},
			dosBlocks:     make(map[types.BlockID]struct{}),
			blockMapPairs: serializedParentBlockMap,
			marshaler:     parentBlockHighTargetUnmarshaler,
			errWant:       nil,
			msg:           "validateHeader should not reject headers whose timestamps are in the near future",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockLowTargetUnmarshaler,
			errWant:                modules.ErrBlockUnsolved,
			msg:                    "validateHeader should reject blocks with an insufficiently low target",
		},
		{
			header:                 mockValidBlock.Header(),
			dosBlocks:              make(map[types.BlockID]struct{}),
			blockMapPairs:          serializedParentBlockMap,
			earliestValidTimestamp: mockValidBlock.Timestamp,
			marshaler:              parentBlockHighTargetUnmarshaler,
			errWant:                nil,
			msg:                    "validateHeader should accept a valid block",
		},
	}
	for _, tt := range tests {
		bucket := mockDbBucket{map[string][]byte{}}
		for _, mapPair := range tt.blockMapPairs {
			bucket.Set(mapPair.key, mapPair.val)
		}
		dbBucketMap := map[string]dbBucket{}
		if tt.useNilBlockMap {
			dbBucketMap[string(BlockMap)] = nil
		} else {
			dbBucketMap[string(BlockMap)] = bucket
		}
		tx := mockDbTx{dbBucketMap}
		cs := ConsensusSet{
			dosBlocks: tt.dosBlocks,
			marshaler: tt.marshaler,
			blockRuleHelper: mockBlockRuleHelper{
				minTimestamp: tt.earliestValidTimestamp,
			},
		}
		err := cs.validateHeader(tx, tt.header)
		if err != tt.errWant {
			t.Errorf("%s: expected to fail with `%v', got: `%v'", tt.msg, tt.errWant, err)
		}
	}
}
func TestIntegrationDoSBlockHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	txnBuilder, err := cst.wallet.StartTransaction()
	if err != nil {
		t.Fatal(err)
	}
	err = txnBuilder.FundSiacoins(types.NewCurrency64(50))
	if err != nil {
		t.Fatal(err)
	}
	txnSet, err := txnBuilder.Sign(true)  
	if err != nil {
		t.Fatal(err)
	}
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	block.Transactions = append(block.Transactions, txnSet...)
	dosBlock, _ := cst.miner.SolveBlock(block, target)
	err = cst.cs.AcceptBlock(dosBlock)
	if err != errSiacoinInputOutputMismatch {
		t.Fatalf("expected %v, got %v", errSiacoinInputOutputMismatch, err)
	}
	err = cst.cs.AcceptBlock(dosBlock)
	if err != errDoSBlock {
		t.Fatalf("expected %v, got %v", errDoSBlock, err)
	}
}
func TestBlockKnownHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	staleBlock, _ := cst.miner.SolveBlock(block, target)
	block1, err := cst.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	block2, err := cst.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	err = cst.cs.AcceptBlock(staleBlock)
	if err != nil && err != modules.ErrNonExtendingBlock {
		t.Fatal(err)
	}
	err = cst.cs.AcceptBlock(block1)
	if err == nil {
		t.Fatal("expected an error upon submitting the block")
	}
	err = cst.cs.AcceptBlock(block2)
	if err == nil {
		t.Fatal("expected an error upon submitting the block")
	}
	err = cst.cs.AcceptBlock(staleBlock)
	if err == nil {
		t.Fatal("expected an error upon submitting the block")
	}
	id, err := cst.cs.dbGetPath(0)
	if err != nil {
		t.Fatal(err)
	}
	genesisBlock, err := cst.cs.dbGetBlockMap(id)
	if err != nil {
		t.Fatal(err)
	}
	err = cst.cs.AcceptBlock(genesisBlock.Block)
	if err == nil {
		t.Fatal("expected an error upon submitting the block")
	}
}
func TestOrphanHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	orphan := types.Block{}
	err = cst.cs.AcceptBlock(orphan)
	if err != errOrphan {
		t.Fatalf("expected %v, got %v", errOrphan, err)
	}
	err = cst.cs.AcceptBlock(orphan)
	if err != errOrphan {
		t.Fatalf("expected %v, got %v", errOrphan, err)
	}
}
func TestMissedTarget(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	for checkTarget(block, block.ID(), target) && block.Nonce[0] != 255 {
		block.Nonce[0]++
	}
	if checkTarget(block, block.ID(), target) {
		t.Fatal("unable to find a failing target")
	}
	err = cst.cs.AcceptBlock(block)
	if err != modules.ErrBlockUnsolved {
		t.Fatalf("expected %v, got %v", modules.ErrBlockUnsolved, err)
	}
}
func TestMinerPayoutHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	block.MinerPayouts = append(block.MinerPayouts, types.SiacoinOutput{Value: types.NewCurrency64(1)})
	solvedBlock, _ := cst.miner.SolveBlock(block, target)
	err = cst.cs.AcceptBlock(solvedBlock)
	if err != errBadMinerPayouts {
		t.Fatalf("expected %v, got %v", errBadMinerPayouts, err)
	}
}
func TestEarlyTimestampHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	minTimestamp := types.CurrentTimestamp()
	cst.cs.blockRuleHelper = mockBlockRuleHelper{
		minTimestamp: minTimestamp,
	}
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	block.Timestamp = minTimestamp - 1
	solvedBlock, _ := cst.miner.SolveBlock(block, target)
	err = cst.cs.AcceptBlock(solvedBlock)
	if err != errEarlyTimestamp {
		t.Fatalf("expected %v, got %v", errEarlyTimestamp, err)
	}
}
func TestFutureTimestampHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	block.Timestamp = types.CurrentTimestamp() + 2 + types.FutureThreshold
	solvedBlock, _ := cst.miner.SolveBlock(block, target)
	err = cst.cs.AcceptBlock(solvedBlock)
	if err != errFutureTimestamp {
		t.Fatalf("expected %v, got %v", errFutureTimestamp, err)
	}
	for i := 0; i < 30; i++ {
		time.Sleep(time.Second * 3)
		_, err = cst.cs.dbGetBlockMap(solvedBlock.ID())
		if err == nil {
			break
		}
	}
	_, err = cst.cs.dbGetBlockMap(solvedBlock.ID())
	if err != nil {
		t.Errorf("Future block not added to consensus set.\nCurrent Timestamp %v\nFutureThreshold: %v\nBlock Timestamp %v\n", types.CurrentTimestamp(), types.FutureThreshold, block.Timestamp)
	}
}
func TestExtremeFutureTimestampHandling(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	block, target, err := cst.miner.BlockForWork()
	if err != nil {
		t.Fatal(err)
	}
	block.Timestamp = types.CurrentTimestamp() + 2 + types.ExtremeFutureThreshold
	solvedBlock, _ := cst.miner.SolveBlock(block, target)
	err = cst.cs.AcceptBlock(solvedBlock)
	if err != errExtremeFutureTimestamp {
		t.Fatalf("expected %v, got %v", errFutureTimestamp, err)
	}
}
func TestBuriedBadTransaction(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	pb := cst.cs.dbCurrentProcessedBlock()
	txnValue := types.NewCurrency64(1200)
	txnBuilder, err := cst.wallet.StartTransaction()
	if err != nil {
		t.Fatal(err)
	}
	err = txnBuilder.FundSiacoins(txnValue)
	if err != nil {
		t.Fatal(err)
	}
	txnBuilder.AddSiacoinOutput(types.SiacoinOutput{Value: txnValue})
	txnSet, err := txnBuilder.Sign(true)
	if err != nil {
		t.Fatal(err)
	}
	err = cst.tpool.AcceptTransactionSet(txnSet)
	if err != nil {
		t.Fatal(err)
	}
	badTxn := types.Transaction{
		SiacoinInputs: []types.SiacoinInput{{}},
	}
	txns := append(cst.tpool.TransactionList(), badTxn)
	block := types.Block{
		ParentID:     pb.Block.ID(),
		Timestamp:    types.CurrentTimestamp(),
		MinerPayouts: []types.SiacoinOutput{{Value: types.CalculateCoinbase(pb.Height + 1)}},
		Transactions: txns,
	}
	block, _ = cst.miner.SolveBlock(block, pb.ChildTarget)
	err = cst.cs.AcceptBlock(block)
	if err == nil {
		t.Error("buried transaction didn't cause an error")
	}
}
func TestInconsistentCheck(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	sfo := types.SiafundOutput{
		Value: types.NewCurrency64(1),
	}
	cst.cs.dbAddSiafundOutput(types.SiafundOutputID{}, sfo)
	defer func() {
		r := recover()
		if r == nil {
			t.Fatalf("inconsistency panic not triggered by corrupted database")
		}
	}()
	_, err = cst.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
}
func TestTaxHardfork(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	t.Parallel()
	cst, err := createConsensusSetTester(t.Name())
	if err != nil {
		t.Fatal(err)
	}
	defer cst.Close()
	payout := types.NewCurrency64(400e6)
	outputSize := types.PostTax(cst.cs.dbBlockHeight(), payout)
	fc := types.FileContract{
		WindowStart:        cst.cs.dbBlockHeight() + 12,
		WindowEnd:          cst.cs.dbBlockHeight() + 14,
		Payout:             payout,
		ValidProofOutputs:  []types.SiacoinOutput{{Value: outputSize}},
		MissedProofOutputs: []types.SiacoinOutput{{Value: outputSize}},
		UnlockHash:         types.UnlockConditions{}.UnlockHash(),  
	}
	txnBuilder, err := cst.wallet.StartTransaction()
	if err != nil {
		t.Fatal(err)
	}
	err = txnBuilder.FundSiacoins(payout)
	if err != nil {
		t.Fatal(err)
	}
	fcIndex := txnBuilder.AddFileContract(fc)
	txnSet, err := txnBuilder.Sign(true)
	if err != nil {
		t.Fatal(err)
	}
	err = cst.tpool.AcceptTransactionSet(txnSet)
	if err != nil {
		t.Fatal(err)
	}
	_, err = cst.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	siafundPool := cst.cs.dbGetSiafundPool()
	if !siafundPool.Equals64(15590e3) {
		t.Fatal("siafund pool was not increased correctly")
	}
	for i := 0; i < 10; i++ {
		_, err = cst.miner.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
	fcid := txnSet[len(txnSet)-1].FileContractID(fcIndex)
	fcr := types.FileContractRevision{
		ParentID:          fcid,
		UnlockConditions:  types.UnlockConditions{},
		NewRevisionNumber: 1,
		NewFileSize:           1,
		NewWindowStart:        cst.cs.dbBlockHeight() + 2,
		NewWindowEnd:          cst.cs.dbBlockHeight() + 4,
		NewValidProofOutputs:  fc.ValidProofOutputs,
		NewMissedProofOutputs: fc.MissedProofOutputs,
	}
	txnBuilder, err = cst.wallet.StartTransaction()
	if err != nil {
		t.Fatal(err)
	}
	txnBuilder.AddFileContractRevision(fcr)
	txnSet, err = txnBuilder.Sign(true)
	if err != nil {
		t.Fatal(err)
	}
	err = cst.tpool.AcceptTransactionSet(txnSet)
	if err != nil {
		t.Fatal(err)
	}
	_, err = cst.miner.AddBlock()
	if err != nil {
		t.Fatal(err)
	}
	for i := 0; i < 6; i++ {
		_, err = cst.miner.AddBlock()
		if err != nil {
			t.Fatal(err)
		}
	}
	siafundPool = cst.cs.dbGetSiafundPool()
	if !siafundPool.Equals64(15590e3) {
		t.Fatal("siafund pool was not increased correctly")
	}
}
type mockGatewayDoesBroadcast struct {
	modules.Gateway
	broadcastCalled chan struct{}
}
func (g *mockGatewayDoesBroadcast) Broadcast(name string, obj interface{}, peers []modules.Peer) {
	g.Gateway.Broadcast(name, obj, peers)
	g.broadcastCalled <- struct{}{}
}