gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/wallet/transactionbuilder_test.go (about)

     1  package wallet
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  
     7  	"gitlab.com/SiaPrime/SiaPrime/modules"
     8  	"gitlab.com/SiaPrime/SiaPrime/types"
     9  )
    10  
    11  // addBlockNoPayout adds a block to the wallet tester that does not have any
    12  // payouts.
    13  func (wt *walletTester) addBlockNoPayout() error {
    14  	block, target, err := wt.miner.BlockForWork()
    15  	if err != nil {
    16  		return err
    17  	}
    18  	// Clear the miner payout so that the wallet is not getting additional
    19  	// outputs from these blocks.
    20  	for i := range block.MinerPayouts {
    21  		if i == len(block.MinerPayouts)-1 {
    22  			// DevSubsidy.
    23  			continue
    24  		}
    25  		block.MinerPayouts[i].UnlockHash = types.UnlockHash{}
    26  	}
    27  
    28  	// Solve and submit the block.
    29  	solvedBlock, _ := wt.miner.SolveBlock(block, target)
    30  	err = wt.cs.AcceptBlock(solvedBlock)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	return nil
    35  }
    36  
    37  // TestViewAdded checks that 'ViewAdded' returns sane-seeming values when
    38  // indicating which elements have been added automatically to a transaction
    39  // set.
    40  func TestViewAdded(t *testing.T) {
    41  	if testing.Short() {
    42  		t.SkipNow()
    43  	}
    44  	wt, err := createWalletTester(t.Name(), modules.ProdDependencies)
    45  	if err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	defer wt.closeWt()
    49  
    50  	// Mine an extra block to get more outputs - the wallet is going to be
    51  	// loading two transactions at the same time.
    52  	_, err = wt.miner.AddBlock()
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  
    57  	// Create a transaction, add money to it, spend the money in a miner fee
    58  	// but do not sign the transaction. The format of this test mimics the way
    59  	// that the host-renter protocol behaves when building a file contract
    60  	// transaction.
    61  	b, err := wt.wallet.StartTransaction()
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  	txnFund := types.NewCurrency64(100e9)
    66  	err = b.FundSiacoins(txnFund)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	_ = b.AddMinerFee(txnFund)
    71  	_ = b.AddSiacoinOutput(types.SiacoinOutput{Value: txnFund})
    72  	unfinishedTxn, unfinishedParents := b.View()
    73  
    74  	// Create a second builder that extends the first, unsigned transaction. Do
    75  	// not sign the transaction, but do give the extensions to the original
    76  	// builder.
    77  	b2, err := wt.wallet.RegisterTransaction(unfinishedTxn, unfinishedParents)
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	err = b2.FundSiacoins(txnFund)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	unfinishedTxn2, unfinishedParents2 := b2.View()
    86  	newParentIndices, newInputIndices, _, _ := b2.ViewAdded()
    87  
    88  	// Add the new elements from b2 to b and sign the transaction, fetching the
    89  	// signature for b.
    90  	for _, parentIndex := range newParentIndices {
    91  		b.AddParents([]types.Transaction{unfinishedParents2[parentIndex]})
    92  	}
    93  	for _, inputIndex := range newInputIndices {
    94  		b.AddSiacoinInput(unfinishedTxn2.SiacoinInputs[inputIndex])
    95  	}
    96  	// Signing with WholeTransaction=true makes the transaction more brittle to
    97  	// construction mistakes, meaning that an error is more likely to turn up.
    98  	set1, err := b.Sign(true)
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	if set1[len(set1)-1].ID() == unfinishedTxn.ID() {
   103  		t.Error("seems like there's memory sharing happening between txn calls")
   104  	}
   105  	// Set1 should be missing some signatures.
   106  	err = wt.tpool.AcceptTransactionSet(set1)
   107  	if err == nil {
   108  		t.Fatal(err)
   109  	}
   110  	unfinishedTxn3, _ := b.View()
   111  	// Only the new signatures are needed because the previous call to 'View'
   112  	// included everything else.
   113  	_, _, _, newTxnSignaturesIndices := b.ViewAdded()
   114  
   115  	// Add the new signatures to b2, and then sign b2's inputs. The resulting
   116  	// set from b2 should be valid.
   117  	for _, sigIndex := range newTxnSignaturesIndices {
   118  		b2.AddTransactionSignature(unfinishedTxn3.TransactionSignatures[sigIndex])
   119  	}
   120  	set2, err := b2.Sign(true)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  	err = wt.tpool.AcceptTransactionSet(set2)
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  	finishedTxn, _ := b2.View()
   129  	_, _, _, newTxnSignaturesIndices3 := b2.ViewAdded()
   130  
   131  	// Add the new signatures from b2 to the b1 transaction, which should
   132  	// complete the transaction and create a transaction set in 'b' that is
   133  	// identical to the transaction set that is in b2.
   134  	for _, sigIndex := range newTxnSignaturesIndices3 {
   135  		b.AddTransactionSignature(finishedTxn.TransactionSignatures[sigIndex])
   136  	}
   137  	set3Txn, set3Parents := b.View()
   138  	err = wt.tpool.AcceptTransactionSet(append(set3Parents, set3Txn))
   139  	if err != modules.ErrDuplicateTransactionSet {
   140  		t.Fatal(err)
   141  	}
   142  }
   143  
   144  // TestDoubleSignError checks that an error is returned if there is a problem
   145  // when trying to call 'Sign' on a transaction twice.
   146  func TestDoubleSignError(t *testing.T) {
   147  	if testing.Short() {
   148  		t.SkipNow()
   149  	}
   150  	wt, err := createWalletTester(t.Name(), modules.ProdDependencies)
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	defer wt.closeWt()
   155  
   156  	// Create a transaction, add money to it, and then call sign twice.
   157  	b, err := wt.wallet.StartTransaction()
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	txnFund := types.NewCurrency64(100e9)
   162  	err = b.FundSiacoins(txnFund)
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  	_ = b.AddMinerFee(txnFund)
   167  	txnSet, err := b.Sign(true)
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  	txnSet2, err := b.Sign(true)
   172  	if err != errBuilderAlreadySigned {
   173  		t.Error("the wrong error is being returned after a double call to sign")
   174  	}
   175  	if err != nil && txnSet2 != nil {
   176  		t.Error("errored call to sign did not return a nil txn set")
   177  	}
   178  	err = wt.tpool.AcceptTransactionSet(txnSet)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  }
   183  
   184  // TestConcurrentBuilders checks that multiple transaction builders can safely
   185  // be opened at the same time, and that they will make valid transactions when
   186  // building concurrently.
   187  func TestConcurrentBuilders(t *testing.T) {
   188  	if testing.Short() {
   189  		t.SkipNow()
   190  	}
   191  	wt, err := createWalletTester(t.Name(), modules.ProdDependencies)
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	defer wt.closeWt()
   196  
   197  	// Mine a few more blocks so that the wallet has lots of outputs to pick
   198  	// from.
   199  	for i := 0; i < 5; i++ {
   200  		_, err := wt.miner.AddBlock()
   201  		if err != nil {
   202  			t.Fatal(err)
   203  		}
   204  	}
   205  
   206  	// Get a baseline balance for the wallet.
   207  	startingSCConfirmed, _, _, err := wt.wallet.ConfirmedBalance()
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	startingOutgoing, startingIncoming, err := wt.wallet.UnconfirmedBalance()
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  	if !startingOutgoing.IsZero() {
   216  		t.Fatal(startingOutgoing)
   217  	}
   218  	if !startingIncoming.IsZero() {
   219  		t.Fatal(startingIncoming)
   220  	}
   221  
   222  	// Create two builders at the same time, then add money to each.
   223  	builder1, err := wt.wallet.StartTransaction()
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	builder2, err := wt.wallet.StartTransaction()
   228  	if err != nil {
   229  		t.Fatal(err)
   230  	}
   231  	// Fund each builder with a siacoin output that is smaller than all of the
   232  	// outputs that the wallet should currently have.
   233  	funding := types.NewCurrency64(10e3).Mul(types.SiacoinPrecision)
   234  	err = builder1.FundSiacoins(funding)
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	err = builder2.FundSiacoins(funding)
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  
   243  	// Get a second reading on the wallet's balance.
   244  	fundedSCConfirmed, _, _, err := wt.wallet.ConfirmedBalance()
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  	if !startingSCConfirmed.Equals(fundedSCConfirmed) {
   249  		t.Fatal("confirmed siacoin balance changed when no blocks have been mined", startingSCConfirmed, fundedSCConfirmed)
   250  	}
   251  
   252  	// Spend the transaction funds on miner fees and the void output.
   253  	builder1.AddMinerFee(types.NewCurrency64(25).Mul(types.SiacoinPrecision))
   254  	builder2.AddMinerFee(types.NewCurrency64(25).Mul(types.SiacoinPrecision))
   255  	// Send the money to the void.
   256  	output := types.SiacoinOutput{Value: types.NewCurrency64(9975).Mul(types.SiacoinPrecision)}
   257  	builder1.AddSiacoinOutput(output)
   258  	builder2.AddSiacoinOutput(output)
   259  
   260  	// Sign the transactions and verify that both are valid.
   261  	tset1, err := builder1.Sign(true)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	tset2, err := builder2.Sign(true)
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  	err = wt.tpool.AcceptTransactionSet(tset1)
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  	err = wt.tpool.AcceptTransactionSet(tset2)
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	// Mine a block to get the transaction sets into the blockchain.
   279  	_, err = wt.miner.AddBlock()
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  }
   284  
   285  // TestConcurrentBuildersSingleOutput probes the behavior when multiple
   286  // builders are created at the same time, but there is only a single wallet
   287  // output that they end up needing to share.
   288  func TestConcurrentBuildersSingleOutput(t *testing.T) {
   289  	if testing.Short() {
   290  		t.SkipNow()
   291  	}
   292  	wt, err := createWalletTester(t.Name(), modules.ProdDependencies)
   293  	if err != nil {
   294  		t.Fatal(err)
   295  	}
   296  	defer wt.closeWt()
   297  
   298  	// Mine MaturityDelay blocks on the wallet using blocks that don't give
   299  	// miner payouts to the wallet, so that all outputs can be condensed into a
   300  	// single confirmed output. Currently the wallet will be getting a new
   301  	// output per block because it has mined some blocks that haven't had their
   302  	// outputs matured.
   303  	for i := types.BlockHeight(0); i < types.MaturityDelay+1; i++ {
   304  		err = wt.addBlockNoPayout()
   305  		if err != nil {
   306  			t.Fatal(err)
   307  		}
   308  	}
   309  
   310  	// Send all coins to a single confirmed output for the wallet.
   311  	unlockConditions, err := wt.wallet.NextAddress()
   312  	if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	scBal, _, _, err := wt.wallet.ConfirmedBalance()
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	// Use a custom builder so that there is no transaction fee.
   320  	builder, err := wt.wallet.StartTransaction()
   321  	if err != nil {
   322  		t.Fatal(err)
   323  	}
   324  	err = builder.FundSiacoins(scBal)
   325  	if err != nil {
   326  		t.Fatal(err)
   327  	}
   328  	output := types.SiacoinOutput{
   329  		Value:      scBal,
   330  		UnlockHash: unlockConditions.UnlockHash(),
   331  	}
   332  	builder.AddSiacoinOutput(output)
   333  	tSet, err := builder.Sign(true)
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	err = wt.tpool.AcceptTransactionSet(tSet)
   338  	if err != nil {
   339  		t.Fatal(err)
   340  	}
   341  	// Get the transaction into the blockchain without giving a miner payout to
   342  	// the wallet.
   343  	err = wt.addBlockNoPayout()
   344  	if err != nil {
   345  		t.Fatal(err)
   346  	}
   347  
   348  	// Get a baseline balance for the wallet.
   349  	startingSCConfirmed, _, _, err := wt.wallet.ConfirmedBalance()
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	startingOutgoing, startingIncoming, err := wt.wallet.UnconfirmedBalance()
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	if !startingOutgoing.IsZero() {
   358  		t.Fatal(startingOutgoing)
   359  	}
   360  	if !startingIncoming.IsZero() {
   361  		t.Fatal(startingIncoming)
   362  	}
   363  
   364  	// Create two builders at the same time, then add money to each.
   365  	builder1, err := wt.wallet.StartTransaction()
   366  	if err != nil {
   367  		t.Fatal(err)
   368  	}
   369  	builder2, err := wt.wallet.StartTransaction()
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	// Fund each builder with a siacoin output.
   374  	funding := types.NewCurrency64(10e3).Mul(types.SiacoinPrecision)
   375  	err = builder1.FundSiacoins(funding)
   376  	if err != nil {
   377  		t.Fatal(err)
   378  	}
   379  	// This add should fail, blocking the builder from completion.
   380  	err = builder2.FundSiacoins(funding)
   381  	if err != modules.ErrIncompleteTransactions {
   382  		t.Fatal(err)
   383  	}
   384  
   385  	// Get a second reading on the wallet's balance.
   386  	fundedSCConfirmed, _, _, err := wt.wallet.ConfirmedBalance()
   387  	if err != nil {
   388  		t.Fatal(err)
   389  	}
   390  	if !startingSCConfirmed.Equals(fundedSCConfirmed) {
   391  		t.Fatal("confirmed siacoin balance changed when no blocks have been mined", startingSCConfirmed, fundedSCConfirmed)
   392  	}
   393  
   394  	// Spend the transaction funds on miner fees and the void output.
   395  	builder1.AddMinerFee(types.NewCurrency64(25).Mul(types.SiacoinPrecision))
   396  	// Send the money to the void.
   397  	output = types.SiacoinOutput{Value: types.NewCurrency64(9975).Mul(types.SiacoinPrecision)}
   398  	builder1.AddSiacoinOutput(output)
   399  
   400  	// Sign the transaction and submit it.
   401  	tset1, err := builder1.Sign(true)
   402  	if err != nil {
   403  		t.Fatal(err)
   404  	}
   405  	err = wt.tpool.AcceptTransactionSet(tset1)
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	// Mine a block to get the transaction sets into the blockchain.
   411  	_, err = wt.miner.AddBlock()
   412  	if err != nil {
   413  		t.Fatal(err)
   414  	}
   415  }
   416  
   417  // TestParallelBuilders checks that multiple transaction builders can safely be
   418  // opened at the same time, and that they will make valid transactions when
   419  // building concurrently, using multiple gothreads to manage the builders.
   420  func TestParallelBuilders(t *testing.T) {
   421  	if testing.Short() {
   422  		t.SkipNow()
   423  	}
   424  	wt, err := createWalletTester(t.Name(), modules.ProdDependencies)
   425  	if err != nil {
   426  		t.Fatal(err)
   427  	}
   428  	defer wt.closeWt()
   429  
   430  	// Mine a few more blocks so that the wallet has lots of outputs to pick
   431  	// from.
   432  	outputsDesired := 10
   433  	for i := 0; i < outputsDesired; i++ {
   434  		_, err := wt.miner.AddBlock()
   435  		if err != nil {
   436  			t.Fatal(err)
   437  		}
   438  	}
   439  	// Add MatruityDelay blocks with no payout to make tracking the balance
   440  	// easier.
   441  	for i := types.BlockHeight(0); i < types.MaturityDelay+1; i++ {
   442  		err = wt.addBlockNoPayout()
   443  		if err != nil {
   444  			t.Fatal(err)
   445  		}
   446  	}
   447  
   448  	// Get a baseline balance for the wallet.
   449  	startingSCConfirmed, _, _, err := wt.wallet.ConfirmedBalance()
   450  	if err != nil {
   451  		t.Fatal(err)
   452  	}
   453  	startingOutgoing, startingIncoming, err := wt.wallet.UnconfirmedBalance()
   454  	if err != nil {
   455  		t.Fatal(err)
   456  	}
   457  	if !startingOutgoing.IsZero() {
   458  		t.Fatal(startingOutgoing)
   459  	}
   460  	if !startingIncoming.IsZero() {
   461  		t.Fatal(startingIncoming)
   462  	}
   463  
   464  	// Create several builders in parallel.
   465  	var wg sync.WaitGroup
   466  	funding := types.NewCurrency64(10e3).Mul(types.SiacoinPrecision)
   467  	for i := 0; i < outputsDesired; i++ {
   468  		wg.Add(1)
   469  		go func() {
   470  			// Create the builder and fund the transaction.
   471  			builder, err := wt.wallet.StartTransaction()
   472  			if err != nil {
   473  				t.Fatal(err)
   474  			}
   475  			err = builder.FundSiacoins(funding)
   476  			if err != nil {
   477  				t.Fatal(err)
   478  			}
   479  
   480  			// Spend the transaction funds on miner fees and the void output.
   481  			builder.AddMinerFee(types.NewCurrency64(25).Mul(types.SiacoinPrecision))
   482  			output := types.SiacoinOutput{Value: types.NewCurrency64(9975).Mul(types.SiacoinPrecision)}
   483  			builder.AddSiacoinOutput(output)
   484  			// Sign the transactions and verify that both are valid.
   485  			tset, err := builder.Sign(true)
   486  			if err != nil {
   487  				t.Fatal(err)
   488  			}
   489  			err = wt.tpool.AcceptTransactionSet(tset)
   490  			if err != nil {
   491  				t.Fatal(err)
   492  			}
   493  			wg.Done()
   494  		}()
   495  	}
   496  	wg.Wait()
   497  
   498  	// Mine a block to get the transaction sets into the blockchain.
   499  	err = wt.addBlockNoPayout()
   500  	if err != nil {
   501  		t.Fatal(err)
   502  	}
   503  
   504  	// Check the final balance.
   505  	endingSCConfirmed, _, _, err := wt.wallet.ConfirmedBalance()
   506  	if err != nil {
   507  		t.Fatal(err)
   508  	}
   509  	expected := startingSCConfirmed.Sub(funding.Mul(types.NewCurrency64(uint64(outputsDesired))))
   510  	if !expected.Equals(endingSCConfirmed) {
   511  		t.Fatal("did not get the expected ending balance", expected, endingSCConfirmed, startingSCConfirmed)
   512  	}
   513  }
   514  
   515  // TestUnconfirmedParents tests the functionality of the transaction builder's
   516  // UnconfirmedParents method.
   517  func TestUnconfirmedParents(t *testing.T) {
   518  	if testing.Short() {
   519  		t.SkipNow()
   520  	}
   521  	wt, err := createWalletTester(t.Name(), &modules.ProductionDependencies{})
   522  	if err != nil {
   523  		t.Fatal(err)
   524  	}
   525  	defer wt.closeWt()
   526  
   527  	// Send all of the wallet's available balance to itself.
   528  	uc, err := wt.wallet.NextAddress()
   529  	if err != nil {
   530  		t.Fatal("Failed to get address", err)
   531  	}
   532  	siacoins, _, _, err := wt.wallet.ConfirmedBalance()
   533  	if err != nil {
   534  		t.Fatal(err)
   535  	}
   536  	tSet, err := wt.wallet.SendSiacoins(siacoins.Sub(types.SiacoinPrecision), uc.UnlockHash())
   537  	if err != nil {
   538  		t.Fatal("Failed to send coins", err)
   539  	}
   540  
   541  	// Create a transaction. That transaction should use siacoin outputs from
   542  	// the unconfirmed transactions in tSet as inputs and is therefore a child
   543  	// of tSet.
   544  	b, err := wt.wallet.StartTransaction()
   545  	if err != nil {
   546  		t.Fatal(err)
   547  	}
   548  	txnFund := types.NewCurrency64(1e3)
   549  	err = b.FundSiacoins(txnFund)
   550  	if err != nil {
   551  		t.Fatal(err)
   552  	}
   553  
   554  	// UnconfirmedParents should return the transactions of the transaction set
   555  	// we used to send money to ourselves.
   556  	parents, err := b.UnconfirmedParents()
   557  	if err != nil {
   558  		t.Fatal(err)
   559  	}
   560  	if len(tSet) != len(parents) {
   561  		t.Fatal("parents should have same length as unconfirmed transaction set")
   562  	}
   563  	for i := 0; i < len(tSet); i++ {
   564  		if tSet[i].ID() != parents[i].ID() {
   565  			t.Error("returned parent doesn't match transaction of transaction set")
   566  		}
   567  	}
   568  }
   569  
   570  func TestFundSiacoinsForOutputs(t *testing.T) {
   571  	if testing.Short() {
   572  		t.SkipNow()
   573  	}
   574  	wt, err := createWalletTester(t.Name(), &modules.ProductionDependencies{})
   575  	if err != nil {
   576  		t.Fatal(err)
   577  	}
   578  	defer wt.closeWt()
   579  
   580  	b, err := wt.wallet.StartTransaction()
   581  	if err != nil {
   582  		t.Fatal(err)
   583  	}
   584  	uc1, err := wt.wallet.NextAddress()
   585  	if err != nil {
   586  		t.Fatal(err)
   587  	}
   588  	uc2, err := wt.wallet.NextAddress()
   589  	if err != nil {
   590  		t.Fatal(err)
   591  	}
   592  
   593  	amount1 := types.NewCurrency64(1000)
   594  	amount2 := types.NewCurrency64(2000)
   595  	output1 := types.SiacoinOutput{
   596  		Value:      amount1,
   597  		UnlockHash: uc1.UnlockHash(),
   598  	}
   599  	output2 := types.SiacoinOutput{
   600  		Value:      amount2,
   601  		UnlockHash: uc2.UnlockHash(),
   602  	}
   603  	minerFee := types.NewCurrency64(750)
   604  
   605  	// Wallet starts off with large inputs from mining blocks, larger than our
   606  	// combined outputs and miner fees
   607  	err = b.FundSiacoinsForOutputs([]types.SiacoinOutput{output1, output2}, minerFee)
   608  	if err != nil {
   609  		t.Fatal(err)
   610  	}
   611  	unfinishedTxn, _ := b.View()
   612  
   613  	// Here we should have 3 outputs, the two specified plus a refund
   614  	if len(unfinishedTxn.SiacoinOutputs) != 3 {
   615  		t.Fatal("incorrect number of outputs generated")
   616  	}
   617  	if len(unfinishedTxn.MinerFees) != 1 {
   618  		t.Fatal("miner fees were not generated but should have been")
   619  	}
   620  	if unfinishedTxn.MinerFees[0].Cmp(minerFee) != 0 {
   621  		t.Fatal("miner fees were not generated but should have been")
   622  	}
   623  
   624  	// General construction seems ok, let's sign and submit it to the tpool
   625  	txSet, err := b.Sign(true)
   626  	if err != nil {
   627  		t.Fatal(err)
   628  	}
   629  
   630  	// If the tpool accepts it, everything looks good
   631  	err = wt.tpool.AcceptTransactionSet(txSet)
   632  	if err != nil {
   633  		t.Fatal(err)
   634  	}
   635  }