Add quorum details page

This is completely different from the old one, made much more compact
and usable using the full list of truncated SN pubkeys in flex boxes.
This commit is contained in:
Jason Rhinelander 2020-10-11 00:07:20 -03:00
parent cecaddc18a
commit fc90738a0e
3 changed files with 232 additions and 2 deletions

View File

@ -145,10 +145,10 @@ def base32z(hex):
@app.template_filter('ellipsize')
def ellipsize(string, leading=10, trailing=5):
def ellipsize(string, leading=10, trailing=5, ellipsis='...'):
if len(string) <= leading + trailing + 3:
return string
return string[0:leading] + "..." + ('' if not trailing else string[-trailing:])
return string[0:leading] + ellipsis + ('' if not trailing else string[-trailing:])
@app.after_request
@ -192,6 +192,29 @@ def get_sns(sns_future, info_future):
awaiting_sns.append(sn)
return awaiting_sns, active_sns, inactive_sns
def get_quorums_future(lmq, lokid, height):
return FutureJSON(lmq, lokid, 'rpc.get_quorum_state', 30,
args={ 'start_height': height-50, 'end_height': height })
def get_quorums(quorums_future):
oblig_quorums, checkpoint_quorums, pulse_quorums = [], [], []
quorums = quorums_future.get()
quorums = quorums['quorums'] if 'quorums' in quorums else []
for q in quorums:
if q['quorum_type'] == 0:
oblig_quorums.append(q)
elif q['quorum_type'] == 1:
checkpoint_quorums.append(q)
elif q['quorum_type'] == 3:
pulse_quorums.append(q)
else:
print("Something getting wrong in quorums: found unknown quorum_type={}".format(q['quorum_type']), file=sys.stderr)
return oblig_quorums, checkpoint_quorums, pulse_quorums
@app.context_processor
def template_globals():
return {
@ -568,6 +591,19 @@ def show_tx(txid, more_details=False):
)
@app.route('/quorums')
def show_quorums():
lmq, lokid = lmq_connection()
info = FutureJSON(lmq, lokid, 'rpc.get_info', 1)
quos = get_quorums_future(lmq, lokid, info.get()['height'])
obl_q, cp_q, pulse_q = get_quorums(quos)
return flask.render_template('quorums.html',
info=info.get(),
quorums=dict(obligation=obl_q, checkpoint=cp_q, pulse=pulse_q),
)
@app.route('/search')
def search():
lmq, lokid = lmq_connection()

View File

