oxen-observer/templates/sn.html
Ian Macdonald 3c55bb8106
Add country data to display of service nodes.
To enable:

```
$ sudo apt install python3-geoip2  # or: 'pip install geoip2' for the latest
$ sudo apt install geoipupdate
```

If necessary, sign up for an account with MaxMind:

  https://www.maxmind.com/en/geolite2/signup

Edit `/etc/GeoIP.conf` with the details of your MaxMind account:

```
AccountID 123456
LicenseKey xxxxxxxxxxxxxxxx
EditionIDs GeoLite2-City GeoLite2-ASN
```

Edit `/etc/cron.d/geoipupdate`:

```
 # MaxMind database updates take place on Tuesdays and Fridays.
 #
00 12    * * 2,5   root    test -x /usr/bin/geoipupdate && grep -q '^AccountID .*[^0]\+' /etc/GeoIP.conf && /usr/bin/geoipupdate
```

Edit `./local_config.py`:

```
config.geoip_dir = '/var/lib/GeoIP'
```
2022-06-30 09:48:28 +02:00

11 KiB

{% extends "_basic.html" %} {% block content %} {%-set portions_base = 2**64 - 4 %} {%-set solo_node = sn.contributors|length == 1 and sn.funded %} {%-set decommed = sn.funded and not sn.active %}

Service Node Details

Service Node Public Key: {{sn.service_node_pubkey}}

{%if sn.pubkey_ed25519 %} {%if sn.pubkey_ed25519 != sn.service_node_pubkey%}

Service Node Auxiliary Pubkey: {{sn.pubkey_ed25519}}

{%endif%}

Lokinet Address: {{sn.pubkey_ed25519 | base32z}}.snode

{%endif%}

Operator Address: {{sn.operator_address}}

Country: {{sn.country}}

{%if sn.city %}

City: {{sn.city}}

{%endif%}

Network: {{sn.asn}}

Metadata

