github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/wallet/transactionbuilder_test.go (about)

     1  package wallet
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/NebulousLabs/Sia/modules"
     7  	"github.com/NebulousLabs/Sia/types"
     8  )
     9  
    10  // TestViewAdded checks that 'ViewAdded' returns sane-seeming values when
    11  // indicating which elements have been added automatically to a transaction
    12  // set.
    13  func TestViewAdded(t *testing.T) {
    14  	if testing.Short() {
    15  		t.SkipNow()
    16  	}
    17  	wt, err := createWalletTester("TestViewAdded")
    18  	if err != nil {
    19  		t.Fatal(err)
    20  	}
    21  	defer wt.closeWt()
    22  
    23  	// Mine an extra block to get more outputs - the wallet is going to be
    24  	// loading two transactions at the same time.
    25  	_, err = wt.miner.AddBlock()
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  
    30  	// Create a transaction, add money to it, spend the money in a miner fee
    31  	// but do not sign the transaction. The format of this test mimics the way
    32  	// that the host-renter protocol behaves when building a file contract
    33  	// transaction.
    34  	b := wt.wallet.StartTransaction()
    35  	txnFund := types.NewCurrency64(100e9)
    36  	err = b.FundSiacoins(txnFund)
    37  	if err != nil {
    38  		t.Fatal(err)
    39  	}
    40  	_ = b.AddMinerFee(txnFund)
    41  	_ = b.AddSiacoinOutput(types.SiacoinOutput{Value: txnFund})
    42  	unfinishedTxn, unfinishedParents := b.View()
    43  
    44  	// Create a second builder that extends the first, unsigned transaction. Do
    45  	// not sign the transaction, but do give the extensions to the original
    46  	// builder.
    47  	b2 := wt.wallet.RegisterTransaction(unfinishedTxn, unfinishedParents)
    48  	err = b2.FundSiacoins(txnFund)
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	unfinishedTxn2, unfinishedParents2 := b2.View()
    53  	newParentIndices, newInputIndices, _, _ := b2.ViewAdded()
    54  
    55  	// Add the new elements from b2 to b and sign the transaction, fetching the
    56  	// signature for b.
    57  	for _, parentIndex := range newParentIndices {
    58  		b.AddParents([]types.Transaction{unfinishedParents2[parentIndex]})
    59  	}
    60  	for _, inputIndex := range newInputIndices {
    61  		b.AddSiacoinInput(unfinishedTxn2.SiacoinInputs[inputIndex])
    62  	}
    63  	// Signing with WholeTransaction=true makes the transaction more brittle to
    64  	// construction mistakes, meaning that an error is more likely to turn up.
    65  	set1, err := b.Sign(true)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	if set1[len(set1)-1].ID() == unfinishedTxn.ID() {
    70  		t.Error("seems like there's memory sharing happening between txn calls")
    71  	}
    72  	// Set1 should be missing some signatures.
    73  	err = wt.tpool.AcceptTransactionSet(set1)
    74  	if err == nil {
    75  		t.Fatal(err)
    76  	}
    77  	unfinishedTxn3, _ := b.View()
    78  	// Only the new signatures are needed because the previous call to 'View'
    79  	// included everything else.
    80  	_, _, _, newTxnSignaturesIndices := b.ViewAdded()
    81  
    82  	// Add the new signatures to b2, and then sign b2's inputs. The resulting
    83  	// set from b2 should be valid.
    84  	for _, sigIndex := range newTxnSignaturesIndices {
    85  		b2.AddTransactionSignature(unfinishedTxn3.TransactionSignatures[sigIndex])
    86  	}
    87  	set2, err := b2.Sign(true)
    88  	err = wt.tpool.AcceptTransactionSet(set2)
    89  	if err != nil {
    90  		t.Fatal(err)
    91  	}
    92  	finishedTxn, _ := b2.View()
    93  	_, _, _, newTxnSignaturesIndices3 := b2.ViewAdded()
    94  
    95  	// Add the new signatures from b2 to the b1 transaction, which should
    96  	// complete the transaction and create a transaction set in 'b' that is
    97  	// identical to the transaction set that is in b2.
    98  	for _, sigIndex := range newTxnSignaturesIndices3 {
    99  		b.AddTransactionSignature(finishedTxn.TransactionSignatures[sigIndex])
   100  	}
   101  	set3Txn, set3Parents := b.View()
   102  	err = wt.tpool.AcceptTransactionSet(append(set3Parents, set3Txn))
   103  	if err != modules.ErrDuplicateTransactionSet {
   104  		t.Fatal(err)
   105  	}
   106  }
   107  
   108  // TestDoubleSignError checks that an error is returned if there is a problem
   109  // when trying to call 'Sign' on a transaction twice.
   110  func TestDoubleSignError(t *testing.T) {
   111  	if testing.Short() {
   112  		t.SkipNow()
   113  	}
   114  	wt, err := createWalletTester("TestDoubleSignError")
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	defer wt.closeWt()
   119  
   120  	// Create a transaction, add money to it, and then call sign twice.
   121  	b := wt.wallet.StartTransaction()
   122  	txnFund := types.NewCurrency64(100e9)
   123  	err = b.FundSiacoins(txnFund)
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  	_ = b.AddMinerFee(txnFund)
   128  	txnSet, err := b.Sign(true)
   129  	if err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	txnSet2, err := b.Sign(true)
   133  	if err != errBuilderAlreadySigned {
   134  		t.Error("the wrong error is being returned after a double call to sign")
   135  	}
   136  	if err != nil && txnSet2 != nil {
   137  		t.Error("errored call to sign did not return a nil txn set")
   138  	}
   139  	err = wt.tpool.AcceptTransactionSet(txnSet)
   140  	if err != nil {
   141  		t.Fatal(err)
   142  	}
   143  }