gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/hostdb/hostweight_test.go (about)

     1  package hostdb
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"gitlab.com/NebulousLabs/fastrand"
     8  
     9  	"gitlab.com/SiaPrime/SiaPrime/build"
    10  	"gitlab.com/SiaPrime/SiaPrime/modules"
    11  	"gitlab.com/SiaPrime/SiaPrime/types"
    12  )
    13  
    14  var (
    15  	// Set the default test allowance
    16  	DefaultTestAllowance = modules.Allowance{
    17  		Funds:       types.SiacoinPrecision.Mul64(1e5),
    18  		Hosts:       uint64(50),
    19  		Period:      types.BlockHeight(12096),
    20  		RenewWindow: types.BlockHeight(4032),
    21  
    22  		ExpectedStorage:    1e12,                                 // 1 TB
    23  		ExpectedUpload:     uint64(200e9) / types.BlocksPerMonth, // 200 GB per month
    24  		ExpectedDownload:   uint64(100e9) / types.BlocksPerMonth, // 100 GB per month
    25  		ExpectedRedundancy: 3.0,                                  // default is 10/30 erasure coding
    26  	}
    27  
    28  	// The default entry to use when performing scoring.
    29  	DefaultHostDBEntry = modules.HostDBEntry{
    30  		HostExternalSettings: modules.HostExternalSettings{
    31  			AcceptingContracts: true,
    32  			MaxDuration:        26e3,
    33  			RemainingStorage:   250e9,
    34  			WindowSize:         144,
    35  
    36  			Collateral:    types.NewCurrency64(1e5).Mul(types.SiacoinPrecision).Div(modules.BlockBytesPerMonthTerabyte),
    37  			MaxCollateral: types.NewCurrency64(5e3).Mul(types.SiacoinPrecision),
    38  
    39  			ContractPrice: types.NewCurrency64(5).Mul(types.SiacoinPrecision),
    40  			StoragePrice:  types.NewCurrency64(5e4).Mul(types.SiacoinPrecision).Div(modules.BlockBytesPerMonthTerabyte),
    41  
    42  			Version: build.Version,
    43  		},
    44  	}
    45  )
    46  
    47  // calculateWeightFromUInt64Price will fill out a host entry with a bunch of
    48  // defaults, and then grab the weight of that host using a set price.
    49  func calculateWeightFromUInt64Price(price, collateral uint64) (weight types.Currency) {
    50  	hdb := bareHostDB()
    51  	hdb.SetAllowance(DefaultTestAllowance)
    52  	hdb.blockHeight = 0
    53  
    54  	entry := DefaultHostDBEntry
    55  	entry.StoragePrice = types.NewCurrency64(price).Mul(types.SiacoinPrecision).Div(modules.BlockBytesPerMonthTerabyte)
    56  	entry.Collateral = types.NewCurrency64(collateral).Mul(types.SiacoinPrecision).Div(modules.BlockBytesPerMonthTerabyte)
    57  
    58  	return hdb.weightFunc(entry).Score()
    59  }
    60  
    61  // TestHostWeightDistinctPrices ensures that the host weight is different if the
    62  // prices are different, and that a higher price has a lower score.
    63  func TestHostWeightDistinctPrices(t *testing.T) {
    64  	if testing.Short() {
    65  		t.SkipNow()
    66  	}
    67  	weight1 := calculateWeightFromUInt64Price(50000, 1e5)
    68  	weight2 := calculateWeightFromUInt64Price(50100, 1e5)
    69  	if weight1.Cmp(weight2) <= 0 {
    70  		t.Log(weight1)
    71  		t.Log(weight2)
    72  		t.Error("Weight of expensive host is not the correct value.")
    73  	}
    74  }
    75  
    76  // TestHostWeightDistinctCollateral ensures that the host weight is different if
    77  // the collaterals are different, and that a higher collateral has a higher
    78  // score.
    79  func TestHostWeightDistinctCollateral(t *testing.T) {
    80  	if testing.Short() {
    81  		t.SkipNow()
    82  	}
    83  	weight1 := calculateWeightFromUInt64Price(300, 100)
    84  	weight2 := calculateWeightFromUInt64Price(300, 99)
    85  	if weight1.Cmp(weight2) <= 0 {
    86  		t.Log(weight1)
    87  		t.Log(weight2)
    88  		t.Error("Weight of expensive host is not the correct value.")
    89  	}
    90  }
    91  
    92  // When the collateral is below the cutoff, the collateral should be more
    93  // important than the price.
    94  func TestHostWeightCollateralBelowCutoff(t *testing.T) {
    95  	if testing.Short() {
    96  		t.SkipNow()
    97  	}
    98  	weight1 := calculateWeightFromUInt64Price(300, 10)
    99  	weight2 := calculateWeightFromUInt64Price(150, 5)
   100  	if weight1.Cmp(weight2) <= 0 {
   101  		t.Log(weight1)
   102  		t.Log(weight2)
   103  		t.Error("Weight of expensive host is not the correct value.")
   104  	}
   105  }
   106  
   107  // When the collateral is below the cutoff, the price should be more important
   108  // than the collateral.
   109  func TestHostWeightCollateralAboveCutoff(t *testing.T) {
   110  	if testing.Short() {
   111  		t.SkipNow()
   112  	}
   113  	weight1 := calculateWeightFromUInt64Price(30000, 100000)
   114  	weight2 := calculateWeightFromUInt64Price(15000, 50000)
   115  	if weight1.Cmp(weight2) >= 0 {
   116  		t.Log(weight1)
   117  		t.Log(weight2)
   118  		t.Error("Weight of expensive host is not the correct value.")
   119  	}
   120  }
   121  
   122  // TestHostWeightIdenticalPrices checks that the weight function is
   123  // deterministic for two hosts that have identical settings - each should get
   124  // the same score.
   125  func TestHostWeightIdenticalPrices(t *testing.T) {
   126  	if testing.Short() {
   127  		t.SkipNow()
   128  	}
   129  	weight1 := calculateWeightFromUInt64Price(42, 100)
   130  	weight2 := calculateWeightFromUInt64Price(42, 100)
   131  	if weight1.Cmp(weight2) != 0 {
   132  		t.Error("Weight of identically priced hosts should be equal.")
   133  	}
   134  }
   135  
   136  // TestHostWeightWithOnePricedZero checks that nothing unexpected happens when
   137  // there is a zero price, and also checks that the zero priced host scores
   138  // higher  than the host that charges money.
   139  func TestHostWeightWithOnePricedZero(t *testing.T) {
   140  	if testing.Short() {
   141  		t.SkipNow()
   142  	}
   143  	weight1 := calculateWeightFromUInt64Price(5, 10)
   144  	weight2 := calculateWeightFromUInt64Price(0, 10)
   145  	if weight1.Cmp(weight2) >= 0 {
   146  		t.Log(weight1)
   147  		t.Log(weight2)
   148  		t.Error("Zero-priced host should have higher weight than nonzero-priced host.")
   149  	}
   150  }
   151  
   152  // TestHostWeightBothPricesZero checks that there is nondeterminism in the
   153  // weight function even with zero value prices.
   154  func TestHostWeightWithBothPricesZero(t *testing.T) {
   155  	if testing.Short() {
   156  		t.SkipNow()
   157  	}
   158  	weight1 := calculateWeightFromUInt64Price(0, 100)
   159  	weight2 := calculateWeightFromUInt64Price(0, 100)
   160  	if weight1.Cmp(weight2) != 0 {
   161  		t.Error("Weight of two zero-priced hosts should be equal.")
   162  	}
   163  }
   164  
   165  // TestHostWeightWithNoCollateral checks that nothing bad (like a panic) happens
   166  // when the collateral is set to zero.
   167  func TestHostWeightWithNoCollateral(t *testing.T) {
   168  	if testing.Short() {
   169  		t.SkipNow()
   170  	}
   171  	weight1 := calculateWeightFromUInt64Price(300, 1)
   172  	weight2 := calculateWeightFromUInt64Price(300, 0)
   173  	if weight1.Cmp(weight2) <= 0 {
   174  		t.Log(weight1)
   175  		t.Log(weight2)
   176  		t.Error("Weight of lower priced host should be higher")
   177  	}
   178  }
   179  
   180  // TestHostWeightMaxDuration checks that the host with an unacceptable duration
   181  // has a lower score.
   182  func TestHostWeightMaxDuration(t *testing.T) {
   183  	if testing.Short() {
   184  		t.SkipNow()
   185  	}
   186  	hdb := bareHostDB()
   187  	hdb.SetAllowance(DefaultTestAllowance)
   188  
   189  	entry := DefaultHostDBEntry
   190  	entry2 := DefaultHostDBEntry
   191  	entry2.MaxDuration = 100 // Shorter than the allowance period.
   192  
   193  	w1 := hdb.weightFunc(entry).Score()
   194  	w2 := hdb.weightFunc(entry2).Score()
   195  	if w1.Cmp(w2) <= 0 {
   196  		t.Error("Acceptable duration should have more weight", w1, w2)
   197  	}
   198  }
   199  
   200  // TestHostWeightStorageRemainingDifferences checks that the host with more
   201  // collateral has more weight.
   202  func TestHostWeightCollateralDifferences(t *testing.T) {
   203  	if testing.Short() {
   204  		t.SkipNow()
   205  	}
   206  	hdb := bareHostDB()
   207  	hdb.SetAllowance(DefaultTestAllowance)
   208  
   209  	entry := DefaultHostDBEntry
   210  	entry2 := DefaultHostDBEntry
   211  	entry2.Collateral = types.NewCurrency64(500).Mul(types.SiacoinPrecision)
   212  
   213  	w1 := hdb.weightFunc(entry).Score()
   214  	w2 := hdb.weightFunc(entry2).Score()
   215  	if w1.Cmp(w2) <= 0 {
   216  		t.Error("Larger collateral should have more weight")
   217  	}
   218  }
   219  
   220  // TestHostWeightStorageRemainingDifferences checks that hosts with less storage
   221  // remaining have a lower weight.
   222  func TestHostWeightStorageRemainingDifferences(t *testing.T) {
   223  	if testing.Short() {
   224  		t.SkipNow()
   225  	}
   226  	hdb := bareHostDB()
   227  
   228  	// Create two entries with different host keys.
   229  	entry := DefaultHostDBEntry
   230  	entry.PublicKey.Key = fastrand.Bytes(16)
   231  	entry2 := DefaultHostDBEntry
   232  	entry2.PublicKey.Key = fastrand.Bytes(16)
   233  
   234  	// The first entry has more storage remaining than the second.
   235  	entry.RemainingStorage = modules.DefaultAllowance.ExpectedStorage // 1e12
   236  	entry2.RemainingStorage = 1e3
   237  
   238  	// The entry with more storage should have the higher score.
   239  	w1 := hdb.weightFunc(entry).Score()
   240  	w2 := hdb.weightFunc(entry2).Score()
   241  	if w1.Cmp(w2) <= 0 {
   242  		t.Log(w1)
   243  		t.Log(w2)
   244  		t.Error("Larger storage remaining should have more weight")
   245  	}
   246  
   247  	// Change both entries to have the same remaining storage but add contractInfo
   248  	// to the HostDB to make it think that we already uploaded some data to one of
   249  	// the entries. This entry should have the higher score.
   250  	entry.RemainingStorage = 1e3
   251  	entry2.RemainingStorage = 1e3
   252  	hdb.knownContracts[entry.PublicKey.String()] = contractInfo{
   253  		HostPublicKey: entry.PublicKey,
   254  		StoredData:    hdb.allowance.ExpectedStorage,
   255  	}
   256  	w1 = hdb.weightFunc(entry).Score()
   257  	w2 = hdb.weightFunc(entry2).Score()
   258  	if w1.Cmp(w2) <= 0 {
   259  		t.Log(w1)
   260  		t.Log(w2)
   261  		t.Error("Entry with uploaded data should have higher score")
   262  	}
   263  }
   264  
   265  // TestHostWeightVersionDifferences checks that a host with an out of date
   266  // version has a lower score than a host with a more recent version.
   267  func TestHostWeightVersionDifferences(t *testing.T) {
   268  	if testing.Short() {
   269  		t.SkipNow()
   270  	}
   271  	hdb := bareHostDB()
   272  
   273  	entry := DefaultHostDBEntry
   274  	entry2 := DefaultHostDBEntry
   275  	entry2.Version = "v1.3.2"
   276  	w1 := hdb.weightFunc(entry)
   277  	w2 := hdb.weightFunc(entry2)
   278  
   279  	if w1.Score().Cmp(w2.Score()) <= 0 {
   280  		t.Log(w1)
   281  		t.Log(w2)
   282  		t.Error("Higher version should have more weight")
   283  	}
   284  }
   285  
   286  // TestHostWeightLifetimeDifferences checks that a host that has been on the
   287  // chain for more time has a higher weight than a host that is newer.
   288  func TestHostWeightLifetimeDifferences(t *testing.T) {
   289  	if testing.Short() {
   290  		t.SkipNow()
   291  	}
   292  	hdb := bareHostDB()
   293  	hdb.blockHeight = 10000
   294  
   295  	entry := DefaultHostDBEntry
   296  	entry2 := DefaultHostDBEntry
   297  	entry2.FirstSeen = 8100
   298  	w1 := hdb.weightFunc(entry).Score()
   299  	w2 := hdb.weightFunc(entry2).Score()
   300  
   301  	if w1.Cmp(w2) <= 0 {
   302  		t.Log(w1)
   303  		t.Log(w2)
   304  		t.Error("Been around longer should have more weight")
   305  	}
   306  }
   307  
   308  // TestHostWeightUptimeDifferences checks that hosts with poorer uptimes have
   309  // lower weights.
   310  func TestHostWeightUptimeDifferences(t *testing.T) {
   311  	if testing.Short() {
   312  		t.SkipNow()
   313  	}
   314  	hdb := bareHostDB()
   315  	hdb.blockHeight = 10000
   316  
   317  	entry := DefaultHostDBEntry
   318  	entry.ScanHistory = modules.HostDBScans{
   319  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   320  		{Timestamp: time.Now().Add(time.Hour * -80), Success: true},
   321  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   322  		{Timestamp: time.Now().Add(time.Hour * -40), Success: true},
   323  		{Timestamp: time.Now().Add(time.Hour * -20), Success: true},
   324  	}
   325  
   326  	entry2 := entry
   327  	entry2.ScanHistory = modules.HostDBScans{
   328  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   329  		{Timestamp: time.Now().Add(time.Hour * -80), Success: true},
   330  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   331  		{Timestamp: time.Now().Add(time.Hour * -40), Success: true},
   332  		{Timestamp: time.Now().Add(time.Hour * -20), Success: false},
   333  	}
   334  	w1 := hdb.weightFunc(entry).Score()
   335  	w2 := hdb.weightFunc(entry2).Score()
   336  
   337  	if w1.Cmp(w2) <= 0 {
   338  		t.Log(w1)
   339  		t.Log(w2)
   340  		t.Error("A host with recorded downtime should have a lower score")
   341  	}
   342  }
   343  
   344  // TestHostWeightUptimeDifferences2 checks that hosts with poorer uptimes have
   345  // lower weights.
   346  func TestHostWeightUptimeDifferences2(t *testing.T) {
   347  	t.Skip("Hostdb is not currently doing exponentiation on uptime")
   348  	if testing.Short() {
   349  		t.SkipNow()
   350  	}
   351  	hdb := bareHostDB()
   352  	hdb.blockHeight = 10000
   353  
   354  	entry := DefaultHostDBEntry
   355  	entry.ScanHistory = modules.HostDBScans{
   356  		{Timestamp: time.Now().Add(time.Hour * -200), Success: true},
   357  		{Timestamp: time.Now().Add(time.Hour * -180), Success: true},
   358  		{Timestamp: time.Now().Add(time.Hour * -160), Success: true},
   359  		{Timestamp: time.Now().Add(time.Hour * -140), Success: true},
   360  		{Timestamp: time.Now().Add(time.Hour * -120), Success: true},
   361  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   362  		{Timestamp: time.Now().Add(time.Hour * -80), Success: false},
   363  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   364  		{Timestamp: time.Now().Add(time.Hour * -40), Success: true},
   365  		{Timestamp: time.Now().Add(time.Hour * -20), Success: true},
   366  	}
   367  
   368  	entry2 := entry
   369  	entry2.ScanHistory = modules.HostDBScans{
   370  		{Timestamp: time.Now().Add(time.Hour * -200), Success: true},
   371  		{Timestamp: time.Now().Add(time.Hour * -180), Success: true},
   372  		{Timestamp: time.Now().Add(time.Hour * -160), Success: true},
   373  		{Timestamp: time.Now().Add(time.Hour * -140), Success: true},
   374  		{Timestamp: time.Now().Add(time.Hour * -120), Success: true},
   375  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   376  		{Timestamp: time.Now().Add(time.Hour * -80), Success: true},
   377  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   378  		{Timestamp: time.Now().Add(time.Hour * -40), Success: false},
   379  		{Timestamp: time.Now().Add(time.Hour * -20), Success: true},
   380  	}
   381  	w1 := hdb.weightFunc(entry).Score()
   382  	w2 := hdb.weightFunc(entry2).Score()
   383  
   384  	if w1.Cmp(w2) <= 0 {
   385  		t.Log(w1)
   386  		t.Log(w2)
   387  		t.Errorf("Downtime that's further in the past should be penalized less")
   388  	}
   389  }
   390  
   391  // TestHostWeightUptimeDifferences3 checks that hosts with poorer uptimes have
   392  // lower weights.
   393  func TestHostWeightUptimeDifferences3(t *testing.T) {
   394  	if testing.Short() {
   395  		t.SkipNow()
   396  	}
   397  	hdb := bareHostDB()
   398  	hdb.blockHeight = 10000
   399  
   400  	entry := DefaultHostDBEntry
   401  	entry.ScanHistory = modules.HostDBScans{
   402  		{Timestamp: time.Now().Add(time.Hour * -200), Success: true},
   403  		{Timestamp: time.Now().Add(time.Hour * -180), Success: true},
   404  		{Timestamp: time.Now().Add(time.Hour * -160), Success: true},
   405  		{Timestamp: time.Now().Add(time.Hour * -140), Success: true},
   406  		{Timestamp: time.Now().Add(time.Hour * -120), Success: true},
   407  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   408  		{Timestamp: time.Now().Add(time.Hour * -80), Success: false},
   409  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   410  		{Timestamp: time.Now().Add(time.Hour * -40), Success: true},
   411  		{Timestamp: time.Now().Add(time.Hour * -20), Success: true},
   412  	}
   413  
   414  	entry2 := entry
   415  	entry2.ScanHistory = modules.HostDBScans{
   416  		{Timestamp: time.Now().Add(time.Hour * -200), Success: true},
   417  		{Timestamp: time.Now().Add(time.Hour * -180), Success: true},
   418  		{Timestamp: time.Now().Add(time.Hour * -160), Success: true},
   419  		{Timestamp: time.Now().Add(time.Hour * -140), Success: true},
   420  		{Timestamp: time.Now().Add(time.Hour * -120), Success: true},
   421  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   422  		{Timestamp: time.Now().Add(time.Hour * -80), Success: false},
   423  		{Timestamp: time.Now().Add(time.Hour * -60), Success: false},
   424  		{Timestamp: time.Now().Add(time.Hour * -40), Success: true},
   425  		{Timestamp: time.Now().Add(time.Hour * -20), Success: true},
   426  	}
   427  	w1 := hdb.weightFunc(entry).Score()
   428  	w2 := hdb.weightFunc(entry2).Score()
   429  
   430  	if w1.Cmp(w2) <= 0 {
   431  		t.Log(w1)
   432  		t.Log(w2)
   433  		t.Error("A host with longer downtime should have a lower score")
   434  	}
   435  }
   436  
   437  // TestHostWeightUptimeDifferences4 checks that hosts with poorer uptimes have
   438  // lower weights.
   439  func TestHostWeightUptimeDifferences4(t *testing.T) {
   440  	if testing.Short() {
   441  		t.SkipNow()
   442  	}
   443  	hdb := bareHostDB()
   444  	hdb.blockHeight = 10000
   445  
   446  	entry := DefaultHostDBEntry
   447  	entry.ScanHistory = modules.HostDBScans{
   448  		{Timestamp: time.Now().Add(time.Hour * -200), Success: true},
   449  		{Timestamp: time.Now().Add(time.Hour * -180), Success: true},
   450  		{Timestamp: time.Now().Add(time.Hour * -160), Success: true},
   451  		{Timestamp: time.Now().Add(time.Hour * -140), Success: true},
   452  		{Timestamp: time.Now().Add(time.Hour * -120), Success: true},
   453  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   454  		{Timestamp: time.Now().Add(time.Hour * -80), Success: true},
   455  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   456  		{Timestamp: time.Now().Add(time.Hour * -40), Success: true},
   457  		{Timestamp: time.Now().Add(time.Hour * -20), Success: false},
   458  	}
   459  
   460  	entry2 := entry
   461  	entry2.ScanHistory = modules.HostDBScans{
   462  		{Timestamp: time.Now().Add(time.Hour * -200), Success: true},
   463  		{Timestamp: time.Now().Add(time.Hour * -180), Success: true},
   464  		{Timestamp: time.Now().Add(time.Hour * -160), Success: true},
   465  		{Timestamp: time.Now().Add(time.Hour * -140), Success: true},
   466  		{Timestamp: time.Now().Add(time.Hour * -120), Success: true},
   467  		{Timestamp: time.Now().Add(time.Hour * -100), Success: true},
   468  		{Timestamp: time.Now().Add(time.Hour * -80), Success: true},
   469  		{Timestamp: time.Now().Add(time.Hour * -60), Success: true},
   470  		{Timestamp: time.Now().Add(time.Hour * -40), Success: false},
   471  		{Timestamp: time.Now().Add(time.Hour * -20), Success: false},
   472  	}
   473  	w1 := hdb.weightFunc(entry).Score()
   474  	w2 := hdb.weightFunc(entry2).Score()
   475  
   476  	if w1.Cmp(w2) <= 0 {
   477  		t.Log(w1)
   478  		t.Log(w2)
   479  		t.Error("longer tail downtime should have a lower score")
   480  	}
   481  }
   482  
   483  // TestHostWeightConstants checks a few relationships between the constants in
   484  // the hostdb.
   485  func TestHostWeightConstants(t *testing.T) {
   486  	// Becaues we no longer use a large base weight, we require that the
   487  	// collateral floor be higher than the price floor, and also that the
   488  	// collateralExponentiationSmall be larger than the
   489  	// priceExponentiationSmall. This protects most hosts from going anywhere
   490  	// near a 0 score.
   491  	if collateralFloor < priceFloor {
   492  		t.Error("Collateral floor should be greater than or equal to price floor")
   493  	}
   494  	if collateralExponentiationSmall < priceExponentiationSmall {
   495  		t.Error("small collateral exponentiation should be larger than small price exponentiation")
   496  	}
   497  
   498  	// Try a few hosts and make sure we always end up with a score that is
   499  	// greater than 1 million.
   500  	weight := calculateWeightFromUInt64Price(300, 100)
   501  	if weight.Cmp(types.NewCurrency64(1e9)) < 0 {
   502  		t.Error("weight is not sufficiently high for hosts")
   503  	}
   504  	weight = calculateWeightFromUInt64Price(1000, 1)
   505  	if weight.Cmp(types.NewCurrency64(1e9)) < 0 {
   506  		t.Error("weight is not sufficiently high for hosts")
   507  	}
   508  
   509  	hdb := bareHostDB()
   510  	hdb.SetAllowance(DefaultTestAllowance)
   511  	hdb.blockHeight = 0
   512  
   513  	entry := DefaultHostDBEntry
   514  	weight = hdb.weightFunc(entry).Score()
   515  	if weight.Cmp(types.NewCurrency64(1e9)) < 0 {
   516  		t.Error("weight is not sufficiently high for hosts")
   517  	}
   518  }