Registration height: {{sn.registration_height}} {%if sn.registration_hf_version < hf.version%} (hardfork v{{sn.registration_hf_version}}) {%endif%} {%if sn.funded%} {%if sn.active%} Active since block: {%else%}{# decommissioned #} Decommissioned since block: {%endif%} {%else%} Last contribution block: {%endif%} {{sn.state_height}} Staking requirement: {{sn.staking_requirement | oxen}} {%if not solo_node%} Operator fee: {{(sn.portions_for_operator / portions_base * 100) | round(3) | chop0}}% {%endif%} Total contributed: {%if sn.total_contributed >= sn.staking_requirement%}100% {%else%} {{sn.total_contributed | oxen}} ({{(sn.total_contributed / sn.staking_requirement * 100) | round(2) | chop0}}%) {%endif%} {%if sn.total_reserved != sn.total_contributed%} Total reserved: {{sn.total_reserved | oxen}} {%endif%} {%if decommed %}Remaining{%else%}Allowed{%endif%} downtime: {%if sn.earned_downtime_blocks > 0%} {{ (sn.earned_downtime_blocks * 120) | reltime(in_ago=false) }} ({{sn.earned_downtime_blocks}} blocks) {%if not decommed and sn.earned_downtime_blocks < 60%} (Note: ≥ 60 blocks required) {%endif%} {%else%} None {%endif%} Version: {%if sn.last_uptime_proof == 0%} Not received {%else%} {{sn.service_node_version[0]}}.{{sn.service_node_version[1]}}.{{sn.service_node_version[2]}} {%endif%} Last uptime proof: {%if sn.last_uptime_proof == 0%} Not received {%else%} {{sn.last_uptime_proof | from_timestamp | ago}} ago {%endif%} {%if info.service_node%}{# SN tests are only conducted by SNs #} sn.storage_server_last_reachable%} class="omg warning"{%endif%}>Storage server: {%if sn.storage_server_last_reachable == 0 and sn.storage_server_last_unreachable == 0%} Not yet tested {%elif sn.storage_server_last_reachable >= sn.storage_server_last_unreachable%} Reachable (as of {{sn.storage_server_last_reachable | from_timestamp | ago}} ago {%else%} Not reachable (as of {{sn.storage_server_last_unreachable | from_timestamp | ago}} ago) {%endif%} sn.lokinet_last_reachable%} class="omg warning"{%endif%}>Lokinet: {%if sn.lokinet_last_reachable == 0 and sn.lokinet_last_unreachable == 0%} Not yet tested {%elif sn.lokinet_last_reachable >= sn.lokinet_last_unreachable%} Reachable (as of {{sn.lokinet_last_reachable | from_timestamp | ago}} ago {%else%} Not reachable (as of {{sn.lokinet_last_unreachable | from_timestamp | ago}} ago) {%endif%} {%endif%} {%set pulse_voted = sn.pulse_participation | selectattr("voted") | list | length%} {%set pulse_total = sn.pulse_participation | length%} = 8 and pulse_voted < 4%} class="omg warning"{%endif%}>Pulse votes: {{pulse_voted}} / {{pulse_total}} {%set cp_voted = sn.checkpoint_participation | selectattr("voted") | list | length%} {%set cp_total = sn.checkpoint_participation | length%} = 8 and cp_voted < 4%} class="omg warning"{%endif%}>Checkpoint votes: {{cp_voted}} / {{cp_total}} Swarm ID: {%if sn.swarm_id == 18446744073709551615%}(none){%else%}0x{{'{:016x}'.format(sn.swarm_id)}}{%endif%} {%set next_test = namespace(height=none)%} {%for q in quorums.obligation[-13:]%} {%if next_test.height%}{%break%}{%endif%} {%if q.height + 13 >= info.height%} {%for w in q.quorum.workers%} {%if w == sn.service_node_pubkey%} {%set next_test.height = q.height + 13%} {%break%} {%endif%} {%endfor%} {%endif%} {%endfor%} Next SN test: {%if next_test.height%} Block {{next_test.height}} ({%if next_test.height == info.height%}Now!{%else%}~{{((next_test.height - info.height) * 120) | reltime(in_ago=false)}}{%endif%}) {%else%} Unknown {%endif%}

Service Node Status

{%if sn.active %}

Registered, staked, and active on the network since block {{sn.state_height}}.

{%elif sn.funded%}

Decommissioned: this service node is registered and staked, but is currently decommissioned (since block {{sn.state_height}}) for failing to meet service node requirements. {%if sn.earned_downtime_blocks > 0%} If it does not return to active duty within {{sn.earned_downtime_blocks}} blocks (about {{(sn.earned_downtime_blocks * 120) | reltime(in_ago=false)}}) it will face deregistration. {%else%} The decommission time has expired; service node deregistration is imminent. {%endif%}

{%else%}

Awaiting registration. This service node has {{(sn.staking_requirement - sn.total_contributed) | oxen}} remaining to be contributed. {%if sn.num_open_spots > 0%} The minimum required stake contribution is {{((sn.staking_requirement - sn.total_reserved) / sn.num_open_spots) | oxen}}. {%endif%}

{%endif%}

{%if sn.requested_unlock_height > 0%} This service node is scheduled to expire at block {{sn.requested_unlock_height}}, in approximately {{((sn.requested_unlock_height - info.height + 1) * 120) | reltime(in_ago=false) }} ({{(server.timestamp + (sn.requested_unlock_height - info.height + 1) * 120) | from_timestamp | format_datetime('short')}} UTC, est.) {%else%} This service node is staking infinitely: no unlock has been initiated by any of its contributors. {%endif%}

{{sn.contributors|length}} Contributor{%if sn.contributors|length > 1%}s{%endif%}

{%for c in sn.contributors%} {%endfor%}
Contributor Amount Reserved
{{c.address}} {{c.amount | oxen}} {%-if c.locked_contributions and c.locked_contributions|length > 1%} ({{c.locked_contributions|length}} contributions) {%endif-%} {{c.reserved | oxen}}
{#FIXME:#} {%if pending_stakes and pending_stakes|length > 0%}

{{pending_stakes|length}} pending mempool contribution(s)

{%for s in pending_stakes%} {%endfor%}
Contributor TX Amount
{{s.address}} {{s.txid}} {{s.amount}}
{%endif%} {%if details_html%}
{{details_html | safe}} {%else%}
Show raw details
{%endif%}
{% endblock %}