Browse Source

Merge branch 'master' into userstats

Conflicts:
	src/connector.c
	src/stratifier.c
master
Con Kolivas 10 years ago
parent
commit
55d1c98f19
  1. 14
      pool/base.php
  2. 12
      pool/db.php
  3. 15
      pool/page.php
  4. 138
      pool/page_addrmgt.php
  5. 4
      pool/page_allwork.php
  6. 31
      pool/page_api.php
  7. 4
      pool/page_blocks.php
  8. 4
      pool/page_ckp.php
  9. 4
      pool/page_help.php
  10. 4
      pool/page_index.php
  11. 9
      pool/page_payments.php
  12. 16
      pool/page_payout.php
  13. 4
      pool/page_pblocks.php
  14. 9
      pool/page_pplns.php
  15. 18
      pool/page_reg.php
  16. 4
      pool/page_reset.php
  17. 18
      pool/page_settings.php
  18. 4
      pool/page_stats.php
  19. 4
      pool/page_userset.php
  20. 4
      pool/page_workers.php
  21. 4
      pool/page_workmgt.php
  22. 14
      pool/prime.php
  23. 2
      pool/socket.php
  24. 185
      src/ckdb.c
  25. 28
      src/ckdb.h
  26. 2
      src/ckdb_btc.c
  27. 287
      src/ckdb_cmd.c
  28. 65
      src/ckdb_data.c
  29. 272
      src/ckdb_dbio.c
  30. 2
      src/ckpmsg.c
  31. 2
      src/ckpool.c
  32. 12
      src/connector.c
  33. 27
      src/libckpool.h
  34. 36
      src/stratifier.c

14
pool/base.php

@ -238,7 +238,7 @@ function dbd($data, $user)
# #
function dbdown() function dbdown()
{ {
gopage(NULL, 'dbd', 'dbd', def_menu(), '', '', true, false, false); gopage(NULL, NULL, 'dbd', 'dbd', def_menu(), '', '', true, false, false);
} }
# #
function syse($data, $user) function syse($data, $user)
@ -248,7 +248,7 @@ function syse($data, $user)
# #
function syserror() function syserror()
{ {
gopage(NULL, 'syse', 'syse', def_menu(), '', '', true, false, false); gopage(NULL, NULL, 'syse', 'syse', def_menu(), '', '', true, false, false);
} }
# #
function f404($data) function f404($data)
@ -258,10 +258,10 @@ function f404($data)
# #
function do404() function do404()
{ {
gopage(NULL, 'f404', 'f404', def_menu(), '', '', true, false, false); gopage(NULL, NULL, 'f404', 'f404', def_menu(), '', '', true, false, false);
} }
# #
function showPage($page, $menu, $name, $user) function showPage($info, $page, $menu, $name, $user)
{ {
# If you are doing development, use without '@' # If you are doing development, use without '@'
# Then switch to '@' when finished # Then switch to '@' when finished
@ -270,14 +270,14 @@ function showPage($page, $menu, $name, $user)
$fun = 'show_' . $page; $fun = 'show_' . $page;
if (function_exists($fun)) if (function_exists($fun))
$fun($page, $menu, $name, $user); $fun($info, $page, $menu, $name, $user);
else else
do404(); do404();
} }
# #
function showIndex() function showIndex()
{ {
showPage('index', def_menu(), '', false); showPage(NULL, 'index', def_menu(), '', false);
} }
# #
function offline() function offline()
@ -286,7 +286,7 @@ function offline()
{ {
$ip = $_SERVER['REMOTE_ADDR']; $ip = $_SERVER['REMOTE_ADDR'];
if ($ip != '192.168.1.666') if ($ip != '192.168.1.666')
gopage(NULL, file_get_contents('./maintenance.txt'), gopage(NULL, NULL, file_get_contents('./maintenance.txt'),
'offline', NULL, '', '', false, false, false); 'offline', NULL, '', '', false, false, false);
} }
} }

12
pool/db.php

@ -180,7 +180,17 @@ function userSettings($user, $email = null, $addr = null, $pass = null)
$flds['email'] = $email; $flds['email'] = $email;
if ($addr != null) if ($addr != null)
{ {
$flds['address'] = $addr; $rows = count($addr);
$i = 0;
foreach ($addr as $ar)
{
$flds['address:'.$i] = $ar['addr'];
// optional - missing = use default
if (isset($ar['ratio']))
$flds['ratio:'.$i] = $ar['ratio'];
$i++;
}
$flds['rows'] = $rows;
$tmo = 3; # 3x the timeout $tmo = 3; # 3x the timeout
} }
if ($pass != null) if ($pass != null)

15
pool/page.php

@ -88,6 +88,8 @@ function pghead($script_marker, $name)
$head .= "<html><head><title>$page_title$name</title>"; $head .= "<html><head><title>$page_title$name</title>";
$head .= "<meta content='text/html; charset=iso-8859-1' http-equiv='Content-Type'>"; $head .= "<meta content='text/html; charset=iso-8859-1' http-equiv='Content-Type'>";
$head .= "<meta content='IE=edge' http-equiv='X-UA-Compatible'>";
$head .= "<meta content='width=device-width, initial-scale=1' name='viewport'>";
$head .= "<script type='text/javascript'>\n"; $head .= "<script type='text/javascript'>\n";
$head .= "function jst(){document.getElementById('jst').style.visibility='hidden';}\n"; $head .= "function jst(){document.getElementById('jst').style.visibility='hidden';}\n";
@ -95,9 +97,10 @@ function pghead($script_marker, $name)
$head .= "<style type='text/css'> $head .= "<style type='text/css'>
form {display: inline-block;} form {display: inline-block;}
html, body {height: 100%; font-family:Arial, Verdana, sans-serif; font-size:12pt; background-color:#eff; text-align: center; background-repeat: no-repeat; background-position: center; } html, body {height: 100%; font-family:Arial, Verdana, sans-serif; font-size:12pt; background-color:#eeffff; text-align: center; background-repeat: no-repeat; background-position: center;}
.page {min-height: 100%; height: auto !important; height: 100%; margin: 0 auto -50px; position: relative;} .page {min-height: 100%; height: auto !important; height: 100%; margin: 0 auto -50px; position: relative;}
div.jst {color:red; font-weight: bold; font-size: 8; text-align: center; vertical-align: top;} div.jst {color:red; font-weight: bold; font-size: 8; text-align: center; vertical-align: top;}
div.accwarn {color:red; font-weight: bold; font-size: 8; text-align: center; vertical-align: top;}
div.topd {background-color:#cff; border-color: #cff; border-style: solid; border-width: 9px;} div.topd {background-color:#cff; border-color: #cff; border-style: solid; border-width: 9px;}
.topdes {color:blue; text-align: right;} .topdes {color:blue; text-align: right;}
.topwho {color:black; font-weight: bold; margin-right: 8px;} .topwho {color:black; font-weight: bold; margin-right: 8px;}
@ -123,6 +126,7 @@ h1 {margin-top: 20px; float:middle; font-size: 20px;}
.title {background-color: #909090;} .title {background-color: #909090;}
.even {background-color: #cccccc;} .even {background-color: #cccccc;}
.odd {background-color: #a8a8a8;} .odd {background-color: #a8a8a8;}
.hid {display: none;}
.dl {text-align: left; padding: 2px 8px;} .dl {text-align: left; padding: 2px 8px;}
.dr {text-align: right; padding: 2px 8px;} .dr {text-align: right; padding: 2px 8px;}
.dc {text-align: center; padding: 2px 8px;} .dc {text-align: center; padding: 2px 8px;}
@ -271,6 +275,12 @@ function pgtop($info, $dotop, $user, $douser)
$top = "<div class=jst id=jst>&nbsp;Javascript isn't enabled."; $top = "<div class=jst id=jst>&nbsp;Javascript isn't enabled.";
$top .= " You need to enable javascript to use"; $top .= " You need to enable javascript to use";
$top .= " the $site_title web site.</div>"; $top .= " the $site_title web site.</div>";
if (isset($info['u_nopayaddr']))
$top .= '<div class=accwarn>Please set a payout address on your account!</div>';
if (isset($info['u_noemail']))
$top .= '<div class=accwarn>Please set an email address on your account!</div>';
$top .= '<div class=topd>'; $top .= '<div class=topd>';
if ($dotop === true) if ($dotop === true)
{ {
@ -427,7 +437,7 @@ function pgfoot()
return $foot; return $foot;
} }
# #
function gopage($data, $pagefun, $page, $menu, $name, $user, $ispage = true, $dotop = true, $douser = true) function gopage($info, $data, $pagefun, $page, $menu, $name, $user, $ispage = true, $dotop = true, $douser = true)
{ {
global $dbg, $stt; global $dbg, $stt;
global $page_scripts; global $page_scripts;
@ -440,6 +450,7 @@ function gopage($data, $pagefun, $page, $menu, $name, $user, $ispage = true, $do
else else
$pg = ''; $pg = '';
if ($info === NULL)
$info = homeInfo($user); $info = homeInfo($user);
if ($ispage == true) if ($ispage == true)

138
pool/page_addrmgt.php

@ -0,0 +1,138 @@
<?php
#
function addrmgtuser($data, $user, $err)
{
$pg = '<h1>Address Management</h1>';
if ($err != '')
$pg .= "<span class=err>$err<br><br></span>";
$pg .= makeForm('addrmgt');
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n";
$pg .= '<tr class=title>';
$pg .= '<td class=dl>Address</td>';
$pg .= '<td class=dr>Ratio</td>';
$pg .= '<td class=dr>%</td>';
$pg .= '</tr>';
# new row template for '+'
$pg .= '<tr class=hid id=bs>';
$pg .= '<td class=dl>';
$pg .= "<input type=text size=42 name='addr:' value=''>";
$pg .= '</td>';
$pg .= '<td class=dr>';
$pg .= "<input type=text size=6 name='ratio:' value='0' id=rat onchange='repc()'>";
$pg .= '</td>';
$pg .= '<td class=dr>';
$pg .= "<span id=per>0.00%</span>";
$pg .= '</td>';
$pg .= "</tr>\n";
$ans = userSettings($user);
$offset = 0;
$count = 0;
if ($ans['STATUS'] == 'ok')
{
$count = $ans['rows'];
for ($i = 0; $i < $count; $i++)
{
if ((($offset) % 2) == 0)
$row = 'even';
else
$row = 'odd';
$pg .= "<tr class=$row>";
$addr = $ans['addr:'.$i];
$pg .= '<td class=dl>';
$pg .= "<input type=text size=42 name='addr:$i' value='$addr'>";
$pg .= '</td>';
$ratio = intval($ans['ratio:'.$i]);
$pg .= '<td class=dr>';
$pg .= "<input type=text size=6 name='ratio:$i' value='$ratio' id=rat$i onchange='repc()'>";
$pg .= '</td>';
$pg .= '<td class=dr>';
$pg .= "<span id=per$i>%</span>";
$pg .= '</td>';
$pg .= "</tr>\n";
$offset++;
}
if ((($offset++) % 2) == 0)
$row = 'even';
else
$row = 'odd';
$pg .= "<tr class=$row id=plus>";
$pg .= '<td colspan=3 class=dl>';
$pg .= "<input type=button value='+' onclick='return adrw();'>";
$pg .= '</td></tr>';
if ((($offset++) % 2) == 0)
$row = 'even';
else
$row = 'odd';
$pg .= "<tr class=$row>";
$pg .= '<td colspan=3 class=dc>';
$pg .= 'Password: <input type=password name=pass size=20>';
$pg .= '&nbsp;<input type=submit name=OK value=Save></td></tr>';
}
$pg .= '<tr><td colspan=3 class=dc><font size=-1><span class=st1>*</span>';
$pg .= ' You must enter your password to save changes<br>';
$pg .= 'A ratio of 0, will remove the address from the payouts</font></td></tr>';
$pg .= "</table><input type=hidden name=rows value=$count id=rows></form>\n";
$pg .= "<script type='text/javascript'>\n";
$pg .= "function adrw(){var p=document.getElementById('plus');";
$pg .= "var r=document.getElementById('rows');var c=parseInt(r.value);";
$pg .= "var bs=document.getElementById('bs');var n=bs.cloneNode(true);n.id='z';";
$pg .= "n.className='odd';var ia=n.childNodes[0].firstChild;ia.name='addr:'+c;ia.value='';";
$pg .= "var ir=n.childNodes[1].firstChild;ir.id='rat'+c;ir.name='ratio:'+c;ir.value='0';";
$pg .= "var ip=n.childNodes[2].firstChild;ip.id='per'+c;ip.innerHTML='0.00%';";
$pg .= "p.parentNode.insertBefore(n, p);";
$pg .= "c++;r.value=c;return true}\n";
$pg .= "function repc(){var c=parseInt(document.getElementById('rows').value);";
$pg .= "if(!isNaN(c)&&c>0&&c<1000){var v=[],tot=0;for(i=0;i<c;i++){";
$pg .= "var o=document.getElementById('rat'+i);var ov=parseInt(o.value);if(!isNaN(ov)&&ov>0)";
$pg .= "{tot+=ov;v[i]=ov}else{o.value='0';v[i]=0}";
$pg .= "}for(i=0;i<c;i++){var p;var r=document.getElementById('per'+i);if(tot<=0)";
$pg .= "{p=0}else{p=v[i]*100/tot};r.innerHTML=p.toFixed(2)+'%';";
$pg .= "}}};\nrepc();</script>";
return $pg;
}
#
function doaddrmgt($data, $user)
{
$err = '';
$OK = getparam('OK', false);
$count = getparam('rows', false);
$pass = getparam('pass', false);
if ($OK == 'Save' && !nuem($count) && !nuem($pass))
{
if ($count > 0 && $count < 1000)
{
$addrarr = array();
for ($i = 0; $i < $count; $i++)
{
$addr = getparam('addr:'.$i, false);
$ratio = getparam('ratio:'.$i, false);
if (!nuem($addr) && !nuem($ratio))
$addrarr[] = array('addr' => $addr, 'ratio' => $ratio);
}
$ans = userSettings($user, null, $addrarr, $pass);
if ($ans['STATUS'] != 'ok')
$err = $ans['ERROR'];
}
}
$pg = addrmgtuser($data, $user, $err);
return $pg;
}
#
function show_addrmgt($info, $page, $menu, $name, $user)
{
gopage($info, NULL, 'doaddrmgt', $page, $menu, $name, $user);
}
#
?>

4
pool/page_allwork.php

@ -39,9 +39,9 @@ function doallwork($data, $user)
return $pg; return $pg;
} }
# #
function show_allwork($page, $menu, $name, $user) function show_allwork($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'doallwork', $page, $menu, $name, $user); gopage($info, NULL, 'doallwork', $page, $menu, $name, $user);
} }
# #
?> ?>

31
pool/page_api.php

@ -9,7 +9,7 @@ function no_api($json = "")
exit(0); exit(0);
} }
# #
function show_api($page, $menu, $name, $user) function show_api($info, $page, $menu, $name, $user)
{ {
global $fld_sep; global $fld_sep;
$u = getparam('username', true); $u = getparam('username', true);
@ -29,27 +29,28 @@ function show_api($page, $menu, $name, $user)
no_api($jfu); no_api($jfu);
if (nuem($work)) if (nuem($work))
{ {
$ans = homeInfo($u); if ($info === NULL)
if ($ans === false) $info = homeInfo($u);
if ($info === false)
no_api($jfu); no_api($jfu);
$rep = fldEncode($ans, 'lastbc', true); $rep = fldEncode($info, 'lastbc', true);
$rep .= fldEncode($ans, 'lastheight', false); $rep .= fldEncode($info, 'lastheight', false);
$rep .= fldEncode($ans, 'currndiff', false); $rep .= fldEncode($info, 'currndiff', false);
$rep .= fldEncode($ans, 'lastblock', false); $rep .= fldEncode($info, 'lastblock', false);
$rep .= fldEncode($ans, 'lastblockheight', false); $rep .= fldEncode($info, 'lastblockheight', false);
$rep .= fldEncode($ans, 'blockacc', false); $rep .= fldEncode($info, 'blockacc', false);
$rep .= fldEncode($ans, 'blockerr', false); $rep .= fldEncode($info, 'blockerr', false);
$rep .= fldEncode($ans, 'p_hashrate5m', false); $rep .= fldEncode($info, 'p_hashrate5m', false);
$rep .= fldEncode($ans, 'p_hashrate1hr', false); $rep .= fldEncode($info, 'p_hashrate1hr', false);
$rep .= fldEncode($ans, 'u_hashrate5m', false); $rep .= fldEncode($info, 'u_hashrate5m', false);
$rep .= fldEncode($ans, 'u_hashrate1hr', false); $rep .= fldEncode($info, 'u_hashrate1hr', false);
} }
else else
{ {
$ans = getWorkers($u); $ans = getWorkers($u);
if ($ans === false) if ($ans === false)
no_api($jfu); no_api($jfu);
$rep .= fldEncode($ans, 'rows', true); $rep = fldEncode($ans, 'rows', true);
$rows = $ans['rows']; $rows = $ans['rows'];
$flds = explode(',', $ans['flds']); $flds = explode(',', $ans['flds']);
$zeflds = ''; $zeflds = '';

4
pool/page_blocks.php

@ -182,9 +182,9 @@ function doblocks($data, $user)
return $pg; return $pg;
} }
# #
function show_blocks($page, $menu, $name, $user) function show_blocks($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'doblocks', $page, $menu, $name, $user); gopage($info, NULL, 'doblocks', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_ckp.php

@ -62,9 +62,9 @@ function dockp($data, $user)
return $pg; return $pg;
} }
# #
function show_ckp($page, $menu, $name, $user) function show_ckp($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dockp', $page, $menu, $name, $user); gopage($info, NULL, 'dockp', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_help.php

@ -5,9 +5,9 @@ function dohelp($data, $user)
return '<h1>Helpless</h1>Helpless'; return '<h1>Helpless</h1>Helpless';
} }
# #
function show_help($page, $menu, $name, $user) function show_help($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dohelp', $page, $menu, $name, $user); gopage($info, NULL, 'dohelp', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_index.php

@ -2,9 +2,9 @@
# #
@include_once('myindex.php'); @include_once('myindex.php');
# #
function show_index($page, $menu, $name, $user) function show_index($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'doindex', $page, $menu, $name, $user); gopage($info, NULL, 'doindex', $page, $menu, $name, $user);
} }
# #
?> ?>

9
pool/page_payments.php

@ -2,7 +2,12 @@
# #
function dopayments($data, $user) function dopayments($data, $user)
{ {
$bc = 'https://blockchain.info/address/';
$addr1 = '1KzFJddTvK9TQWsmWFKYJ9fRx9QeSATyrT';
$pg = '<h1>Payments</h1>'; $pg = '<h1>Payments</h1>';
$pg .= 'The payout transactions on blockchain are here:';
$pg .= " <a href='$bc$addr1' target=_blank>BTC</a><br><br>";
$ans = getPayments($user); $ans = getPayments($user);
@ -34,9 +39,9 @@ function dopayments($data, $user)
return $pg; return $pg;
} }
# #
function show_payments($page, $menu, $name, $user) function show_payments($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dopayments', $page, $menu, $name, $user); gopage($info, NULL, 'dopayments', $page, $menu, $name, $user);
} }
# #
?> ?>

