gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/proto/negotiate_test.go (about)

     1  package proto
     2  
     3  import (
     4  	"net"
     5  	"testing"
     6  
     7  	"gitlab.com/NebulousLabs/errors"
     8  
     9  	"gitlab.com/NebulousLabs/encoding"
    10  	"go.sia.tech/siad/crypto"
    11  	"go.sia.tech/siad/modules"
    12  	"go.sia.tech/siad/types"
    13  )
    14  
    15  // TestNegotiateRevisionStopResponse tests that when the host sends
    16  // StopResponse, the renter continues processing the revision instead of
    17  // immediately terminating.
    18  func TestNegotiateRevisionStopResponse(t *testing.T) {
    19  	// simulate a renter-host connection
    20  	rConn, hConn := net.Pipe()
    21  
    22  	// handle the host's half of the pipe
    23  	go func(c net.Conn) {
    24  		defer func() {
    25  			if err := c.Close(); err != nil {
    26  				t.Error(err)
    27  			}
    28  		}()
    29  		// read revision
    30  		encoding.ReadObject(hConn, new(types.FileContractRevision), 1<<22)
    31  		// write acceptance
    32  		modules.WriteNegotiationAcceptance(hConn)
    33  		// read txn signature
    34  		encoding.ReadObject(hConn, new(types.TransactionSignature), 1<<22)
    35  		// write StopResponse
    36  		modules.WriteNegotiationStop(hConn)
    37  		// write txn signature
    38  		encoding.WriteObject(hConn, types.TransactionSignature{})
    39  	}(hConn)
    40  
    41  	// since the host wrote StopResponse, we should proceed to validating the
    42  	// transaction. This will return a known error because we are supplying an
    43  	// empty revision.
    44  	_, err := negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{}, 0)
    45  	if !errors.Contains(err, types.ErrFileContractWindowStartViolation) {
    46  		t.Fatalf("expected %q, got \"%v\"", types.ErrFileContractWindowStartViolation, err)
    47  	}
    48  	rConn.Close()
    49  
    50  	// same as above, but send an error instead of StopResponse. The error
    51  	// should be returned by negotiateRevision immediately (if it is not, we
    52  	// should expect to see a transaction validation error instead).
    53  	rConn, hConn = net.Pipe()
    54  	go func(c net.Conn) {
    55  		defer func() {
    56  			if err := c.Close(); err != nil {
    57  				t.Error(err)
    58  			}
    59  		}()
    60  		encoding.ReadObject(hConn, new(types.FileContractRevision), 1<<22)
    61  		modules.WriteNegotiationAcceptance(hConn)
    62  		encoding.ReadObject(hConn, new(types.TransactionSignature), 1<<22)
    63  		// write a sentinel error
    64  		modules.WriteNegotiationRejection(hConn, errors.New("sentinel"))
    65  		encoding.WriteObject(hConn, types.TransactionSignature{})
    66  	}(hConn)
    67  	expectedErr := "host did not accept transaction signature: sentinel"
    68  	_, err = negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{}, 0)
    69  	if err == nil || err.Error() != expectedErr {
    70  		t.Fatalf("expected %q, got \"%v\"", expectedErr, err)
    71  	}
    72  	rConn.Close()
    73  }
    74  
    75  // TestNewRevisionFundChecks checks that underflow errors1
    76  func TestNewRevisionFundChecks(t *testing.T) {
    77  	// helper func for revisions
    78  	revWithValues := func(renterFunds, hostCollateralAvailable uint64) types.FileContractRevision {
    79  		validOuts := make([]types.SiacoinOutput, 2)
    80  		missedOuts := make([]types.SiacoinOutput, 3)
    81  
    82  		// funds remaining for renter, and payout to host.
    83  		validOuts[0].Value = types.NewCurrency64(renterFunds)
    84  		validOuts[1].Value = types.NewCurrency64(0)
    85  
    86  		// Void payout from renter
    87  		missedOuts[0].Value = types.NewCurrency64(renterFunds)
    88  
    89  		// Collateral
    90  		missedOuts[1].Value = types.NewCurrency64(hostCollateralAvailable)
    91  
    92  		return types.FileContractRevision{
    93  			NewValidProofOutputs:  validOuts,
    94  			NewMissedProofOutputs: missedOuts,
    95  		}
    96  	}
    97  
    98  	// Cost is less than renter funds should be okay.
    99  	_, err := newDownloadRevision(revWithValues(100, 0), types.NewCurrency64(99))
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	// Cost equal to renter funds should be okay.
   104  	_, err = newDownloadRevision(revWithValues(100, 0), types.NewCurrency64(100))
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	// Cost is more than renter funds should fail.
   109  	_, err = newDownloadRevision(revWithValues(100, 0), types.NewCurrency64(101))
   110  	if !errors.Contains(err, types.ErrRevisionCostTooHigh) {
   111  		t.Fatal(err)
   112  	}
   113  
   114  	// Collateral checks (in each, renter funds <= cost)
   115  	//
   116  	// Cost less than collateral should be okay.
   117  	_, err = newUploadRevision(revWithValues(100, 100), crypto.Hash{}, types.NewCurrency64(99), types.NewCurrency64(99))
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  	// Using up all collateral should be okay.
   122  	_, err = newUploadRevision(revWithValues(100, 100), crypto.Hash{}, types.NewCurrency64(99), types.NewCurrency64(100))
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	// Not enough collateral should cause an error.
   127  	_, err = newUploadRevision(revWithValues(100, 100), crypto.Hash{}, types.NewCurrency64(99), types.NewCurrency64(100))
   128  	if errors.Contains(err, types.ErrRevisionCollateralTooLow) {
   129  		t.Fatal(err)
   130  	}
   131  }