github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/renter/proto/contract_test.go (about)

     1  package proto
     2  
     3  import (
     4  	"bytes"
     5  	"path/filepath"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"SiaPrime/build"
    10  	"SiaPrime/crypto"
    11  	"SiaPrime/encoding"
    12  	"SiaPrime/modules"
    13  	"SiaPrime/types"
    14  )
    15  
    16  // TestContractUncommittedTxn tests that if a contract revision is left in an
    17  // uncommitted state, either version of the contract can be recovered.
    18  func TestContractUncommittedTxn(t *testing.T) {
    19  	if testing.Short() {
    20  		t.SkipNow()
    21  	}
    22  	// create contract set with one contract
    23  	dir := build.TempDir(filepath.Join("proto", t.Name()))
    24  	cs, err := NewContractSet(dir, modules.ProdDependencies)
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	initialHeader := contractHeader{
    29  		Transaction: types.Transaction{
    30  			FileContractRevisions: []types.FileContractRevision{{
    31  				NewRevisionNumber:    1,
    32  				NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
    33  				UnlockConditions: types.UnlockConditions{
    34  					PublicKeys: []types.SiaPublicKey{{}, {}},
    35  				},
    36  			}},
    37  		},
    38  	}
    39  	initialRoots := []crypto.Hash{{1}}
    40  	c, err := cs.managedInsertContract(initialHeader, initialRoots)
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  
    45  	// apply an update to the contract, but don't commit it
    46  	sc := cs.mustAcquire(t, c.ID)
    47  	revisedHeader := contractHeader{
    48  		Transaction: types.Transaction{
    49  			FileContractRevisions: []types.FileContractRevision{{
    50  				NewRevisionNumber:    2,
    51  				NewValidProofOutputs: []types.SiacoinOutput{{}, {}},
    52  				UnlockConditions: types.UnlockConditions{
    53  					PublicKeys: []types.SiaPublicKey{{}, {}},
    54  				},
    55  			}},
    56  		},
    57  		StorageSpending: types.NewCurrency64(7),
    58  		UploadSpending:  types.NewCurrency64(17),
    59  	}
    60  	revisedRoots := []crypto.Hash{{1}, {2}}
    61  	fcr := revisedHeader.Transaction.FileContractRevisions[0]
    62  	newRoot := revisedRoots[1]
    63  	storageCost := revisedHeader.StorageSpending.Sub(initialHeader.StorageSpending)
    64  	bandwidthCost := revisedHeader.UploadSpending.Sub(initialHeader.UploadSpending)
    65  	walTxn, err := sc.recordUploadIntent(fcr, newRoot, storageCost, bandwidthCost)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  
    70  	// the state of the contract should match the initial state
    71  	// NOTE: can't use reflect.DeepEqual for the header because it contains
    72  	// types.Currency fields
    73  	merkleRoots, err := sc.merkleRoots.merkleRoots()
    74  	if err != nil {
    75  		t.Fatal("failed to get merkle roots", err)
    76  	}
    77  	if !bytes.Equal(encoding.Marshal(sc.header), encoding.Marshal(initialHeader)) {
    78  		t.Fatal("contractHeader should match initial contractHeader")
    79  	} else if !reflect.DeepEqual(merkleRoots, initialRoots) {
    80  		t.Fatal("Merkle roots should match initial Merkle roots")
    81  	}
    82  
    83  	// close and reopen the contract set
    84  	cs.Close()
    85  	cs, err = NewContractSet(dir, modules.ProdDependencies)
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	// the uncommitted transaction should be stored in the contract
    90  	sc = cs.mustAcquire(t, c.ID)
    91  	if len(sc.unappliedTxns) != 1 {
    92  		t.Fatal("expected 1 unappliedTxn, got", len(sc.unappliedTxns))
    93  	} else if !bytes.Equal(sc.unappliedTxns[0].Updates[0].Instructions, walTxn.Updates[0].Instructions) {
    94  		t.Fatal("WAL transaction changed")
    95  	}
    96  	// the state of the contract should match the initial state
    97  	merkleRoots, err = sc.merkleRoots.merkleRoots()
    98  	if err != nil {
    99  		t.Fatal("failed to get merkle roots:", err)
   100  	}
   101  	if !bytes.Equal(encoding.Marshal(sc.header), encoding.Marshal(initialHeader)) {
   102  		t.Fatal("contractHeader should match initial contractHeader", sc.header, initialHeader)
   103  	} else if !reflect.DeepEqual(merkleRoots, initialRoots) {
   104  		t.Fatal("Merkle roots should match initial Merkle roots")
   105  	}
   106  
   107  	// apply the uncommitted transaction
   108  	err = sc.commitTxns()
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	// the uncommitted transaction should be gone now
   113  	if len(sc.unappliedTxns) != 0 {
   114  		t.Fatal("expected 0 unappliedTxns, got", len(sc.unappliedTxns))
   115  	}
   116  	// the state of the contract should now match the revised state
   117  	merkleRoots, err = sc.merkleRoots.merkleRoots()
   118  	if err != nil {
   119  		t.Fatal("failed to get merkle roots:", err)
   120  	}
   121  	if !bytes.Equal(encoding.Marshal(sc.header), encoding.Marshal(revisedHeader)) {
   122  		t.Fatal("contractHeader should match revised contractHeader", sc.header, revisedHeader)
   123  	} else if !reflect.DeepEqual(merkleRoots, revisedRoots) {
   124  		t.Fatal("Merkle roots should match revised Merkle roots")
   125  	}
   126  }