16
pool/page_payout.php

@ -5,17 +5,23 @@ function dopayout($data, $user)
$pg = '<h1>Payouts</h1>'; $pg = '<h1>Payouts</h1>';
$pg .= '<table width=75% cellpadding=0 cellspacing=0 border=0>'; $pg .= '<table width=75% cellpadding=0 cellspacing=0 border=0>';
$pg .= '<tr><td class=dc>'; $pg .= '<tr><td class=dc>';
$pg .= 'We use PPLNS (pay per last N shares)<br>'; $pg .= 'We use PPLNS (pay per last N shares)<br><br>';
$pg .= 'Pool fee is 1.5%<br>';
$pg .= 'The N value used for PPLNS is the network difficulty'; $pg .= 'The N value used for PPLNS is the network difficulty';
$pg .= ' when a block is found.'; $pg .= ' when a block is found,<br>';
$pg .= 'but includes the full shift at the start and end of the range,<br>';
$pg .= 'so it usually will be a bit more than N.<br><br>';
$pg .= 'Shifts are ~30s long, however, when a block is found<br>';
$pg .= 'the current shift ends at the point the block was found.<br>';
$pg .= 'A ckpool restart will also start a new shift.<br><br>';
$pg .= 'Transaction fees are included in the miner payout.<br>';
$pg .= 'Pool fee is 0.9% of the total.<br>';
$pg .= '</td></tr></table>'; $pg .= '</td></tr></table>';
return $pg; return $pg;
} }
# #
function show_payout($page, $menu, $name, $user) function show_payout($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dopayout', $page, $menu, $name, $user); gopage($info, NULL, 'dopayout', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_pblocks.php

@ -7,9 +7,9 @@ function dopblocks($data, $user)
return doblocks($data, null); return doblocks($data, null);
} }
# #
function show_pblocks($page, $menu, $name, $user) function show_pblocks($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dopblocks', $page, $menu, $name, $user); gopage($info, NULL, 'dopblocks', $page, $menu, $name, $user);
} }
# #
?> ?>

9
pool/page_pplns.php

@ -42,10 +42,11 @@ function calctx($ans, $count, $miner_sat, $diffacc_total)
$payaddress = $ans['payaddress:'.$i]; $payaddress = $ans['payaddress:'.$i];
if ($payaddress == 'none') if ($payaddress == 'none')
{ {
$len = strlen($username);
$c0 = substr($username, 0, 1); $c0 = substr($username, 0, 1);
$parts = explode('.', $username);
$len = strlen($parts[0]);
if (($c0 == '1' || $c0 == '3') && $len > 26 && $len < 37) if (($c0 == '1' || $c0 == '3') && $len > 26 && $len < 37)
$payaddress = $username; $payaddress = $parts[0];
else else
{ {
if ($pay_sat > 0) if ($pay_sat > 0)
@ -281,9 +282,9 @@ Block: <input type=text name=blk size=10 value='$blkuse'>
return $pg; return $pg;
} }
# #
function show_pplns($page, $menu, $name, $user) function show_pplns($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dopplns', $page, $menu, $name, $user); gopage($info, NULL, 'dopplns', $page, $menu, $name, $user);
} }
# #
?> ?>

18
pool/page_reg.php

@ -79,7 +79,7 @@ function doreg2($data)
return $pg; return $pg;
} }
# #
function try_reg($page, $menu, $name, $u) function try_reg($info, $page, $menu, $name, $u)
{ {
$user = getparam('user', false); $user = getparam('user', false);
$mail = trim(getparam('mail', false)); $mail = trim(getparam('mail', false));
@ -128,12 +128,12 @@ function try_reg($page, $menu, $name, $u)
{ {
$ans = userReg($user, $mail, $pass); $ans = userReg($user, $mail, $pass);
if ($ans['STATUS'] == 'ok') if ($ans['STATUS'] == 'ok')
gopage($data, 'doreg2', $page, $menu, $name, $u, true, true, false); gopage($info, $data, 'doreg2', $page, $menu, $name, $u, true, true, false);
else else
$data['error'] = "Invalid username, password or email address"; $data['error'] = "Invalid username, password or email address";
} }
gopage($data, 'doregres', $page, $menu, $name, $u, true, true, false); gopage($info, $data, 'doregres', $page, $menu, $name, $u, true, true, false);
} }
# #
function doreset2($data) function doreset2($data)
@ -179,7 +179,7 @@ function doreset2($data)
return $pg; return $pg;
} }
# #
function try_reset($page, $menu, $name, $u) function try_reset($info, $page, $menu, $name, $u)
{ {
$user = getparam('user', false); $user = getparam('user', false);
$mail = trim(getparam('mail', false)); $mail = trim(getparam('mail', false));
@ -199,20 +199,20 @@ function try_reset($page, $menu, $name, $u)
{ {
$data = array('user' => $user, 'email' => $mail); $data = array('user' => $user, 'email' => $mail);
gopage($data, 'doreset2', $page, $menu, $name, $u, true, true, false); gopage($info, $data, 'doreset2', $page, $menu, $name, $u, true, true, false);
} }
} }
gopage($data, 'doregres', $page, $menu, $name, $u, true, true, false); gopage($info, $data, 'doregres', $page, $menu, $name, $u, true, true, false);
} }
# #
function show_reg($page, $menu, $name, $u) function show_reg($info, $page, $menu, $name, $u)
{ {
$reg = getparam('Register', false); $reg = getparam('Register', false);
if ($reg !== NULL) if ($reg !== NULL)
try_reg($page, $menu, $name, $u); try_reg($info, $page, $menu, $name, $u);
else else
try_reset($page, $menu, $name, $u); try_reset($info, $page, $menu, $name, $u);
} }
# #
?> ?>

4
pool/page_reset.php

@ -158,9 +158,9 @@ function doreset($data, $u)
return resetfail(); return resetfail();
} }
# #
function show_reset($page, $menu, $name, $u) function show_reset($info, $page, $menu, $name, $u)
{ {
gopage(array(), 'doreset', $page, $menu, $name, $u, true, true, false); gopage($info, array(), 'doreset', $page, $menu, $name, $u, true, true, false);
} }
# #
?> ?>

18
pool/page_settings.php

