fix contact list bug, mutex race conditions, refresh trust

This commit is contained in:
Barry Deen 2024-09-06 16:26:00 -04:00
parent e2b9fbc323
commit cc54cb5464

85
main.go
View File

@ -22,7 +22,9 @@ type Config struct {
DBPath string DBPath string
} }
var pool *nostr.SimplePool var archivePool *nostr.SimplePool
var fetchingPool *nostr.SimplePool
var relays []string var relays []string
var config Config var config Config
var trustNetwork []string var trustNetwork []string
@ -38,7 +40,7 @@ func main() {
relay.Info.Name = config.RelayName relay.Info.Name = config.RelayName
relay.Info.PubKey = config.RelayPubkey relay.Info.PubKey = config.RelayPubkey
relay.Info.Description = config.RelayDescription relay.Info.Description = config.RelayDescription
trustNetwork = append(trustNetwork, config.RelayPubkey) appendPubkey(config.RelayPubkey)
db := lmdb.LMDBBackend{ db := lmdb.LMDBBackend{
Path: getEnv("DB_PATH"), Path: getEnv("DB_PATH"),
@ -47,13 +49,15 @@ func main() {
panic(err) panic(err)
} }
go refreshTrustNetwork(relay) mu.Lock()
go archiveTrustedNotes(relay) copiedTrustNetwork := make([]string, len(trustNetwork))
copy(copiedTrustNetwork, trustNetwork)
mu.Unlock()
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.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 copiedTrustNetwork {
if pk == event.PubKey { if pk == event.PubKey {
return false, "" return false, ""
} }
@ -61,6 +65,7 @@ func main() {
return true, "you are not in the web of trust" return true, "you are not in the web of trust"
}) })
mu.Lock()
relays = []string{ relays = []string{
"wss://nos.lol", "wss://nos.lol",
"wss://nostr.mom", "wss://nostr.mom",
@ -79,10 +84,11 @@ func main() {
"wss://nostr21.com", "wss://nostr21.com",
"wss://nostrue.com", "wss://nostrue.com",
"wss://relay.siamstr.com", "wss://relay.siamstr.com",
"wss://nostrarchives.com",
} }
mu.Unlock()
pool = nostr.NewSimplePool(ctx) go refreshTrustNetwork(relay, ctx)
go archiveTrustedNotes(relay, ctx)
fmt.Println("running on :3334") fmt.Println("running on :3334")
http.ListenAndServe(":3334", relay) http.ListenAndServe(":3334", relay)
@ -112,11 +118,11 @@ func getEnv(key string) string {
return value return value
} }
func refreshTrustNetwork(relay *khatru.Relay) []string { func refreshTrustNetwork(relay *khatru.Relay, ctx context.Context) []string {
ctx := context.Background() fetchingPool = nostr.NewSimplePool(ctx)
ticker := time.NewTicker(10 * time.Minute)
for range ticker.C {
// Function to refresh the trust network
runTrustNetworkRefresh := func() {
timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second) timeoutCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel() defer cancel()
@ -125,7 +131,7 @@ func refreshTrustNetwork(relay *khatru.Relay) []string {
Kinds: []int{nostr.KindContactList}, Kinds: []int{nostr.KindContactList},
}} }}
for ev := range pool.SubManyEose(timeoutCtx, relays, filters) { for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, 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])
} }
@ -141,7 +147,7 @@ func refreshTrustNetwork(relay *khatru.Relay) []string {
} }
for _, chunk := range chunks { for _, chunk := range chunks {
threeTimeoutCtx, tenCancel := context.WithTimeout(ctx, 3*time.Second) threeTimeoutCtx, tenCancel := context.WithTimeout(ctx, 10*time.Second)
defer tenCancel() defer tenCancel()
filters = []nostr.Filter{{ filters = []nostr.Filter{{
@ -149,7 +155,7 @@ func refreshTrustNetwork(relay *khatru.Relay) []string {
Kinds: []int{nostr.KindContactList}, Kinds: []int{nostr.KindContactList},
}} }}
for ev := range pool.SubManyEose(threeTimeoutCtx, relays, filters) { for ev := range fetchingPool.SubManyEose(threeTimeoutCtx, relays, 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])
@ -161,15 +167,22 @@ func refreshTrustNetwork(relay *khatru.Relay) []string {
} }
fmt.Println("trust network size:", len(trustNetwork)) fmt.Println("trust network size:", len(trustNetwork))
getTrustNetworkProfileMetadata(relay) getTrustNetworkProfileMetadata(relay, ctx)
}
runTrustNetworkRefresh()
ticker := time.NewTicker(10 * time.Minute)
defer ticker.Stop()
for range ticker.C {
runTrustNetworkRefresh()
} }
return trustNetwork return trustNetwork
} }
func getTrustNetworkProfileMetadata(relay *khatru.Relay) { func getTrustNetworkProfileMetadata(relay *khatru.Relay, ctx context.Context) {
ctx := context.Background()
chunks := make([][]string, 0) chunks := make([][]string, 0)
for i := 0; i < len(trustNetwork); i += 100 { for i := 0; i < len(trustNetwork); i += 100 {
end := i + 100 end := i + 100
@ -187,8 +200,8 @@ func getTrustNetworkProfileMetadata(relay *khatru.Relay) {
Kinds: []int{nostr.KindProfileMetadata}, Kinds: []int{nostr.KindProfileMetadata},
}} }}
for ev := range pool.SubManyEose(timeoutCtx, relays, filters) { for ev := range fetchingPool.SubManyEose(timeoutCtx, relays, filters) {
relay.AddEvent(timeoutCtx, ev.Event) relay.AddEvent(ctx, ev.Event)
} }
} }
} }
@ -205,19 +218,20 @@ func appendPubkey(pubkey string) {
trustNetwork = append(trustNetwork, pubkey) trustNetwork = append(trustNetwork, pubkey)
} }
func archiveTrustedNotes(relay *khatru.Relay) { func archiveTrustedNotes(relay *khatru.Relay, ctx context.Context) {
// Create a ticker to restart the function every minute
ticker := time.NewTicker(1 * time.Minute) ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop() defer ticker.Stop()
for range ticker.C { archivePool = nostr.NewSimplePool(ctx)
// Copy the current state of trustNetwork at the start of the function
mu.Lock() // Lock while copying the trustNetwork to avoid partial reads for range ticker.C {
localTrustNetwork := make([]string, len(trustNetwork)) mu.Lock()
copy(localTrustNetwork, trustNetwork) trustNetworkCopy := make([]string, len(trustNetwork))
mu.Unlock() // Unlock immediately after copying copy(trustNetworkCopy, trustNetwork)
mu.Unlock()
ctxTimeout, cancel := context.WithTimeout(ctx, 1*time.Minute)
// Create a new context with timeout for each iteration of the loop
ctx := context.Background()
filters := []nostr.Filter{{ filters := []nostr.Filter{{
Kinds: []int{ Kinds: []int{
nostr.KindArticle, nostr.KindArticle,
@ -234,14 +248,21 @@ func archiveTrustedNotes(relay *khatru.Relay) {
}, },
}} }}
// Use the local copy of trustNetwork in the event loop // Iterate over events from the pool and archive trusted notes
for ev := range pool.SubMany(ctx, relays, filters) { for ev := range archivePool.SubManyEose(ctxTimeout, relays, filters) {
for _, trustedPubkey := range localTrustNetwork { for _, trustedPubkey := range trustNetworkCopy {
if ev.Event.PubKey == trustedPubkey { if ev.Event.PubKey == trustedPubkey {
if ev.Event.Kind == nostr.KindContactList {
if len(ev.Event.Tags.GetAll([]string{"p"})) > 2000 {
fmt.Println("archiveTrustedNotes: skipping contact list with more than 2000 contacts. NoteID: ", ev.Event.ID)
continue
}
}
relay.AddEvent(ctx, ev.Event) relay.AddEvent(ctx, ev.Event)
} }
} }
} }
cancel()
fmt.Println("archiveTrustedNotes: finished one cycle, will restart in 1 minute") fmt.Println("archiveTrustedNotes: finished one cycle, will restart in 1 minute")
} }