Commit 43d67461 authored by Jason Rhinelander's avatar Jason Rhinelander
Browse files

Added average effort stats; payment type

parent 7d839fbd
......@@ -11,6 +11,8 @@
PG_CONNECT = { 'dbname': 'graftpools' }
# Number of blocks to use for mean effort statistics
EFFORT_BLOCKS = 14*720
import psycopg2, psycopg2.extras
......@@ -20,6 +22,7 @@ import requests
import socket
import ipaddress
import re
from scipy.stats import gamma
_pgsql = None
......@@ -81,8 +84,22 @@ def pool_stats(env, start_response, q):
data = dict(cur.fetchone())
data['time'] = data['time'].timestamp()
mean_effort = {} # poolid: (mean,count,pval)
cur.execute("SELECT pool, AVG(effort), COUNT(effort) FROM pool_blocks WHERE height >= %s GROUP BY pool",
(data['height'] - EFFORT_BLOCKS,))
for x in cur:
eff, count = x[1], x[2]
# One-sided p-value since we generally expect either too low (potentially faked efforts) or
# too high (potentially stolen blocks)
if eff <= 1:
pval = gamma(count).cdf(eff * count)
else:
pval = gamma(count).sf(eff * count)
mean_effort[x[0]] = (eff * 100, count, pval)
cur.execute("""
SELECT id, name, url, blocks_url, location, height, blocks_found, hashrate, effort, miners, miners_paid, payments, fee, threshold, error,
SELECT id, name, url, blocks_url, location, payment_system,
height, blocks_found, hashrate, effort, miners, miners_paid, payments, fee, threshold, error,
hashrate_1d AS hr1, hashrate_7d AS hr7
FROM pools JOIN pool_stats ON pool = id JOIN pool_agg_stats ON pool_stats.pool = pool_agg_stats.pool
WHERE pool_fetch = %s AND enabled
......@@ -120,6 +137,14 @@ def pool_stats(env, start_response, q):
if p['hashrate'] is not None:
data['hashrate_desynced' if p['desync'] else 'hashrate_synced'] += p['hashrate']
if pool_id in mean_effort:
p['effort_stats'] = {
'mean': mean_effort[pool_id][0],
'blocks': mean_effort[pool_id][1],
'pval': mean_effort[pool_id][2],
'since': data['height'] - EFFORT_BLOCKS
}
data['pools'].append(p)
cur.execute("SELECT pool, hashrate, hour FROM pool_hashrate_chart ORDER BY hour")
......@@ -220,7 +245,7 @@ def add_pool(env, start_response, q):
if auth_failed:
return auth_failed
for x in ('name', 'url', 'blocks_url', 'api', 'api_url', 'location'):
for x in ('name', 'url', 'blocks_url', 'api', 'api_url', 'location', 'payment_system'):
if x not in q:
return error(start_response, "Required parameter '" + x + "' not specified")
......@@ -243,8 +268,10 @@ def add_pool(env, start_response, q):
pg = pgsql()
cur = pg.cursor()
try:
cur.execute("INSERT INTO pools (name, url, blocks_url, api, api_url, enabled, location) VALUES (%s, %s, %s, %s, %s, %s, %s)",
(q['name'], q['url'], q['blocks_url'], q['api'], q['api_url'], bool('enabled' in q and q['enabled']), q['location']))
cur.execute("INSERT INTO pools (name, url, blocks_url, api, api_url, enabled, location, payment_system) "
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
(q['name'], q['url'], q['blocks_url'], q['api'], q['api_url'], bool('enabled' in q and q['enabled']),
q['location'], q['payment_system']))
except psycopg2.Error as e:
return error(start_response, "Unable to insert pool: " + str(e))
......@@ -261,7 +288,7 @@ def modify_pool(env, start_response, q):
update = []
params = []
for x in ('name', 'url', 'blocks_url', 'api', 'api_url', 'location'):
for x in ('name', 'url', 'blocks_url', 'api', 'api_url', 'location', 'payment_system'):
if x in q:
update.append(x)
params.append(q[x])
......@@ -380,6 +407,7 @@ def detect_remote(env, start_response, q):
elif api_url.startswith('/'):
api_url = o.scheme + '://' + h + ('' if not o.port or o.port == (443 if o.scheme == 'https' else 80) else p) + api_url
payment_system = 'Prop?' if detect_type == 'ncp' else 'PPLNS?'
try:
if detect_type == 'ncp':
data = check_ncp(api_url)
......@@ -387,14 +415,18 @@ def detect_remote(env, start_response, q):
pass
else:
detect_type = 'ncp+1' # most other pools get it wrong and report the last block height rather than network height
if 'slushMiningEnabled' in data['config']:
payment_system = 'Score' if data['config']['slushMiningEnabled'] else 'Prop'
elif detect_type == 'nodejs':
data = check_nodejs(api_url)
# Currently I know of API-detectable nodejs-derived pools that get the network height right
detect_type = 'nodejs+1'
if 'pool_list' in data and data['pool_list'] and data['pool_list'][0] == 'pplns':
payment_system = 'PPLNS'
else:
return error(start_response, "Unknown/unsupported API type '" + detect_type + "'")
except Exception as e:
return error(start_response, "Site looks like a {} pool, but the API URL check failed: {}".format(detect_type, e))
start_response('200 OK', [('Content-Type', 'application/json')])
return [json.dumps({ 'api': detect_type, 'api_url': api_url }).encode('utf-8')]
return [json.dumps({ 'api': detect_type, 'api_url': api_url, 'payment_system': payment_system }).encode('utf-8')]
......@@ -73,30 +73,6 @@
</div>
</div>
<div class="pool field">
<label>URL to pool block list</label>
<div class="pool input">
<input id="pool-blocks_url" type="text" />
</div>
<div class="description">
<p>
This is the URL for the pool used on the block explorer to take the user directly to the pool's block list. If you leave it blank
then the main pool URL will be used instead.
</p>
<p>Some common patterns:
<ul class="block-url-patterns">
<li urlTemplate="{URL}#pool_blocks"><code>(url)#pool_blocks</code>
(<a class="try_blocks_url" href="#" target="_blank">link</a>; <a class="use_blocks_url" href="#">use this</a>) — commonly
used for node-cryptonote-pools.</li>
<li urlTemplate="{URL}#/blocks"><code>(url)#/blocks</code>
(<a class="try_blocks_url" href="#" target="_blank">link</a>; <a class="use_blocks_url" href="#">use this</a>) — commonly
used for nodejs-pools.</li>
</ul>
</p>
</div>
</div>
<div class="pool field">
<label>API type</label>
<button id="pool-detect-api">Detect</button>
......@@ -134,6 +110,41 @@
</div>
</div>
<div class="pool field">
<label>Payment system</label>
<div class="pool input">
<input id="pool-payment_system" type="text" />
</div>
<div class="description">
The payment system of the pool, such as <a href="#" id="payments_prop">Prop</a>, <a href="#" id="payments_pplns">PPLNS</a>,
<a href="#" id="payments_score">Score</a>, <a href="#" id="payments_pplnt">PPLNT</a>. Append a ? if unsure.
</div>
</div>
<div class="pool field">
<label>URL to pool block list</label>
<div class="pool input">
<input id="pool-blocks_url" type="text" />
</div>
<div class="description">
<p>
This is the URL for the pool used on the block explorer to take the user directly to the pool's block list. If you leave it blank
then the main pool URL will be used instead.
</p>
<p>Some common patterns:
<ul class="block-url-patterns">
<li urlTemplate="{URL}#pool_blocks"><code>(url)#pool_blocks</code>
(<a class="try_blocks_url" href="#" target="_blank">link</a>; <a class="use_blocks_url" href="#">use this</a>) — commonly
used for node-cryptonote-pools.</li>
<li urlTemplate="{URL}#/blocks"><code>(url)#/blocks</code>
(<a class="try_blocks_url" href="#" target="_blank">link</a>; <a class="use_blocks_url" href="#">use this</a>) — commonly
used for nodejs-pools.</li>
</ul>
</p>
</div>
</div>
<div class="pool field">
<label>Enabled?</label>
<div class="pool input">
......
......@@ -39,13 +39,17 @@ $(function() {
var auth_code = $('#auth_code');
if (auth_code.val() == '') {
console.log("empty auth code");
var auth_cookie = $.cookie('auth_code');
if (auth_cookie) {
console.log("setting auth code from cookie");
auth_code.val(auth_cookie);
}
}
var set_system = function(x) { return function() { $('#pool-payment_system').val(x); return false; }; };
for (let x of ['Score', 'Prop', 'PPLNS', 'PPLNT']) {
console.log(x.toLowerCase());
$('a#payments_' + x.toLowerCase()).off('click').on('click', set_system(x));
}
});
function detect_api() {
......@@ -70,6 +74,9 @@ function detect_api() {
if (data.error) return detect_fail(null, null, data.error);
$('#pool-api').val(data.api);
$('#pool-api_url').val(data.api_url);
let payment_system = $('#pool-payment_system')
if (payment_system.val() == '' && data.payment_system)
payment_system.val(data.payment_system);
}
});
}
......@@ -77,7 +84,7 @@ function detect_api() {
function detect_fail(jqxhr, stat, err) {
var de = $('#detect-error');
de.empty().append($('<h3>API detection failed:</h3><div></div>'))
de.children('div').text(err || 'An unknown error occurred');
de.children('div').text(err || 'An unknown error occurred: ' + jqxhr.status);
de.show();
}
......@@ -106,7 +113,7 @@ function populate_pool_form() {
}
else {
let pool = pools[id];
for (let x of ['name', 'location', 'url', 'blocks_url', 'api', 'api_url']) {
for (let x of ['name', 'location', 'payment_system', 'url', 'blocks_url', 'api', 'api_url']) {
$('#pool-' + x).val(pool[x]);
}
$('#pool-enabled').val(pool.enabled ? '1' : '');
......@@ -117,7 +124,7 @@ function populate_pool_form() {
function submit_fail(jqxhr, stat, err) {
var se = $('.submit-error');
se.empty().append($('<h3>Unable to add/modify pool:</h3><div></div>'));
se.children('div').text(err || 'An unknown error occurred');
se.children('div').text(err || 'An unknown error occurred: ' + jqxhr.responseText);
se.show();
}
......@@ -132,7 +139,7 @@ function submit_pool() {
auth_code: $('#auth_code').val()
};
if (id) data['id'] = id;
for (let x of ['name', 'url', 'location', 'blocks_url', 'api', 'api_url', 'enabled'])
for (let x of ['name', 'url', 'location', 'payment_system', 'blocks_url', 'api', 'api_url', 'enabled'])
data[x] = $('#pool-' + x).val();
$.ajax({
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment