Commit a318c47d authored by David Vorick's avatar David Vorick

re-work hostdb reliability code

Switched the code to a float from uint64 so that precision could remain strong
even when the values are tiny. This means we can apply decay even when the
values are tiny.

Test updated to reflect the clamps and newer decay methods and strengths.
parent c066fc4d
......@@ -98,10 +98,10 @@ type HostDBEntry struct {
HistoricUptime time.Duration `json:"historicuptime"`
ScanHistory HostDBScans `json:"scanhistory"`
HistoricFailedInteractions uint64 `json:"historicfailedinteractions"`
HistoricSuccessfulInteractions uint64 `json:"historicsuccessfulinteractions"`
RecentFailedInteractions uint64 `json:"recentfailedinteractions"`
RecentSuccessfulInteractions uint64 `json:"recentsuccessfulinteractions"`
HistoricFailedInteractions float64 `json:"historicfailedinteractions"`
HistoricSuccessfulInteractions float64 `json:"historicsuccessfulinteractions"`
RecentFailedInteractions float64 `json:"recentfailedinteractions"`
RecentSuccessfulInteractions float64 `json:"recentsuccessfulinteractions"`
LastHistoricUpdate types.BlockHeight
......
......@@ -229,7 +229,14 @@ func (hdb *HostDB) Close() error {
// Host returns the HostSettings associated with the specified NetAddress. If
// no matching host is found, Host returns false.
func (hdb *HostDB) Host(spk types.SiaPublicKey) (modules.HostDBEntry, bool) {
return hdb.hostTree.Select(spk)
host, exists := hdb.hostTree.Select(spk)
if !exists {
return host, exists
}
hdb.mu.RLock()
updateHostHistoricInteractions(&host, hdb.blockHeight)
hdb.mu.RUnlock()
return host, exists
}
// RandomHosts implements the HostDB interface's RandomHosts() method. It takes
......
......@@ -435,8 +435,8 @@ func TestUpdateHistoricInteractions(t *testing.T) {
}
// increment successful and failed interactions by 100
interactions := uint64(100)
for i := uint64(0); i < interactions; i++ {
interactions := 100.0
for i := 0.0; i < interactions; i++ {
hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey)
hdbt.hdb.IncrementFailedInteractions(host.PublicKey)
}
......@@ -458,10 +458,13 @@ func TestUpdateHistoricInteractions(t *testing.T) {
}
// add single block to consensus
hdbt.miner.AddBlock()
_, err = hdbt.miner.AddBlock()
if err != nil {
t.Fatal(err)
}
// increment interactions again by 100
for i := uint64(0); i < interactions; i++ {
for i := 0.0; i < interactions; i++ {
hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey)
hdbt.hdb.IncrementFailedInteractions(host.PublicKey)
}
......@@ -472,24 +475,34 @@ func TestUpdateHistoricInteractions(t *testing.T) {
t.Fatal("Modified host not found in hostdb")
}
// check that recent interactions are exactly 100 again and historic interactions are also exactly 100
// historic actions should have incremented slightly, due to the clamp the
// full interactions should not have made it into the historic group.
if host.RecentFailedInteractions != interactions || host.RecentSuccessfulInteractions != interactions {
t.Errorf("Interactions should be %v but were %v and %v", interactions,
host.RecentFailedInteractions, host.RecentSuccessfulInteractions)
}
if host.HistoricFailedInteractions != interactions || host.HistoricSuccessfulInteractions != interactions {
t.Errorf("Historic Interactions should be %v but were %v and %v", interactions,
host.HistoricFailedInteractions, host.HistoricSuccessfulInteractions)
if host.HistoricFailedInteractions == 0 || host.HistoricSuccessfulInteractions == 0 {
t.Error("historic actions should have updated")
}
// add 10 blocks to consensus
for i := 0; i < 10; i++ {
hdbt.miner.AddBlock()
// add 200 blocks to consensus, adding large numbers of historic actions
// each time, so that the clamp does not need to be in effect anymore.
for i := 0; i < 200; i++ {
for j := uint64(0); j < 10; j++ {
hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey)
hdbt.hdb.IncrementFailedInteractions(host.PublicKey)
}
_, err = hdbt.miner.AddBlock()
if err != nil {
t.Fatal(err)
}
}
// add a single interaction
hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey)
hdbt.hdb.IncrementFailedInteractions(host.PublicKey)
// Add five interactions
for i := 0; i < 5; i++ {
hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey)
hdbt.hdb.IncrementFailedInteractions(host.PublicKey)
}
// get updated host from hostdb
host, ok = hdbt.hdb.Host(host.PublicKey)
......@@ -497,14 +510,49 @@ func TestUpdateHistoricInteractions(t *testing.T) {
t.Fatal("Modified host not found in hostdb")
}
// check that recent interactions are exactly 1 and historic interactions are (100*0.997 + 100)*0.997^9
if host.RecentFailedInteractions != 1 || host.RecentSuccessfulInteractions != 1 {
// check that recent interactions are exactly 5. Save the historic actions
// to check that decay is being handled correctly, and that the recent
// interactions are moved over correctly.
if host.RecentFailedInteractions != 5 || host.RecentSuccessfulInteractions != 5 {
t.Errorf("Interactions should be %v but were %v and %v", interactions,
host.RecentFailedInteractions, host.RecentSuccessfulInteractions)
}
historicFailed := host.HistoricFailedInteractions
if host.HistoricFailedInteractions != host.HistoricSuccessfulInteractions {
t.Error("historic failed and successful should have the same values")
}
// Those two lines need to be split because
expected := uint64((100.0*historicInteractionDecay + 100.0) * math.Pow(historicInteractionDecay, 9))
// Add a single block to apply one round of decay.
_, err = hdbt.miner.AddBlock()
if err != nil {
t.Fatal(err)
}
host, ok = hdbt.hdb.Host(host.PublicKey)
if !ok {
t.Fatal("Modified host not found in hostdb")
}
// Get the historic successful and failed interactions, and see that they
// are decaying properly.
expected := historicFailed*math.Pow(historicInteractionDecay, 1) + 5
if host.HistoricFailedInteractions != expected || host.HistoricSuccessfulInteractions != expected {
t.Errorf("Historic Interactions should be %v but were %v and %v", expected,
host.HistoricFailedInteractions, host.HistoricSuccessfulInteractions)
}
// Add 10 more blocks and check the decay again, make sure it's being
// applied correctly.
for i := 0; i < 10; i++ {
_, err := hdbt.miner.AddBlock()
if err != nil {
t.Fatal(err)
}
}
host, ok = hdbt.hdb.Host(host.PublicKey)
if !ok {
t.Fatal("Modified host not found in hostdb")
}
expected = expected * math.Pow(historicInteractionDecay, 10)
if host.HistoricFailedInteractions != expected || host.HistoricSuccessfulInteractions != expected {
t.Errorf("Historic Interactions should be %v but were %v and %v", expected,
host.HistoricFailedInteractions, host.HistoricSuccessfulInteractions)
......
......@@ -24,16 +24,13 @@ func updateHostHistoricInteractions(host *modules.HostDBEntry, bh types.BlockHei
passedTime := bh - host.LastHistoricUpdate
// tmp float64 values for more accurate decay
hsi := float64(host.HistoricSuccessfulInteractions)
hfi := float64(host.HistoricFailedInteractions)
hsi := host.HistoricSuccessfulInteractions
hfi := host.HistoricFailedInteractions
// Apply the decay of a single block, but only if there are more than
// historicInteractionDecalyLimit datapoints total.
if hsi+hfi > historicInteractionDecayLimit {
decay := historicInteractionDecay
hsi *= decay
hfi *= decay
}
// Apply the decay of a single block.
decay := historicInteractionDecay
hsi *= decay
hfi *= decay
// Apply the recent interactions of that single block. Recent interactions
// cannot represent more than recentInteractionWeightLimit of historic
......@@ -66,8 +63,8 @@ func updateHostHistoricInteractions(host *modules.HostDBEntry, bh types.BlockHei
}
// Set new values
host.HistoricSuccessfulInteractions = uint64(hsi)
host.HistoricFailedInteractions = uint64(hfi)
host.HistoricSuccessfulInteractions = hsi
host.HistoricFailedInteractions = hfi
host.RecentSuccessfulInteractions = 0
host.RecentFailedInteractions = 0
......
......@@ -340,7 +340,7 @@ func rentercontractsviewcmd(cid string) {
if err != nil {
die("Could not fetch details of host: ", err)
}
fmt.Printf(`
fmt.Printf(`
Contract %v
Host: %v (Public Key: %v)
......@@ -365,7 +365,7 @@ Contract %v
currencyUnits(rc.RenterFunds),
filesizeUnits(int64(rc.Size)))
printScoreBreakdown(&hostInfo)
printScoreBreakdown(&hostInfo)
return
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment