performance optimization, sexyness upgrade

This commit is contained in:
Barry Deen 2024-09-07 20:14:43 -04:00
parent 55bae27490
commit dd9763e967

208
main.go
View File

@ -28,19 +28,33 @@ type Config struct {
StaticPath string StaticPath string
} }
var archivePool *nostr.SimplePool var pool *nostr.SimplePool
var fetchingPool *nostr.SimplePool
var relays []string var relays []string
var config Config var config Config
var trustNetwork []string var trustNetwork []string
var mu sync.Mutex var mu sync.Mutex
var trustNetworkFilter *blobloom.Filter
var trustNetworkFilterMu sync.Mutex
var seedRelays []string
func main() { func main() {
fmt.Println("starting") green := "\033[32m"
reset := "\033[0m"
art := `
__ __ ___. _____ ___________ __
/ \ / \ ____\_ |__ _____/ ____\ \__ ___/______ __ __ _______/ |_
\ \/\/ // __ \| __ \ / _ \ __\ | | \_ __ \ | \/ ___/\ __\
\ /\ ___/| \_\ \ ( <_> ) | | | | | \/ | /\___ \ | |
\__/\ / \___ >___ / \____/|__| |____| |__| |____//____ > |__|
\/ \/ \/ \/
`
fmt.Println(green + art + reset)
log.Println("🚀 booting up web of trust relay")
relay := khatru.NewRelay() relay := khatru.NewRelay()
ctx := context.Background() ctx := context.Background()
pool = nostr.NewSimplePool(ctx)
config = LoadConfig() config = LoadConfig()
relay.Info.Name = config.RelayName relay.Info.Name = config.RelayName
@ -49,7 +63,7 @@ func main() {
appendPubkey(config.RelayPubkey) appendPubkey(config.RelayPubkey)
db := lmdb.LMDBBackend{ db := lmdb.LMDBBackend{
Path: getEnv("DB_PATH"), Path: config.DBPath,
} }
if err := db.Init(); err != nil { if err := db.Init(); err != nil {
panic(err) panic(err)
@ -57,6 +71,7 @@ func main() {
relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent) relay.StoreEvent = append(relay.StoreEvent, db.SaveEvent)
relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents) relay.QueryEvents = append(relay.QueryEvents, db.QueryEvents)
relay.DeleteEvent = append(relay.DeleteEvent, db.DeleteEvent)
relay.RejectEvent = append(relay.RejectEvent, func(ctx context.Context, event *nostr.Event) (bool, string) { relay.RejectEvent = append(relay.RejectEvent, func(ctx context.Context, event *nostr.Event) (bool, string) {
for _, pk := range trustNetwork { for _, pk := range trustNetwork {
if pk == event.PubKey { if pk == event.PubKey {
@ -67,7 +82,7 @@ func main() {
}) })
mu.Lock() mu.Lock()
relays = []string{ seedRelays = []string{
"wss://nos.lol", "wss://nos.lol",
"wss://nostr.mom", "wss://nostr.mom",
"wss://purplepag.es", "wss://purplepag.es",
@ -113,7 +128,7 @@ func main() {
mux.Handle("/favicon.ico", http.StripPrefix("/", http.FileServer(http.Dir(config.StaticPath)))) mux.Handle("/favicon.ico", http.StripPrefix("/", http.FileServer(http.Dir(config.StaticPath))))
fmt.Println("running on :3334") log.Println("🎉 relay running on port :3334")
err := http.ListenAndServe(":3334", relay) err := http.ListenAndServe(":3334", relay)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -144,10 +159,23 @@ func getEnv(key string) string {
return value return value
} }
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string { func updateTrustNetworkFilter() {
fetchingPool = nostr.NewSimplePool(ctx) trustNetworkFilterMu.Lock()
defer trustNetworkFilterMu.Unlock()
nKeys := uint64(len(trustNetwork))
log.Println("🌐 updating trust network filter with", nKeys, "keys")
trustNetworkFilter = blobloom.NewOptimized(blobloom.Config{
Capacity: nKeys,
FPRate: 1e-4,
})
for _, trustedPubkey := range trustNetwork {
trustNetworkFilter.Add(xxhash.Sum64([]byte(trustedPubkey)))
}
}
func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
// Function to refresh the trust network
runTrustNetworkRefresh := func() { runTrustNetworkRefresh := func() {
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second) timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel() defer cancel()
@ -157,82 +185,76 @@ func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
Kinds: []int{nostr.KindContactList}, Kinds: []int{nostr.KindContactList},
}} }}
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) { log.Println("🔍 fetching owner's follows")
for ev := range pool.SubManyEose(timeoutCtx, seedRelays, filters) {
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) { for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
appendPubkey(contact[1]) appendPubkey(contact[1])
} }
} }
chunks := make([][]string, 0) follows := make([]string, len(trustNetwork))
for i := 0; i < len(trustNetwork); i += 100 { copy(follows, trustNetwork)
end := i + 100
if end > len(trustNetwork) {
end = len(trustNetwork)
}
chunks = append(chunks, trustNetwork[i:end])
}
for _, chunk := range chunks { log.Println("🌐 building web of trust graph")
threeTimeoutCtx, tenCancel := context.WithTimeout(ctx, 10*time.Second) for i := 0; i < len(follows); i += 200 {
defer tenCancel() timeout, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
end := i + 200
if end > len(follows) {
end = len(follows)
}
filters = []nostr.Filter{{ filters = []nostr.Filter{{
Authors: chunk, Authors: follows[i:end],
Kinds: []int{nostr.KindContactList}, Kinds: []int{nostr.KindContactList, nostr.KindRelayListMetadata, nostr.KindProfileMetadata},
}} }}
for ev := range fetchingPool.SubManyEose(threeTimeoutCtx, relays, filters) { for ev := range pool.SubManyEose(timeout, seedRelays, filters) {
for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) { for _, contact := range ev.Event.Tags.GetAll([]string{"p"}) {
if len(contact) > 1 { if len(contact) > 1 {
appendPubkey(contact[1]) appendPubkey(contact[1])
} else {
fmt.Println("Skipping malformed tag: ", contact)
} }
} }
}
}
getTrustNetworkProfileMetadata(relay, ctx) for _, relay := range ev.Event.Tags.GetAll([]string{"r"}) {
appendRelay(relay[1])
}
if ev.Event.Kind == nostr.KindProfileMetadata {
relay.AddEvent(ctx, ev.Event)
}
}
}
log.Println("🫂 network size:", len(trustNetwork))
log.Println("🔗 relays discovered:", len(relays))
} }
runTrustNetworkRefresh() runTrustNetworkRefresh()
updateTrustNetworkFilter()
ticker := time.NewTicker(10 * time.Minute) ticker := time.NewTicker(24 * time.Hour)
defer ticker.Stop() defer ticker.Stop()
for range ticker.C { for range ticker.C {
runTrustNetworkRefresh() runTrustNetworkRefresh()
updateTrustNetworkFilter()
} }
return trustNetwork return trustNetwork
} }
func getTrustNetworkProfileMetadata(relay *khatru.Relay, ctx context.Context) { func appendRelay(relay string) {
chunks := make([][]string, 0) mu.Lock()
for i := 0; i < len(trustNetwork); i += 100 { defer mu.Unlock()
end := i + 100
if end > len(trustNetwork) { for _, r := range relays {
end = len(trustNetwork) if r == relay {
return
} }
chunks = append(chunks, trustNetwork[i:end])
}
for _, chunk := range chunks {
if len(chunk) == 0 {
continue
}
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
filters := []nostr.Filter{{
Authors: chunk,
Kinds: []int{nostr.KindProfileMetadata},
}}
for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) {
relay.AddEvent(ctx, ev.Event)
}
cancel()
} }
relays = append(relays, relay)
} }
func appendPubkey(pubkey string) { func appendPubkey(pubkey string) {
@ -244,52 +266,48 @@ func appendPubkey(pubkey string) {
return return
} }
} }
if len(pubkey) != 64 {
return
}
trustNetwork = append(trustNetwork, pubkey) trustNetwork = append(trustNetwork, pubkey)
} }
func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) { func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
ticker := time.NewTicker(1 * time.Minute) log.Println("⏳ waiting for trust network to be populated")
archivePool = nostr.NewSimplePool(ctx) time.Sleep(1 * time.Minute)
defer ticker.Stop() timeout, cancel := context.WithTimeout(ctx, 24*time.Hour)
defer cancel()
for range ticker.C { filters := []nostr.Filter{{
timeout, cancel := context.WithTimeout(ctx, 50*time.Second) Kinds: []int{
filters := []nostr.Filter{{ nostr.KindArticle,
Kinds: []int{ nostr.KindDeletion,
nostr.KindArticle, nostr.KindContactList,
nostr.KindDeletion, nostr.KindEncryptedDirectMessage,
nostr.KindContactList, nostr.KindMuteList,
nostr.KindEncryptedDirectMessage, nostr.KindReaction,
nostr.KindMuteList, nostr.KindRelayListMetadata,
nostr.KindReaction, nostr.KindRepost,
nostr.KindRelayListMetadata, nostr.KindZapRequest,
nostr.KindRepost, nostr.KindZap,
nostr.KindZapRequest, nostr.KindTextNote,
nostr.KindZap, },
nostr.KindTextNote, }}
},
}}
nKeys := uint64(len(trustNetwork))
fmt.Println("trust network size:", nKeys)
bloomFilter := blobloom.NewOptimized(blobloom.Config{
Capacity: nKeys,
FPRate: 1e-4,
})
for _, trustedPubkey := range trustNetwork {
bloomFilter.Add(xxhash.Sum64([]byte(trustedPubkey)))
}
for ev := range archivePool.SubMany(timeout, relays, filters) {
if bloomFilter.Has(xxhash.Sum64([]byte(ev.Event.PubKey))) {
if len(ev.Event.Tags) > 2000 {
continue
}
relay.AddEvent(ctx, ev.Event)
log.Println("📦 archiving trusted notes...")
var i int64
trustNetworkFilterMu.Lock()
for ev := range pool.SubMany(timeout, seedRelays, filters) {
if trustNetworkFilter.Has(xxhash.Sum64([]byte(ev.Event.PubKey))) {
if len(ev.Event.Tags) > 2000 {
continue
} }
relay.AddEvent(ctx, ev.Event)
i++
} }
cancel()
} }
trustNetworkFilterMu.Unlock()
fmt.Println("📦 archived", i, "trusted notes")
} }