@ -317,6 +317,99 @@ td.voter-signature {
text-overflow: ellipsis;
}
div.quorums {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
padding: 0;
}
div.quorums>div {
border: 2px solid #008522;
border-radius: 5px;
padding: 0;
flex-grow: 1;
}
div.quorums.obligations>div {
flex-basis: 300px;
margin: 5px;
}
div.quorums.obligations {
margin: 0 -5px;
}
div.quorums.checkpoint>div {
flex-basis: 200px;
margin: 5px;
}
div.quorums.checkpoint {
margin: 0 -5px;
}
div.quorums.pulse>div {
flex-basis: 200px;
margin: 5px;
}
div.quorums.checkpoint {
margin: 0 -5px;
}
h4.curr-height {
margin-top: 0px;
}
div.quorums>div>.validators,
div.quorums>div>.workers {
display: flex;
flex-flow: row wrap;
align-items: baseline;
/*justify-content: center;*/
/*space-between;*/
}
.quorums.obligations .workers, .quorums.pulse .validators {
border-top: 2px solid #008522;
}
.quorums .workers label, .quorums .validators label {
font-weight: bold;
}
.quorums .sn {
display: block;
flex-basis: 40px;
max-width: 60px;
flex-grow: 1;
background-color: #bbb;
border: 1px solid #555;
border-radius: 5px;
overflow: hidden;
text-overflow: "";
margin: 3px 3px;
padding: 1px 1px 1px 1px;
font-size: 10px;
color: black;
text-decoration: none;
}
.quorums .validators .sn {
background-color: #777;
border: 1px solid #aaa;
color: white;
}
.quorums .sn:hover {
background-color: #006a1b;
border-color: #78be20;
color: #78be20;
}
.quorums.pulse .workers .sn {
flex-grow: 1;
max-width: 150px;
}
div.quorums h2 {
background-color: #008522;
color: white;
font-size: 14px;
font-weight: bold;
margin: 0;
}
div.quorums h5 {
margin: 0;
}
td.quorum-pubkey span {
display: inline-block;
width: 80ex;

101
templates/quorums.html Normal file
View File

@ -0,0 +1,101 @@
{% extends "_basic.html" %}
{% block content %}
<div class="Wrapper">
<h2>Service Node testing quorums:</h2>
<div class="TitleUnderliner"></div>
<div class="obligations quorums">
{%for q in quorums.obligation[-18:] | reverse%}
<div>
<h2 title="This testing quorum is determined by block {{q.height}}">
{# quorum height + 13 here because a node only does an obligations test once the
node has at least 11 blocks on top of it, which means it is 13 blocks below the
blockchain height, which means it has to be (at least) the 12th oldest block, +1
because info.height is the top height + 1 #}
Block {{q.height + 13}}
{%if q.height + 13 > info.height%}
(~{{(q.height + 13 - info.height) * 2}} minutes)
{%elif q.height + 13 == info.height%}
(testing now!)
{%else%}
(~{{(info.height - (q.height + 13)) * 2}} minutes ago)
{%endif%}
</h2>
<div class="validators">
<label>Validators:</label>
{%for v in q.quorum.validators%}
<a class="sn" href="/sn/{{v}}" title="{{v}}">{{v}}</a>
{%endfor%}
</div>
<div class="workers">
<label>SNs to test:</label>
{%for w in q.quorum.workers%}
<a class="sn" href="/sn/{{w}}" title="{{w}}">{{w}}</a>
{%endfor%}
</div>
</div>
{%endfor%}
</div>
<h2>Recent pulse quorums:</h2>
<h4 class="curr-height">Current block height: <span class="omg">{{info.height}}</span></h4>
<div class="TitleUnderliner"></div>
<div class="pulse quorums">
{%for q in quorums.pulse[-24:] | reverse%}
{%if q.height == info.height%}
<div title="The shows primary pulse block producer and signers. Note that a backup quorum may produce and sign the block instead if the primary quorum takes too long to produce a block.">
<h2>Next block</h2>
{%else%}
<div>
<h2>Block {{q.height}}</h2>
{%endif%}
<div class="workers">
<label>Block producer:</label>
{%for w in q.quorum.workers%}{#should only be one#}
<a class="sn" href="/sn/{{w}}" title="{{w}}">{{w}}</a>
{%endfor%}
</div>
<div class="validators">
<label>Validators:</label>
{%for v in q.quorum.validators%}
<a class="sn" href="/sn/{{v}}" title="Validator {{loop.index}}/{{q.quorum.validators | length}}">{{v}}</a>
{%endfor%}
</div>
</div>
{%endfor%}
</div>
<h2>Recent checkpoint quorums:</h2>
<h4 class="curr-height">Current block height: <span class="omg">{{info.height}}</span></h4>
<div class="TitleUnderliner"></div>
<div class="checkpoint quorums">
{%for q in quorums.checkpoint[-12:] | reverse%}
<div>
<h2 title="This checkpoint quorum is determined by block {{q.height - 11}}">
Block {{q.height}}
</h2>
<div class="validators">
<!--<label>Service Nodes:</label>-->
{%for v in q.quorum.validators%}
<a class="sn" href="/sn/{{v}}" title="{{v}}
Validator {{loop.index}}/{{q.quorum.validators | length}}">{{v}}</a>
{%endfor%}
</div>
</div>
{%endfor%}
</div>
</div>
{% endblock %}