sdk/hints: sqlite backend and tests.

This commit is contained in:
fiatjaf
2024-09-16 22:23:55 -03:00
parent 4c9ab850a5
commit 2c09338ecb
11 changed files with 380 additions and 34 deletions
@@ -27,13 +27,6 @@ func NewHintDB() *HintDB {
}
func (db *HintDB) Save(pubkey string, relay string, key hints.HintKey, ts nostr.Timestamp) {
now := nostr.Now()
// this is used for calculating what counts as a usable hint
threshold := (now - 60*60*24*180)
if threshold < 0 {
threshold = 0
}
relayIndex := slices.Index(db.RelayBySerial, relay)
if relayIndex == -1 {
relayIndex = len(db.RelayBySerial)
@@ -104,6 +97,9 @@ func (db *HintDB) PrintScores() {
fmt.Println("== relay scores for", pubkey)
for i, re := range rfpk.Entries {
fmt.Printf(" %3d :: %30s (%3d) ::> %12d\n", i, db.RelayBySerial[re.Relay], re.Relay, re.Sum())
// for i, ts := range re.Timestamps {
// fmt.Printf(" %-10d %s\n", ts, hints.HintKey(i).String())
// }
}
}
}
@@ -114,7 +110,7 @@ type RelaysForPubKey struct {
type RelayEntry struct {
Relay int
Timestamps [8]nostr.Timestamp
Timestamps [7]nostr.Timestamp
}
func (re RelayEntry) Sum() int64 {
@@ -125,18 +121,9 @@ func (re RelayEntry) Sum() int64 {
continue
}
hk := hints.HintKey(i)
divisor := int64(now - ts)
if divisor == 0 {
divisor = 1
} else {
divisor = int64(math.Pow(float64(divisor), 1.3))
}
multiplier := hk.BasePoints()
value := multiplier * 10000000000 / divisor
value := float64(hints.HintKey(i).BasePoints()) * 10000000000 / math.Pow(float64(max(now-ts, 1)), 1.3)
// fmt.Println(" ", i, "value:", value)
sum += value
sum += int64(value)
}
return sum
}
-143
View File
@@ -1,143 +0,0 @@
package memory
import (
"testing"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"github.com/stretchr/testify/require"
)
func TestRelayPicking(t *testing.T) {
hdb := NewHintDB()
const key1 = "0000000000000000000000000000000000000000000000000000000000000001"
const key2 = "0000000000000000000000000000000000000000000000000000000000000002"
const key3 = "0000000000000000000000000000000000000000000000000000000000000003"
const key4 = "0000000000000000000000000000000000000000000000000000000000000004"
const relayA = "wss://aaa.com"
const relayB = "wss://bbb.online"
const relayC = "wss://ccc.technology"
hour := nostr.Timestamp((time.Hour).Seconds())
day := hour * 24
// key1: finding out
// add some random parameters things and see what we get
hdb.Save(key1, relayA, hints.LastInTag, nostr.Now()-60*hour)
hdb.Save(key1, relayB, hints.LastInRelayList, nostr.Now()-day*10)
hdb.Save(key1, relayB, hints.LastInNevent, nostr.Now()-day*30)
hdb.Save(key1, relayA, hints.LastInNprofile, nostr.Now()-hour*10)
hdb.PrintScores()
require.Equal(t, []string{relayB, relayA}, hdb.TopN(key1, 3))
hdb.Save(key1, relayA, hints.LastFetchAttempt, nostr.Now()-5*hour)
hdb.Save(key1, relayC, hints.LastInNIP05, nostr.Now()-5*hour)
hdb.PrintScores()
require.Equal(t, []string{relayB, relayC, relayA}, hdb.TopN(key1, 3))
hdb.Save(key1, relayC, hints.LastInTag, nostr.Now()-5*hour)
hdb.Save(key1, relayC, hints.LastFetchAttempt, nostr.Now()-5*hour)
hdb.PrintScores()
require.Equal(t, []string{relayB, relayA, relayC}, hdb.TopN(key1, 3))
hdb.Save(key1, relayA, hints.MostRecentEventFetched, nostr.Now()-day*60)
hdb.PrintScores()
require.Equal(t, []string{relayB, relayA, relayC}, hdb.TopN(key1, 3))
// now let's try a different thing for key2
// key2 has a relay list with A and B
hdb.Save(key2, relayA, hints.LastInRelayList, nostr.Now()-day*25)
hdb.Save(key2, relayB, hints.LastInRelayList, nostr.Now()-day*25)
// but it's old, recently we only see hints for relay C
hdb.Save(key2, relayC, hints.LastInTag, nostr.Now()-5*hour)
hdb.Save(key2, relayC, hints.LastInNIP05, nostr.Now()-5*hour)
hdb.Save(key2, relayC, hints.LastInNevent, nostr.Now()-5*hour)
hdb.Save(key2, relayC, hints.LastInNprofile, nostr.Now()-5*hour)
// at this point we just barely see C coming first
hdb.PrintScores()
require.Equal(t, []string{relayC, relayA, relayB}, hdb.TopN(key2, 3))
// yet a different thing for key3
// it doesn't have relay lists published because it's banned everywhere
// all it has are references to its posts from others
hdb.Save(key3, relayA, hints.LastInTag, nostr.Now()-day*2)
hdb.Save(key3, relayB, hints.LastInNevent, nostr.Now()-day)
hdb.Save(key3, relayB, hints.LastInTag, nostr.Now()-day)
hdb.PrintScores()
require.Equal(t, []string{relayB, relayA}, hdb.TopN(key3, 3))
// we try to fetch events for key3 and we get a very recent one for relay A, an older for relay B
hdb.Save(key3, relayA, hints.LastFetchAttempt, nostr.Now()-5*hour)
hdb.Save(key3, relayA, hints.MostRecentEventFetched, nostr.Now()-day)
hdb.Save(key3, relayB, hints.LastFetchAttempt, nostr.Now()-5*hour)
hdb.Save(key3, relayB, hints.MostRecentEventFetched, nostr.Now()-day*30)
hdb.PrintScores()
require.Equal(t, []string{relayA, relayB}, hdb.TopN(key3, 3))
// for key4 we'll try the alex jones case
// key4 used to publish normally to a bunch of big relays until it got banned
// then it started publishing only to its personal relay
// how long until clients realize that?
banDate := nostr.Now() - day*10
hdb.Save(key4, relayA, hints.LastInRelayList, banDate)
hdb.Save(key4, relayA, hints.LastFetchAttempt, banDate)
hdb.Save(key4, relayA, hints.MostRecentEventFetched, banDate)
hdb.Save(key4, relayA, hints.LastInNprofile, banDate+8*day)
hdb.Save(key4, relayA, hints.LastInNIP05, banDate+5*day)
hdb.Save(key4, relayB, hints.LastInRelayList, banDate)
hdb.Save(key4, relayB, hints.LastFetchAttempt, banDate)
hdb.Save(key4, relayB, hints.MostRecentEventFetched, banDate)
hdb.Save(key4, relayB, hints.LastInNevent, banDate+5*day)
hdb.Save(key4, relayB, hints.LastInNIP05, banDate+8*day)
hdb.Save(key4, relayB, hints.LastInNprofile, banDate+5*day)
hdb.PrintScores()
require.Equal(t, []string{relayA, relayB}, hdb.TopN(key4, 3))
// information about the new relay starts to spread through relay hints in tags only
hdb.Save(key4, relayC, hints.LastInTag, nostr.Now()-5*day)
hdb.Save(key4, relayC, hints.LastInTag, nostr.Now()-5*day)
hdb.Save(key4, relayC, hints.LastInNevent, nostr.Now()-5*day)
hdb.Save(key4, relayC, hints.LastInNIP05, nostr.Now()-5*day)
// as long as we see one tag hint the new relay will already be in our map
hdb.PrintScores()
require.Equal(t, []string{relayA, relayB, relayC}, hdb.TopN(key4, 3))
// client tries to fetch stuff from the old relays, but gets nothing new
hdb.Save(key4, relayA, hints.LastFetchAttempt, nostr.Now()-5*hour)
hdb.Save(key4, relayB, hints.LastFetchAttempt, nostr.Now()-5*hour)
// which is enough for us to transition to the new relay as the toppermost of the uppermost
hdb.PrintScores()
require.Equal(t, []string{relayC, relayA, relayB}, hdb.TopN(key4, 3))
// what if the big relays are attempting to game this algorithm by allowing some of our
// events from time to time while still shadowbanning us?
hdb.Save(key4, relayA, hints.MostRecentEventFetched, nostr.Now()-5*hour)
hdb.Save(key4, relayB, hints.MostRecentEventFetched, nostr.Now()-5*hour)
hdb.PrintScores()
require.Equal(t, []string{relayA, relayB, relayC}, hdb.TopN(key4, 3))
// we'll need overwhelming force from the third relay
// (actually just a relay list with just its name in it will be enough)
hdb.Save(key4, relayC, hints.LastFetchAttempt, nostr.Now()-5*hour)
hdb.Save(key4, relayC, hints.MostRecentEventFetched, nostr.Now()-6*hour)
hdb.Save(key4, relayC, hints.LastInRelayList, nostr.Now()-6*hour)
hdb.PrintScores()
require.Equal(t, []string{relayC, relayA, relayB}, hdb.TopN(key4, 3))
//
//
// things remain the same for key1, key2 and key3
require.Equal(t, []string{relayC, relayA}, hdb.TopN(key2, 2))
require.Equal(t, []string{relayB, relayA, relayC}, hdb.TopN(key1, 3))
require.Equal(t, []string{relayA, relayB}, hdb.TopN(key3, 3))
}