diff --git a/internal/application/services/relaysChecker.go b/internal/application/services/relaysChecker.go index b09c8af..b945ebb 100644 --- a/internal/application/services/relaysChecker.go +++ b/internal/application/services/relaysChecker.go @@ -3,6 +3,7 @@ package services import ( "context" "fmt" + "strings" "sync" "time" @@ -91,10 +92,14 @@ func (rcs *RelayCronService) monitorRelays(ctx context.Context) error { return nil } +func normalizeRelayURI(uri string) string { + return strings.TrimRight(uri, "/") +} + func (rcs *RelayCronService) analyzeRelays(allowedRelays []domain.RelayAllowed, usedRelays []string) ([]string, int) { allowedMap := make(map[string]domain.RelayAllowed) for _, relay := range allowedRelays { - allowedMap[relay.Uri] = relay + allowedMap[normalizeRelayURI(relay.Uri)] = relay } var blacklistedRelays []string @@ -102,7 +107,8 @@ func (rcs *RelayCronService) analyzeRelays(allowedRelays []domain.RelayAllowed, // Check for blacklisted relays for _, used := range usedRelays { - if _, exists := allowedMap[used]; !exists { + normalizedUsed := normalizeRelayURI(used) + if _, exists := allowedMap[normalizedUsed]; !exists { blacklistedRelays = append(blacklistedRelays, used) } } @@ -110,8 +116,9 @@ func (rcs *RelayCronService) analyzeRelays(allowedRelays []domain.RelayAllowed, // Check for mandatory relays in use for _, allowed := range allowedRelays { if allowed.IsMandatory { + normalizedAllowed := normalizeRelayURI(allowed.Uri) for _, used := range usedRelays { - if allowed.Uri == used { + if normalizedAllowed == normalizeRelayURI(used) { mandatoryRelaysUsed++ break } diff --git a/internal/application/services/relaysChecker_test.go b/internal/application/services/relaysChecker_test.go new file mode 100644 index 0000000..e903475 --- /dev/null +++ b/internal/application/services/relaysChecker_test.go @@ -0,0 +1,74 @@ +package services + +import ( + "testing" + + "lido-events/internal/application/domain" +) + +func TestNormalizeRelayURI(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"http://relay.example.com/", "http://relay.example.com"}, + {"http://relay.example.com", "http://relay.example.com"}, + {"http://relay.example.com////", "http://relay.example.com"}, + {"https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com/", "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com"}, + } + + for _, tt := range tests { + result := normalizeRelayURI(tt.input) + if result != tt.expected { + t.Errorf("normalizeRelayURI(%q) = %q; want %q", tt.input, result, tt.expected) + } + } +} + +func TestAnalyzeRelays(t *testing.T) { + rcs := &RelayCronService{} + + allowedRelays := []domain.RelayAllowed{ + {Uri: "https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net", IsMandatory: true, Operator: "Agnostic", Description: "Agnostic Relay"}, + {Uri: "https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com", IsMandatory: true, Operator: "bloXroute", Description: "bloXroute Regulated Relay"}, + {Uri: "https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live", IsMandatory: true, Operator: "Aestus", Description: "Aestus Relay"}, + {Uri: "https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com", IsMandatory: true, Operator: "bloXroute", Description: "bloXroute Max-Profit Relay"}, + {Uri: "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net", IsMandatory: true, Operator: "Flashbots", Description: "Flashbots Relay"}, + {Uri: "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money", IsMandatory: true, Operator: "Ultra Sound", Description: "Ultra Sound Relay"}, + {Uri: "https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@regional.titanrelay.xyz", IsMandatory: false, Operator: "Gattaca", Description: "Titan Relay Regional (filtering)"}, + {Uri: "https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@global.titanrelay.xyz", IsMandatory: false, Operator: "Gattaca", Description: "Titan Relay Global (non-filtering)"}, + {Uri: "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com/", IsMandatory: true, Operator: "Manifold Finance", Description: "Manifold SecureRPC Relay"}, + {Uri: "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay-filtered.ultrasound.money", IsMandatory: true, Operator: "Ultra Sound", Description: "Ultra Sound Relay - filtering"}, + } + + usedRelays := []string{ + "https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@global.titanrelay.xyz", + "https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@regional.titanrelay.xyz", + "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com", + "http://blacklisted.com/", + } + + blacklisted, mandatoryUsed := rcs.analyzeRelays(allowedRelays, usedRelays) + + if len(blacklisted) != 1 || blacklisted[0] != "http://blacklisted.com/" { + t.Errorf("Expected 1 blacklisted relay, got %v", blacklisted) + } + + if mandatoryUsed != 1 { + t.Errorf("Expected 1 mandatory relay used, got %d", mandatoryUsed) + } + + // Test with no mandatory relays used + usedRelaysNone := []string{"https://0x8c4ed5e24fe5c6ae21018437bde147693f68cda427cd1122cf20819c30eda7ed74f72dece09bb313f2a1855595ab677d@regional.titanrelay.xyz"} + _, mandatoryUsedNone := rcs.analyzeRelays(allowedRelays, usedRelaysNone) + if mandatoryUsedNone != 0 { + t.Errorf("Expected 0 mandatory relays used, got %d", mandatoryUsedNone) + } + + // Test with all mandatory relays used + usedRelaysAll := []string{"https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com", "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com"} + _, mandatoryUsedAll := rcs.analyzeRelays(allowedRelays, usedRelaysAll) + if mandatoryUsedAll != 2 { + t.Errorf("Expected 2 mandatory relays used, got %d", mandatoryUsedAll) + } +}