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
9 changed files with 75 additions and 83 deletions
53
observer.py
53
observer.py
|
@ -194,7 +194,7 @@ def get_sns(sns_future, info_future):
|
|||
sn_states = sns_future.get()
|
||||
sn_states = sn_states['service_node_states'] if 'service_node_states' in sn_states else []
|
||||
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['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
|
||||
|
||||
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:
|
||||
mp['transactions'] = []
|
||||
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:
|
||||
txids += b['tx_hashes']
|
||||
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
|
||||
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
|
||||
# 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
|
||||
if blocks[i]['height'] != tx['block_height']:
|
||||
i += 1
|
||||
while i < len(blocks) and blocks[i]['height'] != tx['block_height']:
|
||||
print("Something getting wrong: missing txes?", file=sys.stderr)
|
||||
i += 1
|
||||
if i >= len(blocks):
|
||||
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
|
||||
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',
|
||||
info=info,
|
||||
stake=stake.get(),
|
||||
fees=base_fee.get(),
|
||||
emission=coinbase.get(),
|
||||
accrued_total=sum(accrued.get()['amounts']),
|
||||
accrued_total=accrued_total,
|
||||
hf=hfinfo.get(),
|
||||
active_sns=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,
|
||||
args={
|
||||
"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_raw": True,
|
||||
"prune": True,
|
||||
"stake_info": True,
|
||||
},
|
||||
|
@ -586,9 +597,9 @@ def show_sn(pubkey, more_details=False):
|
|||
# Number of staked contributions
|
||||
sn['num_contributions'] = sum(len(x["locked_contributions"]) for x in sn["contributors"] if "locked_contributions" in x)
|
||||
# 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:
|
||||
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:
|
||||
formatter = HtmlFormatter(cssclass="syntax-highlight", style="paraiso-dark")
|
||||
|
@ -635,14 +646,18 @@ def parse_txs(txs_rpc):
|
|||
return []
|
||||
|
||||
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
|
||||
# multiple incompatible JSON generators 🤮:
|
||||
tx['info'] = json.loads(tx["as_json"])
|
||||
info = json.loads(tx["as_json"])
|
||||
del tx['as_json']
|
||||
# The "extra" field inside as_json is retardedly in per-byte integer values,
|
||||
# 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']
|
||||
|
||||
|
||||
|
@ -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
|
||||
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',
|
||||
args={ 'quorum_type': 0, 'start_height': tx['extra']['sn_state_change']['height'] })
|
||||
|
||||
kindex_info = {} # { amount => { keyindex => {output-info} } }
|
||||
block_info_req = None
|
||||
if 'vin' in tx['info']:
|
||||
if len(tx['info']['vin']) == 1 and 'gen' in tx['info']['vin'][0]:
|
||||
if 'vin' in tx:
|
||||
if len(tx['vin']) == 1 and 'gen' in tx['vin'][0]:
|
||||
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
|
||||
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,
|
||||
# so de-delta them back into indices:
|
||||
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)
|
||||
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={
|
||||
'get_txid': True,
|
||||
'outputs': outs_req,
|
||||
|
@ -778,7 +793,7 @@ def show_tx(txid, more_details=False):
|
|||
'heights': [o["height"] for o in outputs]
|
||||
})
|
||||
i = 0
|
||||
for inp in tx['info']['vin']:
|
||||
for inp in tx['vin']:
|
||||
amount = inp['key']['amount']
|
||||
if amount not in kindex_info:
|
||||
kindex_info[amount] = {}
|
||||
|
|
|
@ -50,7 +50,7 @@ Validator bits: {{"{:011b}".format(block.info.pulse.validator_bitset)}}"><label>
|
|||
{%endif%}
|
||||
|
||||
{%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%}
|
||||
|
||||
|
@ -91,9 +91,9 @@ Note that this value does not include earned transaction fees ({{sum_fees | oxen
|
|||
</tr>
|
||||
<tr>
|
||||
<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.info.version}}</td>
|
||||
<td>{{miner_tx.version}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
{%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>{{fee.display(tx)}}</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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -29,13 +29,13 @@
|
|||
<td>{{symbol.display(tx)}}</td>
|
||||
<td><a href="/tx/{{tx.id_hash}}">{{tx.id_hash}}</a></td>
|
||||
<td>
|
||||
{%if 'rct_signatures' in tx.info%}
|
||||
{{fee.display(tx)}} / {{(tx.info.rct_signatures.txnFee * 1000 / tx.blob_size) | oxen(tag=false, decimals=4)}}
|
||||
{%if 'rct_signatures' in tx%}
|
||||
{{fee.display(tx)}} / {{(tx.rct_signatures.txnFee * 1000 / tx.blob_size) | oxen(tag=false, decimals=4)}}
|
||||
{%else%}
|
||||
N/A
|
||||
{%endif%}
|
||||
</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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
<tr>
|
||||
{%include 'include/sn_kcf.html'%}
|
||||
<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">
|
||||
⛔ {{sn.contribution_open | oxen(tag=false, fixed=true)}}
|
||||
</td>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% macro display(tx, show_zero=false) -%}
|
||||
{% 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 -%}
|
||||
{{ fee | oxen(tag=False, fixed=True, decimals=4) }}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{%- macro display(tx, text=false) -%}
|
||||
{% if tx.info.version >= 4 -%}
|
||||
{% if tx.info.type == 1 and 'sn_state_change' in tx.extra -%}
|
||||
{% if tx.version >= 4 -%}
|
||||
{% if tx.type == 1 and 'sn_state_change' in tx.extra -%}
|
||||
{% if tx.extra.sn_state_change.type == 'decom' -%}
|
||||
<span class="icon" title="Service Node decommission">👎{%if text%} decommission{%endif%}</span>
|
||||
{% elif tx.extra.sn_state_change.type == 'recom' -%}
|
||||
|
@ -12,9 +12,9 @@
|
|||
{% else -%}
|
||||
<span class="icon" title="Unknown state change transaction">❓{%if text%} unknown state change{%endif%}</span><!-- Either a bug or a malformed transaction -->
|
||||
{% 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>
|
||||
{% 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 -%}
|
||||
<span class="icon" title="Oxen Name Service Buying">🎫{%if text%} LNS purchase{%endif%}</span>
|
||||
{% 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>{{fee.display(b.txs[0])}}</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>
|
||||
</tr>
|
||||
{% else %}
|
||||
|
@ -203,7 +203,7 @@
|
|||
<td><a href="/tx/{{tx.tx_hash}}">{{tx.tx_hash}}</a></td>
|
||||
<td>{{fee.display(tx)}}</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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
{%endif%}
|
||||
</span>
|
||||
|
||||
{%if sn.total_reserved != sn.total_contributed%}
|
||||
<span><label>Total reserved:</label> {{sn.total_reserved | oxen}}</span>
|
||||
{%if 'total_reserved' in sn and sn.total_reserved != sn.total_contributed%}
|
||||
<span><label>Reserved stakes:</label> {{(sn.total_reserved - sn.total_contributed) | oxen}}</span>
|
||||
{%endif%}
|
||||
|
||||
<span>
|
||||
|
@ -94,35 +94,10 @@
|
|||
</span>
|
||||
|
||||
{%if info.service_node%}{# SN tests are only conducted by SNs #}
|
||||
<span>
|
||||
<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>
|
||||
{% import 'include/reachable.html' as reachable %}
|
||||
|
||||
<span>
|
||||
<label{%if sn.lokinet_last_unreachable > sn.lokinet_last_reachable%} class="omg warning"{%endif%}>Lokinet:</label>
|
||||
{%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>
|
||||
{{reachable.display(sn)}}
|
||||
{{reachable.display(sn, true)}}
|
||||
{%endif%}
|
||||
|
||||
{%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>
|
||||
remaining to be contributed.
|
||||
{%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%}
|
||||
</p>
|
||||
{%endif%}
|
||||
|
@ -224,7 +200,7 @@
|
|||
({{c.locked_contributions|length}} contributions)
|
||||
{%endif-%}
|
||||
</td>
|
||||
<td>{{c.reserved | oxen}}</td>
|
||||
<td>{{(c.reserved if 'reserved' in c else c.amount) | oxen}}</td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
</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
|
||||
({{tx.received_timestamp | from_timestamp | ago}} ago)</span>
|
||||
{%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 'block_timestamp' in tx%}
|
||||
<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 #}
|
||||
<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
|
||||
{%else%}
|
||||
{{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%}
|
||||
</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>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%}
|
||||
<span><label>Service Node Winner:</label>
|
||||
|
@ -78,10 +78,10 @@
|
|||
</span>
|
||||
{%endif%}
|
||||
</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.info.type == 1 and 'sn_state_change' in tx.extra %}
|
||||
{% if tx.version >= 4 -%}
|
||||
{% if tx.type == 1 and 'sn_state_change' in tx.extra %}
|
||||
<h2>
|
||||
{%- set show_reasons = false -%}
|
||||
{% 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>
|
||||
{%endif%}
|
||||
|
||||
{% elif tx.info.type == 2 %}
|
||||
{% elif tx.type == 2 %}
|
||||
<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><label>Unlock key image:</label> {{unlock_key_image}}</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 %}
|
||||
<h2>🎫 Oxen Name Service Registration</h2>
|
||||
{% 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 %}
|
||||
|
||||
|
||||
{%if tx.info.vout%}
|
||||
{%if tx.vout%}
|
||||
<h2>Outputs</h2>
|
||||
<h4 class="Subtitle">{{tx.info.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>
|
||||
<h4 class="Subtitle">{{tx.vout|length}} output(s) for total of
|
||||
{{tx.vout | sum(attribute='amount') | oxen(zero='<span title="Regular OXEN tx amounts are private">???</span>') | safe}}</h4>
|
||||
<div class="TitleDivider"></div>
|
||||
<div class="tx-outputs">
|
||||
<table class="Table">
|
||||
|
@ -232,7 +232,7 @@ This tx does not includes a vote from this testing service node (only 7 votes ar
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
{%for out in tx.info.vout%}
|
||||
{%for out in tx.vout%}
|
||||
<tr>
|
||||
<td><label>{{loop.index0}}:</label> {{out.target.key}}</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%}
|
||||
#}
|
||||
|
||||
{%if not tx.coinbase and tx.info.vin|length > 0 %}
|
||||
{%if not tx.coinbase and tx.vin|length > 0 %}
|
||||
<div style="height: 1em"></div>
|
||||
|
||||
<h2>Inputs</h2>
|
||||
<h4 class="Subtitle">{{tx.info.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>
|
||||
<h4 class="Subtitle">{{tx.vin|length}} input(s) for total of
|
||||
{{tx.vin | sum(attribute='key.amount') | oxen(zero='<span title="Regular OXEN tx amounts are private">???</span>') | safe}}</h4>
|
||||
<div class="TitleDivider"></div>
|
||||
|
||||
{#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">
|
||||
<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">
|
||||
<td style="text-align: left;" colspan="2">
|
||||
<label>Key Image {{loop.index0}}:</label> {{inp.key.k_image}}
|
||||
|
|
Loading…
Reference in a new issue