@ -33,6 +33,8 @@ function settings($data, $user, $email, $addr, $err)
$pg .= '</center></td></tr>'; $pg .= '</center></td></tr>';
$pg .= '<tr class=dc><td><center>'; $pg .= '<tr class=dc><td><center>';
if (!isset($data['info']['u_multiaddr']))
{
$pg .= makeForm('settings'); $pg .= makeForm('settings');
$pg .= '<table cellpadding=5 cellspacing=0 border=0>'; $pg .= '<table cellpadding=5 cellspacing=0 border=0>';
$pg .= '<tr class=dc><td class=dr colspan=2>'; $pg .= '<tr class=dc><td class=dr colspan=2>';
@ -55,6 +57,7 @@ function settings($data, $user, $email, $addr, $err)
$pg .= '</center></td></tr>'; $pg .= '</center></td></tr>';
$pg .= '<tr class=dc><td><center>'; $pg .= '<tr class=dc><td><center>';
}
$pg .= makeForm('settings'); $pg .= makeForm('settings');
$pg .= '<table cellpadding=5 cellspacing=0 border=0>'; $pg .= '<table cellpadding=5 cellspacing=0 border=0>';
@ -101,10 +104,14 @@ function dosettings($data, $user)
$check = true; $check = true;
break; break;
case 'Address': case 'Address':
if (!isset($data['info']['u_multiaddr']))
{
$addr = getparam('baddr', false); $addr = getparam('baddr', false);
$addrarr = array(array('addr' => $addr));
$pass = getparam('pass', false); $pass = getparam('pass', false);
$ans = userSettings($user, null, $addr, $pass); $ans = userSettings($user, null, $addrarr, $pass);
$check = true; $check = true;
}
break; break;
case 'Password': case 'Password':
$oldpass = getparam('oldpass', false); $oldpass = getparam('oldpass', false);
@ -139,17 +146,18 @@ function dosettings($data, $user)
$email = $ans['email']; $email = $ans['email'];
else else
$email = ''; $email = '';
if (isset($ans['addr'])) // Use the first one - updating will expire all others
$addr = $ans['addr']; if (isset($ans['rows']) and $ans['rows'] > 0)
$addr = $ans['addr:0'];
else else
$addr = ''; $addr = '';
$pg = settings($data, $user, $email, $addr, $err); $pg = settings($data, $user, $email, $addr, $err);
return $pg; return $pg;
} }
# #
function show_settings($page, $menu, $name, $user) function show_settings($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dosettings', $page, $menu, $name, $user); gopage($info, NULL, 'dosettings', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_stats.php

@ -99,9 +99,9 @@ function dostats($data, $user)
return $pg; return $pg;
} }
# #
function show_stats($page, $menu, $name, $user) function show_stats($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'dostats', $page, $menu, $name, $user); gopage($info, NULL, 'dostats', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_userset.php

@ -92,9 +92,9 @@ function douserset($data, $user)
return $pg; return $pg;
} }
# #
function show_userset($page, $menu, $name, $user) function show_userset($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'douserset', $page, $menu, $name, $user); gopage($info, NULL, 'douserset', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_workers.php

@ -188,9 +188,9 @@ function doworkers($data, $user)
return $pg; return $pg;
} }
# #
function show_workers($page, $menu, $name, $user) function show_workers($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'doworkers', $page, $menu, $name, $user); gopage($info, NULL, 'doworkers', $page, $menu, $name, $user);
} }
# #
?> ?>

4
pool/page_workmgt.php

@ -86,9 +86,9 @@ function doworkmgt($data, $user)
return $pg; return $pg;
} }
# #
function show_workmgt($page, $menu, $name, $user) function show_workmgt($info, $page, $menu, $name, $user)
{ {
gopage(NULL, 'doworkmgt', $page, $menu, $name, $user); gopage($info, NULL, 'doworkmgt', $page, $menu, $name, $user);
} }
# #
?> ?>

14
pool/prime.php

@ -8,6 +8,12 @@ include_once('base.php');
# #
function process($p, $user, $menu) function process($p, $user, $menu)
{ {
$info = homeInfo($user);
if (is_array($info) && isset($info['u_multiaddr']))
{
if (isset($menu['Account']))
$menu['Account']['Addresses'] = 'addrmgt';
}
if ($user == 'Kano' || $user == 'ckolivas' || $user == 'wvr2' || $user == 'aphorise') if ($user == 'Kano' || $user == 'ckolivas' || $user == 'wvr2' || $user == 'aphorise')
{ {
$menu['Admin']['ckp'] = 'ckp'; $menu['Admin']['ckp'] = 'ckp';
@ -26,9 +32,9 @@ function process($p, $user, $menu)
} }
if ($page === '') if ($page === '')
showPage('index', $menu, '', $user); showPage($info, 'index', $menu, '', $user);
else else
showPage($page, $menu, $n, $user); showPage($info, $page, $menu, $n, $user);
} }
# #
function def_menu() function def_menu()
@ -80,11 +86,11 @@ function check()
{ {
$p = getparam('k', true); $p = getparam('k', true);
if ($p == 'reset') if ($p == 'reset')
showPage('reset', $dmenu, '', $who); showPage(NULL, 'reset', $dmenu, '', $who);
else else
{ {
if (requestRegister() == true) if (requestRegister() == true)
showPage('reg', $dmenu, '', $who); showPage(NULL, 'reg', $dmenu, '', $who);
else else
{ {
$p = getparam('k', true); $p = getparam('k', true);

2
pool/socket.php

@ -9,7 +9,7 @@ function socktmo($socket, $factor)
$factor = 1; $factor = 1;
# on a slower server increase this base value # on a slower server increase this base value
$tmo = 2; $tmo = 8;
$usetmo = $tmo * $factor; $usetmo = $tmo * $factor;
$sec = floor($usetmo); $sec = floor($usetmo);

185
src/ckdb.c

@ -1070,9 +1070,9 @@ static void free_workinfo_data(K_ITEM *item)
DATA_WORKINFO(workinfo, item); DATA_WORKINFO(workinfo, item);
if (workinfo->transactiontree) if (workinfo->transactiontree)
free(workinfo->transactiontree); FREENULL(workinfo->transactiontree);
if (workinfo->merklehash) if (workinfo->merklehash)
free(workinfo->merklehash); FREENULL(workinfo->merklehash);
} }
static void free_sharesummary_data(K_ITEM *item) static void free_sharesummary_data(K_ITEM *item)
@ -1082,8 +1082,7 @@ static void free_sharesummary_data(K_ITEM *item)
DATA_SHARESUMMARY(sharesummary, item); DATA_SHARESUMMARY(sharesummary, item);
if (sharesummary->workername) { if (sharesummary->workername) {
LIST_MEM_SUB(sharesummary_free, sharesummary->workername); LIST_MEM_SUB(sharesummary_free, sharesummary->workername);
free(sharesummary->workername); FREENULL(sharesummary->workername);
sharesummary->workername = NULL;
} }
SET_CREATEBY(sharesummary_free, sharesummary->createby, EMPTY); SET_CREATEBY(sharesummary_free, sharesummary->createby, EMPTY);
SET_CREATECODE(sharesummary_free, sharesummary->createcode, EMPTY); SET_CREATECODE(sharesummary_free, sharesummary->createcode, EMPTY);
@ -1099,7 +1098,7 @@ static void free_optioncontrol_data(K_ITEM *item)
DATA_OPTIONCONTROL(optioncontrol, item); DATA_OPTIONCONTROL(optioncontrol, item);
if (optioncontrol->optionvalue) if (optioncontrol->optionvalue)
free(optioncontrol->optionvalue); FREENULL(optioncontrol->optionvalue);
} }
static void free_markersummary_data(K_ITEM *item) static void free_markersummary_data(K_ITEM *item)
@ -1108,7 +1107,7 @@ static void free_markersummary_data(K_ITEM *item)
DATA_MARKERSUMMARY(markersummary, item); DATA_MARKERSUMMARY(markersummary, item);
if (markersummary->workername) if (markersummary->workername)
free(markersummary->workername); FREENULL(markersummary->workername);
SET_CREATEBY(markersummary_free, markersummary->createby, EMPTY); SET_CREATEBY(markersummary_free, markersummary->createby, EMPTY);
SET_CREATECODE(markersummary_free, markersummary->createcode, EMPTY); SET_CREATECODE(markersummary_free, markersummary->createcode, EMPTY);
SET_CREATEINET(markersummary_free, markersummary->createinet, EMPTY); SET_CREATEINET(markersummary_free, markersummary->createinet, EMPTY);
@ -1123,9 +1122,9 @@ static void free_workmarkers_data(K_ITEM *item)
DATA_WORKMARKERS(workmarkers, item); DATA_WORKMARKERS(workmarkers, item);
if (workmarkers->poolinstance) if (workmarkers->poolinstance)
free(workmarkers->poolinstance); FREENULL(workmarkers->poolinstance);
if (workmarkers->description) if (workmarkers->description)
free(workmarkers->description); FREENULL(workmarkers->description);
} }
static void free_marks_data(K_ITEM *item) static void free_marks_data(K_ITEM *item)
@ -1134,11 +1133,11 @@ static void free_marks_data(K_ITEM *item)
DATA_MARKS(marks, item); DATA_MARKS(marks, item);
if (marks->poolinstance && marks->poolinstance != EMPTY) if (marks->poolinstance && marks->poolinstance != EMPTY)
free(marks->poolinstance); FREENULL(marks->poolinstance);
if (marks->description && marks->description != EMPTY) if (marks->description && marks->description != EMPTY)
free(marks->description); FREENULL(marks->description);
if (marks->extra && marks->extra != EMPTY) if (marks->extra && marks->extra != EMPTY)
free(marks->extra); FREENULL(marks->extra);
} }
#define FREE_TREE(_tree) \ #define FREE_TREE(_tree) \
@ -1473,7 +1472,7 @@ static enum cmd_values breakdown(K_TREE **trf_root, K_STORE **trf_store,
STRNCPY(transfer->name, json_key); STRNCPY(transfer->name, json_key);
if (!ok || find_in_ktree(*trf_root, item, cmp_transfer, ctx)) { if (!ok || find_in_ktree(*trf_root, item, cmp_transfer, ctx)) {
if (transfer->mvalue != transfer->svalue) if (transfer->mvalue != transfer->svalue)
free(transfer->mvalue); FREENULL(transfer->mvalue);
k_add_head(transfer_free, item); k_add_head(transfer_free, item);
} else { } else {
*trf_root = add_to_ktree(*trf_root, item, cmp_transfer); *trf_root = add_to_ktree(*trf_root, item, cmp_transfer);
@ -1505,7 +1504,7 @@ static enum cmd_values breakdown(K_TREE **trf_root, K_STORE **trf_store,
if (find_in_ktree(*trf_root, item, cmp_transfer, ctx)) { if (find_in_ktree(*trf_root, item, cmp_transfer, ctx)) {
if (transfer->mvalue != transfer->svalue) if (transfer->mvalue != transfer->svalue)
free(transfer->mvalue); FREENULL(transfer->mvalue);
k_add_head(transfer_free, item); k_add_head(transfer_free, item);
} else { } else {
*trf_root = add_to_ktree(*trf_root, item, cmp_transfer); *trf_root = add_to_ktree(*trf_root, item, cmp_transfer);
@ -1946,7 +1945,7 @@ static void summarise_userstats()
//upgrade = false; //upgrade = false;
if (error[0]) if (error[0])
LOGERR(error); LOGERR("%s", error);
} }
if (locked) { if (locked) {
@ -2016,7 +2015,8 @@ static void *logger(__maybe_unused void *arg)
K_ITEM *lq_item; K_ITEM *lq_item;
LOGQUEUE *lq; LOGQUEUE *lq;
char buf[128]; char buf[128];
tv_t now; tv_t now, then;
int count;
pthread_detach(pthread_self()); pthread_detach(pthread_self());
@ -2037,7 +2037,7 @@ static void *logger(__maybe_unused void *arg)
while (lq_item) { while (lq_item) {
DATA_LOGQUEUE(lq, lq_item); DATA_LOGQUEUE(lq, lq_item);
LOGFILE(lq->msg); LOGFILE(lq->msg);
free(lq->msg); FREENULL(lq->msg);
K_WLOCK(logqueue_free); K_WLOCK(logqueue_free);
k_add_head(logqueue_free, lq_item); k_add_head(logqueue_free, lq_item);
@ -2051,18 +2051,26 @@ static void *logger(__maybe_unused void *arg)
} }
K_WLOCK(logqueue_free); K_WLOCK(logqueue_free);
count = logqueue_store->count;
setnow(&now); setnow(&now);
snprintf(buf, sizeof(buf), "logstopping.%d.%ld,%ld", snprintf(buf, sizeof(buf), "logstopping.%d.%ld,%ld",
logqueue_store->count, count, now.tv_sec, now.tv_usec);
now.tv_sec, now.tv_usec);
LOGFILE(buf); LOGFILE(buf);
if (logqueue_store->count) if (count)
LOGERR("%s", buf); LOGERR("%s", buf);
lq_item = logqueue_store->head; lq_item = logqueue_store->head;
copy_tv(&then, &now);
while (lq_item) { while (lq_item) {
DATA_LOGQUEUE(lq, lq_item); DATA_LOGQUEUE(lq, lq_item);
LOGFILE(lq->msg); LOGFILE(lq->msg);
free(lq->msg); FREENULL(lq->msg);
count--;
setnow(&now);
if ((now.tv_sec - then.tv_sec) > 10) {
snprintf(buf, sizeof(buf), "logging ... %d", count);
LOGERR("%s", buf);
copy_tv(&then, &now);
}
lq_item = lq_item->next; lq_item = lq_item->next;
} }
K_WUNLOCK(logqueue_free); K_WUNLOCK(logqueue_free);
@ -2073,6 +2081,7 @@ static void *logger(__maybe_unused void *arg)
snprintf(buf, sizeof(buf), "logstop.%ld,%ld", snprintf(buf, sizeof(buf), "logstop.%ld,%ld",
now.tv_sec, now.tv_usec); now.tv_sec, now.tv_usec);
LOGFILE(buf); LOGFILE(buf);
LOGWARNING("%s", buf);
return NULL; return NULL;
} }
@ -2320,8 +2329,7 @@ static void *socketer(__maybe_unused void *arg)
rep = malloc(siz); rep = malloc(siz);
snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans); snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans);
send_unix_msg(sockd, rep); send_unix_msg(sockd, rep);
free(ans); FREENULL(ans);
ans = NULL;
switch (cmdnum) { switch (cmdnum) {
case CMD_AUTH: case CMD_AUTH:
STORELASTREPLY(auth); STORELASTREPLY(auth);
@ -2385,8 +2393,7 @@ static void *socketer(__maybe_unused void *arg)
rep = malloc(siz); rep = malloc(siz);
snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans); snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans);
send_unix_msg(sockd, rep); send_unix_msg(sockd, rep);
free(ans); FREENULL(ans);
ans = NULL;
if (cmdnum == CMD_DSP) if (cmdnum == CMD_DSP)
free(rep); free(rep);
else { else {
@ -2419,10 +2426,8 @@ static void *socketer(__maybe_unused void *arg)
rep = malloc(siz); rep = malloc(siz);
snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans); snprintf(rep, siz, "%s.%ld.%s", id, now.tv_sec, ans);
send_unix_msg(sockd, rep); send_unix_msg(sockd, rep);
free(ans); FREENULL(ans);
ans = NULL; FREENULL(rep);
free(rep);
rep = NULL;
} }
break; break;
// Always queue (ok.queued) // Always queue (ok.queued)
@ -2494,7 +2499,7 @@ static void *socketer(__maybe_unused void *arg)
while (item) { while (item) {
DATA_TRANSFER(transfer, item); DATA_TRANSFER(transfer, item);
if (transfer->mvalue != transfer->svalue) if (transfer->mvalue != transfer->svalue)
free(transfer->mvalue); FREENULL(transfer->mvalue);
item = item->next; item = item->next;
} }
K_WLOCK(transfer_free); K_WLOCK(transfer_free);
@ -2622,7 +2627,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
while (item) { while (item) {
DATA_TRANSFER(transfer, item); DATA_TRANSFER(transfer, item);
if (transfer->mvalue != transfer->svalue) if (transfer->mvalue != transfer->svalue)
free(transfer->mvalue); FREENULL(transfer->mvalue);
item = item->next; item = item->next;
} }
K_WLOCK(transfer_free); K_WLOCK(transfer_free);
@ -2641,6 +2646,73 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
#define MAX_READ (10 * 1024 * 1024) #define MAX_READ (10 * 1024 * 1024)
static char *reload_buf; static char *reload_buf;
static bool logline(char *buf, int siz, FILE *fp, char *filename)
{
char *ret;
ret = fgets_unlocked(buf, siz, fp);
if (!ret && ferror(fp)) {
int err = errno;
quithere(1, "Read failed on %s (%d) '%s'",
filename, err, strerror(err));
}
if (ret)
return true;
else
return false;
}
static struct decomp {
char *ext;
char *fmt;
} dec_list[] = {
{ ".bz2", "bzcat -q '%s'" },
{ ".gz", "zcat -q '%s'" },
{ ".lrz", "lrzip -q -d -o - '%s'" },
{ NULL, NULL }
};
static bool logopen(char **filename, FILE **fp, bool *apipe)
{
char buf[1024];
char *name;
size_t len;
int i;
*apipe = false;
*fp = NULL;
*fp = fopen(*filename, "re");
if (*fp)
return true;
for (i = 0; dec_list[i].ext; i++) {
len = strlen(*filename) + strlen(dec_list[i].ext);
name = malloc(len + 1);
if (!name)
quithere(1, "(%d) OOM", (int)len);
strcpy(name, *filename);
strcat(name, dec_list[i].ext);
if (access(name, R_OK))
free(name);
else {
snprintf(buf, sizeof(buf), dec_list[i].fmt, name);
*fp = popen(buf, "re");
if (!(*fp)) {
int errn = errno;
quithere(1, "Failed to pipe (%d) \"%s\"",
errn, buf);
} else {
*apipe = true;
free(*filename);
*filename = name;
return true;
}
}
}
return false;
}
/* If the reload start file is missing and -r was specified correctly: /* If the reload start file is missing and -r was specified correctly:
* touch the filename reported in "Failed to open 'filename'", * touch the filename reported in "Failed to open 'filename'",
* if ckdb aborts at the beginning of the reload, then start again */ * if ckdb aborts at the beginning of the reload, then start again */
@ -2652,7 +2724,7 @@ static bool reload_from(tv_t *start)
char *missingfirst = NULL, *missinglast = NULL; char *missingfirst = NULL, *missinglast = NULL;
int missing_count; int missing_count;
int processing; int processing;
bool finished = false, matched = false, ret = true; bool finished = false, matched = false, ret = true, ok, apipe = false;
char *filename = NULL; char *filename = NULL;
uint64_t count, total; uint64_t count, total;
tv_t now; tv_t now;
@ -2672,8 +2744,7 @@ static bool reload_from(tv_t *start)
LOGWARNING("%s(): from %s (stamp %s)", __func__, buf, run); LOGWARNING("%s(): from %s (stamp %s)", __func__, buf, run);
filename = rotating_filename(restorefrom, reload_timestamp.tv_sec); filename = rotating_filename(restorefrom, reload_timestamp.tv_sec);
fp = fopen(filename, "re"); if (!logopen(&filename, &fp, &apipe))
if (!fp)
quithere(1, "Failed to open '%s'", filename); quithere(1, "Failed to open '%s'", filename);
setnow(&now); setnow(&now);
@ -2690,21 +2761,24 @@ static bool reload_from(tv_t *start)
processing++; processing++;
count = 0; count = 0;
while (!everyone_die && !matched && fgets_unlocked(reload_buf, MAX_READ, fp)) while (!everyone_die && !matched &&
logline(reload_buf, MAX_READ, fp, filename))
matched = reload_line(conn, filename, ++count, reload_buf); matched = reload_line(conn, filename, ++count, reload_buf);
if (ferror(fp)) {
int err = errno;
quithere(1, "Read failed on %s (%d) '%s'",
filename, err, strerror(err));
}
LOGWARNING("%s(): %sread %"PRIu64" line%s from %s", LOGWARNING("%s(): %sread %"PRIu64" line%s from %s",
__func__, __func__,
everyone_die ? "Shutdown, aborting - " : "", everyone_die ? "Shutdown, aborting - " : "",
count, count == 1 ? "" : "s", count, count == 1 ? "" : "s",
filename); filename);
total += count; total += count;
if (apipe) {
pclose(fp);
if (count == 0) {
quithere(1, "ABORTING - No data returned from "
"compressed file \"%s\"",
filename);
}
} else
fclose(fp); fclose(fp);
free(filename); free(filename);
if (everyone_die || matched) if (everyone_die || matched)
@ -2715,11 +2789,10 @@ static bool reload_from(tv_t *start)
break; break;
} }
filename = rotating_filename(restorefrom, reload_timestamp.tv_sec); filename = rotating_filename(restorefrom, reload_timestamp.tv_sec);
fp = fopen(filename, "re"); ok = logopen(&filename, &fp, &apipe);
if (!fp) { if (!ok) {
missingfirst = strdup(filename); missingfirst = strdup(filename);
free(filename); FREENULL(filename);
filename = NULL;
errno = 0; errno = 0;
missing_count = 1; missing_count = 1;
setnow(&now); setnow(&now);
@ -2736,26 +2809,23 @@ static bool reload_from(tv_t *start)
break; break;
} }
filename = rotating_filename(restorefrom, reload_timestamp.tv_sec); filename = rotating_filename(restorefrom, reload_timestamp.tv_sec);
fp = fopen(filename, "re"); ok = logopen(&filename, &fp, &apipe);
if (fp) if (ok)
break; break;
errno = 0; errno = 0;
if (missing_count++ > 1) if (missing_count++ > 1)
free(missinglast); free(missinglast);
missinglast = strdup(filename); missinglast = strdup(filename);
free(filename); FREENULL(filename);
filename = NULL;
} }
if (missing_count == 1) if (missing_count == 1)
LOGWARNING("%s(): skipped %s", __func__, missingfirst+rflen); LOGWARNING("%s(): skipped %s", __func__, missingfirst+rflen);
else { else {
LOGWARNING("%s(): skipped %d files from %s to %s", LOGWARNING("%s(): skipped %d files from %s to %s",
__func__, missing_count, missingfirst+rflen, missinglast+rflen); __func__, missing_count, missingfirst+rflen, missinglast+rflen);
free(missinglast); FREENULL(missinglast);
missinglast = NULL;
} }
free(missingfirst); FREENULL(missingfirst);
missingfirst = NULL;
} }
} }
@ -2783,10 +2853,7 @@ static bool reload_from(tv_t *start)
} }
reloading = false; reloading = false;
FREENULL(reload_buf);
free(reload_buf);
reload_buf = NULL;
return ret; return ret;
} }
@ -2818,7 +2885,7 @@ static void process_queued(PGconn *conn, K_ITEM *wq_item)
while (item) { while (item) {
DATA_TRANSFER(transfer, item); DATA_TRANSFER(transfer, item);
if (transfer->mvalue != transfer->svalue) if (transfer->mvalue != transfer->svalue)
free(transfer->mvalue); FREENULL(transfer->mvalue);
item = item->next; item = item->next;
} }
K_WLOCK(transfer_free); K_WLOCK(transfer_free);
@ -3150,7 +3217,7 @@ static void confirm_reload()
} }
if (confirm_last_workinfoid == 0) { if (confirm_last_workinfoid == 0) {
LOGWARNING("%s(): there are no unconfirmed sharesummary records in the DB", LOGWARNING("%s(): there are no unconfirmed sharesummary records in the DB",
__func__, buf); __func__);
return; return;
} }
@ -3220,7 +3287,7 @@ static void confirm_reload()
// last from default // last from default
if (confirm_last_workinfoid < confirm_first_workinfoid) { if (confirm_last_workinfoid < confirm_first_workinfoid) {
LOGWARNING("%s(): no unconfirmed sharesummary records before start", LOGWARNING("%s(): no unconfirmed sharesummary records before start",
__func__, buf); __func__);
return; return;
} }
first_reason = "start range"; first_reason = "start range";

