mirror of
https://github.com/oxen-io/oxen-observer.git
synced 2023-12-14 09:22:54 +01:00
Merge d92abf692b
into 0cafbbaea2
This commit is contained in:
commit
2f98b3a0f7
53
observer.py
53
observer.py
|
@ -194,7 +194,7 @@ def get_sns(sns_future, info_future):
|
||||||
sn_states = sns_future.get()
|
sn_states = sns_future.get()
|
||||||
sn_states = sn_states['service_node_states'] if 'service_node_states' in sn_states else []
|
sn_states = sn_states['service_node_states'] if 'service_node_states' in sn_states else []
|
||||||
for sn in sn_states:
|
for sn in sn_states:
|
||||||
sn['contribution_open'] = sn['staking_requirement'] - sn['total_reserved']
|
sn['contribution_open'] = sn['staking_requirement'] - sn.get('total_reserved', sn['total_contributed'])
|
||||||
sn['contribution_required'] = sn['staking_requirement'] - sn['total_contributed']
|
sn['contribution_required'] = sn['staking_requirement'] - sn['total_contributed']
|
||||||
sn['num_contributions'] = sum(len(x['locked_contributions']) for x in sn['contributors'] if 'locked_contributions' in x)
|
sn['num_contributions'] = sum(len(x['locked_contributions']) for x in sn['contributors'] if 'locked_contributions' in x)
|
||||||
|
|
||||||
|
@ -242,7 +242,13 @@ def parse_mempool(mempool_future):
|
||||||
mp['_sorted'] = True
|
mp['_sorted'] = True
|
||||||
|
|
||||||
for tx in mp['transactions']:
|
for tx in mp['transactions']:
|
||||||
tx['info'] = json.loads(tx["tx_json"])
|
if 'type' not in tx and 'tx_json' in tx:
|
||||||
|
# Legacy code for Oxen 10 and earlier
|
||||||
|
info = json.loads(tx["tx_json"])
|
||||||
|
# FIXME -- do we have parsed extra stuff already?
|
||||||
|
info['tx_extra_raw'] = bytes_to_hex(info['extra'])
|
||||||
|
del info['extra']
|
||||||
|
tx.update(info)
|
||||||
else:
|
else:
|
||||||
mp['transactions'] = []
|
mp['transactions'] = []
|
||||||
return mp
|
return mp
|
||||||
|
@ -327,17 +333,16 @@ def main(refresh=None, page=0, per_page=None, first=None, last=None, style=None)
|
||||||
if 'tx_hashes' in b:
|
if 'tx_hashes' in b:
|
||||||
txids += b['tx_hashes']
|
txids += b['tx_hashes']
|
||||||
if txids:
|
if txids:
|
||||||
txs = parse_txs(tx_req(omq, oxend, txids, cache_key='mempool').get())
|
txs = parse_txs(tx_req(omq, oxend, txids, cache_key='recent').get())
|
||||||
i = 0
|
i = 0
|
||||||
for tx in txs:
|
for tx in txs:
|
||||||
if 'vin' in tx['info'] and len(tx['info']['vin']) == 1 and 'gen' in tx['info']['vin'][0]:
|
if 'vin' in tx and len(tx['vin']) == 1 and 'gen' in tx['vin'][0]:
|
||||||
tx['coinbase'] = True
|
tx['coinbase'] = True
|
||||||
# TXs should come back in the same order so we can just skip ahead one when the block
|
# TXs should come back in the same order so we can just skip ahead one when the block
|
||||||
# height changes rather than needing to search for the block
|
# height changes rather than needing to search for the block
|
||||||
if blocks[i]['height'] != tx['block_height']:
|
if blocks[i]['height'] != tx['block_height']:
|
||||||
i += 1
|
i += 1
|
||||||
while i < len(blocks) and blocks[i]['height'] != tx['block_height']:
|
while i < len(blocks) and blocks[i]['height'] != tx['block_height']:
|
||||||
print("Something getting wrong: missing txes?", file=sys.stderr)
|
|
||||||
i += 1
|
i += 1
|
||||||
if i >= len(blocks):
|
if i >= len(blocks):
|
||||||
print("Something getting wrong: have leftover txes")
|
print("Something getting wrong: have leftover txes")
|
||||||
|
@ -347,12 +352,17 @@ def main(refresh=None, page=0, per_page=None, first=None, last=None, style=None)
|
||||||
# Clean up the SN data a bit to make things easier for the templates
|
# Clean up the SN data a bit to make things easier for the templates
|
||||||
awaiting_sns, active_sns, inactive_sns = get_sns(sns, inforeq)
|
awaiting_sns, active_sns, inactive_sns = get_sns(sns, inforeq)
|
||||||
|
|
||||||
|
accrued = accrued.get()
|
||||||
|
accrued_total = (
|
||||||
|
sum(amt for wallet, amt in accrued['balances'].items()) if 'balances' in accrued else
|
||||||
|
sum(accrued['amounts']))
|
||||||
|
|
||||||
return flask.render_template('index.html',
|
return flask.render_template('index.html',
|
||||||
info=info,
|
info=info,
|
||||||
stake=stake.get(),
|
stake=stake.get(),
|
||||||
fees=base_fee.get(),
|
fees=base_fee.get(),
|
||||||
emission=coinbase.get(),
|
emission=coinbase.get(),
|
||||||
accrued_total=sum(accrued.get()['amounts']),
|
accrued_total=accrued_total,
|
||||||
hf=hfinfo.get(),
|
hf=hfinfo.get(),
|
||||||
active_sns=active_sns,
|
active_sns=active_sns,
|
||||||
active_swarms=len(set(x['swarm_id'] for x in active_sns)),
|
active_swarms=len(set(x['swarm_id'] for x in active_sns)),
|
||||||
|
@ -398,8 +408,9 @@ def tx_req(omq, oxend, txids, cache_key='single', **kwargs):
|
||||||
return FutureJSON(omq, oxend, 'rpc.get_transactions', cache_seconds=10, cache_key=cache_key,
|
return FutureJSON(omq, oxend, 'rpc.get_transactions', cache_seconds=10, cache_key=cache_key,
|
||||||
args={
|
args={
|
||||||
"txs_hashes": txids,
|
"txs_hashes": txids,
|
||||||
"decode_as_json": True,
|
"decode_as_json": True, # Can drop once we no longer need Oxen 10 support
|
||||||
"tx_extra": True,
|
"tx_extra": True,
|
||||||
|
"tx_extra_raw": True,
|
||||||
"prune": True,
|
"prune": True,
|
||||||
"stake_info": True,
|
"stake_info": True,
|
||||||
},
|
},
|
||||||
|
@ -586,9 +597,9 @@ def show_sn(pubkey, more_details=False):
|
||||||
# Number of staked contributions
|
# Number of staked contributions
|
||||||
sn['num_contributions'] = sum(len(x["locked_contributions"]) for x in sn["contributors"] if "locked_contributions" in x)
|
sn['num_contributions'] = sum(len(x["locked_contributions"]) for x in sn["contributors"] if "locked_contributions" in x)
|
||||||
# Number of unfilled, reserved contribution spots:
|
# Number of unfilled, reserved contribution spots:
|
||||||
sn['num_reserved_spots'] = sum(x["amount"] < x["reserved"] for x in sn["contributors"])
|
sn['num_reserved_spots'] = sum('reserved' in x and x["amount"] < x["reserved"] for x in sn["contributors"])
|
||||||
# Available open contribution spots:
|
# Available open contribution spots:
|
||||||
sn['num_open_spots'] = 0 if sn['total_reserved'] >= sn['staking_requirement'] else max(0, 4 - sn['num_contributions'] - sn['num_reserved_spots'])
|
sn['num_open_spots'] = 0 if sn.get('total_reserved', sn['total_contributed']) >= sn['staking_requirement'] else max(0, 4 - sn['num_contributions'] - sn['num_reserved_spots'])
|
||||||
|
|
||||||
if more_details:
|
if more_details:
|
||||||
formatter = HtmlFormatter(cssclass="syntax-highlight", style="paraiso-dark")
|
formatter = HtmlFormatter(cssclass="syntax-highlight", style="paraiso-dark")
|
||||||
|
@ -635,14 +646,18 @@ def parse_txs(txs_rpc):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
for tx in txs_rpc['txs']:
|
for tx in txs_rpc['txs']:
|
||||||
if 'info' not in tx:
|
if 'type' not in tx and 'as_json' in tx:
|
||||||
|
# Pre Oxen 11 crammed the details into "as_json" that we have to parse again
|
||||||
# We have serialized JSON data inside a field in the JSON, because of oxend's
|
# We have serialized JSON data inside a field in the JSON, because of oxend's
|
||||||
# multiple incompatible JSON generators 🤮:
|
# multiple incompatible JSON generators 🤮:
|
||||||
tx['info'] = json.loads(tx["as_json"])
|
info = json.loads(tx["as_json"])
|
||||||
del tx['as_json']
|
del tx['as_json']
|
||||||
# The "extra" field inside as_json is retardedly in per-byte integer values,
|
# The "extra" field inside as_json is retardedly in per-byte integer values,
|
||||||
# convert it to a hex string 🤮:
|
# convert it to a hex string 🤮:
|
||||||
tx['info']['extra'] = bytes_to_hex(tx['info']['extra'])
|
info['tx_extra_raw'] = bytes_to_hex(info['extra'])
|
||||||
|
del info['extra']
|
||||||
|
tx.update(info)
|
||||||
|
|
||||||
return txs_rpc['txs']
|
return txs_rpc['txs']
|
||||||
|
|
||||||
|
|
||||||
|
@ -742,19 +757,19 @@ def show_tx(txid, more_details=False):
|
||||||
|
|
||||||
# If this is a state change, see if we have the quorum stored to provide context
|
# If this is a state change, see if we have the quorum stored to provide context
|
||||||
testing_quorum = None
|
testing_quorum = None
|
||||||
if tx['info']['version'] >= 4 and 'sn_state_change' in tx['extra']:
|
if tx['version'] >= 4 and 'sn_state_change' in tx['extra']:
|
||||||
testing_quorum = FutureJSON(omq, oxend, 'rpc.get_quorum_state', 60, cache_key='tx_state_change',
|
testing_quorum = FutureJSON(omq, oxend, 'rpc.get_quorum_state', 60, cache_key='tx_state_change',
|
||||||
args={ 'quorum_type': 0, 'start_height': tx['extra']['sn_state_change']['height'] })
|
args={ 'quorum_type': 0, 'start_height': tx['extra']['sn_state_change']['height'] })
|
||||||
|
|
||||||
kindex_info = {} # { amount => { keyindex => {output-info} } }
|
kindex_info = {} # { amount => { keyindex => {output-info} } }
|
||||||
block_info_req = None
|
block_info_req = None
|
||||||
if 'vin' in tx['info']:
|
if 'vin' in tx:
|
||||||
if len(tx['info']['vin']) == 1 and 'gen' in tx['info']['vin'][0]:
|
if len(tx['vin']) == 1 and 'gen' in tx['vin'][0]:
|
||||||
tx['coinbase'] = True
|
tx['coinbase'] = True
|
||||||
elif tx['info']['vin'] and config.enable_mixins_details:
|
elif tx['vin'] and config.enable_mixins_details:
|
||||||
# Load output details for all outputs contained in the inputs
|
# Load output details for all outputs contained in the inputs
|
||||||
outs_req = []
|
outs_req = []
|
||||||
for inp in tx['info']['vin']:
|
for inp in tx['vin']:
|
||||||
# Key positions are stored as offsets from the previous index rather than indices,
|
# Key positions are stored as offsets from the previous index rather than indices,
|
||||||
# so de-delta them back into indices:
|
# so de-delta them back into indices:
|
||||||
if 'key_offsets' in inp['key'] and 'key_indices' not in inp['key']:
|
if 'key_offsets' in inp['key'] and 'key_indices' not in inp['key']:
|
||||||
|
@ -766,7 +781,7 @@ def show_tx(txid, more_details=False):
|
||||||
kis.append(kbase)
|
kis.append(kbase)
|
||||||
del inp['key']['key_offsets']
|
del inp['key']['key_offsets']
|
||||||
|
|
||||||
outs_req = [{"amount":inp['key']['amount'], "index":ki} for inp in tx['info']['vin'] for ki in inp['key']['key_indices']]
|
outs_req = [{"amount":inp['key']['amount'], "index":ki} for inp in tx['vin'] for ki in inp['key']['key_indices']]
|
||||||
outputs = FutureJSON(omq, oxend, 'rpc.get_outs', args={
|
outputs = FutureJSON(omq, oxend, 'rpc.get_outs', args={
|
||||||
'get_txid': True,
|
'get_txid': True,
|
||||||
'outputs': outs_req,
|
'outputs': outs_req,
|
||||||
|
@ -778,7 +793,7 @@ def show_tx(txid, more_details=False):
|
||||||
'heights': [o["height"] for o in outputs]
|
'heights': [o["height"] for o in outputs]
|
||||||
})
|
})
|
||||||
i = 0
|
i = 0
|
||||||
for inp in tx['info']['vin']:
|
for inp in tx['vin']:
|
||||||
amount = inp['key']['amount']
|
amount = inp['key']['amount']
|
||||||
if amount not in kindex_info:
|
if amount not in kindex_info:
|
||||||
kindex_info[amount] = {}
|
kindex_info[amount] = {}
|
||||||
|
|
|
@ -50,7 +50,7 @@ Validator bits: {{"{:011b}".format(block.info.pulse.validator_bitset)}}"><label>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
|
||||||
{%set sum_burned = transactions | selectattr('extra.burn_amount') | sum(attribute='extra.burn_amount') %}
|
{%set sum_burned = transactions | selectattr('extra.burn_amount') | sum(attribute='extra.burn_amount') %}
|
||||||
{%set sum_fees = transactions | selectattr('info.rct_signatures') | selectattr('info.rct_signatures.txnFee') | sum(attribute='info.rct_signatures.txnFee') - sum_burned%}
|
{%set sum_fees = transactions | selectattr('rct_signatures') | selectattr('rct_signatures.txnFee') | sum(attribute='rct_signatures.txnFee') - sum_burned%}
|
||||||
|
|
||||||
<span title="{{(block_header.reward - sum_fees) | oxen(fixed=True)}} created in this block.{%if sum_fees > 0%}
|
<span title="{{(block_header.reward - sum_fees) | oxen(fixed=True)}} created in this block.{%if sum_fees > 0%}
|
||||||
|
|
||||||
|
@ -91,9 +91,9 @@ Note that this value does not include earned transaction fees ({{sum_fees | oxen
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="/tx/{{miner_tx.tx_hash}}">{{miner_tx.tx_hash}}</a></td>
|
<td><a href="/tx/{{miner_tx.tx_hash}}">{{miner_tx.tx_hash}}</a></td>
|
||||||
<td>{{miner_tx.info.vout | sum(attribute='amount') | oxen}}</td>
|
<td>{{miner_tx.vout | sum(attribute='amount') | oxen}}</td>
|
||||||
<td>{{miner_tx.size}}</td>
|
<td>{{miner_tx.size}}</td>
|
||||||
<td>{{miner_tx.info.version}}</td>
|
<td>{{miner_tx.version}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
@ -122,7 +122,7 @@ Note that this value does not include earned transaction fees ({{sum_fees | oxen
|
||||||
<td><a href="/tx/{{tx.tx_hash}}">{{tx.tx_hash}}</a></td>
|
<td><a href="/tx/{{tx.tx_hash}}">{{tx.tx_hash}}</a></td>
|
||||||
<td>{{fee.display(tx)}}</td>
|
<td>{{fee.display(tx)}}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>{{tx.info.vin | length}}/{{tx.info.vout | length}}</td>
|
<td>{{tx.vin | length}}/{{tx.vout | length}}</td>
|
||||||
<td>{{tx.size | si}}B</td>
|
<td>{{tx.size | si}}B</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -29,13 +29,13 @@
|
||||||
<td>{{symbol.display(tx)}}</td>
|
<td>{{symbol.display(tx)}}</td>
|
||||||
<td><a href="/tx/{{tx.id_hash}}">{{tx.id_hash}}</a></td>
|
<td><a href="/tx/{{tx.id_hash}}">{{tx.id_hash}}</a></td>
|
||||||
<td>
|
<td>
|
||||||
{%if 'rct_signatures' in tx.info%}
|
{%if 'rct_signatures' in tx%}
|
||||||
{{fee.display(tx)}} / {{(tx.info.rct_signatures.txnFee * 1000 / tx.blob_size) | oxen(tag=false, decimals=4)}}
|
{{fee.display(tx)}} / {{(tx.rct_signatures.txnFee * 1000 / tx.blob_size) | oxen(tag=false, decimals=4)}}
|
||||||
{%else%}
|
{%else%}
|
||||||
N/A
|
N/A
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</td>
|
</td>
|
||||||
<td>{{tx.info.vin | length}}/{{tx.info.vout | length}}</td>
|
<td>{{tx.vin | length}}/{{tx.vout | length}}</td>
|
||||||
<td>{{tx.blob_size | si}}B</td>
|
<td>{{tx.blob_size | si}}B</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
<tr>
|
<tr>
|
||||||
{%include 'include/sn_kcf.html'%}
|
{%include 'include/sn_kcf.html'%}
|
||||||
<td>{{sn.total_contributed | oxen(tag=false, fixed=true)}}</td>
|
<td>{{sn.total_contributed | oxen(tag=false, fixed=true)}}</td>
|
||||||
{%if sn.total_reserved >= sn.staking_requirement%}
|
{% set total_stakes = sn.total_reserved if 'total_reserved' in sn else sn.total_contributed %}
|
||||||
|
{%if total_stakes >= sn.staking_requirement%}
|
||||||
<td title="All remaining contribution room is reserved for specific contributors">
|
<td title="All remaining contribution room is reserved for specific contributors">
|
||||||
⛔ {{sn.contribution_open | oxen(tag=false, fixed=true)}}
|
⛔ {{sn.contribution_open | oxen(tag=false, fixed=true)}}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{% macro display(tx, show_zero=false) -%}
|
{% macro display(tx, show_zero=false) -%}
|
||||||
{% set fee =
|
{% set fee =
|
||||||
(tx.info.rct_signatures.txnFee if 'rct_signatures' in tx.info and 'txnFee' in tx.info.rct_signatures else 0)
|
(tx.rct_signatures.txnFee if 'rct_signatures' in tx and 'txnFee' in tx.rct_signatures else 0)
|
||||||
-%}
|
-%}
|
||||||
{% if fee > 0 or show_zero -%}
|
{% if fee > 0 or show_zero -%}
|
||||||
{{ fee | oxen(tag=False, fixed=True, decimals=4) }}
|
{{ fee | oxen(tag=False, fixed=True, decimals=4) }}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{%- macro display(tx, text=false) -%}
|
{%- macro display(tx, text=false) -%}
|
||||||
{% if tx.info.version >= 4 -%}
|
{% if tx.version >= 4 -%}
|
||||||
{% if tx.info.type == 1 and 'sn_state_change' in tx.extra -%}
|
{% if tx.type == 1 and 'sn_state_change' in tx.extra -%}
|
||||||
{% if tx.extra.sn_state_change.type == 'decom' -%}
|
{% if tx.extra.sn_state_change.type == 'decom' -%}
|
||||||
<span class="icon" title="Service Node decommission">👎{%if text%} decommission{%endif%}</span>
|
<span class="icon" title="Service Node decommission">👎{%if text%} decommission{%endif%}</span>
|
||||||
{% elif tx.extra.sn_state_change.type == 'recom' -%}
|
{% elif tx.extra.sn_state_change.type == 'recom' -%}
|
||||||
|
@ -12,9 +12,9 @@
|
||||||
{% else -%}
|
{% else -%}
|
||||||
<span class="icon" title="Unknown state change transaction">❓{%if text%} unknown state change{%endif%}</span><!-- Either a bug or a malformed transaction -->
|
<span class="icon" title="Unknown state change transaction">❓{%if text%} unknown state change{%endif%}</span><!-- Either a bug or a malformed transaction -->
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
{% elif tx.info.type == 2 -%}
|
{% elif tx.type == 2 -%}
|
||||||
<span class="icon" title="Service Node stake unlock — {{tx.extra.sn_pubkey}}">🔓{%if text%} unlock{%endif%}</span>
|
<span class="icon" title="Service Node stake unlock — {{tx.extra.sn_pubkey}}">🔓{%if text%} unlock{%endif%}</span>
|
||||||
{% elif tx.info.type == 4 and 'ons' in tx.extra -%}
|
{% elif tx.type == 4 and 'ons' in tx.extra -%}
|
||||||
{% if 'buy' in tx.extra.ons -%}
|
{% if 'buy' in tx.extra.ons -%}
|
||||||
<span class="icon" title="Oxen Name Service Buying">🎫{%if text%} LNS purchase{%endif%}</span>
|
<span class="icon" title="Oxen Name Service Buying">🎫{%if text%} LNS purchase{%endif%}</span>
|
||||||
{% elif 'update' in tx.extra.ons -%}
|
{% elif 'update' in tx.extra.ons -%}
|
||||||
|
|
|
@ -177,7 +177,7 @@
|
||||||
<td><a href="/tx/{{b.txs[0].tx_hash}}">{{b.txs[0].tx_hash}}</a></td>
|
<td><a href="/tx/{{b.txs[0].tx_hash}}">{{b.txs[0].tx_hash}}</a></td>
|
||||||
<td>{{fee.display(b.txs[0])}}</td>
|
<td>{{fee.display(b.txs[0])}}</td>
|
||||||
<td>{{b.coinbase_payouts | oxen(tag=False, fixed=True, decimals=2)}}</td>
|
<td>{{b.coinbase_payouts | oxen(tag=False, fixed=True, decimals=2)}}</td>
|
||||||
<td>0/{{b.txs[0].info.vout | length}}</td>
|
<td>0/{{b.txs[0].vout | length}}</td>
|
||||||
<td>{{b.txs[0].size | si}}</td>
|
<td>{{b.txs[0].size | si}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -203,7 +203,7 @@
|
||||||
<td><a href="/tx/{{tx.tx_hash}}">{{tx.tx_hash}}</a></td>
|
<td><a href="/tx/{{tx.tx_hash}}">{{tx.tx_hash}}</a></td>
|
||||||
<td>{{fee.display(tx)}}</td>
|
<td>{{fee.display(tx)}}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>{{tx.info.vin | length}}/{{tx.info.vout | length}}</td>
|
<td>{{tx.vin | length}}/{{tx.vout | length}}</td>
|
||||||
<td>{{tx.size | si}}</td>
|
<td>{{tx.size | si}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -59,8 +59,8 @@
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{%if sn.total_reserved != sn.total_contributed%}
|
{%if 'total_reserved' in sn and sn.total_reserved != sn.total_contributed%}
|
||||||
<span><label>Total reserved:</label> {{sn.total_reserved | oxen}}</span>
|
<span><label>Reserved stakes:</label> {{(sn.total_reserved - sn.total_contributed) | oxen}}</span>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
|
@ -94,35 +94,10 @@
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{%if info.service_node%}{# SN tests are only conducted by SNs #}
|
{%if info.service_node%}{# SN tests are only conducted by SNs #}
|
||||||
<span>
|
{% import 'include/reachable.html' as reachable %}
|
||||||
<label{%if sn.storage_server_last_unreachable > sn.storage_server_last_reachable%} class="omg warning"{%endif%}>Storage server:</label>
|
|
||||||
{%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%}
|
|
||||||
<span title="Last unreachable: {%if sn.storage_server_last_unreachable == 0%}Unknown{%else%}{{sn.storage_server_last_unreachable | from_timestamp | ago}} ago{%endif%}">
|
|
||||||
Reachable (as of {{sn.storage_server_last_reachable | from_timestamp | ago}} ago
|
|
||||||
</span>
|
|
||||||
{%else%}
|
|
||||||
<span title="Last reachable: {%if sn.storage_server_last_reachable == 0%}Unknown{%else%}{{sn.storage_server_last_reachable | from_timestamp | ago}} ago{%endif%}">
|
|
||||||
Not reachable (as of {{sn.storage_server_last_unreachable | from_timestamp | ago}} ago)
|
|
||||||
</span>
|
|
||||||
{%endif%}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span>
|
{{reachable.display(sn)}}
|
||||||
<label{%if sn.lokinet_last_unreachable > sn.lokinet_last_reachable%} class="omg warning"{%endif%}>Lokinet:</label>
|
{{reachable.display(sn, true)}}
|
||||||
{%if sn.lokinet_last_reachable == 0 and sn.lokinet_last_unreachable == 0%}
|
|
||||||
Not yet tested
|
|
||||||
{%elif sn.lokinet_last_reachable >= sn.lokinet_last_unreachable%}
|
|
||||||
<span title="Last unreachable: {%if sn.lokinet_last_unreachable == 0%}Unknown{%else%}{{sn.lokinet_last_unreachable | from_timestamp | ago}} ago{%endif%}">
|
|
||||||
Reachable (as of {{sn.lokinet_last_reachable | from_timestamp | ago}} ago
|
|
||||||
</span>
|
|
||||||
{%else%}
|
|
||||||
<span title="Last reachable: {%if sn.lokinet_last_reachable == 0%}Unknown{%else%}{{sn.lokinet_last_reachable | from_timestamp | ago}} ago{%endif%}">
|
|
||||||
Not reachable (as of {{sn.lokinet_last_unreachable | from_timestamp | ago}} ago)
|
|
||||||
</span>
|
|
||||||
{%endif%}
|
|
||||||
</span>
|
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
|
||||||
{%set pulse_voted = sn.pulse_participation | selectattr("voted") | list | length%}
|
{%set pulse_voted = sn.pulse_participation | selectattr("voted") | list | length%}
|
||||||
|
@ -188,7 +163,8 @@
|
||||||
<p class="sn-awaiting">Awaiting registration. This service node has <span class="oxen required">{{(sn.staking_requirement - sn.total_contributed) | oxen}}</span>
|
<p class="sn-awaiting">Awaiting registration. This service node has <span class="oxen required">{{(sn.staking_requirement - sn.total_contributed) | oxen}}</span>
|
||||||
remaining to be contributed.
|
remaining to be contributed.
|
||||||
{%if sn.num_open_spots > 0%}
|
{%if sn.num_open_spots > 0%}
|
||||||
The minimum required stake contribution is <span class="oxen required">{{((sn.staking_requirement - sn.total_reserved) / sn.num_open_spots) | oxen}}</span>.
|
{%set total_staked = sn.total_reserved if 'total_reserved' in sn else sn.total_contributed%}
|
||||||
|
The minimum required stake contribution is <span class="oxen required">{{((sn.staking_requirement - total_staked) / sn.num_open_spots) | oxen}}</span>.
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</p>
|
</p>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
@ -224,7 +200,7 @@
|
||||||
({{c.locked_contributions|length}} contributions)
|
({{c.locked_contributions|length}} contributions)
|
||||||
{%endif-%}
|
{%endif-%}
|
||||||
</td>
|
</td>
|
||||||
<td>{{c.reserved | oxen}}</td>
|
<td>{{(c.reserved if 'reserved' in c else c.amount) | oxen}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<span title="Unix timestamp: {{tx.received_timestamp}}"><label>In mempool since:</label> {{tx.received_timestamp | from_timestamp | format_datetime('short')}} UTC
|
<span title="Unix timestamp: {{tx.received_timestamp}}"><label>In mempool since:</label> {{tx.received_timestamp | from_timestamp | format_datetime('short')}} UTC
|
||||||
({{tx.received_timestamp | from_timestamp | ago}} ago)</span>
|
({{tx.received_timestamp | from_timestamp | ago}} ago)</span>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
<span><label>TX Version/Type:</label> {{tx.info.version}}/{{sym.display(tx, text=true)}}</span>
|
<span><label>TX Version/Type:</label> {{tx.version}}/{{sym.display(tx, text=true)}}</span>
|
||||||
{%if not have_raw_tx%}
|
{%if not have_raw_tx%}
|
||||||
{%if 'block_timestamp' in tx%}
|
{%if 'block_timestamp' in tx%}
|
||||||
<span title="Unix timestamp: {{tx.block_timestamp}}"><label>Timestamp:</label> {{tx.block_timestamp | from_timestamp | format_datetime('short')}} UTC
|
<span title="Unix timestamp: {{tx.block_timestamp}}"><label>Timestamp:</label> {{tx.block_timestamp | from_timestamp | format_datetime('short')}} UTC
|
||||||
|
@ -56,17 +56,17 @@
|
||||||
|
|
||||||
{# FIXME - if in mempool then link to mempool page instead #}
|
{# FIXME - if in mempool then link to mempool page instead #}
|
||||||
<span><label>Fee (Per kB):</label>
|
<span><label>Fee (Per kB):</label>
|
||||||
{%if tx.coinbase or 'rct_signatures' not in tx.info%}
|
{%if tx.coinbase or 'rct_signatures' not in tx%}
|
||||||
N/A
|
N/A
|
||||||
{%else%}
|
{%else%}
|
||||||
{{fee.display(tx)}}
|
{{fee.display(tx)}}
|
||||||
({{(tx.info.rct_signatures.txnFee * 1000 / tx.size) | oxen(tag=false, decimals=6)}})
|
({{(tx.rct_signatures.txnFee * 1000 / tx.size) | oxen(tag=false, decimals=6)}})
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</span>
|
</span>
|
||||||
<span title="{{tx.size}} bytes"><label>TX Size:</label> {{tx.size|si}}B</span>
|
<span title="{{tx.size}} bytes"><label>TX Size:</label> {{tx.size|si}}B</span>
|
||||||
|
|
||||||
<span><label>No. Confirmations:</label> {%if 'block_height' in tx%}{{info.height - tx.block_height}}{%else%}None (in mempool){%endif%}</span>
|
<span><label>No. Confirmations:</label> {%if 'block_height' in tx%}{{info.height - tx.block_height}}{%else%}None (in mempool){%endif%}</span>
|
||||||
<span><label>RingCT/RingCT Type:</label> {%if tx.info.version >= 2 and 'rct_signatures' in tx.info and not tx.coinbase%}Yes/{{tx.info.rct_signatures.type}}{%else%}No{%endif%}</span>
|
<span><label>RingCT/RingCT Type:</label> {%if tx.version >= 2 and 'rct_signatures' in tx and not tx.coinbase%}Yes/{{tx.rct_signatures.type}}{%else%}No{%endif%}</span>
|
||||||
|
|
||||||
{%if tx.coinbase and tx.extra.sn_winner%}
|
{%if tx.coinbase and tx.extra.sn_winner%}
|
||||||
<span><label>Service Node Winner:</label>
|
<span><label>Service Node Winner:</label>
|
||||||
|
@ -78,10 +78,10 @@
|
||||||
</span>
|
</span>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="info-item"><label>Extra: </label>{{tx.info.extra}}</div>
|
<div class="info-item"><label>Extra: </label>{{tx.tx_extra_raw}}</div>
|
||||||
|
|
||||||
{% if tx.info.version >= 4 -%}
|
{% if tx.version >= 4 -%}
|
||||||
{% if tx.info.type == 1 and 'sn_state_change' in tx.extra %}
|
{% if tx.type == 1 and 'sn_state_change' in tx.extra %}
|
||||||
<h2>
|
<h2>
|
||||||
{%- set show_reasons = false -%}
|
{%- set show_reasons = false -%}
|
||||||
{% if tx.extra.sn_state_change.type == 'decom' -%}
|
{% if tx.extra.sn_state_change.type == 'decom' -%}
|
||||||
|
@ -159,12 +159,12 @@ This tx does not includes a vote from this testing service node (only 7 votes ar
|
||||||
</div>
|
</div>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
|
|
||||||
{% elif tx.info.type == 2 %}
|
{% elif tx.type == 2 %}
|
||||||
<h2>🔓 Service Node Unlock</h2>
|
<h2>🔓 Service Node Unlock</h2>
|
||||||
<p class="unlock-pubkey"><label>Service Node Public Key:</label> <a href="/sn/{{tx.extra.sn_pubkey}}">{{tx.extra.sn_pubkey}}</a></p>
|
<p class="unlock-pubkey"><label>Service Node Public Key:</label> <a href="/sn/{{tx.extra.sn_pubkey}}">{{tx.extra.sn_pubkey}}</a></p>
|
||||||
<p><label>Unlock key image:</label> {{unlock_key_image}}</p> {# FIXME #}
|
<p><label>Unlock key image:</label> {{unlock_key_image}}</p> {# FIXME #}
|
||||||
<p><label>Unlock signature:</label> {{unlock_signature}}</p> {# FIXME #}
|
<p><label>Unlock signature:</label> {{unlock_signature}}</p> {# FIXME #}
|
||||||
{% elif tx.info.type == 4 and 'lns' in tx.extra %}
|
{% elif tx.type == 4 and 'lns' in tx.extra %}
|
||||||
{% if 'buy' in tx.extra.lns %}
|
{% if 'buy' in tx.extra.lns %}
|
||||||
<h2>🎫 Oxen Name Service Registration</h2>
|
<h2>🎫 Oxen Name Service Registration</h2>
|
||||||
{% elif 'update' in tx.extra.lns %}
|
{% elif 'update' in tx.extra.lns %}
|
||||||
|
@ -216,10 +216,10 @@ This tx does not includes a vote from this testing service node (only 7 votes ar
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{%if tx.info.vout%}
|
{%if tx.vout%}
|
||||||
<h2>Outputs</h2>
|
<h2>Outputs</h2>
|
||||||
<h4 class="Subtitle">{{tx.info.vout|length}} output(s) for total of
|
<h4 class="Subtitle">{{tx.vout|length}} output(s) for total of
|
||||||
{{tx.info.vout | sum(attribute='amount') | oxen(zero='<span title="Regular LOKI tx amounts are private">???</span>') | safe}}</h4>
|
{{tx.vout | sum(attribute='amount') | oxen(zero='<span title="Regular OXEN tx amounts are private">???</span>') | safe}}</h4>
|
||||||
<div class="TitleDivider"></div>
|
<div class="TitleDivider"></div>
|
||||||
<div class="tx-outputs">
|
<div class="tx-outputs">
|
||||||
<table class="Table">
|
<table class="Table">
|
||||||
|
@ -232,7 +232,7 @@ This tx does not includes a vote from this testing service node (only 7 votes ar
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{%for out in tx.info.vout%}
|
{%for out in tx.vout%}
|
||||||
<tr>
|
<tr>
|
||||||
<td><label>{{loop.index0}}:</label> {{out.target.key}}</td>
|
<td><label>{{loop.index0}}:</label> {{out.target.key}}</td>
|
||||||
<td>{{out.amount | oxen(zero='?')}}</td>
|
<td>{{out.amount | oxen(zero='?')}}</td>
|
||||||
|
@ -549,12 +549,12 @@ This tx does not includes a vote from this testing service node (only 7 votes ar
|
||||||
{%endif%}
|
{%endif%}
|
||||||
#}
|
#}
|
||||||
|
|
||||||
{%if not tx.coinbase and tx.info.vin|length > 0 %}
|
{%if not tx.coinbase and tx.vin|length > 0 %}
|
||||||
<div style="height: 1em"></div>
|
<div style="height: 1em"></div>
|
||||||
|
|
||||||
<h2>Inputs</h2>
|
<h2>Inputs</h2>
|
||||||
<h4 class="Subtitle">{{tx.info.vin|length}} input(s) for total of
|
<h4 class="Subtitle">{{tx.vin|length}} input(s) for total of
|
||||||
{{tx.info.vin | sum(attribute='key.amount') | oxen(zero='<span title="Regular LOKI tx amounts are private">???</span>') | safe}}</h4>
|
{{tx.vin | sum(attribute='key.amount') | oxen(zero='<span title="Regular OXEN tx amounts are private">???</span>') | safe}}</h4>
|
||||||
<div class="TitleDivider"></div>
|
<div class="TitleDivider"></div>
|
||||||
|
|
||||||
{#FIXME#}
|
{#FIXME#}
|
||||||
|
@ -574,7 +574,7 @@ This tx does not includes a vote from this testing service node (only 7 votes ar
|
||||||
|
|
||||||
<div class="tx-inputs">
|
<div class="tx-inputs">
|
||||||
<table class="Table">
|
<table class="Table">
|
||||||
{%for inp in tx.info.vin if 'key' in inp%}
|
{%for inp in tx.vin if 'key' in inp%}
|
||||||
<tr class="tx-input-key-image">
|
<tr class="tx-input-key-image">
|
||||||
<td style="text-align: left;" colspan="2">
|
<td style="text-align: left;" colspan="2">
|
||||||
<label>Key Image {{loop.index0}}:</label> {{inp.key.k_image}}
|
<label>Key Image {{loop.index0}}:</label> {{inp.key.k_image}}
|
||||||
|
|
Loading…
Reference in a new issue