gitlab.com/jokerrs1/Sia@v1.3.2/modules/transactionpool/transactionpool_test.go (about)

     1  package transactionpool
     2  
     3  import (
     4  	"path/filepath"
     5  	"testing"
     6  
     7  	"github.com/NebulousLabs/Sia/build"
     8  	"github.com/NebulousLabs/Sia/crypto"
     9  	"github.com/NebulousLabs/Sia/modules"
    10  	"github.com/NebulousLabs/Sia/modules/consensus"
    11  	"github.com/NebulousLabs/Sia/modules/gateway"
    12  	"github.com/NebulousLabs/Sia/modules/miner"
    13  	"github.com/NebulousLabs/Sia/modules/wallet"
    14  	"github.com/NebulousLabs/Sia/types"
    15  	"github.com/NebulousLabs/fastrand"
    16  )
    17  
    18  // A tpoolTester is used during testing to initialize a transaction pool and
    19  // useful helper modules.
    20  type tpoolTester struct {
    21  	cs        modules.ConsensusSet
    22  	gateway   modules.Gateway
    23  	tpool     *TransactionPool
    24  	miner     modules.TestMiner
    25  	wallet    modules.Wallet
    26  	walletKey crypto.TwofishKey
    27  
    28  	persistDir string
    29  }
    30  
    31  // blankTpoolTester returns a ready-to-use tpool tester, with all modules
    32  // initialized, without mining a block.
    33  func blankTpoolTester(name string) (*tpoolTester, error) {
    34  	// Initialize the modules.
    35  	testdir := build.TempDir(modules.TransactionPoolDir, name)
    36  	g, err := gateway.New("localhost:0", false, filepath.Join(testdir, modules.GatewayDir))
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	cs, err := consensus.New(g, false, filepath.Join(testdir, modules.ConsensusDir))
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	tp, err := New(cs, g, filepath.Join(testdir, modules.TransactionPoolDir))
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir))
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	var key crypto.TwofishKey
    53  	fastrand.Read(key[:])
    54  	_, err = w.Encrypt(key)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	err = w.Unlock(key)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir))
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	// Assemble all of the objects into a tpoolTester
    68  	return &tpoolTester{
    69  		cs:        cs,
    70  		gateway:   g,
    71  		tpool:     tp,
    72  		miner:     m,
    73  		wallet:    w,
    74  		walletKey: key,
    75  
    76  		persistDir: testdir,
    77  	}, nil
    78  }
    79  
    80  // createTpoolTester returns a ready-to-use tpool tester, with all modules
    81  // initialized.
    82  func createTpoolTester(name string) (*tpoolTester, error) {
    83  	tpt, err := blankTpoolTester(name)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	// Mine blocks until there is money in the wallet.
    89  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
    90  		b, _ := tpt.miner.FindBlock()
    91  		err = tpt.cs.AcceptBlock(b)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  	}
    96  
    97  	return tpt, nil
    98  }
    99  
   100  // Close safely closes the tpoolTester, calling a panic in the event of an
   101  // error since there isn't a good way to errcheck when deferring a Close.
   102  func (tpt *tpoolTester) Close() error {
   103  	errs := []error{
   104  		tpt.cs.Close(),
   105  		tpt.gateway.Close(),
   106  		tpt.tpool.Close(),
   107  		tpt.miner.Close(),
   108  		tpt.wallet.Close(),
   109  	}
   110  	if err := build.JoinErrors(errs, "; "); err != nil {
   111  		panic(err)
   112  	}
   113  	return nil
   114  }
   115  
   116  // TestIntegrationNewNilInputs tries to trigger a panic with nil inputs.
   117  func TestIntegrationNewNilInputs(t *testing.T) {
   118  	// Create a gateway and consensus set.
   119  	testdir := build.TempDir(modules.TransactionPoolDir, t.Name())
   120  	g, err := gateway.New("localhost:0", false, filepath.Join(testdir, modules.GatewayDir))
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	cs, err := consensus.New(g, false, filepath.Join(testdir, modules.ConsensusDir))
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	tpDir := filepath.Join(testdir, modules.TransactionPoolDir)
   129  
   130  	// Try all combinations of nil inputs.
   131  	_, err = New(nil, nil, tpDir)
   132  	if err == nil {
   133  		t.Error(err)
   134  	}
   135  	_, err = New(nil, g, tpDir)
   136  	if err != errNilCS {
   137  		t.Error(err)
   138  	}
   139  	_, err = New(cs, nil, tpDir)
   140  	if err != errNilGateway {
   141  		t.Error(err)
   142  	}
   143  	_, err = New(cs, g, tpDir)
   144  	if err != nil {
   145  		t.Error(err)
   146  	}
   147  }
   148  
   149  // TestGetTransaction verifies that the transaction pool's Transaction() method
   150  // works correctly.
   151  func TestGetTransaction(t *testing.T) {
   152  	if testing.Short() {
   153  		t.SkipNow()
   154  	}
   155  	tpt, err := createTpoolTester(t.Name())
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  	defer tpt.Close()
   160  
   161  	value := types.NewCurrency64(35e6)
   162  	fee := types.NewCurrency64(3e2)
   163  	emptyUH := types.UnlockConditions{}.UnlockHash()
   164  	txnBuilder := tpt.wallet.StartTransaction()
   165  	err = txnBuilder.FundSiacoins(value)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	txnBuilder.AddMinerFee(fee)
   170  	output := types.SiacoinOutput{
   171  		Value:      value.Sub(fee),
   172  		UnlockHash: emptyUH,
   173  	}
   174  	txnBuilder.AddSiacoinOutput(output)
   175  	txnSet, err := txnBuilder.Sign(true)
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  	childrenSet := []types.Transaction{{
   180  		SiacoinInputs: []types.SiacoinInput{{
   181  			ParentID: txnSet[len(txnSet)-1].SiacoinOutputID(0),
   182  		}},
   183  		SiacoinOutputs: []types.SiacoinOutput{{
   184  			Value:      value.Sub(fee),
   185  			UnlockHash: emptyUH,
   186  		}},
   187  	}}
   188  
   189  	superSet := append(txnSet, childrenSet...)
   190  	err = tpt.tpool.AcceptTransactionSet(superSet)
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  
   195  	targetTxn := childrenSet[0]
   196  	txn, parents, exists := tpt.tpool.Transaction(targetTxn.ID())
   197  	if !exists {
   198  		t.Fatal("transaction set did not exist")
   199  	}
   200  	if txn.ID() != targetTxn.ID() {
   201  		t.Fatal("returned the wrong transaction")
   202  	}
   203  	if len(parents) != len(txnSet) {
   204  		t.Fatal("transaction had wrong number of parents")
   205  	}
   206  	for i, txn := range txnSet {
   207  		if parents[i].ID() != txn.ID() {
   208  			t.Fatal("returned the wrong parent")
   209  		}
   210  	}
   211  }
   212  
   213  // TestBlockFeeEstimation checks that the fee estimation algorithm is reasonably
   214  // on target when the tpool is relying on blockchain based fee estimation.
   215  func TestFeeEstimation(t *testing.T) {
   216  	if testing.Short() || !build.VLONG {
   217  		t.Skip("Tpool is too slow to run this test regularly")
   218  	}
   219  	tpt, err := createTpoolTester(t.Name())
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  	defer tpt.Close()
   224  
   225  	// Prepare a bunch of outputs for a series of graphs to fill up the
   226  	// transaction pool.
   227  	graphLens := 400                                                                     // 80 kb per graph
   228  	numGraphs := int(types.BlockSizeLimit) * blockFeeEstimationDepth / (graphLens * 206) // Enough to fill 'estimation depth' blocks.
   229  	graphFund := types.SiacoinPrecision.Mul64(1000)
   230  	var outputs []types.SiacoinOutput
   231  	for i := 0; i < numGraphs+1; i++ {
   232  		outputs = append(outputs, types.SiacoinOutput{
   233  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
   234  			Value:      graphFund,
   235  		})
   236  	}
   237  	txns, err := tpt.wallet.SendSiacoinsMulti(outputs)
   238  	if err != nil {
   239  		t.Error(err)
   240  	}
   241  
   242  	// Mine the graph setup in the consensus set so that the graph outputs are
   243  	// distinct transaction sets.
   244  	_, err = tpt.miner.AddBlock()
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	// Create all of the graphs.
   250  	finalTxn := txns[len(txns)-1]
   251  	var graphs [][]types.Transaction
   252  	for i := 0; i < numGraphs; i++ {
   253  		var edges []types.TransactionGraphEdge
   254  		var cumFee types.Currency
   255  		for j := 0; j < graphLens; j++ {
   256  			fee := types.SiacoinPrecision.Mul64(uint64(j + i + 1)).Div64(200)
   257  			cumFee = cumFee.Add(fee)
   258  			edges = append(edges, types.TransactionGraphEdge{
   259  				Dest:   j + 1,
   260  				Fee:    fee,
   261  				Source: j,
   262  				Value:  graphFund.Sub(cumFee),
   263  			})
   264  		}
   265  		graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
   266  		if err != nil {
   267  			t.Fatal(err)
   268  		}
   269  		graphs = append(graphs, graph)
   270  	}
   271  
   272  	// One block at a time, add graphs to the tpool and blockchain. Then check
   273  	// the median fee estimation and see that it's the right value.
   274  	var prevMin types.Currency
   275  	for i := 0; i < blockFeeEstimationDepth; i++ {
   276  		// Insert enough graphs to fill a block.
   277  		for j := 0; j < numGraphs/blockFeeEstimationDepth; j++ {
   278  			err = tpt.tpool.AcceptTransactionSet(graphs[0])
   279  			if err != nil {
   280  				t.Fatal(err)
   281  			}
   282  			graphs = graphs[1:]
   283  		}
   284  
   285  		// Add a block to the transaction pool.
   286  		_, err = tpt.miner.AddBlock()
   287  		if err != nil {
   288  			t.Fatal(err)
   289  		}
   290  
   291  		// Check that max is always greater than min.
   292  		min, max := tpt.tpool.FeeEstimation()
   293  		if min.Cmp(max) > 0 {
   294  			t.Error("max fee is less than min fee estimation")
   295  		}
   296  
   297  		// If we're over halfway through the depth, the suggested fee should
   298  		// start to exceed the default.
   299  		if i > blockFeeEstimationDepth/2 {
   300  			if min.Cmp(minEstimation) <= 0 {
   301  				t.Error("fee estimation does not seem to be increasing")
   302  			}
   303  			if min.Cmp(prevMin) <= 0 {
   304  				t.Error("fee estimation does not seem to be increasing")
   305  			}
   306  		}
   307  		prevMin = min
   308  
   309  		// Reset the tpool to verify that the persist structures are
   310  		// functioning.
   311  		//
   312  		// TODO: For some reason, closing and re-opeining the tpool results in
   313  		// incredible performance penalties.
   314  		/*
   315  			err = tpt.tpool.Close()
   316  			if err != nil {
   317  				t.Fatal(err)
   318  			}
   319  			tpt.tpool, err = New(tpt.cs, tpt.gateway, tpt.persistDir)
   320  			if err != nil {
   321  				t.Fatal(err)
   322  			}
   323  		*/
   324  	}
   325  
   326  	// Mine a few blocks and then check that the fee estimation has returned to
   327  	// minimum as congestion clears up.
   328  	for i := 0; i < (blockFeeEstimationDepth/2)+1; i++ {
   329  		_, err = tpt.miner.AddBlock()
   330  		if err != nil {
   331  			t.Fatal(err)
   332  		}
   333  	}
   334  	min, _ := tpt.tpool.FeeEstimation()
   335  	if !(min.Cmp(minEstimation) == 0) {
   336  		t.Error("fee estimator does not seem to be reducing with empty blocks.")
   337  	}
   338  }
   339  
   340  // TestTpoolScalability fills the whole transaction pool with complex
   341  // transactions, then mines enough blocks to empty it out. Running sequentially,
   342  // the test should take less than 250ms per mb that the transaction pool fills
   343  // up, and less than 250ms per mb to empty out - indicating linear scalability
   344  // and tolerance for a larger pool size.
   345  func TestTpoolScalability(t *testing.T) {
   346  	if testing.Short() || !build.VLONG {
   347  		t.Skip("Tpool is too slow to run this test regularly")
   348  	}
   349  	tpt, err := createTpoolTester(t.Name())
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	defer tpt.Close()
   354  
   355  	// Mine a few more blocks to get some extra funding.
   356  	for i := 0; i < 3; i++ {
   357  		_, err := tpt.miner.AddBlock()
   358  		if err != nil {
   359  			t.Fatal(err)
   360  		}
   361  	}
   362  
   363  	// Prepare a bunch of outputs for a series of graphs to fill up the
   364  	// transaction pool.
   365  	rows := 10                                         // needs to factor into exclusively '2's and '5's.
   366  	graphSize := 11796                                 // Measured with logging. Change if 'rows' changes.
   367  	numGraphs := TransactionPoolSizeTarget / graphSize // Enough to fill the transaction pool.
   368  	graphFund := types.SiacoinPrecision.Mul64(2000)
   369  	var outputs []types.SiacoinOutput
   370  	for i := 0; i < numGraphs+1; i++ {
   371  		outputs = append(outputs, types.SiacoinOutput{
   372  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
   373  			Value:      graphFund,
   374  		})
   375  	}
   376  	txns, err := tpt.wallet.SendSiacoinsMulti(outputs)
   377  	if err != nil {
   378  		t.Error(err)
   379  	}
   380  
   381  	// Mine the graph setup in the consensus set so that the graph outputs are
   382  	// distinct transaction sets.
   383  	_, err = tpt.miner.AddBlock()
   384  	if err != nil {
   385  		t.Fatal(err)
   386  	}
   387  
   388  	// Create all of the graphs.
   389  	finalTxn := txns[len(txns)-1]
   390  	var graphs [][]types.Transaction
   391  	for i := 0; i < numGraphs; i++ {
   392  		var edges []types.TransactionGraphEdge
   393  
   394  		// Create the root of the graph.
   395  		feeValues := types.SiacoinPrecision
   396  		firstRowValues := graphFund.Sub(feeValues.Mul64(uint64(rows))).Div64(uint64(rows))
   397  		for j := 0; j < rows; j++ {
   398  			edges = append(edges, types.TransactionGraphEdge{
   399  				Dest:   j + 1,
   400  				Fee:    types.SiacoinPrecision,
   401  				Source: 0,
   402  				Value:  firstRowValues,
   403  			})
   404  		}
   405  
   406  		// Create each row of the graph.
   407  		var firstNodeValue types.Currency
   408  		nodeIndex := 1
   409  		for j := 0; j < rows; j++ {
   410  			// Create the first node in the row, which has an increasing
   411  			// balance.
   412  			rowValue := firstRowValues.Sub(types.SiacoinPrecision.Mul64(uint64(j + 1)))
   413  			firstNodeValue = firstNodeValue.Add(rowValue)
   414  			edges = append(edges, types.TransactionGraphEdge{
   415  				Dest:   nodeIndex + (rows - j),
   416  				Fee:    types.SiacoinPrecision,
   417  				Source: nodeIndex,
   418  				Value:  firstNodeValue,
   419  			})
   420  			nodeIndex++
   421  
   422  			// Create the remaining nodes in this row.
   423  			for k := j + 1; k < rows; k++ {
   424  				edges = append(edges, types.TransactionGraphEdge{
   425  					Dest:   nodeIndex + (rows - (j + 1)),
   426  					Fee:    types.SiacoinPrecision,
   427  					Source: nodeIndex,
   428  					Value:  rowValue,
   429  				})
   430  				nodeIndex++
   431  			}
   432  		}
   433  
   434  		// Build the graph and add it to the stack of graphs.
   435  		graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
   436  		if err != nil {
   437  			t.Fatal(err)
   438  		}
   439  		graphs = append(graphs, graph)
   440  	}
   441  
   442  	// Add all of the root transactions to the blockchain to throw off the
   443  	// parent math off for the transaction pool.
   444  	for _, graph := range graphs {
   445  		err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
   446  		if err != nil {
   447  			t.Fatal(err)
   448  		}
   449  	}
   450  	_, err = tpt.miner.AddBlock()
   451  	if err != nil {
   452  		t.Fatal(err)
   453  	}
   454  
   455  	// Add all of the transactions in each graph into the tpool, one transaction
   456  	// at a time, interweaved, chaotically.
   457  	for i := 1; i < len(graphs[0]); i++ {
   458  		for j := 0; j < len(graphs); j++ {
   459  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graphs[j][i]})
   460  			if err != nil {
   461  				t.Fatal(err, i, j)
   462  			}
   463  		}
   464  	}
   465  
   466  	// Mine blocks until the tpool is gone.
   467  	for tpt.tpool.transactionListSize > 0 {
   468  		_, err := tpt.miner.AddBlock()
   469  		if err != nil {
   470  			t.Fatal(err)
   471  		}
   472  	}
   473  }
   474  
   475  // TestHeapFees creates a large number of transaction graphs with increasing fee
   476  // value. Then it checks that those sets with higher value transaction fees are
   477  // prioritized for placement in blocks.
   478  func TestHeapFees(t *testing.T) {
   479  	if testing.Short() || !build.VLONG {
   480  		t.SkipNow()
   481  	}
   482  	tpt, err := createTpoolTester(t.Name())
   483  	if err != nil {
   484  		t.Fatal(err)
   485  	}
   486  	defer tpt.Close()
   487  
   488  	// Mine a few more blocks to get some extra funding.
   489  	for i := 0; i < 4; i++ {
   490  		_, err := tpt.miner.AddBlock()
   491  		if err != nil {
   492  			t.Fatal(err)
   493  		}
   494  	}
   495  
   496  	// Create transaction graph setup.
   497  	coinFrac := types.SiacoinPrecision
   498  	numGraphs := 110
   499  	graphFund := coinFrac.Mul64(12210)
   500  	var outputs []types.SiacoinOutput
   501  	for i := 0; i < numGraphs; i++ {
   502  		outputs = append(outputs, types.SiacoinOutput{
   503  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
   504  			Value:      graphFund,
   505  		})
   506  	}
   507  	txns, err := tpt.wallet.SendSiacoinsMulti(outputs)
   508  	if err != nil {
   509  		t.Error(err)
   510  	}
   511  	// Mine the graph setup in the consensus set so that the graph outputs are
   512  	// transaction sets. This guarantees that the parent of every graph will be
   513  	// its own output.
   514  	_, err = tpt.miner.AddBlock()
   515  	if err != nil {
   516  		t.Fatal(err)
   517  	}
   518  	finalTxn := txns[len(txns)-1]
   519  	// For each output, create 250 transactions
   520  	var graphs [][]types.Transaction
   521  	for i := 0; i < numGraphs; i++ {
   522  		var edges []types.TransactionGraphEdge
   523  		var cumFee types.Currency
   524  		for j := 0; j < numGraphs; j++ {
   525  			fee := coinFrac.Mul64(uint64((j + 1)))
   526  			cumFee = cumFee.Add(fee)
   527  			edges = append(edges, types.TransactionGraphEdge{
   528  				Dest:   j + 1,
   529  				Fee:    fee,
   530  				Source: 0,
   531  				Value:  fee,
   532  			})
   533  		}
   534  		for k := 0; k < numGraphs; k++ {
   535  			fee := coinFrac.Mul64(uint64(k + 1)).Div64(2)
   536  			cumFee = cumFee.Add(fee)
   537  			edges = append(edges, types.TransactionGraphEdge{
   538  				Dest:   k + 251,
   539  				Fee:    fee,
   540  				Source: k + 1,
   541  				Value:  fee,
   542  			})
   543  		}
   544  		graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
   545  		if err != nil {
   546  			t.Fatal(err)
   547  		}
   548  		graphs = append(graphs, graph)
   549  
   550  	}
   551  	// Accept the parent node of each graph so that its outputs we can test
   552  	// spending its outputs after mining the next block.
   553  	for _, graph := range graphs {
   554  		err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
   555  		if err != nil {
   556  			t.Fatal(err)
   557  		}
   558  	}
   559  	block, err := tpt.miner.AddBlock()
   560  	if err != nil {
   561  		t.Fatal(err)
   562  	}
   563  
   564  	// Now accept all the other nodes of each graph.
   565  	for _, graph := range graphs {
   566  		for _, txn := range graph[1:] {
   567  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
   568  			if err != nil {
   569  				t.Fatal(err)
   570  			}
   571  		}
   572  	}
   573  	// Now we mine 2 blocks in sequence and check that higher fee transactions
   574  	// show up to the first block.
   575  	block, err = tpt.miner.AddBlock()
   576  	if err != nil {
   577  		t.Fatal(err)
   578  	}
   579  
   580  	var totalFee1 types.Currency
   581  	expectedFee1 := coinFrac.Mul64(321915)
   582  
   583  	// Add up total fees
   584  	numTxns1 := 0
   585  	maxFee1 := types.SiacoinPrecision.Div64(1000000)
   586  	minFee1 := types.SiacoinPrecision.Mul64(1000000)
   587  	for _, txn := range block.Transactions {
   588  		for _, fee := range txn.MinerFees {
   589  			if fee.Cmp(maxFee1) >= 0 {
   590  				maxFee1 = fee
   591  			}
   592  			if fee.Cmp(minFee1) <= 0 {
   593  				minFee1 = fee
   594  			}
   595  			totalFee1 = totalFee1.Add(fee)
   596  			numTxns1++
   597  		}
   598  	}
   599  	avgFee1 := totalFee1.Div64(uint64(numTxns1))
   600  	if totalFee1.Cmp(expectedFee1) != 0 {
   601  		t.Error("totalFee1 different than expected fee.", totalFee1.String(), expectedFee1.String())
   602  		//t.Log(totalFee1.Sub(expectedFee1).HumanString())
   603  
   604  	}
   605  
   606  	// Mine the next block so we can check the transactions inside
   607  	block, err = tpt.miner.AddBlock()
   608  	if err != nil {
   609  		t.Fatal(err)
   610  	}
   611  
   612  	var totalFee2 types.Currency
   613  	expectedFee2 := coinFrac.Mul64(13860)
   614  
   615  	// Add up total fees
   616  	numTxns2 := 0
   617  	maxFee2 := types.SiacoinPrecision.Div64(1000000)
   618  	minFee2 := types.SiacoinPrecision.Mul64(1000000)
   619  	for _, txn := range block.Transactions {
   620  		for _, fee := range txn.MinerFees {
   621  			if fee.Cmp(maxFee2) >= 0 {
   622  				maxFee2 = fee
   623  			}
   624  			if fee.Cmp(minFee2) <= 0 {
   625  				minFee2 = fee
   626  			}
   627  			totalFee2 = totalFee2.Add(fee)
   628  			numTxns2++
   629  		}
   630  	}
   631  	avgFee2 := totalFee2.Div64(uint64(numTxns2))
   632  	if totalFee2.Cmp(expectedFee2) != 0 {
   633  		t.Error("totalFee2 different than expected fee.", totalFee2.String(), expectedFee2.String())
   634  		//t.Log(totalFee2.Sub(expectedFee2).HumanString())
   635  	}
   636  	if avgFee1.Cmp(avgFee2) <= 0 {
   637  		t.Error("Expected average fee from first block to be greater than average fee from second block.")
   638  	}
   639  	if totalFee1.Cmp(totalFee2) <= 0 {
   640  		t.Error("Expected total fee from first block to be greater than total fee from second block.")
   641  	}
   642  	if numTxns1 < numTxns2 {
   643  		t.Error("Expected more transactions in the first block than second block.")
   644  	}
   645  	if maxFee1.Cmp(maxFee2) <= 0 {
   646  		t.Error("Expected highest fee from first block to be greater than highest fee from second block.")
   647  	}
   648  	if minFee1.Cmp(maxFee2) < 0 {
   649  		t.Error("Expected lowest fee from first block to be greater than or equal to than highest fee from second block.")
   650  	}
   651  	if maxFee1.Cmp(minFee1) <= 0 {
   652  		t.Error("Expected highest fee from first block to be greater than lowest fee from first block.")
   653  	}
   654  	if maxFee2.Cmp(minFee2) <= 0 {
   655  		t.Error("Expected highest fee from second block to be greater than lowest fee from second block.")
   656  	}
   657  }
   658  
   659  // TestBigTpool creates 3 chunks of 10,000 transactions such that the second
   660  // chunk has much greater fees than the first chunk, and the third chunk has
   661  // much greater fees than the second chunk. The fees in each chunk are also
   662  // increasing. Then, to induce move lots of movement of transactions in and out
   663  // of the miner's unsolved block, we make the tester accept the transactions by
   664  // interleaving subsets of the chunks. We then check that the miner produces the
   665  // expected sequence of blocks.
   666  func TestBigTpool(t *testing.T) {
   667  	if testing.Short() || !build.VLONG {
   668  		t.SkipNow()
   669  	}
   670  	tpt, err := createTpoolTester(t.Name())
   671  	if err != nil {
   672  		t.Fatal(err)
   673  	}
   674  	defer tpt.Close()
   675  
   676  	// Mine a few more blocks to get some extra funding.
   677  	for i := 0; i < 4; i++ {
   678  		_, err := tpt.miner.AddBlock()
   679  		if err != nil {
   680  			t.Fatal(err)
   681  		}
   682  	}
   683  
   684  	// Create transaction graph setup.
   685  	coinFrac := types.SiacoinPrecision.Div64(1)
   686  	feeFrac := types.SiacoinPrecision.Div64(10)
   687  	numGraphsPerChunk := 1000
   688  	transactionSetSizes := []int{1, 2, 5, 10, 20}
   689  
   690  	var outputs1 []types.SiacoinOutput
   691  	var outputs2 []types.SiacoinOutput
   692  	var outputs3 []types.SiacoinOutput
   693  
   694  	// Create outputs to be spent in the first chunk.
   695  	for i := 1; i <= numGraphsPerChunk; i++ {
   696  		value := coinFrac.Mul64(25).Add(feeFrac.Mul64(uint64(i))).Mul64(2)
   697  		outputs1 = append(outputs1, types.SiacoinOutput{
   698  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
   699  			Value:      value,
   700  		})
   701  	}
   702  	// There's so many outputs that they need to be put into multiple
   703  	// transactions. We can fit around 500 outputs per transaction.
   704  	var outputTxns1 [][]types.Transaction
   705  	for i := 0; i < numGraphsPerChunk/500; i++ {
   706  		txns, err := tpt.wallet.SendSiacoinsMulti(outputs1[500*i : (500*i)+500])
   707  		if err != nil {
   708  			t.Error(err)
   709  		}
   710  		outputTxns1 = append(outputTxns1, txns)
   711  	}
   712  
   713  	counter := 1
   714  	var graphs [][]types.Transaction
   715  	for _, output := range outputTxns1 {
   716  		finalTxn := output[len(output)-1]
   717  		for i := 0; i < 500; i++ { // 500 is the the number of outputs
   718  			var edges []types.TransactionGraphEdge
   719  			totalValue := coinFrac.Mul64(25).Add(feeFrac.Mul64(uint64(counter))).Mul64(2)
   720  			setSize := transactionSetSizes[fastrand.Intn(5)] // 1, 2, 5, 10, or 20 with equal probability
   721  			txTotalVal := totalValue.Div64(uint64(setSize))
   722  			txFee := txTotalVal.Div64(5)
   723  			txVal := txTotalVal.Sub(txFee)
   724  			txFee2 := txVal.Div64(2)
   725  			txVal2 := txVal.Sub(txFee2)
   726  
   727  			for i := 0; i < setSize; i++ {
   728  				edges = append(edges, types.TransactionGraphEdge{
   729  					Dest:   i + 1,
   730  					Fee:    txFee,
   731  					Source: 0,
   732  					Value:  txVal,
   733  				})
   734  			}
   735  			for i := 0; i < setSize; i++ {
   736  				edges = append(edges, types.TransactionGraphEdge{
   737  					Dest:   i + 1 + setSize,
   738  					Fee:    txFee2,
   739  					Source: i + 1,
   740  					Value:  txVal2,
   741  				})
   742  			}
   743  			graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
   744  			if err != nil {
   745  				t.Fatal(err)
   746  			}
   747  			graphs = append(graphs, graph)
   748  			counter++
   749  		}
   750  	}
   751  	////////////////////////////////////////////////////////////////////////////
   752  	// Chunk 2
   753  	////////////////////////////////////////////////////////////////////////////
   754  	// Create outputs to be spent in the second chunk.
   755  	for i := 1; i <= numGraphsPerChunk; i++ {
   756  		value := coinFrac.Mul64(60).Add(feeFrac.Mul64(uint64(i))).Mul64(2)
   757  		outputs2 = append(outputs2, types.SiacoinOutput{
   758  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
   759  			Value:      value,
   760  		})
   761  	}
   762  	// There's so many outputs that they need to be put into multiple
   763  	// transactions. We can fit around 500 outputs per transaction.
   764  	var outputTxns2 [][]types.Transaction
   765  	for i := 0; i < numGraphsPerChunk/500; i++ {
   766  		txns, err := tpt.wallet.SendSiacoinsMulti(outputs2[500*i : (500*i)+500])
   767  		if err != nil {
   768  			t.Error(err)
   769  		}
   770  		outputTxns2 = append(outputTxns2, txns)
   771  	}
   772  
   773  	counter = 1
   774  	var graphs2 [][]types.Transaction
   775  	for _, output := range outputTxns2 {
   776  		finalTxn := output[len(output)-1]
   777  		for i := 0; i < 500; i++ { // 500 is the the number of outputs.
   778  			var edges []types.TransactionGraphEdge
   779  			totalValue := coinFrac.Mul64(60).Add(feeFrac.Mul64(uint64(counter))).Mul64(2)
   780  			setSize := transactionSetSizes[fastrand.Intn(5)] // 1, 2, 5, 10, or 20 with equal probability
   781  			txTotalVal := totalValue.Div64(uint64(setSize))
   782  			txFee := txTotalVal.Div64(5)
   783  			txVal := txTotalVal.Sub(txFee)
   784  			txFee2 := txVal.Div64(2)
   785  			txVal2 := txVal.Sub(txFee2)
   786  
   787  			for i := 0; i < setSize; i++ {
   788  				edges = append(edges, types.TransactionGraphEdge{
   789  					Dest:   i + 1,
   790  					Fee:    txFee,
   791  					Source: 0,
   792  					Value:  txVal,
   793  				})
   794  			}
   795  			for i := 0; i < setSize; i++ {
   796  				edges = append(edges, types.TransactionGraphEdge{
   797  					Dest:   i + 1 + setSize,
   798  					Fee:    txFee2,
   799  					Source: i + 1,
   800  					Value:  txVal2,
   801  				})
   802  			}
   803  			graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
   804  			if err != nil {
   805  				t.Fatal(err)
   806  			}
   807  			graphs2 = append(graphs2, graph)
   808  			counter++
   809  		}
   810  	}
   811  	////////////////////////////////////////////////////////////////////////////
   812  	// Chunk 3
   813  	////////////////////////////////////////////////////////////////////////////
   814  	// Create outputs to be spent in the third chunk.
   815  	for i := 1; i <= numGraphsPerChunk; i++ {
   816  		value := coinFrac.Mul64(110).Add(feeFrac.Mul64(uint64(i))).Mul64(2)
   817  		outputs3 = append(outputs3, types.SiacoinOutput{
   818  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
   819  			Value:      value,
   820  		})
   821  	}
   822  	// There's so many outputs that they need to be put into multiple
   823  	// transactions. We can fit around 500 outputs per transaction.
   824  	var outputTxns3 [][]types.Transaction
   825  	for i := 0; i < numGraphsPerChunk/500; i++ {
   826  		txns, err := tpt.wallet.SendSiacoinsMulti(outputs3[500*i : (500*i)+500])
   827  		if err != nil {
   828  			t.Error(err)
   829  		}
   830  		outputTxns3 = append(outputTxns3, txns)
   831  	}
   832  
   833  	counter = 1
   834  	var graphs3 [][]types.Transaction
   835  	for _, output := range outputTxns3 {
   836  		finalTxn := output[len(output)-1]
   837  		for i := 0; i < 500; i++ { // 500 is the the number of outputs.
   838  			var edges []types.TransactionGraphEdge
   839  			totalValue := coinFrac.Mul64(110).Add(feeFrac.Mul64(uint64(counter))).Mul64(2)
   840  			setSize := transactionSetSizes[fastrand.Intn(5)] // 1, 2, 5, 10, or 20 with equal probability
   841  			txTotalVal := totalValue.Div64(uint64(setSize))
   842  			txFee := txTotalVal.Div64(5)
   843  			txVal := txTotalVal.Sub(txFee)
   844  			txFee2 := txVal.Div64(2)
   845  			txVal2 := txVal.Sub(txFee2)
   846  
   847  			for i := 0; i < setSize; i++ {
   848  				edges = append(edges, types.TransactionGraphEdge{
   849  					Dest:   i + 1,
   850  					Fee:    txFee,
   851  					Source: 0,
   852  					Value:  txVal,
   853  				})
   854  			}
   855  			for i := 0; i < setSize; i++ {
   856  				edges = append(edges, types.TransactionGraphEdge{
   857  					Dest:   i + 1 + setSize,
   858  					Fee:    txFee2,
   859  					Source: i + 1,
   860  					Value:  txVal2,
   861  				})
   862  			}
   863  			graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
   864  			if err != nil {
   865  				t.Fatal(err)
   866  			}
   867  			graphs3 = append(graphs3, graph)
   868  			counter++
   869  		}
   870  	}
   871  
   872  	block, err := tpt.miner.AddBlock()
   873  	if err != nil {
   874  		t.Fatal(err)
   875  	}
   876  
   877  	// Accept the parent node of each graph so that its outputs we can test
   878  	// spending its outputs after mining the next block.
   879  	c := 0
   880  	for _, graph := range graphs {
   881  		err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
   882  		if err != nil {
   883  			t.Fatal(err)
   884  		}
   885  		c++
   886  	}
   887  	_, err = tpt.miner.AddBlock()
   888  	if err != nil {
   889  		t.Fatal(err)
   890  	}
   891  	for _, graph := range graphs2 {
   892  		err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
   893  		if err != nil {
   894  			t.Fatal(err)
   895  		}
   896  	}
   897  	_, err = tpt.miner.AddBlock()
   898  	if err != nil {
   899  		t.Fatal(err)
   900  	}
   901  	for _, graph := range graphs3 {
   902  		err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
   903  		if err != nil {
   904  			t.Fatal(err)
   905  		}
   906  	}
   907  	_, err = tpt.miner.AddBlock()
   908  	if err != nil {
   909  		t.Fatal(err)
   910  	}
   911  
   912  	var totalGraph [][]types.Transaction
   913  	totalGraph = append(totalGraph, graphs...)
   914  	totalGraph = append(totalGraph, graphs2...)
   915  	totalGraph = append(totalGraph, graphs3...)
   916  
   917  	//  Add transactions one megabyte at a time.
   918  	firstMix := fastrand.Perm(670) // around 670 graphs make 1MB of transactions
   919  	secondMix := fastrand.Perm(670)
   920  	thirdMix := fastrand.Perm(670)
   921  	fourthMix := fastrand.Perm(670)
   922  	fifthMix := fastrand.Perm(320)
   923  
   924  	for _, i := range firstMix {
   925  		graph := totalGraph[i]
   926  		for _, txn := range graph[1:] {
   927  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
   928  			if err != nil {
   929  				t.Fatal(err)
   930  			}
   931  		}
   932  	}
   933  	for _, i := range secondMix {
   934  		graph := totalGraph[i+670]
   935  		for _, txn := range graph[1:] {
   936  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
   937  			if err != nil {
   938  				t.Fatal(err)
   939  			}
   940  		}
   941  	}
   942  	for _, i := range thirdMix {
   943  		graph := totalGraph[i+670+670]
   944  		for _, txn := range graph[1:] {
   945  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
   946  			if err != nil {
   947  				t.Fatal(err)
   948  			}
   949  		}
   950  	}
   951  	for _, i := range fourthMix {
   952  		graph := totalGraph[i+670+670+670]
   953  		for _, txn := range graph[1:] {
   954  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
   955  			if err != nil {
   956  				t.Fatal(err)
   957  			}
   958  		}
   959  	}
   960  	for _, i := range fifthMix {
   961  		graph := totalGraph[i+670+670+670+670]
   962  		for _, txn := range graph[1:] {
   963  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
   964  			if err != nil {
   965  				t.Fatal(err)
   966  			}
   967  		}
   968  	}
   969  
   970  	block, err = tpt.miner.AddBlock()
   971  	if err != nil {
   972  		t.Fatal(err)
   973  	}
   974  	var totalFee1 types.Currency
   975  	minFee1 := types.SiacoinPrecision.Mul64(10000000000) // All the fees are much smaller than 1 SC.
   976  	for _, tx := range block.Transactions {
   977  		for _, fee := range tx.MinerFees {
   978  			totalFee1 = totalFee1.Add(fee)
   979  			if fee.Cmp(minFee1) < 0 {
   980  				minFee1 = fee
   981  			}
   982  		}
   983  	}
   984  
   985  	block, err = tpt.miner.AddBlock()
   986  	if err != nil {
   987  		t.Fatal(err)
   988  	}
   989  	var totalFee2 types.Currency
   990  	maxFee2 := types.ZeroCurrency
   991  	minFee2 := types.SiacoinPrecision.Mul64(10000000000) // All the fees are much smaller than 1 SC.
   992  	for _, tx := range block.Transactions {
   993  		for _, fee := range tx.MinerFees {
   994  			totalFee2 = totalFee2.Add(fee)
   995  			if fee.Cmp(minFee2) < 0 {
   996  				minFee2 = fee
   997  			}
   998  			if fee.Cmp(maxFee2) > 0 {
   999  				maxFee2 = fee
  1000  			}
  1001  		}
  1002  	}
  1003  
  1004  	block, err = tpt.miner.AddBlock()
  1005  	if err != nil {
  1006  		t.Fatal(err)
  1007  	}
  1008  	var totalFee3 types.Currency
  1009  	maxFee3 := types.ZeroCurrency
  1010  	minFee3 := types.SiacoinPrecision.Mul64(10000000000) // All the fees are much smaller than 1 SC.
  1011  	for _, tx := range block.Transactions {
  1012  		for _, fee := range tx.MinerFees {
  1013  			totalFee3 = totalFee3.Add(fee)
  1014  			if fee.Cmp(minFee3) < 0 {
  1015  				minFee3 = fee
  1016  			}
  1017  			if fee.Cmp(maxFee3) > 0 {
  1018  				maxFee3 = fee
  1019  			}
  1020  		}
  1021  	}
  1022  
  1023  	block, err = tpt.miner.AddBlock()
  1024  	if err != nil {
  1025  		t.Fatal(err)
  1026  	}
  1027  	totalFee4 := types.ZeroCurrency
  1028  	maxFee4 := types.ZeroCurrency
  1029  	for _, tx := range block.Transactions {
  1030  		for _, fee := range tx.MinerFees {
  1031  			totalFee4 = totalFee4.Add(fee)
  1032  			if fee.Cmp(maxFee4) > 0 {
  1033  				maxFee4 = fee
  1034  			}
  1035  		}
  1036  	}
  1037  
  1038  	// Check that the total fees from each block are decreasing.
  1039  	if totalFee1.Cmp(totalFee2) < 0 {
  1040  		t.Error("Expected fees from the first block to be greater than from the second block.")
  1041  	}
  1042  	if totalFee2.Cmp(totalFee3) < 0 {
  1043  		t.Error("Expected fees from the second block to be greater than from the third block.")
  1044  	}
  1045  	if totalFee3.Cmp(totalFee4) < 0 {
  1046  		t.Error("Expected fees from the third block to be greater than from the fourth block.")
  1047  	}
  1048  	// Check that the min fees from each block is greater than or equal to the max fee for
  1049  	// the block mined after it.
  1050  	if minFee1.Cmp(maxFee2) < 0 {
  1051  		t.Error("Expected min fee from the first block to be greater than the max fee from the second block.")
  1052  	}
  1053  	if minFee2.Cmp(maxFee3) < 0 {
  1054  		t.Error("Expected min fee from the second block to be greater than the max fee from the third block.")
  1055  	}
  1056  	if minFee3.Cmp(maxFee4) < 0 {
  1057  		t.Error("Expected min fee from the third block to be greater than the max fee from the fourth block.")
  1058  	}
  1059  }
  1060  
  1061  // TestTpoolRevert tests proper transaction pool reverts. In this test we create
  1062  // two testers who set up the same outputs for a group of transaction sets. Then
  1063  // one accepts a small subset of those sets, mines a block, and passes that
  1064  // block to the other tester. Then that tester mines two blocks. We check that
  1065  // the total fee for all 3 blocks is as expected, and that the last block only
  1066  // has transactions with fees less than those in the block prior.
  1067  func TestTpoolRevert(t *testing.T) {
  1068  	if testing.Short() || !build.VLONG {
  1069  		t.SkipNow()
  1070  	}
  1071  
  1072  	tpt, err := blankTpoolTester(t.Name())
  1073  	if err != nil {
  1074  		t.Fatal(err)
  1075  	}
  1076  	tpt2, err := blankTpoolTester(t.Name() + "2")
  1077  	if err != nil {
  1078  		t.Fatal(err)
  1079  	}
  1080  	defer tpt.Close()
  1081  	defer tpt2.Close()
  1082  
  1083  	// Mine blocks until there is money in the wallet. We have to make sure they
  1084  	// are on the same chain by feeding all blocks to the other tester.
  1085  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
  1086  		b, _ := tpt.miner.FindBlock()
  1087  		err = tpt.cs.AcceptBlock(b)
  1088  		if err != nil {
  1089  			t.Fatal(err)
  1090  		}
  1091  		err = tpt2.cs.AcceptBlock(b)
  1092  		if err != nil {
  1093  			t.Fatal(err)
  1094  		}
  1095  	}
  1096  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
  1097  		b, _ := tpt2.miner.FindBlock()
  1098  		err = tpt2.cs.AcceptBlock(b)
  1099  		if err != nil {
  1100  			t.Fatal(err)
  1101  		}
  1102  		err = tpt.cs.AcceptBlock(b)
  1103  		if err != nil {
  1104  			t.Fatal(err)
  1105  		}
  1106  	}
  1107  
  1108  	// Mine a few more blocks to get some extra funding.
  1109  	for i := 0; i < 4; i++ {
  1110  		block, err := tpt.miner.AddBlock()
  1111  		if err != nil {
  1112  			t.Fatal(err)
  1113  		}
  1114  		err = tpt2.cs.AcceptBlock(block)
  1115  		if err != nil {
  1116  			t.Fatal(err)
  1117  		}
  1118  	}
  1119  
  1120  	// Create transaction graph setup.
  1121  	coinFrac := types.SiacoinPrecision
  1122  	numGraphs := 110
  1123  	graphFund := coinFrac.Mul64(12210)
  1124  	var outputs []types.SiacoinOutput
  1125  	for i := 0; i < numGraphs; i++ {
  1126  		outputs = append(outputs, types.SiacoinOutput{
  1127  			UnlockHash: types.UnlockConditions{}.UnlockHash(),
  1128  			Value:      graphFund,
  1129  		})
  1130  	}
  1131  	txns, err := tpt.wallet.SendSiacoinsMulti(outputs)
  1132  	if err != nil {
  1133  		t.Error(err)
  1134  	}
  1135  	// Mine the graph setup in the consensus set so that the graph outputs are
  1136  	// transaction sets. This guarantees that the parent of every graph will be
  1137  	// its own output.
  1138  	block, err := tpt.miner.AddBlock()
  1139  	if err != nil {
  1140  		t.Fatal(err)
  1141  	}
  1142  	err = tpt2.cs.AcceptBlock(block)
  1143  	if err != nil {
  1144  		t.Fatal(err)
  1145  	}
  1146  
  1147  	finalTxn := txns[len(txns)-1]
  1148  	// For each output, create 250 transactions
  1149  	var graphs [][]types.Transaction
  1150  	for i := 0; i < numGraphs; i++ {
  1151  		var edges []types.TransactionGraphEdge
  1152  		var cumFee types.Currency
  1153  		for j := 0; j < numGraphs; j++ {
  1154  			fee := coinFrac.Mul64(uint64((j + 1)))
  1155  			cumFee = cumFee.Add(fee)
  1156  			edges = append(edges, types.TransactionGraphEdge{
  1157  				Dest:   j + 1,
  1158  				Fee:    fee,
  1159  				Source: 0,
  1160  				Value:  fee,
  1161  			})
  1162  		}
  1163  		for k := 0; k < numGraphs; k++ {
  1164  			fee := coinFrac.Mul64(uint64(k + 1)).Div64(2)
  1165  			cumFee = cumFee.Add(fee)
  1166  			edges = append(edges, types.TransactionGraphEdge{
  1167  				Dest:   k + 251,
  1168  				Fee:    fee,
  1169  				Source: k + 1,
  1170  				Value:  fee,
  1171  			})
  1172  		}
  1173  		graph, err := types.TransactionGraph(finalTxn.SiacoinOutputID(uint64(i)), edges)
  1174  		if err != nil {
  1175  			t.Fatal(err)
  1176  		}
  1177  		graphs = append(graphs, graph)
  1178  
  1179  	}
  1180  	// Accept the parent node of each graph so that its outputs we can test
  1181  	// spending its outputs after mining the next block.
  1182  	for _, graph := range graphs {
  1183  		err := tpt.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
  1184  		if err != nil {
  1185  			t.Fatal(err)
  1186  		}
  1187  		err = tpt2.tpool.AcceptTransactionSet([]types.Transaction{graph[0]})
  1188  		if err != nil {
  1189  			t.Fatal(err)
  1190  		}
  1191  	}
  1192  	block, err = tpt.miner.AddBlock()
  1193  	if err != nil {
  1194  		t.Fatal(err)
  1195  	}
  1196  	err = tpt2.cs.AcceptBlock(block)
  1197  	if err != nil {
  1198  		t.Fatal(err)
  1199  	}
  1200  
  1201  	// Now accept all the other nodes of each graph.
  1202  	for _, graph := range graphs {
  1203  		for _, txn := range graph[1:] {
  1204  			err := tpt.tpool.AcceptTransactionSet([]types.Transaction{txn})
  1205  			if err != nil {
  1206  				t.Fatal(err)
  1207  			}
  1208  		}
  1209  	}
  1210  	// Accept a randomly selected subset of transactions with the other tester.
  1211  	randSet := fastrand.Perm(len(graphs))
  1212  	for i := 0; i < len(randSet)/10; i++ {
  1213  		graph := graphs[randSet[i]]
  1214  		for _, txn := range graph[1:] {
  1215  			err := tpt2.tpool.AcceptTransactionSet([]types.Transaction{txn})
  1216  			if err != nil {
  1217  				t.Fatal(err)
  1218  			}
  1219  		}
  1220  	}
  1221  
  1222  	// Now the second tester mines the random subset, and gives the block to the
  1223  	// first tester.
  1224  	block, err = tpt2.miner.AddBlock()
  1225  	if err != nil {
  1226  		t.Fatal(err)
  1227  	}
  1228  	err = tpt.cs.AcceptBlock(block)
  1229  	if err != nil {
  1230  		t.Fatal(err)
  1231  	}
  1232  
  1233  	//Now we add up all the fees from this first block.
  1234  	var totalFeeRandBlock types.Currency
  1235  	for _, tx := range block.Transactions {
  1236  		for _, fee := range tx.MinerFees {
  1237  			totalFeeRandBlock = totalFeeRandBlock.Add(fee)
  1238  		}
  1239  	}
  1240  
  1241  	// Mine the next block so we can check the transactions inside
  1242  	block, err = tpt.miner.AddBlock()
  1243  	if err != nil {
  1244  		t.Fatal(err)
  1245  	}
  1246  	var totalFee1 types.Currency
  1247  	maxFee1 := types.SiacoinPrecision.Div64(1000000)
  1248  	minFee1 := types.SiacoinPrecision.Mul64(1000000)
  1249  	for _, txn := range block.Transactions {
  1250  		for _, fee := range txn.MinerFees {
  1251  			if fee.Cmp(maxFee1) >= 0 {
  1252  				maxFee1 = fee
  1253  			}
  1254  			if fee.Cmp(minFee1) <= 0 {
  1255  				minFee1 = fee
  1256  			}
  1257  			totalFee1 = totalFee1.Add(fee)
  1258  		}
  1259  	}
  1260  
  1261  	// Mine the next block so we can check the transactions inside
  1262  	block, err = tpt.miner.AddBlock()
  1263  	if err != nil {
  1264  		t.Fatal(err)
  1265  	}
  1266  	var totalFee2 types.Currency
  1267  	maxFee2 := types.SiacoinPrecision.Div64(1000000)
  1268  	minFee2 := types.SiacoinPrecision.Mul64(1000000)
  1269  	for _, txn := range block.Transactions {
  1270  		for _, fee := range txn.MinerFees {
  1271  			if fee.Cmp(maxFee2) >= 0 {
  1272  				maxFee2 = fee
  1273  			}
  1274  			if fee.Cmp(minFee2) <= 0 {
  1275  				minFee2 = fee
  1276  			}
  1277  			totalFee2 = totalFee2.Add(fee)
  1278  		}
  1279  	}
  1280  
  1281  	totalFeeAcrossBlocks := totalFeeRandBlock.Add(totalFee1).Add(totalFee2)
  1282  	totalExpectedFee := types.SiacoinPrecision.Mul64(13860).Add(types.SiacoinPrecision.Mul64(321915))
  1283  	if totalFeeAcrossBlocks.Cmp(totalExpectedFee) != 0 {
  1284  		t.Error("Fee different from expected.")
  1285  	}
  1286  	if maxFee1.Cmp(maxFee2) <= 0 {
  1287  		t.Error("Expected highest fee from first block to be greater than highest fee from second block.")
  1288  	}
  1289  	if minFee1.Cmp(maxFee2) < 0 {
  1290  		t.Error("Expected lowest fee from first block to be greater than or equal to than highest fee from second block.")
  1291  	}
  1292  	if maxFee1.Cmp(minFee1) < 0 {
  1293  		t.Error("Expected highest fee from first block to be greater than lowest fee from first block.")
  1294  	}
  1295  	if maxFee2.Cmp(minFee2) < 0 {
  1296  		t.Error("Expected highest fee from second block to be greater than lowest fee from second block.")
  1297  	}
  1298  }