28
src/ckdb.h

@ -52,7 +52,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "0.9.6" #define DB_VERSION "0.9.6"
#define CKDB_VERSION DB_VERSION"-0.665" #define CKDB_VERSION DB_VERSION"-0.744"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -64,6 +64,13 @@
#define STRINT(x) STRINT2(x) #define STRINT(x) STRINT2(x)
#define STRINT2(x) #x #define STRINT2(x) #x
#define FREENULL(mem) do { \
if (mem) { \
free(mem); \
mem = NULL; \
} \
} while (0)
// So they can fit into a 1 byte flag field // So they can fit into a 1 byte flag field
#define TRUE_STR "Y" #define TRUE_STR "Y"
#define FALSE_STR "N" #define FALSE_STR "N"
@ -702,6 +709,9 @@ extern K_TREE *useratts_root;
extern K_LIST *useratts_free; extern K_LIST *useratts_free;
extern K_STORE *useratts_store; extern K_STORE *useratts_store;
// This att means the user uses multiple % based payout addresses
#define USER_MULTI_PAYOUT "PayAddresses"
// WORKERS // WORKERS
typedef struct workers { typedef struct workers {
int64_t workerid; int64_t workerid;
@ -744,17 +754,21 @@ typedef struct paymentaddresses {
char payaddress[TXT_BIG+1]; char payaddress[TXT_BIG+1];
int32_t payratio; int32_t payratio;
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
bool match; // Non-db field
} PAYMENTADDRESSES; } PAYMENTADDRESSES;
#define ALLOC_PAYMENTADDRESSES 1024 #define ALLOC_PAYMENTADDRESSES 1024
#define LIMIT_PAYMENTADDRESSES 0 #define LIMIT_PAYMENTADDRESSES 0
#define INIT_PAYMENTADDRESSES(_item) INIT_GENERIC(_item, paymentaddresses) #define INIT_PAYMENTADDRESSES(_item) INIT_GENERIC(_item, paymentaddresses)
#define DATA_PAYMENTADDRESSES(_var, _item) DATA_GENERIC(_var, _item, paymentaddresses, true) #define DATA_PAYMENTADDRESSES(_var, _item) DATA_GENERIC(_var, _item, paymentaddresses, true)
#define DATA_PAYMENTADDRESSES_NULL(_var, _item) DATA_GENERIC(_var, _item, paymentaddresses, false)
extern K_TREE *paymentaddresses_root; extern K_TREE *paymentaddresses_root;
extern K_LIST *paymentaddresses_free; extern K_LIST *paymentaddresses_free;
extern K_STORE *paymentaddresses_store; extern K_STORE *paymentaddresses_store;
#define PAYRATIODEF 1000000
// PAYMENTS // PAYMENTS
typedef struct payments { typedef struct payments {
int64_t paymentid; int64_t paymentid;
@ -857,6 +871,12 @@ typedef struct optioncontrol {
#error "START_POOL_HEIGHT must = (OPTIONCONTROL_HEIGHT+1)" #error "START_POOL_HEIGHT must = (OPTIONCONTROL_HEIGHT+1)"
#endif #endif
/* If set, then cmd_auth() will create unknown users
* It will use the optionvalue as the hex sha256 password hash
* A blank or random/invalid hash will mean the accounts created
* are password locked, like an address account is */
#define OPTIONCONTROL_AUTOADDUSER "AutoAddUser"
extern K_TREE *optioncontrol_root; extern K_TREE *optioncontrol_root;
extern K_LIST *optioncontrol_free; extern K_LIST *optioncontrol_free;
extern K_STORE *optioncontrol_store; extern K_STORE *optioncontrol_store;
@ -1540,7 +1560,9 @@ extern K_ITEM *new_default_worker(PGconn *conn, bool update, int64_t userid, cha
char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root); char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root);
extern void dsp_paymentaddresses(K_ITEM *item, FILE *stream); extern void dsp_paymentaddresses(K_ITEM *item, FILE *stream);
extern cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_paymentaddresses(int64_t userid); extern K_ITEM *find_paymentaddresses(int64_t userid, K_TREE_CTX *ctx);
extern K_ITEM *find_one_payaddress(int64_t userid, char *payaddress, K_TREE_CTX *ctx);
extern K_ITEM *find_any_payaddress(char *payaddress);
extern cmp_t cmp_payments(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_payments(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now); extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now);
@ -1682,7 +1704,7 @@ extern bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault,
char *idlenotificationtime, char *by, char *code, char *idlenotificationtime, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root, bool check); char *inet, tv_t *cd, K_TREE *trf_root, bool check);
extern bool workers_fill(PGconn *conn); extern bool workers_fill(PGconn *conn);
extern K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress, extern bool paymentaddresses_set(PGconn *conn, int64_t userid, K_LIST *pa_store,
char *by, char *code, char *inet, tv_t *cd, char *by, char *code, char *inet, tv_t *cd,
K_TREE *trf_root); K_TREE *trf_root);
extern bool paymentaddresses_fill(PGconn *conn); extern bool paymentaddresses_fill(PGconn *conn);

