Summary
The public /mnstats mapData country distribution appears to be materially wrong versus the current Chainz masternode/IP dataset, and the displayed percentages can exceed 100% because the backend country map and frontend denominator use different cohorts.
Evidence
At the time of checking on 2026-05-08:
https://sysnode.info/mnstats reports mn_stats.enabled = 1,944, mn_stats.total = 2,243.
- The published
mapData country counts sum to 2,163, not 1,944.
- The top Sysnode country rows are:
IRN: 644 (33.1% when divided by enabled nodes)
DEU: 613
USA: 246
FIN: 220
CYP: 204
- The first 8 Sysnode country percentages add up to about
106%, which confirms the denominator/cohort mismatch.
The backend builds mapData in services/masternodeTracker.js by iterating every masternode_list row and geolocating node.address with the local geoip-country package. It does not filter to status === 'ENABLED', while the frontend CountryList divides each country count by mn_stats.enabled.
Chainz comparison
The current Chainz endpoint used by their page (/explorer/masternodes.data.dws?coin=sys&mn=&fmt.js) reports 2,243 nodes across 2,168 servers and shows Germany / United Kingdom / Poland leading, matching their UI screenshot.
Examples of the same large IP ranges:
151.244.*: Sysnode appears to classify this range into Iran-heavy counts; Chainz classifies 255 nodes mostly as GB (245 GB, 6 IR, 4 US).
31.56.*: Chainz classifies 253 nodes mostly as GB (245 GB, 4 IR, 3 DE, 1 NL).
143.20.*: Chainz classifies 207 nodes mostly as PL (201 PL, 6 GB).
5.180.*: Chainz classifies 204 nodes mostly as PL (193 PL, 11 DE).
31.58.*: Chainz classifies 133 nodes mostly as DE (118 DE, 9 US, 3 NL, 2 IR, 1 PL).
These ranges line up closely with Sysnode’s inflated Iran / USA / Cyprus counts, suggesting the bundled GeoIP database is stale or inaccurate for the current hosting provider allocations.
Impact
The Home and Network pages can display a misleading geographic distribution. In the current data, Iran appears as the leading country on Sysnode (644 nodes / 33.1%), while Chainz shows Iran around 15 nodes / 1%.
This also creates mathematically invalid percentages because mapData is counted over a different cohort than the enabled-node denominator.
Suggested fixes
- Decide what the location chart is meant to represent: enabled sentry nodes only, or all registered masternodes.
- Make the backend
mapData cohort match the denominator exposed to the frontend. If the UI says enabled nodes, only count node.status === 'ENABLED' and expose the map denominator explicitly.
- Replace or refresh the GeoIP source. Options:
- update/switch from the bundled
geoip-country database to a maintained GeoLite2/IP2Location-style dataset with a repeatable update process,
- cache Chainz-style IP info if that is accepted as the comparison source,
- expose
unknown instead of forcing stale country assignments when confidence/source age is poor.
- Add a regression test that verifies
sum(mapData[*].masternodes) <= enabled for an enabled-only map, or that the response exposes and the UI uses the correct map-specific denominator.
Safe reproduction
curl -fsSL https://sysnode.info/mnstats | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{const j=JSON.parse(s); const entries=Object.entries(j.mapData||{}); const mapTotal=entries.reduce((sum,[,v])=>sum+Number(v.masternodes||0),0); const enabled=Number(String(j.stats?.mn_stats?.enabled||0).replace(/,/g,"")); console.log({enabled,mapTotal,top:entries.sort((a,b)=>(b[1].masternodes||0)-(a[1].masternodes||0)).slice(0,8).map(([cc,v])=>[cc,v.masternodes])});})'
curl -fsSL 'https://chainz.cryptoid.info/explorer/masternodes.data.dws?coin=sys&mn=&fmt.js' | node -e 'let s="";process.stdin.on("data",d=>s+=d);process.stdin.on("end",()=>{const rows=JSON.parse(s); const t={}; let nodes=0; for (const r of rows){ const cc=r.cc||"???"; t[cc]??={servers:0,nodes:0}; t[cc].servers++; t[cc].nodes+=Number(r.nb||0); nodes+=Number(r.nb||0);} console.log({servers:rows.length,nodes,top:Object.entries(t).sort((a,b)=>b[1].servers-a[1].servers).slice(0,12)});})'
Summary
The public
/mnstatsmapDatacountry distribution appears to be materially wrong versus the current Chainz masternode/IP dataset, and the displayed percentages can exceed 100% because the backend country map and frontend denominator use different cohorts.Evidence
At the time of checking on 2026-05-08:
https://sysnode.info/mnstatsreportsmn_stats.enabled = 1,944,mn_stats.total = 2,243.mapDatacountry counts sum to2,163, not1,944.IRN: 644(33.1%when divided by enabled nodes)DEU: 613USA: 246FIN: 220CYP: 204106%, which confirms the denominator/cohort mismatch.The backend builds
mapDatainservices/masternodeTracker.jsby iterating everymasternode_listrow and geolocatingnode.addresswith the localgeoip-countrypackage. It does not filter tostatus === 'ENABLED', while the frontendCountryListdivides each country count bymn_stats.enabled.Chainz comparison
The current Chainz endpoint used by their page (
/explorer/masternodes.data.dws?coin=sys&mn=&fmt.js) reports2,243nodes across2,168servers and shows Germany / United Kingdom / Poland leading, matching their UI screenshot.Examples of the same large IP ranges:
151.244.*: Sysnode appears to classify this range into Iran-heavy counts; Chainz classifies 255 nodes mostly asGB(245 GB,6 IR,4 US).31.56.*: Chainz classifies 253 nodes mostly asGB(245 GB,4 IR,3 DE,1 NL).143.20.*: Chainz classifies 207 nodes mostly asPL(201 PL,6 GB).5.180.*: Chainz classifies 204 nodes mostly asPL(193 PL,11 DE).31.58.*: Chainz classifies 133 nodes mostly asDE(118 DE,9 US,3 NL,2 IR,1 PL).These ranges line up closely with Sysnode’s inflated Iran / USA / Cyprus counts, suggesting the bundled GeoIP database is stale or inaccurate for the current hosting provider allocations.
Impact
The Home and Network pages can display a misleading geographic distribution. In the current data, Iran appears as the leading country on Sysnode (
644 nodes / 33.1%), while Chainz shows Iran around15 nodes / 1%.This also creates mathematically invalid percentages because
mapDatais counted over a different cohort than the enabled-node denominator.Suggested fixes
mapDatacohort match the denominator exposed to the frontend. If the UI says enabled nodes, only countnode.status === 'ENABLED'and expose the map denominator explicitly.geoip-countrydatabase to a maintained GeoLite2/IP2Location-style dataset with a repeatable update process,unknowninstead of forcing stale country assignments when confidence/source age is poor.sum(mapData[*].masternodes) <= enabledfor an enabled-only map, or that the response exposes and the UI uses the correct map-specific denominator.Safe reproduction