gitlab.com/jokerrs1/Sia@v1.3.2/node/api/ecosystem_test.go (about)

     1  package api
     2  
     3  // ecosystem_test.go provides tests for whole-ecosystem testing, consisting of
     4  // multiple full, non-state-sharing nodes connected in various arrangements and
     5  // performing various full-ecosystem tasks.
     6  //
     7  // To the absolute greatest extent possible, nodes are queried and updated
     8  // exclusively through the API.
     9  
    10  import (
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/NebulousLabs/Sia/build"
    15  	"github.com/NebulousLabs/Sia/types"
    16  )
    17  
    18  // TestHostPoorConnectivity creates several full server testers and links them
    19  // together in a way that might mimic a full host ecosystem with a renter, and
    20  // then isolates one of the hosts from the network, denying the host proper
    21  // transaction propagation. The renters performed chained contract forming and
    22  // uploading in the same manner that might happen in the wild, and then the
    23  // host must get a file contract to the blockchain despite not getting any of
    24  // the dependencies into the transaction pool from the flood network.
    25  func TestHostPoorConnectivity(t *testing.T) {
    26  	if testing.Short() || !build.VLONG {
    27  		t.SkipNow()
    28  	}
    29  	t.Parallel()
    30  
    31  	// Create the various nodes that will be forming the simulated ecosystem of
    32  	// this test.
    33  	stLeader, err := createServerTester(t.Name())
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	defer stLeader.panicClose()
    38  	stHost1, err := blankServerTester(t.Name() + " - Host 1")
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	defer stHost1.panicClose()
    43  	stHost2, err := blankServerTester(t.Name() + " - Host 2")
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  	defer stHost2.panicClose()
    48  	stHost3, err := blankServerTester(t.Name() + " - Host 3")
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	defer stHost3.panicClose()
    53  	stHost4, err := blankServerTester(t.Name() + " - Host 4")
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	defer stHost4.panicClose()
    58  	stRenter1, err := blankServerTester(t.Name() + " - Renter 1")
    59  	if err != nil {
    60  		t.Fatal(err)
    61  	}
    62  	defer stRenter1.panicClose()
    63  	stRenter2, err := blankServerTester(t.Name() + " - Renter 2")
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	defer stRenter2.panicClose()
    68  
    69  	// Fetch all of the addresses of the nodes that got created.
    70  	var ggSTL, ggSTH1, ggSTH2, ggSTH3, ggSTH4, ggSTR1, ggSTR2 GatewayGET
    71  	err = stLeader.getAPI("/gateway", &ggSTL)
    72  	if err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	err = stHost1.getAPI("/gateway", &ggSTH1)
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	err = stHost2.getAPI("/gateway", &ggSTH2)
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	err = stHost3.getAPI("/gateway", &ggSTH3)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	err = stHost4.getAPI("/gateway", &ggSTH4)
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	err = stRenter1.getAPI("/gateway", &ggSTR1)
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  	err = stRenter2.getAPI("/gateway", &ggSTR2)
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  
   100  	// Connect all of the peers in a circle, so that everyone is connected but
   101  	// there are a lot of hops.
   102  	err = stLeader.stdPostAPI("/gateway/connect/"+string(ggSTH1.NetAddress), nil)
   103  	if err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	err = stHost1.stdPostAPI("/gateway/connect/"+string(ggSTH2.NetAddress), nil)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	err = stHost2.stdPostAPI("/gateway/connect/"+string(ggSTH3.NetAddress), nil)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  	err = stHost3.stdPostAPI("/gateway/connect/"+string(ggSTH4.NetAddress), nil)
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	err = stHost4.stdPostAPI("/gateway/connect/"+string(ggSTR1.NetAddress), nil)
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	err = stRenter1.stdPostAPI("/gateway/connect/"+string(ggSTR2.NetAddress), nil)
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	err = stRenter2.stdPostAPI("/gateway/connect/"+string(ggSTL.NetAddress), nil)
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  
   131  	// Connectivity check - all nodes should be synchronized to the leader's
   132  	// chain, which should have been the longest.
   133  	allTesters := []*serverTester{stLeader, stHost1, stHost2, stHost3, stHost4, stRenter1, stRenter2}
   134  	chainTip, err := synchronizationCheck(allTesters)
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  
   139  	// Mine a block from each node, to give the node money in the wallet that
   140  	// is recognized by the shared chain.
   141  	for i := range allTesters {
   142  		// Wait until the current tester has 'chainTip' as its current
   143  		// block, to make sure the network is building a community chain
   144  		// instead of creating orphans.
   145  		var cg ConsensusGET
   146  		success := false
   147  		for j := 0; j < 100; j++ {
   148  			err = allTesters[i].getAPI("/consensus", &cg)
   149  			if err != nil {
   150  				t.Fatal(err)
   151  			}
   152  			if cg.CurrentBlock == chainTip {
   153  				success = true
   154  				break
   155  			}
   156  			time.Sleep(time.Millisecond * 100)
   157  		}
   158  		if !success {
   159  			t.Fatal("nodes do not seem to be synchronizing")
   160  		}
   161  		err := allTesters[i].cs.Flush()
   162  		if err != nil {
   163  			t.Fatal(err)
   164  		}
   165  
   166  		// Mine a block for this node. The next iteration will wait for
   167  		// synchronization before mining the block for the next node.
   168  		block, err := allTesters[i].miner.AddBlock()
   169  		if err != nil {
   170  			t.Fatal(err, i)
   171  		}
   172  		chainTip = block.ID()
   173  	}
   174  
   175  	// Wait until the leader has the most recent block.
   176  	var cg ConsensusGET
   177  	success := false
   178  	for i := 0; i < 100; i++ {
   179  		err = allTesters[0].getAPI("/consensus", &cg)
   180  		if err != nil {
   181  			t.Fatal(err)
   182  		}
   183  		if cg.CurrentBlock == chainTip {
   184  			success = true
   185  			break
   186  		}
   187  		time.Sleep(time.Millisecond * 100)
   188  	}
   189  	if !success {
   190  		t.Fatal("nodes do not seem to be synchronizing")
   191  	}
   192  
   193  	// Make sure that everyone has the most recent block.
   194  	_, err = synchronizationCheck(allTesters)
   195  	if err != nil {
   196  		t.Fatal(err)
   197  	}
   198  
   199  	// Mine blocks from the leader until everyone's miner payouts have matured
   200  	// and become spendable.
   201  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
   202  		_, err := stLeader.miner.AddBlock()
   203  		if err != nil {
   204  			t.Fatal(err)
   205  		}
   206  	}
   207  	_, err = synchronizationCheck(allTesters)
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  }