2
src/ckdb_btc.c

@ -329,7 +329,7 @@ void btc_blockstatus(BLOCKS *blocks)
len = strlen(blocks->blockhash); len = strlen(blocks->blockhash);
if (len != SHA256SIZHEX) { if (len != SHA256SIZHEX) {
LOGERR("%s() invalid blockhash size %d (%d) for block %d", LOGERR("%s() invalid blockhash size %d (%d) for block %d",
__func__, len, SHA256SIZHEX, blocks->height); __func__, (int)len, SHA256SIZHEX, blocks->height);
/* So we don't keep repeating the message /* So we don't keep repeating the message
* This should never happen */ * This should never happen */

287
src/ckdb_cmd.c

@ -161,16 +161,21 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
__maybe_unused char *code, __maybe_unused char *inet, __maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root) __maybe_unused tv_t *notcd, K_TREE *trf_root)
{ {
K_ITEM *i_username, *i_passwordhash, *i_address, *i_email, *u_item, *pa_item; K_ITEM *i_username, *i_passwordhash, *i_rows, *i_address, *i_ratio;
K_ITEM *i_email, *u_item, *pa_item, *old_pa_item;
char *email, *address; char *email, *address;
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
char tmp[1024]; char tmp[1024];
PAYMENTADDRESSES *paymentaddresses; PAYMENTADDRESSES *row, *pa;
K_STORE *pa_store = NULL;
K_TREE_CTX ctx[1];
USERS *users; USERS *users;
char *reason = NULL; char *reason = NULL;
char *answer = NULL; char *answer = NULL;
size_t len, off; size_t len, off;
int32_t ratio;
int rows, i;
bool ok; bool ok;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -206,18 +211,33 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
APPEND_REALLOC(answer, off, len, tmp); APPEND_REALLOC(answer, off, len, tmp);
K_RLOCK(paymentaddresses_free); K_RLOCK(paymentaddresses_free);
pa_item = find_paymentaddresses(users->userid); pa_item = find_paymentaddresses(users->userid, ctx);
K_RUNLOCK(paymentaddresses_free); rows = 0;
if (pa_item) { if (pa_item) {
DATA_PAYMENTADDRESSES(paymentaddresses, pa_item); DATA_PAYMENTADDRESSES(row, pa_item);
snprintf(tmp, sizeof(tmp), "addr=%s", while (pa_item && CURRENT(&(row->expirydate)) &&
paymentaddresses->payaddress); row->userid == users->userid) {
snprintf(tmp, sizeof(tmp), "addr:%d=%s%c",
rows, row->payaddress, FLDSEP);
APPEND_REALLOC(answer, off, len, tmp); APPEND_REALLOC(answer, off, len, tmp);
} else { snprintf(tmp, sizeof(tmp), "ratio:%d=%d%c",
snprintf(tmp, sizeof(tmp), "addr="); rows, row->payratio, FLDSEP);
APPEND_REALLOC(answer, off, len, tmp); APPEND_REALLOC(answer, off, len, tmp);
rows++;
pa_item = prev_in_ktree(ctx);
DATA_PAYMENTADDRESSES_NULL(row, pa_item);
}
} }
K_RUNLOCK(paymentaddresses_free);
snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c",
rows, FLDSEP,
"addr,ratio", FLDSEP);
APPEND_REALLOC(answer, off, len, tmp);
snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s",
"PaymentAddresses", FLDSEP, "");
APPEND_REALLOC(answer, off, len, tmp);
} else { } else {
if (!check_hash(users, transfer_data(i_passwordhash))) { if (!check_hash(users, transfer_data(i_passwordhash))) {
reason = "Incorrect password"; reason = "Incorrect password";
@ -235,30 +255,105 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
email = NULL; email = NULL;
} }
i_address = optional_name(trf_root, "address",
// address rows
i_rows = optional_name(trf_root, "rows",
1, (char *)intpatt,
reply, siz);
if (!i_rows && *reply) {
// Exists, but invalid
reason = "System error";
goto struckout;
}
if (i_rows) {
rows = atoi(transfer_data(i_rows));
if (rows < 0) {
reason = "System error";
goto struckout;
}
if (rows > 0) {
pa_store = k_new_store(paymentaddresses_free);
K_WLOCK(paymentaddresses_free);
for (i = 0; i < rows; i++) {
snprintf(tmp, sizeof(tmp), "ratio:%d", i);
i_ratio = optional_name(trf_root, tmp,
1, (char *)intpatt,
reply, siz);
if (*reply) {
K_WUNLOCK(paymentaddresses_free);
reason = "Invalid ratio";
goto struckout;
}
if (i_ratio)
ratio = atoi(transfer_data(i_ratio));
else
ratio = PAYRATIODEF;
/* 0 = expire/remove the address
* intpatt means it will be >= 0 */
if (ratio == 0)
continue;
snprintf(tmp, sizeof(tmp), "address:%d", i);
i_address = require_name(trf_root, tmp,
ADDR_MIN_LEN, ADDR_MIN_LEN,
(char *)addrpatt, (char *)addrpatt,
reply, siz); reply, siz);
if (i_address) if (!i_address) {
address = transfer_data(i_address); K_WUNLOCK(paymentaddresses_free);
else {
if (*reply) {
reason = "Invalid address"; reason = "Invalid address";
goto struckout; goto struckout;
} }
address = NULL; address = transfer_data(i_address);
pa_item = pa_store->head;
while (pa_item) {
DATA_PAYMENTADDRESSES(row, pa_item);
if (strcmp(row->payaddress, address) == 0) {
K_WUNLOCK(paymentaddresses_free);
reason = "Duplicate address";
goto struckout;
}
pa_item = pa_item->next;
}
pa_item = k_unlink_head(paymentaddresses_free);
DATA_PAYMENTADDRESSES(row, pa_item);
bzero(row, sizeof(*row));
STRNCPY(row->payaddress, address);
row->payratio = ratio;
k_add_head(pa_store, pa_item);
}
K_WUNLOCK(paymentaddresses_free);
} }
}
/* If all addresses have a ratio of zero
* pa_store->count will be 0 */
if ((email == NULL || *email == '\0') && if ((email == NULL || *email == '\0') &&
(address == NULL || *address == '\0')) { (pa_store == NULL || pa_store->count == 0)) {
reason = "Missing/Invalid value"; reason = "Missing/Invalid value";
goto struckout; goto struckout;
} }
if (address && *address) { if (pa_store && pa_store->count > 0) {
if (!btc_valid_address(address)) { pa_item = pa_store->head;
while (pa_item) {
DATA_PAYMENTADDRESSES(row, pa_item);
// Only EVER validate addresses once ... for now
old_pa_item = find_any_payaddress(row->payaddress);
if (old_pa_item) {
/* This test effectively means that
* two users can never add the same
* payout address */
DATA_PAYMENTADDRESSES(pa, old_pa_item);
if (pa->userid != users->userid) {
reason = "Unavailable BTC address";
goto struckout;
}
} else if (!btc_valid_address(row->payaddress)) {
reason = "Invalid BTC address"; reason = "Invalid BTC address";
goto struckout; goto struckout;
} }
pa_item = pa_item->next;
}
} }
if (email && *email) { if (email && *email) {
@ -274,9 +369,9 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
} }
if (address && *address) { if (pa_store && pa_store->count > 0) {
ok = paymentaddresses_set(conn, users->userid, ok = paymentaddresses_set(conn, users->userid,
address, by, pa_store, by,
code, inet, code, inet,
now, trf_root); now, trf_root);
if (!ok) { if (!ok) {
@ -289,6 +384,15 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
struckout: struckout:
if (pa_store) {
if (pa_store->count) {
K_WLOCK(paymentaddresses_free);
k_list_transfer_to_head(pa_store, paymentaddresses_free);
K_WUNLOCK(paymentaddresses_free);
}
k_free_store(pa_store);
pa_store = NULL;
}
if (reason) { if (reason) {
snprintf(reply, siz, "ERR.%s", reason); snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s.%s", cmd, id, reply); LOGERR("%s.%s.%s", cmd, id, reply);
@ -1665,7 +1769,7 @@ awconf:
return strdup(reply); return strdup(reply);
} }
LOGERR("%s.bad.cmd %s", cmd); LOGERR("%s.bad.cmd %s", id, cmd);
return strdup("bad.cmd"); return strdup("bad.cmd");
} }
@ -1801,9 +1905,11 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid; K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid;
K_ITEM *i_enonce1, *i_useragent, *i_preauth; K_ITEM *i_enonce1, *i_useragent, *i_preauth, *u_item, *oc_item;
USERS *users = NULL; USERS *users = NULL;
char *username;
WORKERS *workers = NULL; WORKERS *workers = NULL;
OPTIONCONTROL *optioncontrol;
bool ok; bool ok;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -1816,6 +1922,7 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
i_username = require_name(trf_root, "username", 1, NULL, reply, siz); i_username = require_name(trf_root, "username", 1, NULL, reply, siz);
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
username = transfer_data(i_username);
i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz);
if (!i_workername) if (!i_workername)
@ -1837,8 +1944,23 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
if (!i_preauth) if (!i_preauth)
i_preauth = &auth_preauth; i_preauth = &auth_preauth;
K_RLOCK(optioncontrol_free);
oc_item = find_optioncontrol(OPTIONCONTROL_AUTOADDUSER, cd);
K_RUNLOCK(optioncontrol_free);
if (oc_item) {
K_RLOCK(users_free);
u_item = find_users(username);
K_RUNLOCK(users_free);
if (!u_item) {
DATA_OPTIONCONTROL(optioncontrol, oc_item);
u_item = users_add(conn, username, EMPTY,
optioncontrol->optionvalue,
by, code, inet, cd, trf_root);
}
}
ok = auths_add(conn, transfer_data(i_poolinstance), ok = auths_add(conn, transfer_data(i_poolinstance),
transfer_data(i_username), username,
transfer_data(i_workername), transfer_data(i_workername),
transfer_data(i_clientid), transfer_data(i_clientid),
transfer_data(i_enonce1), transfer_data(i_enonce1),
@ -2031,6 +2153,7 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
__maybe_unused tv_t *notcd, K_TREE *trf_root) __maybe_unused tv_t *notcd, K_TREE *trf_root)
{ {
K_ITEM *i_username, *u_item, *b_item, *p_item, *us_item, look; K_ITEM *i_username, *u_item, *b_item, *p_item, *us_item, look;
K_ITEM *ua_item, *pa_item;
double u_hashrate5m, u_hashrate1hr; double u_hashrate5m, u_hashrate1hr;
char reply[1024], tmp[1024], *buf; char reply[1024], tmp[1024], *buf;
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
@ -2171,9 +2294,34 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
K_RUNLOCK(users_free); K_RUNLOCK(users_free);
} }
// User info to add to or affect the web site display
if (u_item) {
DATA_USERS(users, u_item);
K_RLOCK(useratts_free);
ua_item = find_useratts(users->userid, USER_MULTI_PAYOUT);
K_RUNLOCK(useratts_free);
if (ua_item) {
snprintf(tmp, sizeof(tmp),
"u_multiaddr=1%c", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
if (!(*(users->emailaddress))) {
snprintf(tmp, sizeof(tmp),
"u_noemail=1%c", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
K_RLOCK(paymentaddresses_free);
pa_item = find_paymentaddresses(users->userid, ctx);
K_RUNLOCK(paymentaddresses_free);
if (!pa_item) {
snprintf(tmp, sizeof(tmp),
"u_nopayaddr=1%c", FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
}
}
has_uhr = false; has_uhr = false;
if (p_item && u_item) { if (p_item && u_item) {
DATA_USERS(users, u_item);
K_TREE *userstats_workername_root = new_ktree(); K_TREE *userstats_workername_root = new_ktree();
u_hashrate5m = u_hashrate1hr = 0.0; u_hashrate5m = u_hashrate1hr = 0.0;
u_elapsed = -1; u_elapsed = -1;
@ -2740,7 +2888,7 @@ static char *cmd_setopts(PGconn *conn, char *cmd, char *id,
ExecStatusType rescode; ExecStatusType rescode;
PGresult *res; PGresult *res;
bool conned = false; bool conned = false;
K_ITEM *t_item, *oc_item = NULL; K_ITEM *t_item, *oc_item = NULL, *ok = NULL;
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
@ -2788,10 +2936,11 @@ static char *cmd_setopts(PGconn *conn, char *cmd, char *id,
} }
begun = true; begun = true;
} }
if (optioncontrol_item_add(conn, oc_item, now, begun)) { ok = optioncontrol_item_add(conn, oc_item, now, begun);
oc_item = NULL; oc_item = NULL;
if (ok)
db++; db++;
} else { else {
reason = "DBERR"; reason = "DBERR";
goto rollback; goto rollback;
} }
@ -2845,11 +2994,14 @@ static char *cmd_setopts(PGconn *conn, char *cmd, char *id,
} }
begun = true; begun = true;
} }
if (!optioncontrol_item_add(conn, oc_item, now, begun)) { ok = optioncontrol_item_add(conn, oc_item, now, begun);
oc_item = NULL;
if (ok)
db++;
else {
reason = "DBERR"; reason = "DBERR";
goto rollback; goto rollback;
} }
db++;
} }
rollback: rollback:
if (begun) { if (begun) {
@ -2864,15 +3016,6 @@ rollback:
if (conned) if (conned)
PQfinish(conn); PQfinish(conn);
if (reason) { if (reason) {
if (oc_item) {
if (optioncontrol->optionvalue) {
free(optioncontrol->optionvalue);
optioncontrol->optionvalue = NULL;
}
K_WLOCK(optioncontrol_free);
k_add_head(optioncontrol_free, oc_item);
K_WUNLOCK(optioncontrol_free);
}
snprintf(reply, siz, "ERR.%s", reason); snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s.%s", cmd, id, reply); LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply); return strdup(reply);
@ -2975,7 +3118,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
int64_t ss_count, wm_count, ms_count; int64_t ss_count, wm_count, ms_count;
char tv_buf[DATE_BUFSIZ]; char tv_buf[DATE_BUFSIZ];
tv_t cd, begin_tv, block_tv, end_tv; tv_t cd, begin_tv, block_tv, end_tv;
K_TREE_CTX ctx[1], wm_ctx[1], ms_ctx[1]; K_TREE_CTX ctx[1], wm_ctx[1], ms_ctx[1], pay_ctx[1];
double ndiff, total_diff, elapsed; double ndiff, total_diff, elapsed;
double diff_times = 1.0; double diff_times = 1.0;
double diff_add = 0.0; double diff_add = 0.0;
@ -3258,42 +3401,72 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
K_RLOCK(users_free); K_RLOCK(users_free);
u_item = find_userid(miningpayouts->userid); u_item = find_userid(miningpayouts->userid);
K_RUNLOCK(users_free); K_RUNLOCK(users_free);
if (u_item) { if (!u_item) {
snprintf(reply, siz,
"ERR.unknown userid %"PRId64,
miningpayouts->userid);
goto shazbot;
}
DATA_USERS(users, u_item);
K_ITEM *pa_item; K_ITEM *pa_item;
PAYMENTADDRESSES *pa; PAYMENTADDRESSES *pa;
char *payaddress; int64_t paytotal;
double amount;
int count;
pa_item = find_paymentaddresses(miningpayouts->userid); K_RLOCK(paymentaddresses_free);
pa_item = find_paymentaddresses(miningpayouts->userid, pay_ctx);
if (pa_item) { if (pa_item) {
paytotal = 0;
DATA_PAYMENTADDRESSES(pa, pa_item); DATA_PAYMENTADDRESSES(pa, pa_item);
payaddress = pa->payaddress; while (pa_item && CURRENT(&(pa->expirydate)) &&
} else pa->userid == miningpayouts->userid) {
payaddress = "none"; paytotal += pa->payratio;
pa_item = prev_in_ktree(pay_ctx);
DATA_PAYMENTADDRESSES_NULL(pa, pa_item);
}
count = 0;
pa_item = find_paymentaddresses(miningpayouts->userid, pay_ctx);
DATA_PAYMENTADDRESSES_NULL(pa, pa_item);
while (pa_item && CURRENT(&(pa->expirydate)) &&
pa->userid == miningpayouts->userid) {
amount = (double)(miningpayouts->amount) *
(double)pa->payratio / (double)paytotal;
DATA_USERS(users, u_item);
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"user:%d=%s%cpayaddress:%d=%s%c", "user:%d=%s.%d%cpayaddress:%d=%s%c",
rows, users->username, FLDSEP, rows, users->username, ++count, FLDSEP,
rows, payaddress, FLDSEP); rows, pa->payaddress, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp),
"diffacc_user:%d=%.1f%c",
rows, amount, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
rows++;
pa_item = prev_in_ktree(pay_ctx);
DATA_PAYMENTADDRESSES_NULL(pa, pa_item);
}
K_RUNLOCK(paymentaddresses_free);
} else { } else {
K_RUNLOCK(paymentaddresses_free);
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"user:%d=%"PRId64"%cpayaddress:%d=none%c", "user:%d=%s.0%cpayaddress:%d=%s%c",
rows, miningpayouts->userid, FLDSEP, rows, users->username, FLDSEP,
rows, FLDSEP); rows, "none", FLDSEP);
}
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"diffacc_user:%d=%"PRId64"%c", "diffacc_user:%d=%"PRId64"%c",
rows, rows,
miningpayouts->amount, miningpayouts->amount,
FLDSEP); FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
mu_item = next_in_ktree(ctx);
rows++; rows++;
} }
mu_item = next_in_ktree(ctx);
}
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"rows=%d%cflds=%s%c", "rows=%d%cflds=%s%c",
rows, FLDSEP, rows, FLDSEP,

65
src/ckdb_data.c

@ -488,7 +488,7 @@ K_ITEM *_optional_name(K_TREE *trf_root, char *name, int len, char *patt,
dlen = 0; dlen = 0;
if (!mvalue || (int)dlen < len) { if (!mvalue || (int)dlen < len) {
if (!mvalue) { if (!mvalue) {
LOGERR("%s(): field '%s' NULL (%d) from %s():%d", LOGERR("%s(): field '%s' NULL (%d:%d) from %s():%d",
__func__, name, (int)dlen, len, func, line); __func__, name, (int)dlen, len, func, line);
} else } else
snprintf(reply, siz, "failed.short %s", name); snprintf(reply, siz, "failed.short %s", name);
@ -1108,35 +1108,37 @@ void dsp_paymentaddresses(K_ITEM *item, FILE *stream)
} }
} }
// order by userid asc,expirydate desc,payaddress asc // order by expirydate asc,userid asc,payaddress asc
cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b) cmp_t cmp_paymentaddresses(K_ITEM *a, K_ITEM *b)
{ {
PAYMENTADDRESSES *pa, *pb; PAYMENTADDRESSES *pa, *pb;
DATA_PAYMENTADDRESSES(pa, a); DATA_PAYMENTADDRESSES(pa, a);
DATA_PAYMENTADDRESSES(pb, b); DATA_PAYMENTADDRESSES(pb, b);
cmp_t c = CMP_BIGINT(pa->userid, pb->userid); cmp_t c = CMP_TV(pa->expirydate, pb->expirydate);
if (c == 0) { if (c == 0) {
c = CMP_TV(pb->expirydate, pa->expirydate); c = CMP_BIGINT(pa->userid, pb->userid);
if (c == 0) if (c == 0)
c = CMP_STR(pa->payaddress, pb->payaddress); c = CMP_STR(pa->payaddress, pb->payaddress);
} }
return c; return c;
} }
// Only one for now ... /* Find the last CURRENT paymentaddresses for the given userid
K_ITEM *find_paymentaddresses(int64_t userid) * N.B. there can be more than one
* any more will be prev_in_ktree(ctx): CURRENT and userid matches */
K_ITEM *find_paymentaddresses(int64_t userid, K_TREE_CTX *ctx)
{ {
PAYMENTADDRESSES paymentaddresses, *pa; PAYMENTADDRESSES paymentaddresses, *pa;
K_TREE_CTX ctx[1];
K_ITEM look, *item; K_ITEM look, *item;
paymentaddresses.userid = userid; paymentaddresses.expirydate.tv_sec = default_expiry.tv_sec;
paymentaddresses.expirydate.tv_usec = default_expiry.tv_usec;
paymentaddresses.userid = userid+1;
paymentaddresses.payaddress[0] = '\0'; paymentaddresses.payaddress[0] = '\0';
paymentaddresses.expirydate.tv_sec = DATE_S_EOT;
INIT_PAYMENTADDRESSES(&look); INIT_PAYMENTADDRESSES(&look);
look.data = (void *)(&paymentaddresses); look.data = (void *)(&paymentaddresses);
item = find_after_in_ktree(paymentaddresses_root, &look, cmp_paymentaddresses, ctx); item = find_before_in_ktree(paymentaddresses_root, &look, cmp_paymentaddresses, ctx);
if (item) { if (item) {
DATA_PAYMENTADDRESSES(pa, item); DATA_PAYMENTADDRESSES(pa, item);
if (pa->userid == userid && CURRENT(&(pa->expirydate))) if (pa->userid == userid && CURRENT(&(pa->expirydate)))
@ -1147,6 +1149,43 @@ K_ITEM *find_paymentaddresses(int64_t userid)
return NULL; return NULL;
} }
K_ITEM *find_one_payaddress(int64_t userid, char *payaddress, K_TREE_CTX *ctx)
{
PAYMENTADDRESSES paymentaddresses;
K_ITEM look;
paymentaddresses.expirydate.tv_sec = default_expiry.tv_sec;
paymentaddresses.expirydate.tv_usec = default_expiry.tv_usec;
paymentaddresses.userid = userid;
STRNCPY(paymentaddresses.payaddress, payaddress);
INIT_PAYMENTADDRESSES(&look);
look.data = (void *)(&paymentaddresses);
return find_in_ktree(paymentaddresses_root, &look, cmp_paymentaddresses, ctx);
}
/* This will match any user that has the payaddress
* This avoids the bitcoind delay of rechecking an address
* that has EVER been seen before
* However, also, cmd_userset() that uses it, effectively ensures
* that 2 standard users, that mine to a username rather than
* a bitcoin address, cannot ever use the same bitcoin address */
K_ITEM *find_any_payaddress(char *payaddress)
{
PAYMENTADDRESSES *pa;
K_TREE_CTX ctx[1];
K_ITEM *item;
item = first_in_ktree(paymentaddresses_root, ctx);
DATA_PAYMENTADDRESSES_NULL(pa, item);
while (item) {
if (strcmp(pa->payaddress, payaddress) == 0)
return item;
item = next_in_ktree(ctx);
}
return NULL;
}
// order by userid asc,paydate asc,payaddress asc,expirydate desc // order by userid asc,paydate asc,payaddress asc,expirydate desc
cmp_t cmp_payments(K_ITEM *a, K_ITEM *b) cmp_t cmp_payments(K_ITEM *a, K_ITEM *b)
{ {
@ -1749,8 +1788,8 @@ void auto_age_older(PGconn *conn, int64_t workinfoid, char *poolinstance,
min_buf, max_buf); min_buf, max_buf);
} }
LOGWARNING("%s() Auto-aged %"PRId64"(%"PRId64") " LOGWARNING("%s() Auto-aged %"PRId64"(%"PRId64") "
"share%s %d sharesummar%s %d workinfoid%s " "share%s %"PRId64" sharesummar%s %"PRId32
"%s %s", " workinfoid%s %s %s",
__func__, __func__,
s_count_tot, s_diff_tot, s_count_tot, s_diff_tot,
(s_count_tot == 1) ? "" : "s", (s_count_tot == 1) ? "" : "s",
@ -2028,7 +2067,7 @@ void set_block_share_counters()
LOGEMERG("%s(): ERROR workmarker %"PRId64" has an invalid" LOGEMERG("%s(): ERROR workmarker %"PRId64" has an invalid"
" workinfoid range start=%"PRId64" end=%"PRId64 " workinfoid range start=%"PRId64" end=%"PRId64
" due to pool lastblock=%"PRId32 " due to pool lastblock=%"PRId32
" workinfoid="PRId64, " workinfoid=%"PRId64,
__func__, workmarkers->markerid, __func__, workmarkers->markerid,
workmarkers->workinfoidstart, workmarkers->workinfoidstart,
workmarkers->workinfoidend, workmarkers->workinfoidend,

272
src/ckdb_dbio.c

@ -1427,10 +1427,10 @@ bool workers_fill(PGconn *conn)
return ok; return ok;
} }
/* Whatever the current paymentaddresses are, replace them with this one /* Whatever the current paymentaddresses are, replace them with the list
* Code allows for zero, one or more current payment address * in pa_store
* even though there currently can only be zero or one */ * Code allows for zero, one or more current payment address */
K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress, bool paymentaddresses_set(PGconn *conn, int64_t userid, K_STORE *pa_store,
char *by, char *code, char *inet, tv_t *cd, char *by, char *code, char *inet, tv_t *cd,
K_TREE *trf_root) K_TREE *trf_root)
{ {
@ -1438,45 +1438,33 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
bool conned = false; bool conned = false;
PGresult *res; PGresult *res;
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
K_ITEM *item, *old, *this, look; K_ITEM *item, *match, *next, *prev;
PAYMENTADDRESSES *row, pa, *thispa; PAYMENTADDRESSES *row, *pa;
char *upd, *ins; char *upd = NULL, *ins;
bool ok = false; size_t len, off;
char *params[4 + HISTORYDATECOUNT]; bool ok = false, first;
int n, par = 0; char *params[1002]; // Limit of 999 addresses per user
char tmp[1024];
int n, par = 0, count, matches;
LOGDEBUG("%s(): add", __func__); LOGDEBUG("%s(): add", __func__);
K_WLOCK(paymentaddresses_free); // Quick early abort
item = k_unlink_head(paymentaddresses_free); if (pa_store->count > 999)
K_WUNLOCK(paymentaddresses_free); return false;
DATA_PAYMENTADDRESSES(row, item);
row->paymentaddressid = nextid(conn, "paymentaddressid", 1,
cd, by, code, inet);
if (row->paymentaddressid == 0)
goto unitem;
row->userid = userid;
STRNCPY(row->payaddress, payaddress);
row->payratio = 1000000;
HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row);
upd = "update paymentaddresses set expirydate=$1 where userid=$2 and expirydate=$3"; /* Since we are merging the changes in rather than just
par = 0; * replacing the db contents, lock the data for the duration
params[par++] = tv_to_buf(cd, NULL, 0); * of the update to ensure nothing else changes it */
params[par++] = bigint_to_buf(row->userid, NULL, 0); K_WLOCK(paymentaddresses_free);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 3, params);
if (conn == NULL) { if (conn == NULL) {
conn = dbconnect(); conn = dbconnect();
conned = true; conned = true;
} }
/* This means the nextid updates will rollback on an error, but also
* means that it will lock the nextid record for the whole update */
res = PQexec(conn, "Begin", CKPQ_WRITE); res = PQexec(conn, "Begin", CKPQ_WRITE);
rescode = PQresultStatus(res); rescode = PQresultStatus(res);
if (!PGOK(rescode)) { if (!PGOK(rescode)) {
@ -1485,6 +1473,64 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
} }
PQclear(res); PQclear(res);
// First step - DB expire all the old/changed records in RAM
LOGDEBUG("%s(): Step 1 userid=%"PRId64, __func__, userid);
count = matches = 0;
APPEND_REALLOC_INIT(upd, off, len);
APPEND_REALLOC(upd, off, len,
"update paymentaddresses set expirydate=$1 where "
"userid=$2 and expirydate=$3 and payaddress in (");
par = 0;
params[par++] = tv_to_buf(cd, NULL, 0);
params[par++] = bigint_to_buf(userid, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
first = true;
item = find_paymentaddresses(userid, ctx);
DATA_PAYMENTADDRESSES_NULL(row, item);
while (item && CURRENT(&(row->expirydate)) && row->userid == userid) {
/* This is only possible if the DB was directly updated with
* more than 999 records then reloaded (or a code bug) */
if (++count > 999)
break;
// Find the RAM record in pa_store
match = pa_store->head;
while (match) {
DATA_PAYMENTADDRESSES(pa, match);
if (strcmp(pa->payaddress, row->payaddress) == 0 &&
pa->payratio == row->payratio) {
pa->match = true; // Don't store it
matches++;
break;
}
match = match->next;
}
if (!match) {
// No matching replacement, so expire 'row'
params[par++] = str_to_buf(row->payaddress, NULL, 0);
if (!first)
APPEND_REALLOC(upd, off, len, ",");
first = false;
snprintf(tmp, sizeof(tmp), "$%d", par);
APPEND_REALLOC(upd, off, len, tmp);
}
item = prev_in_ktree(ctx);
DATA_PAYMENTADDRESSES_NULL(row, item);
}
LOGDEBUG("%s(): Step 1 par=%d count=%d matches=%d first=%s", __func__,
par, count, matches, first ? "true" : "false");
// Too many, or none need expiring = don't do the update
if (count > 999 || first == true) {
for (n = 0; n < par; n++)
free(params[n]);
par = 0;
// Too many
if (count > 999)
goto rollback;
} else {
APPEND_REALLOC(upd, off, len, ")");
PARCHKVAL(par, par, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res); rescode = PQresultStatus(res);
PQclear(res); PQclear(res);
@ -1493,22 +1539,44 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
goto rollback; goto rollback;
} }
LOGDEBUG("%s(): Step 1 expired %d", __func__, par-3);
for (n = 0; n < par; n++) for (n = 0; n < par; n++)
free(params[n]); free(params[n]);
par = 0;
}
// Second step - add the non-matching records to the DB
LOGDEBUG("%s(): Step 2", __func__);
ins = "insert into paymentaddresses " ins = "insert into paymentaddresses "
"(paymentaddressid,userid,payaddress,payratio" "(paymentaddressid,userid,payaddress,payratio"
HISTORYDATECONTROL ") values (" PQPARAM9 ")"; HISTORYDATECONTROL ") values (" PQPARAM9 ")";
count = 0;
match = pa_store->head;
while (match) {
DATA_PAYMENTADDRESSES(row, match);
if (!row->match) {
row->paymentaddressid = nextid(conn, "paymentaddressid", 1,
cd, by, code, inet);
if (row->paymentaddressid == 0)
goto rollback;
row->userid = userid;
HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row);
par = 0; par = 0;
params[par++] = bigint_to_buf(row->paymentaddressid, NULL, 0); params[par++] = bigint_to_buf(row->paymentaddressid, NULL, 0);
params[par++] = bigint_to_buf(row->userid, NULL, 0); params[par++] = bigint_to_buf(row->userid, NULL, 0);
params[par++] = str_to_buf(row->payaddress, NULL, 0); params[par++] = str_to_buf(row->payaddress, NULL, 0);
params[par++] = int_to_buf(row->payratio, NULL, 0); params[par++] = int_to_buf(row->payratio, NULL, 0);
HISTORYDATEPARAMS(params, par, row); HISTORYDATEPARAMS(params, par, row);
PARCHK(par, params); PARCHKVAL(par, 9, params); // As per PQPARAM9 above
res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); res = PQexecParams(conn, ins, par, NULL, (const char **)params,
NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res); rescode = PQresultStatus(res);
PQclear(res); PQclear(res);
if (!PGOK(rescode)) { if (!PGOK(rescode)) {
@ -1516,6 +1584,16 @@ K_ITEM *paymentaddresses_set(PGconn *conn, int64_t userid, char *payaddress,
goto rollback; goto rollback;
} }
for (n = 0; n < par; n++)
free(params[n]);
par = 0;
count++;
}
match = match->next;
}
LOGDEBUG("%s(): Step 2 inserted %d", __func__, count);
ok = true; ok = true;
rollback: rollback:
if (ok) if (ok)
@ -1529,46 +1607,62 @@ unparam:
PQfinish(conn); PQfinish(conn);
for (n = 0; n < par; n++) for (n = 0; n < par; n++)
free(params[n]); free(params[n]);
unitem: FREENULL(upd);
K_WLOCK(paymentaddresses_free); // Third step - do step 1 and 2 to the RAM version of the DB
if (!ok) LOGDEBUG("%s(): Step 3, ok=%s", __func__, ok ? "true" : "false");
k_add_head(paymentaddresses_free, item); matches = count = n = 0;
if (ok) {
// Change the expiry on all records that we expired in the DB
item = find_paymentaddresses(userid, ctx);
DATA_PAYMENTADDRESSES_NULL(row, item);
while (item && CURRENT(&(row->expirydate)) && row->userid == userid) {
prev = prev_in_ktree(ctx);
// Find the RAM record in pa_store
match = pa_store->head;
while (match) {
DATA_PAYMENTADDRESSES(pa, match);
if (strcmp(pa->payaddress, row->payaddress) == 0 &&
pa->payratio == row->payratio) {
break;
}
match = match->next;
}
if (match)
matches++;
else { else {
// Change the expiry on all the old ones // It wasn't a match, thus it was expired
pa.userid = userid; n++;
pa.expirydate.tv_sec = DATE_S_EOT; paymentaddresses_root = remove_from_ktree(paymentaddresses_root, item,
pa.payaddress[0] = '\0';
INIT_PAYMENTADDRESSES(&look);
look.data = (void *)(&pa);
// Tree order is expirydate desc
old = find_after_in_ktree(paymentaddresses_root, &look,
cmp_paymentaddresses, ctx);
while (old) {
this = old;
DATA_PAYMENTADDRESSES(thispa, this);
if (thispa->userid != userid)
break;
old = next_in_ktree(ctx);
/* Tree remove+add below doesn't matter since
* this test will avoid reprocessing */
if (CURRENT(&(thispa->expirydate))) {
paymentaddresses_root = remove_from_ktree(paymentaddresses_root, this,
cmp_paymentaddresses); cmp_paymentaddresses);
copy_tv(&(thispa->expirydate), cd); copy_tv(&(row->expirydate), cd);
paymentaddresses_root = add_to_ktree(paymentaddresses_root, this, paymentaddresses_root = add_to_ktree(paymentaddresses_root, item,
cmp_paymentaddresses); cmp_paymentaddresses);
} }
item = prev;
DATA_PAYMENTADDRESSES_NULL(row, item);
} }
paymentaddresses_root = add_to_ktree(paymentaddresses_root, item,
// Add in all the non-matching ps_store
match = pa_store->head;
while (match) {
next = match->next;
DATA_PAYMENTADDRESSES(pa, match);
if (!pa->match) {
paymentaddresses_root = add_to_ktree(paymentaddresses_root, match,
cmp_paymentaddresses); cmp_paymentaddresses);
k_add_head(paymentaddresses_store, item); k_unlink_item(pa_store, match);
k_add_head(paymentaddresses_store, match);
count++;
} }
match = next;
}
}
LOGDEBUG("%s(): Step 3, untouched %d expired %d added %d", __func__, matches, n, count);
K_WUNLOCK(paymentaddresses_free); K_WUNLOCK(paymentaddresses_free);
if (ok) // Calling function must clean up anything left in pa_store
return item; return ok;
else
return NULL;
} }
bool paymentaddresses_fill(PGconn *conn) bool paymentaddresses_fill(PGconn *conn)
@ -1841,7 +1935,7 @@ K_ITEM *optioncontrol_item_add(PGconn *conn, K_ITEM *oc_item, tv_t *cd, bool beg
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
PGresult *res; PGresult *res;
K_ITEM *old_item, look; K_ITEM *old_item, look;
OPTIONCONTROL *row; OPTIONCONTROL *row, *optioncontrol;
char *upd, *ins; char *upd, *ins;
bool ok = false; bool ok = false;
char *params[4 + HISTORYDATECOUNT]; char *params[4 + HISTORYDATECOUNT];
@ -1935,13 +2029,17 @@ nostart:
free(params[n]); free(params[n]);
K_WLOCK(optioncontrol_free); K_WLOCK(optioncontrol_free);
if (!ok) if (!ok) {
// Cleanup item passed in
FREENULL(row->optionvalue);
k_add_head(optioncontrol_free, oc_item); k_add_head(optioncontrol_free, oc_item);
else { } else {
// Discard it // Discard old
if (old_item) { if (old_item) {
DATA_OPTIONCONTROL(optioncontrol, old_item);
optioncontrol_root = remove_from_ktree(optioncontrol_root, old_item, optioncontrol_root = remove_from_ktree(optioncontrol_root, old_item,
cmp_optioncontrol); cmp_optioncontrol);
FREENULL(optioncontrol->optionvalue);
k_add_head(optioncontrol_free, old_item); k_add_head(optioncontrol_free, old_item);
} }
optioncontrol_root = add_to_ktree(optioncontrol_root, oc_item, cmp_optioncontrol); optioncontrol_root = add_to_ktree(optioncontrol_root, oc_item, cmp_optioncontrol);
@ -1962,7 +2060,6 @@ K_ITEM *optioncontrol_add(PGconn *conn, char *optionname, char *optionvalue,
{ {
K_ITEM *item; K_ITEM *item;
OPTIONCONTROL *row; OPTIONCONTROL *row;
bool ok = false;
LOGDEBUG("%s(): add", __func__); LOGDEBUG("%s(): add", __func__);
@ -1990,19 +2087,7 @@ K_ITEM *optioncontrol_add(PGconn *conn, char *optionname, char *optionvalue,
HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row); HISTORYDATETRANSFER(trf_root, row);
ok = optioncontrol_item_add(conn, item, cd, begun); return optioncontrol_item_add(conn, item, cd, begun);
if (!ok) {
free(row->optionvalue);
K_WLOCK(optioncontrol_free);
k_add_head(optioncontrol_free, item);
K_WUNLOCK(optioncontrol_free);
}
if (ok)
return item;
else
return NULL;
} }
bool optioncontrol_fill(PGconn *conn) bool optioncontrol_fill(PGconn *conn)
@ -2084,8 +2169,10 @@ bool optioncontrol_fill(PGconn *conn)
optioncontrol_root = add_to_ktree(optioncontrol_root, item, cmp_optioncontrol); optioncontrol_root = add_to_ktree(optioncontrol_root, item, cmp_optioncontrol);
k_add_head(optioncontrol_store, item); k_add_head(optioncontrol_store, item);
} }
if (!ok) if (!ok) {
FREENULL(row->optionvalue);
k_add_head(optioncontrol_free, item); k_add_head(optioncontrol_free, item);
}
K_WUNLOCK(optioncontrol_free); K_WUNLOCK(optioncontrol_free);
PQclear(res); PQclear(res);
@ -2148,10 +2235,8 @@ int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstance,
K_WLOCK(workinfo_free); K_WLOCK(workinfo_free);
if (find_in_ktree(workinfo_root, item, cmp_workinfo, ctx)) { if (find_in_ktree(workinfo_root, item, cmp_workinfo, ctx)) {
free(row->transactiontree); FREENULL(row->transactiontree);
row->transactiontree = NULL; FREENULL(row->merklehash);
free(row->merklehash);
row->merklehash = NULL;
workinfoid = row->workinfoid; workinfoid = row->workinfoid;
k_add_head(workinfo_free, item); k_add_head(workinfo_free, item);
K_WUNLOCK(workinfo_free); K_WUNLOCK(workinfo_free);
@ -2213,10 +2298,8 @@ unparam:
K_WLOCK(workinfo_free); K_WLOCK(workinfo_free);
if (workinfoid == -1) { if (workinfoid == -1) {
free(row->transactiontree); FREENULL(row->transactiontree);
row->transactiontree = NULL; FREENULL(row->merklehash);
free(row->merklehash);
row->merklehash = NULL;
k_add_head(workinfo_free, item); k_add_head(workinfo_free, item);
} else { } else {
if (row->transactiontree && *(row->transactiontree)) { if (row->transactiontree && *(row->transactiontree)) {
@ -3165,8 +3248,7 @@ bool sharesummary_fill(PGconn *conn)
DATA_SHARESUMMARY(row, item); DATA_SHARESUMMARY(row, item);
if (row->workername) { if (row->workername) {
LIST_MEM_SUB(sharesummary_free, row->workername); LIST_MEM_SUB(sharesummary_free, row->workername);
free(row->workername); FREENULL(row->workername);
row->workername = NULL;
} }
k_add_head(sharesummary_free, item); k_add_head(sharesummary_free, item);
} }

2
src/ckpmsg.c

@ -130,7 +130,7 @@ int main(int argc, char **argv)
continue; continue;
} }
mkstamp(stamp, sizeof(stamp)); mkstamp(stamp, sizeof(stamp));
LOGNOTICE("%s Received response: %s", stamp, buf); LOGMSGSIZ(65536, LOG_NOTICE, "%s Received response: %s", stamp, buf);
} }
dealloc(buf); dealloc(buf);

2
src/ckpool.c

@ -694,7 +694,7 @@ static bool write_pid(ckpool_t *ckp, const char *path, pid_t pid)
if (ckp->handover) { if (ckp->handover) {
if (pid_wait(oldpid, 500)) if (pid_wait(oldpid, 500))
goto out; goto out;
LOGWARNING("Old process pid %d failed to shutdown cleanly, terminating"); LOGWARNING("Old process pid %d failed to shutdown cleanly, terminating", oldpid);
} }
if (!ckp->killold) { if (!ckp->killold) {
LOGEMERG("Process %s pid %d still exists, start ckpool with -k if you wish to kill it", LOGEMERG("Process %s pid %d still exists, start ckpool with -k if you wish to kill it",

12
src/connector.c

@ -219,7 +219,7 @@ static int drop_client(cdata_t *cdata, client_instance_t *client)
ck_wunlock(&cdata->lock); ck_wunlock(&cdata->lock);
if (fd > -1) if (fd > -1)
LOGINFO("Connector dropped client %d fd %d", client->id, fd); LOGINFO("Connector dropped client %"PRId64" fd %d", client->id, fd);
return fd; return fd;
} }
@ -320,7 +320,7 @@ reparse:
if (!(val = json_loads(msg, 0, NULL))) { if (!(val = json_loads(msg, 0, NULL))) {
char *buf = strdup("Invalid JSON, disconnecting\n"); char *buf = strdup("Invalid JSON, disconnecting\n");
LOGINFO("Client id %d sent invalid json message %s", client->id, msg); LOGINFO("Client id %ld sent invalid json message %s", client->id, msg);
send_client(cdata, client->id, buf); send_client(cdata, client->id, buf);
invalidate_client(ckp, cdata, client); invalidate_client(ckp, cdata, client);
return; return;
@ -480,11 +480,11 @@ void *sender(void *arg)
ret = wait_write_select(fd, 0); ret = wait_write_select(fd, 0);
if (ret < 1) { if (ret < 1) {
if (ret < 0) { if (ret < 0) {
LOGINFO("Client id %d fd %d interrupted", client->id, fd); LOGINFO("Client id %ld fd %d interrupted", client->id, fd);
invalidate_client(ckp, cdata, client); invalidate_client(ckp, cdata, client);
goto contfree; goto contfree;
} }
LOGDEBUG("Client %d not ready for writes", client->id); LOGDEBUG("Client %"PRId64" not ready for writes", client->id);
/* Append it to the tail of the delayed sends list. /* Append it to the tail of the delayed sends list.
* This is the only function that alters it so no * This is the only function that alters it so no
@ -496,7 +496,7 @@ void *sender(void *arg)
while (sender_send->len) { while (sender_send->len) {
ret = send(fd, sender_send->buf + ofs, sender_send->len , 0); ret = send(fd, sender_send->buf + ofs, sender_send->len , 0);
if (unlikely(ret < 0)) { if (unlikely(ret < 0)) {
LOGINFO("Client id %d fd %d disconnected", client->id, fd); LOGINFO("Client id %ld fd %d disconnected", client->id, fd);
invalidate_client(ckp, cdata, client); invalidate_client(ckp, cdata, client);
break; break;
} }
@ -589,7 +589,7 @@ static void passthrough_client(cdata_t *cdata, client_instance_t *client)
{ {
char *buf; char *buf;
LOGINFO("Connector adding passthrough client %d", client->id); LOGINFO("Connector adding passthrough client %"PRId64, client->id);
client->passthrough = true; client->passthrough = true;
ASPRINTF(&buf, "{\"result\": true}\n"); ASPRINTF(&buf, "{\"result\": true}\n");
send_client(cdata, client->id, buf); send_client(cdata, client->id, buf);

27
src/libckpool.h

@ -191,14 +191,25 @@ static inline void flip_80(void *dest_p, const void *src_p)
void logmsg(int loglevel, const char *fmt, ...); void logmsg(int loglevel, const char *fmt, ...);
#define LOGEMERG(fmt, ...) logmsg(LOG_EMERG, fmt, ##__VA_ARGS__) #define DEFLOGBUFSIZ 512
#define LOGALERT(fmt, ...) logmsg(LOG_ALERT, fmt, ##__VA_ARGS__)
#define LOGCRIT(fmt, ...) logmsg(LOG_CRIT, fmt, ##__VA_ARGS__) #define LOGMSGSIZ(__siz, __lvl, __fmt, ...) do { \
#define LOGERR(fmt, ...) logmsg(LOG_ERR, fmt, ##__VA_ARGS__) char tmp42[__siz]; \
#define LOGWARNING(fmt, ...) logmsg(LOG_WARNING, fmt, ##__VA_ARGS__) snprintf(tmp42, sizeof(tmp42), __fmt, ##__VA_ARGS__); \
#define LOGNOTICE(fmt, ...) logmsg(LOG_NOTICE, fmt, ##__VA_ARGS__) logmsg(__lvl, "%s", tmp42); \
#define LOGINFO(fmt, ...) logmsg(LOG_INFO, fmt, ##__VA_ARGS__) } while(0)
#define LOGDEBUG(fmt, ...) logmsg(LOG_DEBUG, fmt, ##__VA_ARGS__)
#define LOGMSG(_lvl, _fmt, ...) \
LOGMSGSIZ(DEFLOGBUFSIZ, _lvl, _fmt, ##__VA_ARGS__)
#define LOGEMERG(fmt, ...) LOGMSG(LOG_EMERG, fmt, ##__VA_ARGS__)
#define LOGALERT(fmt, ...) LOGMSG(LOG_ALERT, fmt, ##__VA_ARGS__)
#define LOGCRIT(fmt, ...) LOGMSG(LOG_CRIT, fmt, ##__VA_ARGS__)
#define LOGERR(fmt, ...) LOGMSG(LOG_ERR, fmt, ##__VA_ARGS__)
#define LOGWARNING(fmt, ...) LOGMSG(LOG_WARNING, fmt, ##__VA_ARGS__)
#define LOGNOTICE(fmt, ...) LOGMSG(LOG_NOTICE, fmt, ##__VA_ARGS__)
#define LOGINFO(fmt, ...) LOGMSG(LOG_INFO, fmt, ##__VA_ARGS__)
#define LOGDEBUG(fmt, ...) LOGMSG(LOG_DEBUG, fmt, ##__VA_ARGS__)
#define IN_FMT_FFL " in %s %s():%d" #define IN_FMT_FFL " in %s %s():%d"
#define quitfrom(status, _file, _func, _line, fmt, ...) do { \ #define quitfrom(status, _file, _func, _line, fmt, ...) do { \

36
src/stratifier.c

@ -2636,12 +2636,12 @@ out:
if (client->first_invalid < client->last_share.tv_sec || !client->first_invalid) if (client->first_invalid < client->last_share.tv_sec || !client->first_invalid)
client->first_invalid = now_t; client->first_invalid = now_t;
else if (client->first_invalid && client->first_invalid < now_t - 120) { else if (client->first_invalid && client->first_invalid < now_t - 120) {
LOGNOTICE("Client %d rejecting for 120s, disconnecting", client->id); LOGNOTICE("Client %ld rejecting for 120s, disconnecting", client->id);
stratum_send_message(sdata, client, "Disconnecting for continuous invalid shares"); stratum_send_message(sdata, client, "Disconnecting for continuous invalid shares");
client->reject = 2; client->reject = 2;
} else if (client->first_invalid && client->first_invalid < now_t - 60) { } else if (client->first_invalid && client->first_invalid < now_t - 60) {
if (!client->reject) { if (!client->reject) {
LOGINFO("Client %d rejecting for 60s, sending diff", client->id); LOGINFO("Client %ld rejecting for 60s, sending diff", client->id);
stratum_send_diff(sdata, client); stratum_send_diff(sdata, client);
client->reject = 1; client->reject = 1;
} }
@ -2763,8 +2763,10 @@ static void set_worker_mindiff(ckpool_t *ckp, const char *workername, int mindif
ck_runlock(&sdata->instance_lock); ck_runlock(&sdata->instance_lock);
/* They may just have not connected yet */ /* They may just have not connected yet */
if (!instance) if (!instance) {
return LOGINFO("Failed to find user %s in set_worker_mindiff", username); LOGINFO("Failed to find user %s in set_worker_mindiff", username);
return;
}
/* Then find the matching worker instance */ /* Then find the matching worker instance */
ck_rlock(&sdata->instance_lock); ck_rlock(&sdata->instance_lock);
@ -2777,11 +2779,15 @@ static void set_worker_mindiff(ckpool_t *ckp, const char *workername, int mindif
ck_runlock(&sdata->instance_lock); ck_runlock(&sdata->instance_lock);
/* They may just not be connected at the moment */ /* They may just not be connected at the moment */
if (!worker) if (!worker) {
return LOGINFO("Failed to find worker %s in set_worker_mindiff", workername); LOGINFO("Failed to find worker %s in set_worker_mindiff", workername);
return;
}
if (mindiff < 1) if (mindiff < 1) {
return LOGINFO("Worker %s requested invalid diff %ld", worker->workername, mindiff); LOGINFO("Worker %s requested invalid diff %d", worker->workername, mindiff);
return;
}
if (mindiff < ckp->mindiff) if (mindiff < ckp->mindiff)
mindiff = ckp->mindiff; mindiff = ckp->mindiff;
if (mindiff == worker->mindiff) if (mindiff == worker->mindiff)
@ -2816,12 +2822,16 @@ static void suggest_diff(stratum_instance_t *client, const char *method, json_t
sdata_t *sdata = client->ckp->data; sdata_t *sdata = client->ckp->data;
int64_t sdiff; int64_t sdiff;
if (unlikely(!client->authorised)) if (unlikely(!client->authorised)) {
return LOGWARNING("Attempted to suggest diff on unauthorised client %ld", client->id); LOGWARNING("Attempted to suggest diff on unauthorised client %ld", client->id);
return;
}
if (arr_val && json_is_integer(arr_val)) if (arr_val && json_is_integer(arr_val))
sdiff = json_integer_value(arr_val); sdiff = json_integer_value(arr_val);
else if (sscanf(method, "mining.suggest_difficulty(%ld", &sdiff) != 1) else if (sscanf(method, "mining.suggest_difficulty(%ld", &sdiff) != 1) {
return LOGINFO("Failed to parse suggest_difficulty for client %ld", client->id); LOGINFO("Failed to parse suggest_difficulty for client %"PRId64, client->id);
return;
}
if (sdiff == client->suggest_diff) if (sdiff == client->suggest_diff)
return; return;
client->suggest_diff = sdiff; client->suggest_diff = sdiff;
@ -2848,7 +2858,7 @@ static void parse_method(sdata_t *sdata, const int64_t client_id, json_t *id_val
} }
if (unlikely(client->reject == 2)) { if (unlikely(client->reject == 2)) {
LOGINFO("Dropping client %d tagged for lazy invalidation", client_id); LOGINFO("Dropping client %"PRId64" tagged for lazy invalidation", client_id);
snprintf(buf, 255, "dropclient=%ld", client->id); snprintf(buf, 255, "dropclient=%ld", client->id);
send_proc(client->ckp->connector, buf); send_proc(client->ckp->connector, buf);
goto out; goto out;

Loading…
Cancel
Save