Merge branch 'master' into multiproxy
This commit is contained in:
commit
d8f63d8075
7
README
7
README
@ -80,12 +80,15 @@ sudo apt-get install build-essential
|
||||
make
|
||||
|
||||
|
||||
Building with ckdb requires installation of the postgresql development library.
|
||||
Building with ckdb requires installation of the postgresql, gsl and ssl
|
||||
development libraries.
|
||||
|
||||
sudo apt-get install build-essential libpq-dev
|
||||
sudo apt-get install build-essential libpq-dev libgsl0ldbl libgsl0-dev
|
||||
./configure
|
||||
make
|
||||
|
||||
N.B. ckdb also requires libssl-dev but libpq-dev depends on it and installs it
|
||||
|
||||
|
||||
Building from git also requires autoconf and automake
|
||||
|
||||
|
||||
@ -8,7 +8,8 @@ include_once('param.php');
|
||||
function go()
|
||||
{
|
||||
$a = getparam('a', true);
|
||||
if (substr($a, 0, 1) != '1')
|
||||
$f = substr($a, 0, 1);
|
||||
if ($f != '1' and $f != '3')
|
||||
return;
|
||||
if (strlen($a) < 24)
|
||||
return;
|
||||
|
||||
@ -28,6 +28,42 @@ function dq($str)
|
||||
return str_replace('"', "\\\"", $str);
|
||||
}
|
||||
#
|
||||
function daysago($val)
|
||||
{
|
||||
if ($val < -13)
|
||||
return '';
|
||||
|
||||
if ($val < 60)
|
||||
$des = number_format($val,0).'s';
|
||||
else
|
||||
{
|
||||
$val = $val/60;
|
||||
if ($val < 60)
|
||||
$des = number_format($val,1).'min';
|
||||
else
|
||||
{
|
||||
$val = $val/60;
|
||||
if ($val < 24)
|
||||
$des = number_format($val,1).'hrs';
|
||||
else
|
||||
{
|
||||
$val = $val/24;
|
||||
if ($val < 43)
|
||||
$des = number_format($val,1).'days';
|
||||
else
|
||||
{
|
||||
$val = $val/7;
|
||||
if ($val < 10000)
|
||||
$des = number_format($val,1).'wks';
|
||||
else
|
||||
$des = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $des;
|
||||
}
|
||||
#
|
||||
function howlongago($sec)
|
||||
{
|
||||
if ($sec < 60)
|
||||
|
||||
@ -186,7 +186,7 @@ function twofaSetup($to, $whoip, $emailinfo)
|
||||
return false;
|
||||
|
||||
$message = "2FA is ready to be tested.$eol";
|
||||
$message = "It will be enabled once you test it.$eol$eol";
|
||||
$message .= "It will be enabled once you test it.$eol$eol";
|
||||
$message .= $ret;
|
||||
|
||||
return sendnoheader($to, "2FA is Ready to be Enabled", $message, $emailinfo);
|
||||
@ -211,6 +211,46 @@ function twofaEnabled($to, $whoip, $emailinfo)
|
||||
return sendnoheader($to, "2FA is Enabled", $message, $emailinfo);
|
||||
}
|
||||
#
|
||||
function twofaCancel($to, $whoip, $emailinfo)
|
||||
{
|
||||
global $eol;
|
||||
|
||||
if (!isset($emailinfo['KWebURL']))
|
||||
return false;
|
||||
|
||||
$web = $emailinfo['KWebURL'];
|
||||
|
||||
$ret = emailEnd('2fa change', $whoip, $emailinfo);
|
||||
if ($ret === false)
|
||||
return false;
|
||||
|
||||
$message = "2FA setup was cancelled on your account.$eol";
|
||||
$message .= "You can set it up later if you want.$eol$eol";
|
||||
$message .= $ret;
|
||||
|
||||
return sendnoheader($to, "2FA was Cancelled", $message, $emailinfo);
|
||||
}
|
||||
#
|
||||
function twofaRemove($to, $whoip, $emailinfo)
|
||||
{
|
||||
global $eol;
|
||||
|
||||
if (!isset($emailinfo['KWebURL']))
|
||||
return false;
|
||||
|
||||
$web = $emailinfo['KWebURL'];
|
||||
|
||||
$ret = emailEnd('2fa change', $whoip, $emailinfo);
|
||||
if ($ret === false)
|
||||
return false;
|
||||
|
||||
$message = "2FA was removed from your account.$eol";
|
||||
$message .= "You can set it up again later if you want.$eol$eol";
|
||||
$message .= $ret;
|
||||
|
||||
return sendnoheader($to, "2FA was Removed", $message, $emailinfo);
|
||||
}
|
||||
#
|
||||
# getOpts required for email
|
||||
# If they aren't all setup in the DB then email functions will return false
|
||||
function emailOptList()
|
||||
|
||||
@ -6,6 +6,7 @@ function GBaseJS()
|
||||
function sep(d){ans={};var ar=d.split('\\t');var l=ar.length;for(var i=0;i<l;i++){var e=ar[i].indexOf('=');ans[ar[i].substr(0,e)]=ar[i].substr(e+1)}return ans}
|
||||
function dfmt(c,e){var d=new Date(e*1000);var DD,HH,MM;if(c['utc']){DD=d.getUTCDate();HH=d.getUTCHours();MM=d.getUTCMinutes()}else{DD=d.getDate();HH=d.getHours();MM=d.getMinutes()}var ans=''+DD+'/';if(HH<10){ans += '0'}ans += ''+HH+':';if(MM<10){ans += '0'}ans += ''+MM;return ans}
|
||||
function ccb(c,n){var e=document.getElementById(n);c[n]=(e&&e.checked)}
|
||||
function ccbd(c,n,d){var e=document.getElementById(n);if(e){c[n]=e.checked}else{c[n]=d}}
|
||||
function gch(z,zm){if(z<0.5){return 0.5}if(z>(zm-0.5)){return(zm-0.5)}return z}
|
||||
function gchx(c,x){return gch(x*c['xm']+c['xo'],c['ctx'].canvas.width)}
|
||||
function gchy(c,y){return gch((1-y)*c['ym']+c['yo'],c['ctx'].canvas.height)}
|
||||
@ -27,7 +28,7 @@ function gfl(c){c['ctx'].fill()}
|
||||
function gst(c){c['ctx'].stroke()}
|
||||
function gfi(c){gle(c);gst(c)}
|
||||
function gbd(c){gbe(c,0,0);gln(c,1,0);gln(c,1,1);gln(c,0,1);gle(c);gfl(c);gst(c)}
|
||||
function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av,w,cols){gtso(c,xs,ys);gss(c,'black');glw(c,1.5);gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c);glw(c,0.2);var hi=c['ctx'].measureText('M').width, wi=c['ctx'].measureText('1').width;for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')}gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left');var m=Math.round(0.5+xn/20.0);for(var i=0;i<xn;i++){var n=ar[nx+i];var x=ar[vx+i];var xo=(x-x0)/(x1-x0);if(c['skey'] && (i<(xn-1)) && (i%m) == 0){gbe(c,xo,0);gln(c,xo,-0.01);gst(c);gfz(c,xo,0,0,-hi*1.5,n,'#00a050','center')}if(c['slines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}}var xhr=3600+x1-(x1%3600);gss(c,'brown');if(c['tkey'] || c['tlines']){var hlv=c['hln'][c['hl']];hrs=c['hrs'][c['hr']]*3600/hlv;var l=0;tpos=2.7;if(c['over']){tpos=1.5}for(var i=xhr;i>=x0;i-=hrs){var n=dfmt(c,i);var xo=(i-x0)/(x1-x0);if(xo<=1 && c['tkey'] && ((l%hlv)==0)){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*tpos,n,'brown','center')}if(xo<=1 && c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}l++}}glw(c,1);if(c['smooth']){for(var j=1;j<w.length;j++){var f=1;gss(c,cols[j-1]);var xa=0,ya=0,xb=0,yb=0;for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[w[j]+vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0;xb=xo;yb=yo}else{gct(c,(xa+xb)/2,(ya+yb)/2,xb,yb,(xb+xo)/2,(yb+yo)/2)}xa=xb;ya=yb;xb=xo;yb=yo}gct(c,(xa+xb)/2,(ya+yb)/2,xo,yo,xo,yo);gst(c)}}else{for(var j=1;j<w.length;j++){var f=1;gss(c,cols[j-1]);for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[w[j]+vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0}else{gln(c,xo,yo)}}gst(c)}}glw(c,1);for(var j=1;j<w.length;j++){if(av[j-1]>0){gss(c,'red');var y=(av[j-1]-y0)/(y1-y0);gbe(c,0,y);gln(c,1,y);gst(c);var t=''+av[j-1].toFixed(2)+'av';gfz(c,1,y,1,0,t,cols[j-1],'left')}}if(c['tkey']){var col,hrl=c['hrs'].length;for(var i=0;i<hrl;i++){if(c['hr']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+1)*2,''+c['hrs'][i],col,'end')}for(var i=0;i<c['hln'].length;i++){if(c['hl']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+2+hrl)*2,''+c['hrs'][i],col,'end')}}}
|
||||
function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av,w,cols){gtso(c,xs,ys);gss(c,'black');glw(c,1.5);gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c);glw(c,0.2);var hi=c['ctx'].measureText('M').width, wi=c['ctx'].measureText('0').width;for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')}gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left');var m=Math.round(0.5+xn/20.0);for(var i=0;i<xn;i++){var n=ar[nx+i];var x=ar[vx+i];var xo=(x-x0)/(x1-x0);if(c['skey'] && (i<(xn-1)) && (i%m) == 0){gbe(c,xo,0);gln(c,xo,-0.01);gst(c);gfz(c,xo,0,0,-hi*1.5,n,'#00a050','center')}if(c['slines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}}var xhr=3600+x1-(x1%3600);gss(c,'brown');if(c['tkey'] || c['tlines']){var hlv=c['hln'][c['hl']];hrs=c['hrs'][c['hr']]*3600/hlv;var l=0;tpos=2.7;if(c['over']){tpos=1.5}for(var i=xhr;i>=x0;i-=hrs){var n=dfmt(c,i);var xo=(i-x0)/(x1-x0);if(xo<=1 && c['tkey'] && ((l%hlv)==0)){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*tpos,n,'brown','center')}if(xo<=1 && c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}l++}}glw(c,1);if(c['smooth']){for(var j=1;j<w.length;j++){if(c['lin'+j]){var f=1;gss(c,cols[j-1]);var xa=0,ya=0,xb=0,yb=0;for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[w[j]+vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0;xb=xo;yb=yo}else{gct(c,(xa+xb)/2,(ya+yb)/2,xb,yb,(xb+xo)/2,(yb+yo)/2)}xa=xb;ya=yb;xb=xo;yb=yo}gct(c,(xa+xb)/2,(ya+yb)/2,xo,yo,xo,yo);gst(c)}}}else{for(var j=1;j<w.length;j++){if(c['lin'+j]){var f=1;gss(c,cols[j-1]);for(var i=0;i<xn;i++){var x=ar[vx+i];var y=ar[w[j]+vy+i];var xo=(x-x0)/(x1-x0);var yo=(y-y0)/(y1-y0);if(f==1){gbe(c,xo,yo);f=0}else{gln(c,xo,yo)}}gst(c)}}}glw(c,1);for(var j=1;j<w.length;j++){if(av[j-1]>0 && c['lin'+j]){gss(c,'red');var y=(av[j-1]-y0)/(y1-y0);gbe(c,0,y);gln(c,1,y);gst(c);var t=''+av[j-1].toFixed(2)+'av';gfz(c,1,y,1,0,t,cols[j-1],'left')}}if(c['tkey']){var col,hrl=c['hrs'].length;for(var i=0;i<hrl;i++){if(c['hr']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+1)*2,''+c['hrs'][i],col,'end')}for(var i=0;i<c['hln'].length;i++){if(c['hl']==i){col='red'}else{col='black'}gfz(c,1,0,c['xo']-c['pxe'],hi*(i+2+hrl)*2,''+c['hrs'][i],col,'end')}}}
|
||||
function sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}}
|
||||
function gc2(c){var div=document.getElementById('can0');while (div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['pxe']=Math.max(Math.round(c['xm']/250),1)}
|
||||
function gc(c){c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.max(Math.round(c['wx']*0.9+0.5),400);c['ym']=Math.max(Math.round(c['wy']*0.8+0.5),400);if(c['ym']>c['xm']){c['ym']=c['xm']}gc2(c)}
|
||||
@ -36,6 +37,7 @@ function opts(t,i){var e=document.getElementById(i);if(t.checked){e.style.visibi
|
||||
function ghrs(c){c['hrs']=[1,2,3,4,6,8,12,24,48];c['hln']=[1,2,3,4,6]}
|
||||
function ghg(c,dx){var tl=dx/(gchx(c,1)/50)/3600;for(var j=c['hrs'].length-1;j>=0;j--){if(tl<c['hrs'][j]){c['hr']=j}else{break}}if(tl<0.5){var tb=1/tl;for(var k=0;k<c['hln'].length;k++){if(c['hln'][k]<tb){c['hl']=k}else{break}}}else{c['hl']=1}}
|
||||
function gopt(c,cbx){for(var i=0;i<cbx.length;i++){ccb(c,cbx[i])}}
|
||||
function gsh(c,w){for(var i=1;i<w.length;i++){ccbd(c,'lin'+i,true)}}
|
||||
function doinit(cbx,xon){for(var i=0;i<cbx.length;i++){var e=document.getElementById(cbx[i]);if(e){var n=gcn(cbx[i]);if(n==''){if(xon[cbx[i]]){e.checked=true}else{e.checked=false}}else{if(n=='1'){e.checked=true}else{e.checked=false}}}}}
|
||||
";
|
||||
return $g;
|
||||
@ -97,6 +99,7 @@ span.hdr {font-weight:bold;text-decoration:underline;}
|
||||
span.nn {font-weight:bold;color:red;}
|
||||
span.warn {color:orange;font-weight:bold;}
|
||||
span.urg {color:red;font-weight:bold;}
|
||||
span.notice {color:blue;font-weight:bold;font-size:120%;}
|
||||
span.err {color:red;font-weight:bold;font-size:120%;}
|
||||
span.alert {color:red;font-weight:bold;font-size:250%;}
|
||||
input.tiny {width:0px;height:0px;margin:0px;padding:0px;outline:none;border:0px;}
|
||||
@ -104,16 +107,20 @@ input.tiny {width:0px;height:0px;margin:0px;padding:0px;outline:none;border:0px;
|
||||
#n42 a {color:#fff;text-decoration:none;padding:6px;display:block;}
|
||||
#n42 td {min-width:100px;float:left;vertical-align:top;padding:0px 2px;}
|
||||
#n42 td.navboxr {float:right;}
|
||||
#n42 td.nav0 {position:relative;}
|
||||
#n42 td.nav {position:relative;}
|
||||
#n42 td.ts {border-width:1px;border-color:#0022ee;border-style:solid none none none;}
|
||||
#n42 div.sub {left:0px;z-index:42;position:absolute;visibility:hidden;}
|
||||
#n42 td.nav0:hover {background:#0099ee;}
|
||||
#n42 td.nav:hover {background:#0099ee;}
|
||||
#n42 td.nav:hover div.sub {background:#0077ee;visibility:visible;}
|
||||
h1 {margin-top:20px;float:middle;font-size:20px;}
|
||||
.foot, .push {height:50px;}
|
||||
.title {background-color:#909090;}
|
||||
.even {background-color:#cccccc;}
|
||||
.evenu td {background-color:#cccccc;border-bottom:2px solid red;}
|
||||
.odd {background-color:#a8a8a8;}
|
||||
.oddu td {background-color:#a8a8a8;border-bottom:2px solid red;}
|
||||
.hid {display:none;}
|
||||
.dl {text-align:left;padding:2px 8px;}
|
||||
.dr {text-align:right;padding:2px 8px;}
|
||||
|
||||
@ -490,7 +490,7 @@ function pgmenu($menus)
|
||||
$first = false;
|
||||
if ($submenu == $menu)
|
||||
{
|
||||
$ret .= "<tr><td class=nav onclick=''>".makeLink($item)."$menu</a>";
|
||||
$ret .= "<tr><td class=nav0>".makeLink($item)."$menu</a>";
|
||||
$ret .= '<div class=sub><table cellpadding=0 cellspacing=0 border=0 width=100%>';
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ function app_txt($ones)
|
||||
return $app;
|
||||
}
|
||||
#
|
||||
function set_2fa($data, $user, $tfa, $ans, $err)
|
||||
function set_2fa($data, $user, $tfa, $ans, $err, $msg)
|
||||
{
|
||||
$draw = false;
|
||||
|
||||
@ -20,10 +20,12 @@ function set_2fa($data, $user, $tfa, $ans, $err)
|
||||
if ($err !== null and $err != '')
|
||||
$pg .= "<span class=err>$err<br><br></span>";
|
||||
|
||||
if ($msg !== null and $msg != '')
|
||||
$pg .= "<span class=notice>$msg<br><br></span>";
|
||||
|
||||
$pg .= '<table cellpadding=20 cellspacing=0 border=1>';
|
||||
$pg .= '<tr class=dc><td><center>';
|
||||
|
||||
$pg .= makeForm('2fa');
|
||||
$pg .= '<table cellpadding=5 cellspacing=0 border=0>';
|
||||
$pg .= '<tr class=dc><td>';
|
||||
switch ($tfa)
|
||||
@ -33,9 +35,10 @@ function set_2fa($data, $user, $tfa, $ans, $err)
|
||||
$pg .= "You don't have Two Factor Authentication (2FA) setup yet<br><br>";
|
||||
$pg .= 'To use 2FA you need an App on your phone/tablet<br>';
|
||||
$pg .= app_txt('ones');
|
||||
$pg .= makeForm('2fa');
|
||||
$pg .= 'Click here to begin the setup process for 2FA: ';
|
||||
$pg .= '<input type=submit name=Setup value=Setup>';
|
||||
$pg .= '</td></tr>';
|
||||
$pg .= '</form></td></tr>';
|
||||
break;
|
||||
case 'test':
|
||||
$pg .= '<tr class=dc><td>';
|
||||
@ -66,8 +69,9 @@ function set_2fa($data, $user, $tfa, $ans, $err)
|
||||
$pg .= '<div id=can0><canvas id=can width=1 height=1>';
|
||||
$pg .= 'A qrcode will show here if your browser supports html5/canvas';
|
||||
$pg .= "</canvas></div><br>";
|
||||
$pg .= makeForm('2fa');
|
||||
$pg .= 'Then enter your App 2FA Value: <input name=Value value="" size=10> ';
|
||||
$pg .= '<input type=submit name=Test value=Test></td></tr>';
|
||||
$pg .= '<input type=submit name=Test value=Test></form></td></tr>';
|
||||
$pg .= '<tr class=dl><td>';
|
||||
$pg .= app_txt('2FA apps');
|
||||
$pg .= '<span class=urg>N.B.</span> if you wish to setup 2FA on more than one device,<br>';
|
||||
@ -79,20 +83,32 @@ function set_2fa($data, $user, $tfa, $ans, $err)
|
||||
$pg .= 'so your should copy it and store it somewhere securely.<br>';
|
||||
$pg .= 'For security reasons, the site will not show you an active <span class=urg>2FA Secret Key</span>.<br>';
|
||||
$pg .= '</td></tr>';
|
||||
$pg .= '<tr class=dl><td>';
|
||||
$pg .= makeForm('2fa');
|
||||
$pg .= '<br>If you wish to cancel setting up 2FA, click here: ';
|
||||
$pg .= '<input type=submit name=Cancel value=Cancel></form></td></tr>';
|
||||
break;
|
||||
case 'ok':
|
||||
$pg .= '<tr class=dc><td>';
|
||||
$pg .= '2FA is enabled on your account.<br><br>';
|
||||
$pg .= 'If you wish to replace your Secret Key with a new one:<br><br>';
|
||||
$pg .= makeForm('2fa');
|
||||
$pg .= 'Current 2FA Value: <input name=Value value="" size=10> ';
|
||||
$pg .= '<input type=submit name=New value=New><span class=st1>*</span><br><br>';
|
||||
$pg .= '<input type=submit name=New value=New><span class=st1>*</span>';
|
||||
$pg .= '</form><br><br>';
|
||||
$pg .= '<span class=st1>*</span>WARNING: replacing the Secret Key will disable 2FA<br>';
|
||||
$pg .= 'until you successfully test the new key,<br>';
|
||||
$pg .= 'thus getting a new key is effectively the same as disabling 2FA.<br><br>';
|
||||
$pg .= '</td></tr>';
|
||||
$pg .= '<tr class=dc><td>';
|
||||
$pg .= makeForm('2fa');
|
||||
$pg .= 'If you wish to remove 2FA from your account,<br>';
|
||||
$pg .= 'enter your App 2FA Value: <input name=Value value="" size=10><br>';
|
||||
$pg .= 'then click remove: <input type=submit name=Remove value=Remove>';
|
||||
$pg .= '</form></td></tr>';
|
||||
break;
|
||||
}
|
||||
$pg .= '</table></form>';
|
||||
$pg .= '</table>';
|
||||
$pg .= '</center></td></tr>';
|
||||
|
||||
$pg .= '<tr class=dl><td>';
|
||||
@ -147,34 +163,53 @@ function set_2fa($data, $user, $tfa, $ans, $err)
|
||||
#
|
||||
function do2fa($data, $user)
|
||||
{
|
||||
$mailmode = '';
|
||||
$err = '';
|
||||
$msg = '';
|
||||
$setup = getparam('Setup', false);
|
||||
$testemail = false;
|
||||
if ($setup === 'Setup')
|
||||
{
|
||||
// rand() included as part of the entropy
|
||||
$ans = get2fa($user, 'setup', rand(1073741824,2147483647), 0);
|
||||
$testemail = true;
|
||||
$mailmode = 'Setup';
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = getparam('Value', false);
|
||||
$test = getparam('Test', false);
|
||||
if ($test === 'Test' and $value !== null)
|
||||
$can = getparam('Cancel', false);
|
||||
if ($can === 'Cancel')
|
||||
{
|
||||
$ans = get2fa($user, 'test', 0, $value);
|
||||
$testemail = true;
|
||||
$ans = get2fa($user, 'untest', 0, 0);
|
||||
$mailmode = 'Cancel';
|
||||
}
|
||||
else
|
||||
{
|
||||
$nw = getparam('New', false);
|
||||
if ($nw === 'New' and $value !== null)
|
||||
$value = getparam('Value', false);
|
||||
$test = getparam('Test', false);
|
||||
if ($test === 'Test' and $value !== null)
|
||||
{
|
||||
$ans = get2fa($user, 'new', rand(1073741824,2147483647), $value);
|
||||
$testemail = true;
|
||||
$ans = get2fa($user, 'test', 0, $value);
|
||||
$mailmode = 'Test';
|
||||
}
|
||||
else
|
||||
$ans = get2fa($user, '', 0, 0);
|
||||
{
|
||||
$nw = getparam('New', false);
|
||||
if ($nw === 'New' and $value !== null)
|
||||
{
|
||||
$ans = get2fa($user, 'new', rand(1073741824,2147483647), $value);
|
||||
$mailmode = 'New';
|
||||
}
|
||||
else
|
||||
{
|
||||
$rem = getparam('Remove', false);
|
||||
if ($rem === 'Remove' and $value !== null)
|
||||
{
|
||||
$ans = get2fa($user, 'remove', 0, $value);
|
||||
$mailmode = 'Remove';
|
||||
}
|
||||
else
|
||||
$ans = get2fa($user, '', 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ans['STATUS'] != 'ok')
|
||||
@ -184,7 +219,7 @@ function do2fa($data, $user)
|
||||
if (isset($ans['2fa_error']))
|
||||
$err = $ans['2fa_error'];
|
||||
|
||||
if ($testemail and $err == '')
|
||||
if ($mailmode != '' and $err == '')
|
||||
{
|
||||
$ans2 = userSettings($user);
|
||||
if ($ans2['STATUS'] != 'ok')
|
||||
@ -199,12 +234,16 @@ function do2fa($data, $user)
|
||||
$err = 'An error occurred, check your details below';
|
||||
else
|
||||
{
|
||||
if ($setup === 'Setup')
|
||||
if ($mailmode === 'Setup')
|
||||
twofaSetup($email, zeip(), $emailinfo);
|
||||
else if ($test === 'Test')
|
||||
else if ($mailmode === 'Test')
|
||||
twofaEnabled($email, zeip(), $emailinfo);
|
||||
else if ($nw === 'New')
|
||||
else if ($mailmode === 'New')
|
||||
twofaSetup($email, zeip(), $emailinfo);
|
||||
else if ($mailmode === 'Cancel')
|
||||
twofaCancel($email, zeip(), $emailinfo);
|
||||
else if ($mailmode === 'Remove')
|
||||
twofaRemove($email, zeip(), $emailinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,7 +252,10 @@ function do2fa($data, $user)
|
||||
$tfa = null;
|
||||
else
|
||||
$tfa = $ans['2fa_status'];
|
||||
$pg = set_2fa($data, $user, $tfa, $ans, $err);
|
||||
if (isset($ans['2fa_msg']))
|
||||
$msg = $ans['2fa_msg'];
|
||||
|
||||
$pg = set_2fa($data, $user, $tfa, $ans, $err, $msg);
|
||||
return $pg;
|
||||
}
|
||||
#
|
||||
|
||||
@ -93,12 +93,15 @@ function doblocks($data, $user)
|
||||
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n";
|
||||
$pg .= "<tr class=title>";
|
||||
$pg .= "<td class=dl>Description</td>";
|
||||
$pg .= "<td class=dr>Time</td>";
|
||||
$pg .= "<td class=dr>Diff%</td>";
|
||||
$pg .= "<td class=dr>Mean%</td>";
|
||||
$pg .= "<td class=dr>CDF[Erl]</td>";
|
||||
$pg .= "<td class=dr>Luck%</td>";
|
||||
$pg .= "</tr>\n";
|
||||
|
||||
$since = $data['info']['lastblock'];
|
||||
|
||||
$count = $ans['s_rows'];
|
||||
for ($i = 0; $i < $count; $i++)
|
||||
{
|
||||
@ -108,6 +111,7 @@ function doblocks($data, $user)
|
||||
$row = 'odd';
|
||||
|
||||
$desc = $ans['s_desc:'.$i];
|
||||
$age = daysago($since - $ans['s_prevcreatedate:'.$i]);
|
||||
$diff = number_format(100 * $ans['s_diffratio:'.$i], 2);
|
||||
$mean = number_format(100 * $ans['s_diffmean:'.$i], 2);
|
||||
|
||||
@ -120,6 +124,7 @@ function doblocks($data, $user)
|
||||
|
||||
$pg .= "<tr class=$row>";
|
||||
$pg .= "<td class=dl>$desc Blocks</td>";
|
||||
$pg .= "<td class=dr>$age</td>";
|
||||
$pg .= "<td class=dr>$diff%</td>";
|
||||
$pg .= "<td class=dr>$mean%</td>";
|
||||
$pg .= "<td class=dr$bg>$cdferldsp</td>";
|
||||
|
||||
@ -14,6 +14,7 @@ function dompayouts($data, $user)
|
||||
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n";
|
||||
$pg .= "<tr class=title>";
|
||||
$pg .= "<td class=dr>Block</td>";
|
||||
$pg .= "<td class=dr>Block UTC</td>";
|
||||
$pg .= "<td class=dr>Miner Reward</td>";
|
||||
$pg .= "<td class=dr>N Diff</td>";
|
||||
$pg .= "<td class=dr>N Range</td>";
|
||||
@ -36,6 +37,7 @@ function dompayouts($data, $user)
|
||||
|
||||
$pg .= "<tr class=$row>";
|
||||
$pg .= '<td class=dr>'.$ans['height:'.$i].'</td>';
|
||||
$pg .= '<td class=dr>'.gmdate('j/M H:i',$ans['blockcreatedate:'.$i]).'</td>';
|
||||
$pg .= '<td class=dr>'.btcfmt($ans['minerreward:'.$i]).'</td>';
|
||||
$diffused = $ans['diffused:'.$i];
|
||||
$pg .= '<td class=dr>'.difffmt($diffused).'</td>';
|
||||
@ -63,7 +65,7 @@ function dompayouts($data, $user)
|
||||
|
||||
$pg .= "<tr class=$row>";
|
||||
$pg .= '<td class=dr>Total:</td>';
|
||||
$pg .= '<td class=dl colspan=7></td>';
|
||||
$pg .= '<td class=dl colspan=8></td>';
|
||||
$pg .= '<td class=dr>'.btcfmt($totamt).'</td>';
|
||||
$pg .= "</tr>\n";
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ $g = "function gdrw(c,d,cbx){gc(c);ghrs(c);gopt(c,cbx);
|
||||
gfs(c,'white');gss(c,'#0000c0');glw(c,2);gbd(c);
|
||||
var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0,tda=[];
|
||||
var w=d['arp'].split(',');var cols=d['cols'].split(',');
|
||||
gsh(c,w);
|
||||
for(var j=1;j<w.length;j++){tda[j-1]=0}
|
||||
for(var i=0;i<rows;i++){var s=parseFloat(d['start:'+i]);var e=parseFloat(d['end:'+i]);d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax<e){xmax=e}d['vx:'+i]=(s+e)/2.0;
|
||||
for(var j=1;j<w.length;j++){var pre=w[j];var ths=0,nam=pre+'diffacc:'+i;if(d[nam]){var da=parseFloat(d[nam]);ths=(da/(e-s))*Math.pow(2,32)/Math.pow(10,12);tda[j-1]+=da}d[pre+'ths:'+i]=ths;if(ymin==-1||ymin>ths){ymin=ths}if(ths>ymax)ymax=ths}
|
||||
|
||||
@ -65,7 +65,8 @@ function doregres($data, $u)
|
||||
<td class=dl><input type=submit name=Register value=Register></td></tr>
|
||||
<tr><td colspan=2 class=dc><br><font size=-1><span class=st1>*</span>
|
||||
All fields are required<br>Your Username can't be a BTC address</font></td></tr>
|
||||
<tr><td colspan=2 class=dc><br>". passrequires() . "</td></tr>
|
||||
<tr><td colspan=2 class=dc><font size=-1><br>Note: your username is upper/lowercase sensitive,<br>
|
||||
and you must also have upper/lowercase correct on all your miners<br><br>" . passrequires() . "</font></td></tr>
|
||||
</table>
|
||||
</form>";
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ function doshifts($data, $user)
|
||||
$pg .= "<td class=dr>Avg Hs</td>";
|
||||
$pg .= "<td class=dr>Shares</td>";
|
||||
$pg .= "<td class=dr>Avg Share</td>";
|
||||
$pg .= "<td class=dr>Rewards</td>";
|
||||
$pg .= "</tr>\n";
|
||||
|
||||
if (($ans['STATUS'] != 'ok') || !isset($ans['prefix_all']))
|
||||
@ -26,10 +27,14 @@ function doshifts($data, $user)
|
||||
$pg = '<h1>Last '.($count+1).' Shifts</h1>'.$pg;
|
||||
for ($i = 0; $i < $count; $i++)
|
||||
{
|
||||
$u = '';
|
||||
if (isset($ans['lastpayoutstart:'.$i])
|
||||
&& $ans['lastpayoutstart:'.$i] != '')
|
||||
$u = 'u';
|
||||
if (($i % 2) == 0)
|
||||
$row = 'even';
|
||||
$row = "even$u";
|
||||
else
|
||||
$row = 'odd';
|
||||
$row = "odd$u";
|
||||
|
||||
$pg .= "<tr class=$row>";
|
||||
$shifname = $ans['shift:'.$i];
|
||||
@ -66,6 +71,7 @@ function doshifts($data, $user)
|
||||
else
|
||||
$avgsh = 0;
|
||||
$pg .= '<td class=dr>'.number_format($avgsh, 2).'</td>';
|
||||
$pg .= '<td class=dr>'.$ans['rewards:'.$i].'</td>';
|
||||
$pg .= "</tr>\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ $g = "function gdrw(c,d,cbx){gc(c);ghrs(c);gopt(c,cbx);
|
||||
gfs(c,'white');gss(c,'#0000c0');glw(c,2);gbd(c);
|
||||
var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0,tda=[];
|
||||
var w=d['arp'].split(',');var cols=d['cols'].split(',');
|
||||
gsh(c,w);
|
||||
for(var j=1;j<w.length;j++){tda[j-1]=0}
|
||||
for(var i=0;i<rows;i++){var s=parseFloat(d['start:'+i]);var e=parseFloat(d['end:'+i]);d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax<e){xmax=e}d['vx:'+i]=(s+e)/2.0;
|
||||
for(var j=1;j<w.length;j++){var pre=w[j];var ths=0,nam=pre+'diffacc:'+i;if(d[nam]){var da=parseFloat(d[nam]);ths=(da/(e-s))*Math.pow(2,32)/Math.pow(10,12);tda[j-1]+=da}d[pre+'ths:'+i]=ths;if(ymin==-1||ymin>ths){ymin=ths}if(ths>ymax)ymax=ths;document.getElementById('worker'+j).value=d[pre+'worker']}
|
||||
@ -72,7 +73,8 @@ function dousperf($data, $user)
|
||||
$pg .= '<form>';
|
||||
|
||||
$tt = "<ul class=tip><li>all = all workers</li><li>noname = worker with no workername</li>";
|
||||
$tt .= "<li>or full workername without the username i.e. .worker or _worker</li></ul>";
|
||||
$tt .= "<li>or full workername without the username i.e. .worker or _worker</li>";
|
||||
$tt .= "<li>add a '*' on the end to match multiple workers e.g. .S3*</li></ul>";
|
||||
$pg .= "<span class=q onclick='tip(\"wtip\",6000)'>?</span>";
|
||||
$pg .= "<span class=tip0><span class=notip id=wtip>$tt</span></span>";
|
||||
|
||||
@ -82,7 +84,8 @@ function dousperf($data, $user)
|
||||
foreach ($cols as $col)
|
||||
{
|
||||
$i++;
|
||||
$pg .= " <span class=nb><font color=$col>Worker$i:</font>";
|
||||
$pg .= " <span class=nb><font color=$col>Worker$i";
|
||||
$pg .= "<input type=checkbox id=lin$i checked onclick='godrw(0)'>:</font>";
|
||||
$pg .= "<input type=text size=10 id=worker$i$onch> </span>";
|
||||
|
||||
if ($i > 1)
|
||||
|
||||
@ -8,7 +8,8 @@ include_once('param.php');
|
||||
function go()
|
||||
{
|
||||
$a = getparam('a', true);
|
||||
if (substr($a, 0, 1) != '1')
|
||||
$f = substr($a, 0, 1);
|
||||
if ($f != '1' and $f != '3')
|
||||
return;
|
||||
if (preg_match('/^[a-zA-Z0-9]{24,}[\._]?[a-zA-Z0-9\._]*$/', $a) === false)
|
||||
return;
|
||||
|
||||
51
src/ckdb.c
51
src/ckdb.c
@ -36,30 +36,7 @@
|
||||
* much larger DB tables so that ckdb is effectively ready for messages
|
||||
* almost immediately
|
||||
* The first ckpool message allows us to know where ckpool is up to
|
||||
* in the CCLs and thus where to stop processing the CCLs to stay in
|
||||
* sync with ckpool
|
||||
* If ckpool isn't running, then the reload will complete at the end of
|
||||
* the last CCL file, however if the 1st message arrives from ckpool while
|
||||
* processing the CCLs, that will mark the point where to stop processing
|
||||
* but can also produce a fatal error at the end of processing, reporting
|
||||
* the ckpool message, if the message was not found in the CCL processing
|
||||
* after the message was received
|
||||
* This can be caused by two circumstances:
|
||||
* 1) the disk had not yet written it to the CCL when ckdb read EOF and
|
||||
* ckpool was started at about the same time as the reload completed.
|
||||
* This can be seen if the message displayed in the fatal error IS NOT
|
||||
* in ckdb's message logfile.
|
||||
* A ckdb restart will resolve this
|
||||
* 2) ckpool was started at the time of the end of the reload, but the
|
||||
* message was written to disk and found in the CCL before it was
|
||||
* processed in the message queue.
|
||||
* This can be seen if the message displayed in the fatal error IS in
|
||||
* ckdb's message logfile and means the messages after it in ckdb's
|
||||
* message logfile have already been processed.
|
||||
* Again, a ckdb restart will resolve this
|
||||
* In both the above (very rare) cases, if ckdb was to continue running,
|
||||
* it would break the synchronisation and could cause DB problems, so
|
||||
* ckdb aborting and needing a complete restart resolves it
|
||||
* in the CCLs - see reload_from() for how this is handled
|
||||
* The users table, required for the authorise messages, is always updated
|
||||
* immediately
|
||||
*/
|
||||
@ -301,6 +278,7 @@ static sem_t socketer_sem;
|
||||
char *btc_server = "http://127.0.0.1:8330";
|
||||
char *btc_auth;
|
||||
int btc_timeout = 5;
|
||||
cklock_t btc_lock;
|
||||
|
||||
char *by_default = "code";
|
||||
char *inet_default = "127.0.0.1";
|
||||
@ -442,6 +420,7 @@ K_STORE *miningpayouts_store;
|
||||
// PAYOUTS
|
||||
K_TREE *payouts_root;
|
||||
K_TREE *payouts_id_root;
|
||||
K_TREE *payouts_wid_root;
|
||||
K_LIST *payouts_free;
|
||||
K_STORE *payouts_store;
|
||||
cklock_t process_pplns_lock;
|
||||
@ -794,12 +773,11 @@ static bool getdata3()
|
||||
if (!confirm_sharesummary) {
|
||||
if (!(ok = paymentaddresses_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
/* FYI must be after blocks */
|
||||
if (!(ok = payments_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
if (!(ok = miningpayouts_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
if (!(ok = payouts_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
}
|
||||
if (!(ok = workinfo_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
@ -808,6 +786,11 @@ static bool getdata3()
|
||||
/* must be after workinfo */
|
||||
if (!(ok = workmarkers_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
if (!confirm_sharesummary) {
|
||||
/* must be after workmarkers */
|
||||
if (!(ok = payouts_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
}
|
||||
if (!(ok = markersummary_fill(conn)) || everyone_die)
|
||||
goto sukamudai;
|
||||
if (!confirm_sharesummary && !everyone_die)
|
||||
@ -1104,6 +1087,7 @@ static void alloc_storage()
|
||||
payouts_store = k_new_store(payouts_free);
|
||||
payouts_root = new_ktree();
|
||||
payouts_id_root = new_ktree();
|
||||
payouts_wid_root = new_ktree();
|
||||
|
||||
auths_free = k_new_list("Auths", sizeof(AUTHS),
|
||||
ALLOC_AUTHS, LIMIT_AUTHS, true);
|
||||
@ -1322,6 +1306,7 @@ static void dealloc_storage()
|
||||
FREE_ALL(poolstats);
|
||||
FREE_ALL(auths);
|
||||
|
||||
FREE_TREE(payouts_wid);
|
||||
FREE_TREE(payouts_id);
|
||||
FREE_TREE(payouts);
|
||||
FREE_STORE_DATA(payouts);
|
||||
@ -1498,8 +1483,7 @@ static bool setup_data()
|
||||
if (workinfo_current) {
|
||||
DATA_WORKINFO(wic, workinfo_current);
|
||||
STRNCPY(wi.coinbase1, wic->coinbase1);
|
||||
wi.createdate.tv_sec = 0L;
|
||||
wi.createdate.tv_usec = 0L;
|
||||
DATE_ZERO(&(wi.createdate));
|
||||
INIT_WORKINFO(&look);
|
||||
look.data = (void *)(&wi);
|
||||
// Find the first workinfo for this height
|
||||
@ -1539,7 +1523,7 @@ static bool setup_data()
|
||||
(_seqset)->seqdata[_i].firsttime.tv_sec = \
|
||||
(_seqset)->seqdata[_i].firsttime.tv_usec = \
|
||||
(_seqset)->seqdata[_i].lasttime.tv_sec = \
|
||||
(_seqset)->seqdata[_i].lasttime.tv_usec = 0; \
|
||||
(_seqset)->seqdata[_i].lasttime.tv_usec = 0L; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
@ -2917,7 +2901,7 @@ static void summarise_blocks()
|
||||
K_RUNLOCK(blocks_free);
|
||||
if (!b_prev) {
|
||||
wi_start = 0;
|
||||
elapsed_start.tv_sec = elapsed_start.tv_usec = 0L;
|
||||
DATE_ZERO(&elapsed_start);
|
||||
prev_hi = 0;
|
||||
} else {
|
||||
DATA_BLOCKS(prev_blocks, b_prev);
|
||||
@ -2936,7 +2920,7 @@ static void summarise_blocks()
|
||||
copy_tv(&elapsed_start, &(prev_workinfo->createdate));
|
||||
prev_hi = prev_blocks->height;
|
||||
}
|
||||
elapsed_finish.tv_sec = elapsed_finish.tv_usec = 0L;
|
||||
DATE_ZERO(&elapsed_finish);
|
||||
|
||||
// Add up the sharesummaries, abort if any SUMMARY_NEW
|
||||
looksharesummary.workinfoid = wi_finish;
|
||||
@ -3958,6 +3942,7 @@ static void *socketer(__maybe_unused void *arg)
|
||||
case CMD_USERSTATUS:
|
||||
case CMD_SHSTA:
|
||||
case CMD_USERINFO:
|
||||
case CMD_BTCSET:
|
||||
ans = ckdb_cmds[msgline->which_cmds].func(NULL,
|
||||
msgline->cmd,
|
||||
msgline->id,
|
||||
@ -4297,6 +4282,7 @@ static void reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
|
||||
case CMD_PSHIFT:
|
||||
case CMD_SHSTA:
|
||||
case CMD_USERINFO:
|
||||
case CMD_BTCSET:
|
||||
LOGERR("%s() INVALID message line %"PRIu64
|
||||
" ignored '%.42s...",
|
||||
__func__, count,
|
||||
@ -5134,7 +5120,7 @@ static void confirm_reload()
|
||||
}
|
||||
} else {
|
||||
if (confirm_first_workinfoid == 0) {
|
||||
start.tv_sec = start.tv_usec = 0;
|
||||
DATE_ZERO(&start);
|
||||
LOGWARNING("%s() no start workinfo found ... "
|
||||
"using time 0", __func__);
|
||||
} else {
|
||||
@ -5610,6 +5596,7 @@ int main(int argc, char **argv)
|
||||
ckp.main.processname = strdup("main");
|
||||
|
||||
cklock_init(&last_lock);
|
||||
cklock_init(&btc_lock);
|
||||
cklock_init(&seq_lock);
|
||||
cklock_init(&process_pplns_lock);
|
||||
|
||||
|
||||
44
src/ckdb.h
44
src/ckdb.h
@ -55,7 +55,7 @@
|
||||
|
||||
#define DB_VLOCK "1"
|
||||
#define DB_VERSION "1.0.2"
|
||||
#define CKDB_VERSION DB_VERSION"-1.222"
|
||||
#define CKDB_VERSION DB_VERSION"-1.241"
|
||||
|
||||
#define WHERE_FFL " - from %s %s() line %d"
|
||||
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__
|
||||
@ -270,6 +270,8 @@ extern const tv_t date_eot;
|
||||
#define DATE_BEGIN 1388620800L
|
||||
extern const tv_t date_begin;
|
||||
|
||||
#define DATE_ZERO(_tv) (_tv)->tv_sec = (_tv)->tv_usec = 0L
|
||||
|
||||
#define BTC_TO_D(_amt) ((double)((_amt) / 100000000.0))
|
||||
|
||||
// argv -y - don't run in ckdb mode, just confirm sharesummaries
|
||||
@ -335,6 +337,8 @@ extern cklock_t last_lock;
|
||||
extern char *btc_server;
|
||||
extern char *btc_auth;
|
||||
extern int btc_timeout;
|
||||
// Lock access to the above variables so they can be changed
|
||||
extern cklock_t btc_lock;
|
||||
|
||||
#define EDDB "expirydate"
|
||||
#define CDDB "createdate"
|
||||
@ -401,6 +405,7 @@ enum cmd_values {
|
||||
CMD_PSHIFT,
|
||||
CMD_SHSTA,
|
||||
CMD_USERINFO,
|
||||
CMD_BTCSET,
|
||||
CMD_END
|
||||
};
|
||||
|
||||
@ -589,8 +594,7 @@ enum cmd_values {
|
||||
STRNCPY(_row->createby, _by); \
|
||||
STRNCPY(_row->createcode, _code); \
|
||||
STRNCPY(_row->createinet, _inet); \
|
||||
_row->modifydate.tv_sec = 0; \
|
||||
_row->modifydate.tv_usec = 0; \
|
||||
DATE_ZERO(&(_row->modifydate)); \
|
||||
_row->modifyby[0] = '\0'; \
|
||||
_row->modifycode[0] = '\0'; \
|
||||
_row->modifyinet[0] = '\0'; \
|
||||
@ -612,8 +616,7 @@ enum cmd_values {
|
||||
SET_CREATEBY(_list, _row->createby, _by); \
|
||||
SET_CREATECODE(_list, _row->createcode, _code); \
|
||||
SET_CREATEINET(_list, _row->createinet, _inet); \
|
||||
_row->modifydate.tv_sec = 0; \
|
||||
_row->modifydate.tv_usec = 0; \
|
||||
DATE_ZERO(&(_row->modifydate)); \
|
||||
SET_MODIFYBY(_list, _row->modifyby, EMPTY); \
|
||||
SET_MODIFYCODE(_list, _row->modifycode, EMPTY); \
|
||||
SET_MODIFYINET(_list, _row->modifyinet, EMPTY); \
|
||||
@ -1493,6 +1496,10 @@ typedef struct blocks {
|
||||
double diffmean;
|
||||
double cdferl;
|
||||
double luck;
|
||||
|
||||
// To save looking them up when needed
|
||||
tv_t prevcreatedate; // non-DB field
|
||||
tv_t blockcreatedate; // non-DB field
|
||||
} BLOCKS;
|
||||
|
||||
#define ALLOC_BLOCKS 100
|
||||
@ -1545,6 +1552,11 @@ extern K_STORE *blocks_store;
|
||||
extern tv_t blocks_stats_time;
|
||||
extern bool blocks_stats_rebuild;
|
||||
|
||||
// Default number of blocks to display on web
|
||||
#define BLOCKS_DEFAULT 42
|
||||
// OptionControl can override it
|
||||
#define BLOCKS_SETTING_NAME "BlocksPageSize"
|
||||
|
||||
// MININGPAYOUTS
|
||||
typedef struct miningpayouts {
|
||||
int64_t payoutid;
|
||||
@ -1570,6 +1582,7 @@ typedef struct payouts {
|
||||
int64_t payoutid;
|
||||
int32_t height;
|
||||
char blockhash[TXT_BIG+1];
|
||||
tv_t blockcreatedate; // non-DB field
|
||||
int64_t minerreward;
|
||||
int64_t workinfoidstart;
|
||||
int64_t workinfoidend;
|
||||
@ -1591,6 +1604,7 @@ typedef struct payouts {
|
||||
|
||||
extern K_TREE *payouts_root;
|
||||
extern K_TREE *payouts_id_root;
|
||||
extern K_TREE *payouts_wid_root;
|
||||
extern K_LIST *payouts_free;
|
||||
extern K_STORE *payouts_store;
|
||||
extern cklock_t process_pplns_lock;
|
||||
@ -1893,6 +1907,9 @@ typedef struct workmarkers {
|
||||
int64_t workinfoidstart;
|
||||
char *description;
|
||||
char status[TXT_FLAG+1];
|
||||
int rewards; // non-DB field
|
||||
double pps_value; // non-DB field
|
||||
double rewarded; // non-DB field
|
||||
HISTORYDATECONTROLFIELDS;
|
||||
} WORKMARKERS;
|
||||
|
||||
@ -2297,6 +2314,10 @@ extern const char *blocks_confirmed(char *confirmed);
|
||||
extern void zero_on_new_block();
|
||||
extern void set_block_share_counters();
|
||||
extern bool check_update_blocks_stats(tv_t *stats);
|
||||
#define set_blockcreatedate(_h) _set_blockcreatedate(_h, WHERE_FFL_HERE)
|
||||
extern bool _set_blockcreatedate(int32_t oldest_height, WHERE_FFL_ARGS);
|
||||
#define set_prevcreatedate(_h) _set_prevcreatedate(_h, WHERE_FFL_HERE)
|
||||
extern bool _set_prevcreatedate(int32_t oldest_height, WHERE_FFL_ARGS);
|
||||
extern cmp_t cmp_miningpayouts(K_ITEM *a, K_ITEM *b);
|
||||
extern K_ITEM *find_miningpayouts(int64_t payoutid, int64_t userid);
|
||||
extern K_ITEM *first_miningpayouts(int64_t payoutid, K_TREE_CTX *ctx);
|
||||
@ -2305,9 +2326,11 @@ extern K_TREE *upd_add_mu(K_TREE *mu_root, K_STORE *mu_store, int64_t userid,
|
||||
double diffacc);
|
||||
extern cmp_t cmp_payouts(K_ITEM *a, K_ITEM *b);
|
||||
extern cmp_t cmp_payouts_id(K_ITEM *a, K_ITEM *b);
|
||||
extern cmp_t cmp_payouts_wid(K_ITEM *a, K_ITEM *b);
|
||||
extern K_ITEM *find_payouts(int32_t height, char *blockhash);
|
||||
extern K_ITEM *find_last_payouts();
|
||||
extern K_ITEM *find_payoutid(int64_t payoutid);
|
||||
extern K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx);
|
||||
extern double payout_stats(PAYOUTS *payouts, char *statname);
|
||||
extern bool process_pplns(int32_t height, char *blockhash, tv_t *now);
|
||||
extern cmp_t cmp_auths(K_ITEM *a, K_ITEM *b);
|
||||
@ -2335,11 +2358,13 @@ extern bool make_markersummaries(bool msg, char *by, char *code, char *inet,
|
||||
extern void dsp_workmarkers(K_ITEM *item, FILE *stream);
|
||||
extern cmp_t cmp_workmarkers(K_ITEM *a, K_ITEM *b);
|
||||
extern cmp_t cmp_workmarkers_workinfoid(K_ITEM *a, K_ITEM *b);
|
||||
extern K_ITEM *find_workmarkers(int64_t workinfoid, bool anystatus, char status);
|
||||
extern K_ITEM *find_workmarkers(int64_t workinfoid, bool anystatus, char status, K_TREE_CTX *ctx);
|
||||
extern K_ITEM *find_workmarkerid(int64_t markerid, bool anystatus, char status);
|
||||
extern bool workmarkers_generate(PGconn *conn, char *err, size_t siz,
|
||||
char *by, char *code, char *inet, tv_t *cd,
|
||||
K_TREE *trf_root, bool none_error);
|
||||
extern bool reward_shifts(PAYOUTS *payouts, bool lock, int delta);
|
||||
extern bool shift_rewards(K_ITEM *wm_item);
|
||||
extern cmp_t cmp_marks(K_ITEM *a, K_ITEM *b);
|
||||
extern K_ITEM *find_marks(int64_t workinfoid);
|
||||
extern const char *marks_marktype(char *marktype);
|
||||
@ -2358,8 +2383,8 @@ extern K_ITEM *_find_create_userinfo(int64_t userid, bool lock, WHERE_FFL_ARGS);
|
||||
#define userinfo_update(_s, _ss, _ms) _userinfo_update(_s, _ss, _ms, true, true)
|
||||
extern void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary,
|
||||
MARKERSUMMARY *markersummary, bool ss_sub, bool lock);
|
||||
#define userinfo_block(_blocks, _isnew) _userinfo_block(_blocks, _isnew, true)
|
||||
extern void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock);
|
||||
#define userinfo_block(_blocks, _isnew, _delta) _userinfo_block(_blocks, _isnew, _delta, true)
|
||||
extern void _userinfo_block(BLOCKS *blocks, enum info_type isnew, int delta, bool lock);
|
||||
|
||||
// ***
|
||||
// *** PostgreSQL functions ckdb_dbio.c
|
||||
@ -2608,6 +2633,7 @@ extern bool check_2fa(USERS *users, int32_t value);
|
||||
extern bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
|
||||
char *inet, tv_t *cd, K_TREE *trf_root);
|
||||
extern K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by,
|
||||
char *code, char *inet, tv_t *cd, K_TREE *trf_root);
|
||||
char *code, char *inet, tv_t *cd, K_TREE *trf_root,
|
||||
bool check);
|
||||
|
||||
#endif
|
||||
|
||||
@ -32,9 +32,11 @@ static char *btc_data(char *json, size_t *len)
|
||||
|
||||
APPEND_REALLOC_INIT(buf, off, *len);
|
||||
APPEND_REALLOC(buf, off, *len, "POST / HTTP/1.1\n");
|
||||
ck_wlock(&btc_lock);
|
||||
snprintf(tmp, sizeof(tmp), "Authorization: Basic %s\n", btc_auth);
|
||||
APPEND_REALLOC(buf, off, *len, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "Host: %s/\n", btc_server);
|
||||
ck_wunlock(&btc_lock);
|
||||
APPEND_REALLOC(buf, off, *len, tmp);
|
||||
APPEND_REALLOC(buf, off, *len, "Content-Type: application/json\n");
|
||||
snprintf(tmp, sizeof(tmp), "Content-Length: %d\n\n", (int)strlen(json));
|
||||
|
||||
428
src/ckdb_cmd.c
428
src/ckdb_cmd.c
@ -213,7 +213,7 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
int32_t entropy, value;
|
||||
USERS *users;
|
||||
char *action, *buf = NULL, *st = NULL;
|
||||
char *sfa_status = EMPTY, *sfa_error = EMPTY;
|
||||
char *sfa_status = EMPTY, *sfa_error = EMPTY, *sfa_msg = EMPTY;
|
||||
bool ok = false, key = false;
|
||||
|
||||
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
|
||||
@ -301,9 +301,24 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
else {
|
||||
key = false;
|
||||
sfa_status = "ok";
|
||||
sfa_msg = "2FA Enabled";
|
||||
}
|
||||
// Report sfa_error to web
|
||||
ok = true;
|
||||
} else if (strcmp(action, "untest") == 0) {
|
||||
// Can't untest if it's not ready to test
|
||||
if ((users->databits & (USER_TOTPAUTH | USER_TEST2FA))
|
||||
!= (USER_TOTPAUTH | USER_TEST2FA))
|
||||
goto dame;
|
||||
// since it's currently test, the value isn't required
|
||||
u_new = remove_2fa(u_item, 0, by, code, inet, now,
|
||||
trf_root, false);
|
||||
if (u_new) {
|
||||
ok = true;
|
||||
sfa_status = EMPTY;
|
||||
key = false;
|
||||
sfa_msg = "2FA Cancelled";
|
||||
}
|
||||
} else if (strcmp(action, "new") == 0) {
|
||||
// Can't new if 2FA isn't already present -> setup
|
||||
if ((users->databits & USER_TOTPAUTH) == 0)
|
||||
@ -329,23 +344,27 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
// Can't remove if 2FA isn't already present
|
||||
if (!(users->databits & (USER_TOTPAUTH | USER_TEST2FA)))
|
||||
goto dame;
|
||||
// remove requires value
|
||||
value = (int32_t)atoi(transfer_data(i_value));
|
||||
if (!check_2fa(users, value)) {
|
||||
sfa_error = "Invalid code";
|
||||
// Report sfa_error to web
|
||||
ok = true;
|
||||
} else {
|
||||
/* already tested 2fa so don't retest, also,
|
||||
* a retest will fail using the same value */
|
||||
u_new = remove_2fa(u_item, value, by, code,
|
||||
inet, now, trf_root);
|
||||
inet, now, trf_root, false);
|
||||
if (u_new) {
|
||||
ok = true;
|
||||
sfa_status = EMPTY;
|
||||
key = false;
|
||||
sfa_msg = "2FA Removed";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key) {
|
||||
char *keystr, *issuer = "Kano";
|
||||
char *keystr, *issuer = "KanoCKDB";
|
||||
char cd_buf[DATE_BUFSIZ];
|
||||
unsigned char *bin;
|
||||
OPTIONCONTROL *oc;
|
||||
@ -411,8 +430,9 @@ dame:
|
||||
return strdup("failed.");
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "2fa_status=%s%c2fa_error=%s",
|
||||
sfa_status, FLDSEP, sfa_error);
|
||||
snprintf(tmp, sizeof(tmp), "2fa_status=%s%c2fa_error=%s%c2fa_msg=%s",
|
||||
sfa_status, FLDSEP, sfa_error, FLDSEP,
|
||||
sfa_msg);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
LOGDEBUG("%s.%s-%s.%s", id, transfer_data(i_username), action, buf);
|
||||
return buf;
|
||||
@ -1116,7 +1136,7 @@ static char *cmd_workerstats(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
}
|
||||
|
||||
static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
__maybe_unused tv_t *now, __maybe_unused char *by,
|
||||
tv_t *now, __maybe_unused char *by,
|
||||
__maybe_unused char *code, __maybe_unused char *inet,
|
||||
__maybe_unused tv_t *notcd,
|
||||
__maybe_unused K_TREE *trf_root)
|
||||
@ -1128,13 +1148,16 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
char tmp[1024];
|
||||
char *buf, *desc, desc_buf[64];
|
||||
size_t len, off;
|
||||
int32_t height = -1;
|
||||
tv_t first_cd = {0,0}, stats_tv = {0,0}, stats_tv2 = {0,0};
|
||||
tv_t stats_tv = {0,0}, stats_tv2 = {0,0};
|
||||
int rows, srows, tot, seq;
|
||||
int64_t maxrows;
|
||||
bool has_stats;
|
||||
|
||||
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
|
||||
|
||||
// 0 means just the system setting
|
||||
maxrows = user_sys_setting(0, BLOCKS_SETTING_NAME, BLOCKS_DEFAULT, now);
|
||||
|
||||
APPEND_REALLOC_INIT(buf, off, len);
|
||||
APPEND_REALLOC(buf, off, len, "ok.");
|
||||
|
||||
@ -1158,15 +1181,8 @@ redo:
|
||||
}
|
||||
seq = tot;
|
||||
b_item = last_in_ktree(blocks_root, ctx);
|
||||
while (b_item && rows < 42) {
|
||||
while (b_item && rows < (int)maxrows) {
|
||||
DATA_BLOCKS(blocks, b_item);
|
||||
/* For each block remember the initial createdate
|
||||
* Reverse sort order the oldest expirydate is first
|
||||
* which should be the 'n' record */
|
||||
if (height != blocks->height) {
|
||||
height = blocks->height;
|
||||
copy_tv(&first_cd, &(blocks->createdate));
|
||||
}
|
||||
if (CURRENT(&(blocks->expirydate))) {
|
||||
if (blocks->confirmed[0] == BLOCKS_ORPHAN ||
|
||||
blocks->confirmed[0] == BLOCKS_REJECT) {
|
||||
@ -1203,16 +1219,24 @@ redo:
|
||||
snprintf(tmp, sizeof(tmp), "workername:%d=%s%c", rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
// When block was found
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"first"CDTRF":%d=%ld%c", rows,
|
||||
first_cd.tv_sec, FLDSEP);
|
||||
blocks->blockcreatedate.tv_sec, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
// Last time block was updated
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
CDTRF":%d=%ld%c", rows,
|
||||
blocks->createdate.tv_sec, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
// When previous valid block was found
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"prev"CDTRF":%d=%ld%c", rows,
|
||||
blocks->prevcreatedate.tv_sec, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"confirmed:%d=%s%cstatus:%d=%s%c", rows,
|
||||
blocks->confirmed, FLDSEP, rows,
|
||||
@ -1299,12 +1323,18 @@ redo:
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"s_seq:%d=%d%c"
|
||||
"s_desc:%d=%s%c"
|
||||
"s_height:%d=%d%c"
|
||||
"s_"CDTRF":%d=%ld%c"
|
||||
"s_prev"CDTRF":%d=%ld%c"
|
||||
"s_diffratio:%d=%.8f%c"
|
||||
"s_diffmean:%d=%.8f%c"
|
||||
"s_cdferl:%d=%.8f%c"
|
||||
"s_luck:%d=%.8f%c",
|
||||
srows, seq, FLDSEP,
|
||||
srows, desc, FLDSEP,
|
||||
srows, (int)(blocks->height), FLDSEP,
|
||||
srows, blocks->blockcreatedate.tv_sec, FLDSEP,
|
||||
srows, blocks->prevcreatedate.tv_sec, FLDSEP,
|
||||
srows, blocks->diffratio, FLDSEP,
|
||||
srows, blocks->diffmean, FLDSEP,
|
||||
srows, blocks->cdferl, FLDSEP,
|
||||
@ -1336,7 +1366,8 @@ redo:
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"s_rows=%d%cs_flds=%s%c",
|
||||
srows, FLDSEP,
|
||||
"s_seq,s_desc,s_diffratio,s_diffmean,s_cdferl,s_luck",
|
||||
"s_seq,s_desc,s_height,s_"CDTRF",s_prev"CDTRF",s_diffratio,"
|
||||
"s_diffmean,s_cdferl,s_luck",
|
||||
FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
@ -1344,8 +1375,8 @@ redo:
|
||||
"rows=%d%cflds=%s%c",
|
||||
rows, FLDSEP,
|
||||
"seq,height,blockhash,nonce,reward,workername,first"CDTRF","
|
||||
CDTRF",confirmed,status,info,statsconf,diffacc,diffinv,"
|
||||
"shareacc,shareinv,elapsed,netdiff,diffratio,cdf,luck",
|
||||
CDTRF",prev"CDTRF",confirmed,status,info,statsconf,diffacc,"
|
||||
"diffinv,shareacc,shareinv,elapsed,netdiff,diffratio,cdf,luck",
|
||||
FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
@ -1697,8 +1728,7 @@ static char *cmd_percent(char *cmd, char *id, tv_t *now, USERS *users)
|
||||
// Add up all user's worker stats to be divided into payout percentages
|
||||
lookworkers.userid = users->userid;
|
||||
lookworkers.workername[0] = '\0';
|
||||
lookworkers.expirydate.tv_sec = 0;
|
||||
lookworkers.expirydate.tv_usec = 0;
|
||||
DATE_ZERO(&(lookworkers.expirydate));
|
||||
w_look.data = (void *)(&lookworkers);
|
||||
w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
|
||||
DATA_WORKERS_NULL(workers, w_item);
|
||||
@ -1959,8 +1989,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
|
||||
lookworkers.userid = users->userid;
|
||||
lookworkers.workername[0] = '\0';
|
||||
lookworkers.expirydate.tv_sec = 0;
|
||||
lookworkers.expirydate.tv_usec = 0;
|
||||
DATE_ZERO(&(lookworkers.expirydate));
|
||||
w_look.data = (void *)(&lookworkers);
|
||||
w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
|
||||
DATA_WORKERS_NULL(workers, w_item);
|
||||
@ -1974,7 +2003,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
copy_tv(&last_share, &(workerstatus->last_share));
|
||||
K_RUNLOCK(workerstatus_free);
|
||||
} else
|
||||
last_share.tv_sec = last_share.tv_usec = 0L;
|
||||
DATE_ZERO(&last_share);
|
||||
|
||||
if (tvdiff(now, &last_share) < oldworkers) {
|
||||
str_to_buf(workers->workername, reply, sizeof(reply));
|
||||
@ -2012,7 +2041,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
w_elapsed = -1;
|
||||
|
||||
if (!ws_item) {
|
||||
w_lastshare.tv_sec = 0;
|
||||
w_lastshare.tv_sec = 0L;
|
||||
w_lastdiff = w_diffacc =
|
||||
w_diffinv = w_diffsta =
|
||||
w_diffdup = w_diffhi =
|
||||
@ -2020,7 +2049,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
w_shareinv = w_sharesta =
|
||||
w_sharedup = w_sharehi =
|
||||
w_sharerej = w_active_diffacc = 0;
|
||||
w_active_start.tv_sec = 0;
|
||||
w_active_start.tv_sec = 0L;
|
||||
} else {
|
||||
DATA_WORKERSTATUS(workerstatus, ws_item);
|
||||
// It's bad to read possibly changing data
|
||||
@ -4009,8 +4038,8 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
|
||||
LOGDEBUG("%s(): height %"PRId32, __func__, height);
|
||||
|
||||
block_tv.tv_sec = block_tv.tv_usec = 0L;
|
||||
cd.tv_sec = cd.tv_usec = 0L;
|
||||
DATE_ZERO(&block_tv);
|
||||
DATE_ZERO(&cd);
|
||||
lookblocks.height = height + 1;
|
||||
lookblocks.blockhash[0] = '\0';
|
||||
INIT_BLOCKS(&b_look);
|
||||
@ -4437,7 +4466,6 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
PAYMENTS *payments;
|
||||
PAYOUTS *payouts;
|
||||
BLOCKS lookblocks, *blocks;
|
||||
tv_t block_tv = { 0L, 0L };
|
||||
WORKINFO *bworkinfo, *workinfo;
|
||||
char ndiffbin[TXT_SML+1];
|
||||
double ndiff;
|
||||
@ -4461,36 +4489,26 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
|
||||
LOGDEBUG("%s(): height %"PRId32, __func__, height);
|
||||
|
||||
lookblocks.height = height + 1;
|
||||
lookblocks.height = height;
|
||||
lookblocks.blockhash[0] = '\0';
|
||||
INIT_BLOCKS(&b_look);
|
||||
b_look.data = (void *)(&lookblocks);
|
||||
K_RLOCK(blocks_free);
|
||||
b_item = find_before_in_ktree(blocks_root, &b_look, cmp_blocks, b_ctx);
|
||||
b_item = find_after_in_ktree(blocks_root, &b_look, cmp_blocks, b_ctx);
|
||||
K_RUNLOCK(blocks_free);
|
||||
if (!b_item) {
|
||||
K_RUNLOCK(blocks_free);
|
||||
snprintf(reply, siz, "ERR.no block height %"PRId32, height);
|
||||
snprintf(reply, siz, "ERR.no block height >= %"PRId32, height);
|
||||
return strdup(reply);
|
||||
}
|
||||
DATA_BLOCKS(blocks, b_item);
|
||||
while (b_item && blocks->height == height) {
|
||||
if (blocks->confirmed[0] == BLOCKS_NEW)
|
||||
copy_tv(&block_tv, &(blocks->createdate));
|
||||
// Allow any state, but report it
|
||||
if (CURRENT(&(blocks->expirydate)))
|
||||
break;
|
||||
b_item = prev_in_ktree(b_ctx);
|
||||
DATA_BLOCKS_NULL(blocks, b_item);
|
||||
}
|
||||
K_RUNLOCK(blocks_free);
|
||||
if (!b_item || blocks->height != height) {
|
||||
snprintf(reply, siz, "ERR.no block height %"PRId32, height);
|
||||
return strdup(reply);
|
||||
}
|
||||
if (block_tv.tv_sec == 0) {
|
||||
snprintf(reply, siz, "ERR.block %"PRId32" missing '%s' record",
|
||||
height,
|
||||
blocks_confirmed(BLOCKS_NEW_STR));
|
||||
if (blocks->blockcreatedate.tv_sec == 0) {
|
||||
snprintf(reply, siz, "ERR.block %"PRId32" has 0 blockcreatedate",
|
||||
height);
|
||||
return strdup(reply);
|
||||
}
|
||||
if (!CURRENT(&(blocks->expirydate))) {
|
||||
@ -4667,10 +4685,11 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
snprintf(tmp, sizeof(tmp), "begin_epoch=%ld%c",
|
||||
workinfo->createdate.tv_sec, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
tv_to_buf(&block_tv, tv_buf, sizeof(tv_buf));
|
||||
tv_to_buf(&(blocks->blockcreatedate), tv_buf, sizeof(tv_buf));
|
||||
snprintf(tmp, sizeof(tmp), "block_stamp=%s%c", tv_buf, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "block_epoch=%ld%c", block_tv.tv_sec, FLDSEP);
|
||||
snprintf(tmp, sizeof(tmp), "block_epoch=%ld%c",
|
||||
blocks->blockcreatedate.tv_sec, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
tv_to_buf(&(payouts->lastshareacc), tv_buf, sizeof(tv_buf));
|
||||
snprintf(tmp, sizeof(tmp), "end_stamp=%s%c", tv_buf, FLDSEP);
|
||||
@ -4780,6 +4799,8 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
|
||||
snprintf(reply, siz, "failed payout %"PRId64, payoutid);
|
||||
return strdup(reply);
|
||||
}
|
||||
// Original wasn't generated, so reward it
|
||||
reward_shifts(payouts2, true, 1);
|
||||
DATA_PAYOUTS(payouts2, p2_item);
|
||||
DATA_PAYOUTS(old_payouts2, old_p2_item);
|
||||
snprintf(msg, sizeof(msg),
|
||||
@ -4849,6 +4870,8 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
|
||||
snprintf(reply, siz, "failed payout %"PRId64, payoutid);
|
||||
return strdup(reply);
|
||||
}
|
||||
// Original was generated, so undo the reward
|
||||
reward_shifts(payouts2, true, -1);
|
||||
DATA_PAYOUTS(payouts2, p2_item);
|
||||
DATA_PAYOUTS(old_payouts2, old_p2_item);
|
||||
snprintf(msg, sizeof(msg),
|
||||
@ -4866,6 +4889,7 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
|
||||
return strdup(reply);
|
||||
TXT_TO_BIGINT("payoutid", transfer_data(i_payoutid), payoutid);
|
||||
|
||||
// payouts_full_expire updates the shift rewards
|
||||
p_item = payouts_full_expire(conn, payoutid, now, true);
|
||||
if (!p_item) {
|
||||
snprintf(reply, siz, "failed payout %"PRId64, payoutid);
|
||||
@ -4902,6 +4926,7 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
|
||||
return strdup(reply);
|
||||
TXT_TO_CTV("addrdate", transfer_data(i_addrdate), addrdate);
|
||||
|
||||
// process_pplns updates the shift rewards
|
||||
if (addrdate.tv_sec == 0)
|
||||
ok = process_pplns(height, blockhash, NULL);
|
||||
else
|
||||
@ -4982,6 +5007,11 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"block"CDTRF":%d=%ld%c", rows,
|
||||
payouts->blockcreatedate.tv_sec, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
bigint_to_buf(payouts->elapsed, reply,
|
||||
sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "elapsed:%d=%s%c",
|
||||
@ -5026,7 +5056,7 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c",
|
||||
rows, FLDSEP,
|
||||
"payoutid,height,elapsed,amount,diffacc,minerreward,diffused,status",
|
||||
"payoutid,height,block"CDTRF",elapsed,amount,diffacc,minerreward,diffused,status",
|
||||
FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
@ -5037,15 +5067,16 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Find the offset, in list, of the workername
|
||||
* -1 means NULL list, empty list or not found */
|
||||
static int worker_offset(char **list, char *workername)
|
||||
typedef struct worker_match {
|
||||
char *worker;
|
||||
bool match;
|
||||
size_t len;
|
||||
bool used;
|
||||
} WM;
|
||||
|
||||
static char *worker_offset(char *workername)
|
||||
{
|
||||
char *c1, *c2;
|
||||
int i;
|
||||
|
||||
if (!list || !(*list))
|
||||
return -1;
|
||||
|
||||
/* Find the start of the workername including the SEP */
|
||||
c1 = strchr(workername, WORKSEP1);
|
||||
@ -5057,11 +5088,8 @@ static int worker_offset(char **list, char *workername)
|
||||
// No workername after the username
|
||||
if (!c1)
|
||||
c1 = WORKERS_EMPTY;
|
||||
for (i = 0; list[i]; i++) {
|
||||
if (strcmp(c1, list[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
|
||||
return c1;
|
||||
}
|
||||
|
||||
/* Some arbitrarily large limit, increase it if needed
|
||||
@ -5069,28 +5097,19 @@ static int worker_offset(char **list, char *workername)
|
||||
#define SELECT_LIMIT 63
|
||||
|
||||
/* select is a string of workernames separated by WORKERS_SEL_SEP
|
||||
* Return an array of strings of select broken up
|
||||
* The array is terminated by NULL
|
||||
* Setup the wm array of workers with select broken up
|
||||
* The wm array is terminated by workers = NULL
|
||||
* and will have 0 elements if select is NULL/empty
|
||||
* The count of the first occurrence of WORKERS_ALL is returned in *all_count,
|
||||
* The count of the first occurrence of WORKERS_ALL is returned,
|
||||
* or -1 if WORKERS_ALL isn't found */
|
||||
static char **select_list(char *select, int *all_count)
|
||||
static int select_list(WM *wm, char *select)
|
||||
{
|
||||
size_t len, offset, siz;
|
||||
char **list = NULL;
|
||||
int count;
|
||||
int count, all_count = -1;
|
||||
size_t len, offset;
|
||||
char *end;
|
||||
|
||||
*all_count = -1;
|
||||
|
||||
siz = sizeof(char *) * (SELECT_LIMIT + 1);
|
||||
list = malloc(siz);
|
||||
if (!list)
|
||||
quithere(1, "malloc (%d) OOM", (int)siz);
|
||||
list[0] = NULL;
|
||||
|
||||
if (select == NULL || *select == '\0')
|
||||
return list;
|
||||
return all_count;
|
||||
|
||||
len = strlen(select);
|
||||
count = 0;
|
||||
@ -5099,24 +5118,24 @@ static char **select_list(char *select, int *all_count)
|
||||
if (select[offset] == WORKERS_SEL_SEP)
|
||||
offset++;
|
||||
else {
|
||||
list[count] = select + offset;
|
||||
list[count+1] = NULL;
|
||||
end = strchr(list[count], WORKERS_SEL_SEP);
|
||||
wm[count].worker = select + offset;
|
||||
wm[count+1].worker = NULL;
|
||||
end = strchr(wm[count].worker, WORKERS_SEL_SEP);
|
||||
if (end != NULL) {
|
||||
offset = 1 + end - select;
|
||||
*end = '\0';
|
||||
}
|
||||
|
||||
if (*all_count == -1 &&
|
||||
strcasecmp(list[count], WORKERS_ALL) == 0) {
|
||||
*all_count = count;
|
||||
if (all_count == -1 &&
|
||||
strcasecmp(wm[count].worker, WORKERS_ALL) == 0) {
|
||||
all_count = count;
|
||||
}
|
||||
|
||||
if (end == NULL || ++count > SELECT_LIMIT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
return all_count;
|
||||
}
|
||||
|
||||
static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
@ -5129,7 +5148,7 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
K_TREE_CTX wm_ctx[1], ms_ctx[1];
|
||||
WORKMARKERS *wm;
|
||||
WORKINFO *wi;
|
||||
MARKERSUMMARY markersummary, *ms, ms_add;
|
||||
MARKERSUMMARY markersummary, *ms, ms_add[SELECT_LIMIT+1];
|
||||
PAYOUTS *payouts;
|
||||
USERS *users;
|
||||
MARKS *marks = NULL;
|
||||
@ -5137,14 +5156,14 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
char tmp[1024];
|
||||
size_t siz = sizeof(reply);
|
||||
char *select = NULL;
|
||||
char **selects = NULL;
|
||||
bool used[SELECT_LIMIT];
|
||||
char *buf;
|
||||
WM workm[SELECT_LIMIT+1];
|
||||
char *buf, *work;
|
||||
size_t len, off;
|
||||
tv_t marker_end = { 0L, 0L };
|
||||
int rows, want, i, where_all;
|
||||
int64_t maxrows;
|
||||
double wm_count, d;
|
||||
int64_t last_payout_start = 0;
|
||||
|
||||
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
|
||||
|
||||
@ -5171,23 +5190,34 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
wm_count *= 1.42;
|
||||
if (maxrows < wm_count)
|
||||
maxrows = wm_count;
|
||||
last_payout_start = payouts->workinfoidstart;
|
||||
}
|
||||
|
||||
i_select = optional_name(trf_root, "select", 1, NULL, reply, siz);
|
||||
if (i_select)
|
||||
select = strdup(transfer_data(i_select));
|
||||
|
||||
selects = select_list(select, &where_all);
|
||||
bzero(workm, sizeof(workm));
|
||||
where_all = select_list(&(workm[0]), select);
|
||||
// Nothing selected = all
|
||||
if (*selects == NULL) {
|
||||
if (workm[0].worker == NULL) {
|
||||
where_all = 0;
|
||||
selects[0] = WORKERS_ALL;
|
||||
selects[1] = NULL;
|
||||
workm[0].worker = WORKERS_ALL;
|
||||
} else {
|
||||
for (i = 0; workm[i].worker; i++) {
|
||||
// N.B. len is only used if match is true
|
||||
len = workm[i].len = strlen(workm[i].worker);
|
||||
// If at least 3 characters and last is '*'
|
||||
if (len > 2 && workm[i].worker[len-1] == '*') {
|
||||
workm[i].worker[len-1] = '\0';
|
||||
workm[i].match = true;
|
||||
workm[i].len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bzero(used, sizeof(used));
|
||||
if (where_all >= 0)
|
||||
used[where_all] = true;
|
||||
workm[where_all].used = true;
|
||||
|
||||
APPEND_REALLOC_INIT(buf, off, len);
|
||||
APPEND_REALLOC(buf, off, len, "ok.");
|
||||
@ -5216,7 +5246,12 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
wm->workinfoidend);
|
||||
}
|
||||
|
||||
bzero(&ms_add, sizeof(ms_add));
|
||||
// Zero everything for this shift
|
||||
bzero(ms_add, sizeof(ms_add));
|
||||
for (i = 0; workm[i].worker; i++) {
|
||||
if (i != where_all)
|
||||
workm[i].used = false;
|
||||
}
|
||||
|
||||
markersummary.markerid = wm->markerid;
|
||||
markersummary.userid = users->userid;
|
||||
@ -5227,50 +5262,57 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
DATA_MARKERSUMMARY_NULL(ms, ms_item);
|
||||
while (ms_item && ms->markerid == wm->markerid &&
|
||||
ms->userid == users->userid) {
|
||||
ms_add.diffacc += ms->diffacc;
|
||||
ms_add.diffsta += ms->diffsta;
|
||||
ms_add.diffdup += ms->diffdup;
|
||||
ms_add.diffhi += ms->diffhi;
|
||||
ms_add.diffrej += ms->diffrej;
|
||||
ms_add.shareacc += ms->shareacc;
|
||||
ms_add.sharesta += ms->sharesta;
|
||||
ms_add.sharedup += ms->sharedup;
|
||||
ms_add.sharehi += ms->sharehi;
|
||||
ms_add.sharerej += ms->sharerej;
|
||||
|
||||
want = worker_offset(selects, ms->workername);
|
||||
if (want >= 0) {
|
||||
used[want] = true;
|
||||
double_to_buf(ms->diffacc, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_diffacc:%d=%s%c",
|
||||
want, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
d = ms->diffsta + ms->diffdup +
|
||||
ms->diffhi + ms->diffrej;
|
||||
double_to_buf(d, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_diffinv:%d=%s%c",
|
||||
want, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
double_to_buf(ms->shareacc, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_shareacc:%d=%s%c",
|
||||
want, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
d = ms->sharesta + ms->sharedup +
|
||||
ms->sharehi + ms->sharerej;
|
||||
double_to_buf(d, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_shareinv:%d=%s%c",
|
||||
want, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
work = worker_offset(ms->workername);
|
||||
for (want = 0; workm[want].worker; want++) {
|
||||
if ((want == where_all) ||
|
||||
(workm[want].match && strncmp(work, workm[want].worker, workm[want].len) == 0) ||
|
||||
(!(workm[want].match) && strcmp(workm[want].worker, work) == 0)) {
|
||||
workm[want].used = true;
|
||||
ms_add[want].diffacc += ms->diffacc;
|
||||
ms_add[want].diffsta += ms->diffsta;
|
||||
ms_add[want].diffdup += ms->diffdup;
|
||||
ms_add[want].diffhi += ms->diffhi;
|
||||
ms_add[want].diffrej += ms->diffrej;
|
||||
ms_add[want].shareacc += ms->shareacc;
|
||||
ms_add[want].sharesta += ms->sharesta;
|
||||
ms_add[want].sharedup += ms->sharedup;
|
||||
ms_add[want].sharehi += ms->sharehi;
|
||||
ms_add[want].sharerej += ms->sharerej;
|
||||
}
|
||||
}
|
||||
|
||||
ms_item = next_in_ktree(ms_ctx);
|
||||
DATA_MARKERSUMMARY_NULL(ms, ms_item);
|
||||
}
|
||||
K_RUNLOCK(markersummary_free);
|
||||
|
||||
for (i = 0; i <= SELECT_LIMIT; i++) {
|
||||
if (workm[i].used) {
|
||||
double_to_buf(ms_add[i].diffacc, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_diffacc:%d=%s%c",
|
||||
i, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
d = ms_add[i].diffsta + ms_add[i].diffdup +
|
||||
ms_add[i].diffhi + ms_add[i].diffrej;
|
||||
double_to_buf(d, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_diffinv:%d=%s%c",
|
||||
i, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
double_to_buf(ms_add[i].shareacc, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_shareacc:%d=%s%c",
|
||||
i, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
d = ms_add[i].sharesta + ms_add[i].sharedup +
|
||||
ms_add[i].sharehi + ms_add[i].sharerej;
|
||||
double_to_buf(d, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_shareinv:%d=%s%c",
|
||||
i, rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (marker_end.tv_sec == 0L) {
|
||||
wi_item = next_workinfo(wm->workinfoidend, NULL);
|
||||
if (!wi_item) {
|
||||
@ -5286,7 +5328,6 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
wm->workinfoidend);
|
||||
snprintf(reply, siz, "data error 1");
|
||||
free(buf);
|
||||
free(selects);
|
||||
return(strdup(reply));
|
||||
}
|
||||
DATA_WORKINFO(wi, wi_item);
|
||||
@ -5307,7 +5348,6 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
wm->workinfoidstart);
|
||||
snprintf(reply, siz, "data error 2");
|
||||
free(buf);
|
||||
free(selects);
|
||||
return(strdup(reply));
|
||||
}
|
||||
DATA_WORKINFO(wi, wi_item);
|
||||
@ -5338,35 +5378,18 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
rows, reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
if (where_all >= 0) {
|
||||
double_to_buf(ms_add.diffacc, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_diffacc:%d=%s%c",
|
||||
where_all, rows,
|
||||
reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "rewards:%d=%d%c",
|
||||
rows, wm->rewards, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
d = ms_add.diffsta + ms_add.diffdup +
|
||||
ms_add.diffhi + ms_add.diffrej;
|
||||
double_to_buf(d, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_diffinv:%d=%s%c",
|
||||
where_all, rows,
|
||||
reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
snprintf(tmp, sizeof(tmp), "lastpayoutstart:%d=%s%c",
|
||||
rows,
|
||||
(wm->workinfoidstart ==
|
||||
last_payout_start) ?
|
||||
"Y" : EMPTY,
|
||||
FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
double_to_buf(ms_add.shareacc, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_shareacc:%d=%s%c",
|
||||
where_all, rows,
|
||||
reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
d = ms_add.sharesta + ms_add.sharedup +
|
||||
ms_add.sharehi + ms_add.sharerej;
|
||||
double_to_buf(d, reply, sizeof(reply));
|
||||
snprintf(tmp, sizeof(tmp), "%d_shareinv:%d=%s%c",
|
||||
where_all, rows,
|
||||
reply, FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
}
|
||||
rows++;
|
||||
|
||||
// Setup for next shift
|
||||
@ -5379,11 +5402,13 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
}
|
||||
K_RUNLOCK(workmarkers_free);
|
||||
|
||||
for (i = 0; selects[i]; i++) {
|
||||
if (used[i]) {
|
||||
for (i = 0; workm[i].worker; i++) {
|
||||
if (workm[i].used) {
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"%d_worker=%s%c",
|
||||
i, selects[i], FLDSEP);
|
||||
"%d_worker=%s%s%c",
|
||||
i, workm[i].worker,
|
||||
workm[i].match ? "*" : EMPTY,
|
||||
FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
"%d_flds=%s%c", i,
|
||||
@ -5404,13 +5429,14 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
* other workers start >= 0 and finish <= rows-1 */
|
||||
snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c",
|
||||
rows, FLDSEP,
|
||||
"markerid,shift,start,end", FLDSEP);
|
||||
"markerid,shift,start,end,rewards,"
|
||||
"lastpayoutstart", FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "arn=%s", "Shifts");
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
for (i = 0; selects[i]; i++) {
|
||||
if (used[i]) {
|
||||
for (i = 0; workm[i].worker; i++) {
|
||||
if (workm[i].used) {
|
||||
snprintf(tmp, sizeof(tmp), ",Worker_%d", i);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
}
|
||||
@ -5418,15 +5444,14 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%carp=", FLDSEP);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
for (i = 0; selects[i]; i++) {
|
||||
if (used[i]) {
|
||||
for (i = 0; workm[i].worker; i++) {
|
||||
if (workm[i].used) {
|
||||
snprintf(tmp, sizeof(tmp), ",%d_", i);
|
||||
APPEND_REALLOC(buf, off, len, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
LOGDEBUG("%s.ok.%s", id, transfer_data(i_username));
|
||||
free(selects);
|
||||
return(buf);
|
||||
}
|
||||
|
||||
@ -5537,7 +5562,7 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
USEINFO(marks, 1, 1);
|
||||
USEINFO(blocks, 1, 1);
|
||||
USEINFO(miningpayouts, 1, 1);
|
||||
USEINFO(payouts, 1, 2);
|
||||
USEINFO(payouts, 1, 3);
|
||||
USEINFO(auths, 1, 1);
|
||||
USEINFO(poolstats, 1, 1);
|
||||
USEINFO(userstats, 2, 1);
|
||||
@ -6300,6 +6325,60 @@ static char *cmd_userinfo(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Set/show the BTC server settings
|
||||
* You must supply the btcserver to change anything
|
||||
* The format for userpass is username:password
|
||||
* If you don't supply the btcserver it will simply report the current server
|
||||
* If supply btcserver but not the userpass it will use the current userpass
|
||||
* The reply will ONLY contain the URL, not the user/pass */
|
||||
static char *cmd_btcset(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
__maybe_unused tv_t *now, __maybe_unused char *by,
|
||||
__maybe_unused char *code, __maybe_unused char *inet,
|
||||
__maybe_unused tv_t *notcd, K_TREE *trf_root)
|
||||
{
|
||||
K_ITEM *i_btcserver, *i_userpass;
|
||||
char *btcserver = NULL, *userpass = NULL, *tmp;
|
||||
char reply[1024] = "";
|
||||
size_t siz = sizeof(reply);
|
||||
char buf[256];
|
||||
|
||||
i_btcserver = optional_name(trf_root, "btcserver", 1, NULL, reply, siz);
|
||||
if (i_btcserver) {
|
||||
btcserver = strdup(transfer_data(i_btcserver));
|
||||
i_userpass = optional_name(trf_root, "userpass", 0, NULL, reply, siz);
|
||||
if (i_userpass)
|
||||
userpass = transfer_data(i_userpass);
|
||||
|
||||
ck_wlock(&btc_lock);
|
||||
btc_server = btcserver;
|
||||
btcserver = NULL;
|
||||
if (userpass) {
|
||||
if (btc_auth) {
|
||||
tmp = btc_auth;
|
||||
while (*tmp)
|
||||
*(tmp++) = '\0';
|
||||
}
|
||||
FREENULL(btc_auth);
|
||||
btc_auth = http_base64(userpass);
|
||||
}
|
||||
ck_wunlock(&btc_lock);
|
||||
|
||||
if (userpass) {
|
||||
tmp = userpass;
|
||||
while (*tmp)
|
||||
*(tmp++) = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
FREENULL(btcserver);
|
||||
|
||||
ck_wlock(&btc_lock);
|
||||
snprintf(buf, sizeof(buf), "ok.btcserver=%s", btc_server);
|
||||
ck_wunlock(&btc_lock);
|
||||
LOGDEBUG("%s.%s.%s", id, cmd, buf);
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
// TODO: limit access by having seperate sockets for each
|
||||
#define ACCESS_POOL "p"
|
||||
#define ACCESS_SYSTEM "s"
|
||||
@ -6414,5 +6493,6 @@ struct CMDS ckdb_cmds[] = {
|
||||
{ CMD_PSHIFT, "pshift", false, false, cmd_pshift, SEQ_NONE, ACCESS_SYSTEM ACCESS_WEB },
|
||||
{ CMD_SHSTA, "shsta", true, false, cmd_shsta, SEQ_NONE, ACCESS_SYSTEM },
|
||||
{ CMD_USERINFO, "userinfo", false, false, cmd_userinfo, SEQ_NONE, ACCESS_WEB },
|
||||
{ CMD_BTCSET, "btcset", false, false, cmd_btcset, SEQ_NONE, ACCESS_SYSTEM },
|
||||
{ CMD_END, NULL, false, false, NULL, SEQ_NONE, NULL }
|
||||
};
|
||||
|
||||
@ -237,14 +237,17 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
|
||||
}
|
||||
|
||||
K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
|
||||
char *inet, tv_t *cd, K_TREE *trf_root)
|
||||
char *inet, tv_t *cd, K_TREE *trf_root, bool check)
|
||||
{
|
||||
K_ITEM *u_item = NULL;
|
||||
USERS *old_users, *users;
|
||||
bool ok, did = false;
|
||||
bool ok = true, did = false;
|
||||
|
||||
DATA_USERS(old_users, old_u_item);
|
||||
ok = check_2fa(old_users, value);
|
||||
/* N.B. check_2fa will fail if it is called a second time
|
||||
* with the same value */
|
||||
if (check)
|
||||
ok = check_2fa(old_users, value);
|
||||
if (ok) {
|
||||
K_WLOCK(users_free);
|
||||
u_item = k_unlink_head(users_free);
|
||||
|
||||
422
src/ckdb_data.c
422
src/ckdb_data.c
@ -369,8 +369,7 @@ void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t s
|
||||
long sec, nsec;
|
||||
int c;
|
||||
// Caller test for tv_sec=0 for failure
|
||||
((tv_t *)data)->tv_sec = 0L;
|
||||
((tv_t *)data)->tv_usec = 0L;
|
||||
DATE_ZERO((tv_t *)data);
|
||||
c = sscanf(fld, "%ld,%ld", &sec, &nsec);
|
||||
if (c > 0) {
|
||||
((tv_t *)data)->tv_sec = (time_t)sec;
|
||||
@ -882,12 +881,17 @@ K_ITEM *_find_create_workerstatus(int64_t userid, char *workername,
|
||||
K_WUNLOCK(workerstatus_free);
|
||||
|
||||
if (ws_err) {
|
||||
LOGERR("%s(): CREATED Missing workerstatus %"PRId64"/%s"
|
||||
WHERE_FFL WHERE_FFL,
|
||||
__func__, userid, workername,
|
||||
file2, func2, line2, WHERE_FFL_PASS);
|
||||
LOGNOTICE("%s(): CREATED Missing workerstatus"
|
||||
" %"PRId64"/%s"
|
||||
WHERE_FFL WHERE_FFL,
|
||||
__func__, userid, workername,
|
||||
file2, func2, line2, WHERE_FFL_PASS);
|
||||
if (w_err) {
|
||||
LOGERR("%s(): %s Missing worker %"PRId64"/%s",
|
||||
int sta = LOG_ERR;
|
||||
if (w_item)
|
||||
sta = LOG_NOTICE;
|
||||
LOGMSG(sta,
|
||||
"%s(): %s Missing worker %"PRId64"/%s",
|
||||
__func__,
|
||||
w_item ? "CREATED" : "FAILED TO CREATE",
|
||||
userid, workername);
|
||||
@ -1469,8 +1473,7 @@ K_ITEM *first_workers(int64_t userid, K_TREE_CTX *ctx)
|
||||
|
||||
workers.userid = userid;
|
||||
workers.workername[0] = '\0';
|
||||
workers.expirydate.tv_sec = 0L;
|
||||
workers.expirydate.tv_usec = 0L;
|
||||
DATE_ZERO(&(workers.expirydate));
|
||||
|
||||
INIT_WORKERS(&look);
|
||||
look.data = (void *)(&workers);
|
||||
@ -1623,8 +1626,7 @@ K_ITEM *find_paymentaddresses_create(int64_t userid, K_TREE_CTX *ctx)
|
||||
K_ITEM look, *item;
|
||||
|
||||
paymentaddresses.userid = userid;
|
||||
paymentaddresses.createdate.tv_sec = 0;
|
||||
paymentaddresses.createdate.tv_usec = 0;
|
||||
DATE_ZERO(&(paymentaddresses.createdate));
|
||||
paymentaddresses.payaddress[0] = '\0';
|
||||
|
||||
INIT_PAYMENTADDRESSES(&look);
|
||||
@ -1844,8 +1846,7 @@ K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height)
|
||||
* activationdate will all be the default value and not
|
||||
* decide the outcome */
|
||||
STRNCPY(optioncontrol.optionname, optionname);
|
||||
optioncontrol.activationdate.tv_sec = 0L;
|
||||
optioncontrol.activationdate.tv_usec = 0L;
|
||||
DATE_ZERO(&(optioncontrol.activationdate));
|
||||
optioncontrol.activationheight = OPTIONCONTROL_HEIGHT - 1;
|
||||
optioncontrol.expirydate.tv_sec = default_expiry.tv_sec;
|
||||
optioncontrol.expirydate.tv_usec = default_expiry.tv_usec;
|
||||
@ -2040,8 +2041,8 @@ bool workinfo_age(int64_t workinfoid, char *poolinstance, char *by, char *code,
|
||||
|
||||
LOGDEBUG("%s(): age", __func__);
|
||||
|
||||
ss_first->tv_sec = ss_first->tv_usec =
|
||||
ss_last->tv_sec = ss_last->tv_usec = 0;
|
||||
DATE_ZERO(ss_first);
|
||||
DATE_ZERO(ss_last);
|
||||
*ss_count = *s_count = *s_diff = 0;
|
||||
|
||||
wi_item = find_workinfo(workinfoid, NULL);
|
||||
@ -2065,7 +2066,7 @@ bool workinfo_age(int64_t workinfoid, char *poolinstance, char *by, char *code,
|
||||
}
|
||||
|
||||
K_RLOCK(workmarkers_free);
|
||||
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED);
|
||||
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED, NULL);
|
||||
K_RUNLOCK(workmarkers_free);
|
||||
// Should never happen?
|
||||
if (wm_item && !reloading) {
|
||||
@ -2137,8 +2138,7 @@ bool workinfo_age(int64_t workinfoid, char *poolinstance, char *by, char *code,
|
||||
lookshares.workinfoid = workinfoid;
|
||||
lookshares.userid = sharesummary->userid;
|
||||
strcpy(lookshares.workername, sharesummary->workername);
|
||||
lookshares.createdate.tv_sec = 0;
|
||||
lookshares.createdate.tv_usec = 0;
|
||||
DATE_ZERO(&(lookshares.createdate));
|
||||
|
||||
s_look.data = (void *)(&lookshares);
|
||||
K_WLOCK(shares_free);
|
||||
@ -2385,8 +2385,8 @@ void auto_age_older(int64_t workinfoid, char *poolinstance, char *by,
|
||||
cmp_sharesummary_workinfoid, ctx);
|
||||
DATA_SHARESUMMARY_NULL(sharesummary, ss_item);
|
||||
|
||||
ss_first_min.tv_sec = ss_first_min.tv_usec =
|
||||
ss_last_max.tv_sec = ss_last_max.tv_usec = 0;
|
||||
DATE_ZERO(&ss_first_min);
|
||||
DATE_ZERO(&ss_last_max);
|
||||
ss_count_tot = s_count_tot = s_diff_tot = 0;
|
||||
|
||||
found = false;
|
||||
@ -2628,8 +2628,7 @@ K_ITEM *find_prev_blocks(int32_t height)
|
||||
* not NEW, blocks, which might not find the right one */
|
||||
lookblocks.height = height;
|
||||
lookblocks.blockhash[0] = '\0';
|
||||
lookblocks.expirydate.tv_sec = 0L;
|
||||
lookblocks.expirydate.tv_usec = 0L;
|
||||
DATE_ZERO(&(lookblocks.expirydate));
|
||||
|
||||
INIT_BLOCKS(&look);
|
||||
look.data = (void *)(&lookblocks);
|
||||
@ -2919,8 +2918,8 @@ bool check_update_blocks_stats(tv_t *stats)
|
||||
K_RUNLOCK(workinfo_free);
|
||||
if (!w_item) {
|
||||
setnow(&now);
|
||||
if (!blocks->workinfoid != last_missing_workinfoid ||
|
||||
tvdiff(&now, &last_message) >= 5.0) {
|
||||
if (blocks->workinfoid != last_missing_workinfoid ||
|
||||
tvdiff(&now, &last_message) >= 15.0) {
|
||||
LOGEMERG("%s(): missing block workinfoid %"
|
||||
PRId32"/%"PRId64"/%s",
|
||||
__func__, blocks->height,
|
||||
@ -2988,6 +2987,184 @@ bool check_update_blocks_stats(tv_t *stats)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Must be under K_WLOCK(blocks_free) when called except during DB load
|
||||
bool _set_blockcreatedate(int32_t oldest_height, WHERE_FFL_ARGS)
|
||||
{
|
||||
K_TREE_CTX ctx[1];
|
||||
BLOCKS *blocks;
|
||||
K_ITEM *b_item;
|
||||
int32_t height;
|
||||
char blockhash[TXT_BIG+1];
|
||||
char cd_buf[DATE_BUFSIZ];
|
||||
tv_t createdate;
|
||||
bool ok = true;
|
||||
|
||||
// No blocks?
|
||||
if (blocks_store->count == 0)
|
||||
return true;
|
||||
|
||||
height = 0;
|
||||
blockhash[0] = '\0';
|
||||
DATE_ZERO(&createdate);
|
||||
b_item = last_in_ktree(blocks_root, ctx);
|
||||
DATA_BLOCKS_NULL(blocks, b_item);
|
||||
while (b_item && blocks->height >= oldest_height) {
|
||||
// NEW will be first going back
|
||||
if (blocks->confirmed[0] == BLOCKS_NEW) {
|
||||
height = blocks->height;
|
||||
STRNCPY(blockhash, blocks->blockhash);
|
||||
copy_tv(&createdate, &(blocks->createdate));
|
||||
}
|
||||
if (blocks->height != height ||
|
||||
strcmp(blocks->blockhash, blockhash) != 0) {
|
||||
// Missing NEW
|
||||
tv_to_buf(&(blocks->expirydate), cd_buf, sizeof(cd_buf));
|
||||
LOGEMERG("%s() block %"PRId32"/%s/%s/%s has no '"
|
||||
BLOCKS_NEW_STR "' prev was %"PRId32"/%s."
|
||||
WHERE_FFL,
|
||||
__func__,
|
||||
blocks->height, blocks->blockhash,
|
||||
blocks->confirmed, cd_buf,
|
||||
height, blockhash, WHERE_FFL_PASS);
|
||||
ok = false;
|
||||
|
||||
height = blocks->height;
|
||||
STRNCPY(blockhash, blocks->blockhash);
|
||||
// set a useable (incorrect) value
|
||||
copy_tv(&createdate, &(blocks->createdate));
|
||||
}
|
||||
// Always update it
|
||||
copy_tv(&(blocks->blockcreatedate), &createdate);
|
||||
|
||||
b_item = prev_in_ktree(ctx);
|
||||
DATA_BLOCKS_NULL(blocks, b_item);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Must be under K_WLOCK(blocks_free) when called except during DB load
|
||||
bool _set_prevcreatedate(int32_t oldest_height, WHERE_FFL_ARGS)
|
||||
{
|
||||
K_ITEM look, *b_item = NULL, *wi_item;
|
||||
BLOCKS lookblocks, *blocks = NULL;
|
||||
K_TREE_CTX b_ctx[1], wi_ctx[1];
|
||||
WORKINFO *workinfo;
|
||||
char curr_blockhash[TXT_BIG+1];
|
||||
char cd_buf[DATE_BUFSIZ];
|
||||
int32_t curr_height;
|
||||
tv_t prev_createdate;
|
||||
tv_t curr_createdate;
|
||||
bool ok = true, currok = false;
|
||||
|
||||
// No blocks?
|
||||
if (blocks_store->count == 0)
|
||||
return true;
|
||||
|
||||
// Find first 'ok' block before oldest_height
|
||||
lookblocks.height = oldest_height;
|
||||
lookblocks.blockhash[0] = '\0';
|
||||
DATE_ZERO(&(lookblocks.expirydate));
|
||||
|
||||
INIT_BLOCKS(&look);
|
||||
look.data = (void *)(&lookblocks);
|
||||
b_item = find_before_in_ktree(blocks_root, &look, cmp_blocks, b_ctx);
|
||||
while (b_item) {
|
||||
DATA_BLOCKS(blocks, b_item);
|
||||
if (CURRENT(&(blocks->expirydate)) &&
|
||||
blocks->confirmed[0] != BLOCKS_ORPHAN &&
|
||||
blocks->confirmed[0] != BLOCKS_REJECT)
|
||||
break;
|
||||
b_item = prev_in_ktree(b_ctx);
|
||||
}
|
||||
|
||||
// Setup prev_createdate
|
||||
if (b_item) {
|
||||
/* prev_createdate is the ok b_item (before oldest_height)
|
||||
* _set_blockcreatedate() should always be called
|
||||
* before calling _set_prevcreatedate() */
|
||||
copy_tv(&prev_createdate, &(blocks->blockcreatedate));
|
||||
|
||||
/* Move b_item forward to the next block
|
||||
* since we don't have the prev value for b_item and
|
||||
* also don't need to update the b_item block */
|
||||
curr_height = blocks->height;
|
||||
STRNCPY(curr_blockhash, blocks->blockhash);
|
||||
while (b_item && blocks->height == curr_height &&
|
||||
strcmp(blocks->blockhash, curr_blockhash) == 0) {
|
||||
b_item = next_in_ktree(b_ctx);
|
||||
DATA_BLOCKS_NULL(blocks, b_item);
|
||||
}
|
||||
} else {
|
||||
/* There's none before oldest_height, so instead use:
|
||||
* 'Pool Start' = first workinfo createdate */
|
||||
K_RLOCK(workinfo_free);
|
||||
wi_item = first_in_ktree(workinfo_root, wi_ctx);
|
||||
K_RUNLOCK(workinfo_free);
|
||||
if (wi_item) {
|
||||
DATA_WORKINFO(workinfo, wi_item);
|
||||
copy_tv(&prev_createdate, &(workinfo->createdate));
|
||||
} else {
|
||||
/* Shouldn't be possible since this function is first
|
||||
* called after workinfo is loaded and the workinfo
|
||||
* for each block must exist - thus data corruption */
|
||||
DATE_ZERO(&prev_createdate);
|
||||
LOGEMERG("%s() DB/tree corruption - blocks exist but "
|
||||
"no workinfo exist!"
|
||||
WHERE_FFL,
|
||||
__func__, WHERE_FFL_PASS);
|
||||
ok = false;
|
||||
}
|
||||
b_item = first_in_ktree(blocks_root, b_ctx);
|
||||
}
|
||||
|
||||
// curr_* is unset and will be set first time in the while loop
|
||||
curr_height = 0;
|
||||
curr_blockhash[0] = '\0';
|
||||
DATE_ZERO(&curr_createdate);
|
||||
currok = false;
|
||||
while (b_item) {
|
||||
DATA_BLOCKS(blocks, b_item);
|
||||
// While the same block, keep setting it
|
||||
if (blocks->height == curr_height &&
|
||||
strcmp(blocks->blockhash, curr_blockhash) == 0) {
|
||||
copy_tv(&(blocks->prevcreatedate), &prev_createdate);
|
||||
} else {
|
||||
// Next block - if currok then 'prev' becomes 'curr'
|
||||
if (currok)
|
||||
copy_tv(&prev_createdate, &curr_createdate);
|
||||
|
||||
// New curr - CURRENT will be first
|
||||
if (!CURRENT(&(blocks->expirydate))) {
|
||||
tv_to_buf(&(blocks->expirydate), cd_buf,
|
||||
sizeof(cd_buf));
|
||||
LOGEMERG("%s() block %"PRId32"/%s/%s/%s first "
|
||||
"record is not CURRENT" WHERE_FFL,
|
||||
__func__,
|
||||
blocks->height, blocks->blockhash,
|
||||
blocks->confirmed, cd_buf,
|
||||
WHERE_FFL_PASS);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
curr_height = blocks->height;
|
||||
STRNCPY(curr_blockhash, blocks->blockhash);
|
||||
copy_tv(&curr_createdate, &(blocks->blockcreatedate));
|
||||
|
||||
if (CURRENT(&(blocks->expirydate)) &&
|
||||
blocks->confirmed[0] != BLOCKS_ORPHAN &&
|
||||
blocks->confirmed[0] != BLOCKS_REJECT)
|
||||
currok = true;
|
||||
else
|
||||
currok = false;
|
||||
|
||||
// Set it
|
||||
copy_tv(&(blocks->prevcreatedate), &prev_createdate);
|
||||
}
|
||||
b_item = next_in_ktree(b_ctx);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* order by payoutid asc,userid asc,expirydate asc
|
||||
* i.e. only one payout amount per block per user */
|
||||
cmp_t cmp_miningpayouts(K_ITEM *a, K_ITEM *b)
|
||||
@ -3031,8 +3208,7 @@ K_ITEM *first_miningpayouts(int64_t payoutid, K_TREE_CTX *ctx)
|
||||
|
||||
miningpayouts.payoutid = payoutid;
|
||||
miningpayouts.userid = 0;
|
||||
miningpayouts.expirydate.tv_sec = 0;
|
||||
miningpayouts.expirydate.tv_usec = 0;
|
||||
DATE_ZERO(&(miningpayouts.expirydate));
|
||||
|
||||
INIT_MININGPAYOUTS(&look);
|
||||
look.data = (void *)(&miningpayouts);
|
||||
@ -3109,6 +3285,22 @@ cmp_t cmp_payouts_id(K_ITEM *a, K_ITEM *b)
|
||||
return c;
|
||||
}
|
||||
|
||||
/* order by workinfoidend asc,expirydate asc
|
||||
* This must use workinfoidend, not workinfoidstart, since a change
|
||||
* in the payout PPLNS N could have 2 payouts with the same start,
|
||||
* but currently there is only one payout per block
|
||||
* i.e. workinfoidend can only have one payout */
|
||||
cmp_t cmp_payouts_wid(K_ITEM *a, K_ITEM *b)
|
||||
{
|
||||
PAYOUTS *pa, *pb;
|
||||
DATA_PAYOUTS(pa, a);
|
||||
DATA_PAYOUTS(pb, b);
|
||||
cmp_t c = CMP_BIGINT(pa->workinfoidend, pb->workinfoidend);
|
||||
if (c == 0)
|
||||
c = CMP_TV(pa->expirydate, pb->expirydate);
|
||||
return c;
|
||||
}
|
||||
|
||||
K_ITEM *find_payouts(int32_t height, char *blockhash)
|
||||
{
|
||||
PAYOUTS payouts;
|
||||
@ -3157,6 +3349,24 @@ K_ITEM *find_payoutid(int64_t payoutid)
|
||||
return find_in_ktree(payouts_id_root, &look, cmp_payouts_id, ctx);
|
||||
}
|
||||
|
||||
// First payouts workinfoidend equal or before workinfoidend
|
||||
K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx)
|
||||
{
|
||||
PAYOUTS payouts;
|
||||
K_TREE_CTX ctx0[1];
|
||||
K_ITEM look;
|
||||
|
||||
if (ctx == NULL)
|
||||
ctx = ctx0;
|
||||
|
||||
payouts.workinfoidend = workinfoidend+1;
|
||||
DATE_ZERO(&(payouts.expirydate));
|
||||
|
||||
INIT_PAYOUTS(&look);
|
||||
look.data = (void *)(&payouts);
|
||||
return find_before_in_ktree(payouts_wid_root, &look, cmp_payouts_wid, ctx);
|
||||
}
|
||||
|
||||
/* Values from payout stats, returns -1 if statname isn't found
|
||||
* If code needs a value then it probably really should be a new payouts field
|
||||
* rather than stored in the stats passed to the pplns2 web page
|
||||
@ -3252,9 +3462,9 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
PAYMENTS *payments;
|
||||
WORKINFO *workinfo;
|
||||
PAYOUTS *payouts, *payouts2;
|
||||
BLOCKS *blocks, *blocks2;
|
||||
BLOCKS *blocks;
|
||||
USERS *users;
|
||||
K_ITEM *p_item, *old_p_item, *b_item, *b2_item, *w_item, *wb_item;
|
||||
K_ITEM *p_item, *old_p_item, *b_item, *w_item, *wb_item;
|
||||
K_ITEM *u_item, *mu_item, *oc_item, *pay_item, *p2_item, *old_p2_item;
|
||||
SHARESUMMARY looksharesummary, *sharesummary;
|
||||
WORKMARKERS lookworkmarkers, *workmarkers;
|
||||
@ -3291,7 +3501,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
if (p_item) {
|
||||
DATA_PAYOUTS(payouts, p_item);
|
||||
tv_to_buf(&(payouts->createdate), cd_buf, sizeof(cd_buf));
|
||||
LOGERR("%s(): payout for block %"PRId32"/%s already exists"
|
||||
LOGERR("%s(): payout for block %"PRId32"/%s already exists "
|
||||
"%"PRId64"/%"PRId64"/%"PRId64"/%s",
|
||||
__func__, height, blockhash, payouts->payoutid,
|
||||
payouts->workinfoidstart, payouts->workinfoidend,
|
||||
@ -3302,37 +3512,16 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
// Check the block status
|
||||
K_RLOCK(blocks_free);
|
||||
b_item = find_blocks(height, blockhash, b_ctx);
|
||||
K_RUNLOCK(blocks_free);
|
||||
if (!b_item) {
|
||||
K_RUNLOCK(blocks_free);
|
||||
LOGERR("%s(): no block %"PRId32"/%s for payout",
|
||||
__func__, height, blockhash);
|
||||
goto oku;
|
||||
}
|
||||
DATA_BLOCKS(blocks, b_item);
|
||||
b2_item = b_item;
|
||||
DATA_BLOCKS(blocks2, b2_item);
|
||||
while (b2_item && blocks2->height == height &&
|
||||
strcmp(blocks2->blockhash, blockhash) == 0) {
|
||||
if (blocks2->confirmed[0] == BLOCKS_NEW) {
|
||||
copy_tv(&end_tv, &(blocks2->createdate));
|
||||
if (!addr_cd)
|
||||
addr_cd = &(blocks2->createdate);
|
||||
break;
|
||||
}
|
||||
b2_item = next_in_ktree(b_ctx);
|
||||
DATA_BLOCKS_NULL(blocks2, b2_item);
|
||||
}
|
||||
K_RUNLOCK(blocks_free);
|
||||
// If addr_cd was null it should've been set to the block NEW createdate
|
||||
if (!addr_cd || end_tv.tv_sec == 0) {
|
||||
LOGEMERG("%s(): missing %s record for block %"PRId32
|
||||
"/%"PRId64"/%s/%s/%"PRId64,
|
||||
__func__, blocks_confirmed(BLOCKS_NEW_STR),
|
||||
blocks->height, blocks->workinfoid,
|
||||
blocks->workername, blocks->confirmed,
|
||||
blocks->reward);
|
||||
goto oku;
|
||||
}
|
||||
copy_tv(&end_tv, &(blocks->blockcreatedate));
|
||||
if (!addr_cd)
|
||||
addr_cd = &(blocks->blockcreatedate);
|
||||
|
||||
LOGDEBUG("%s(): block %"PRId32"/%"PRId64"/%s/%s/%"PRId64,
|
||||
__func__, blocks->height, blocks->workinfoid,
|
||||
@ -3363,11 +3552,11 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
|
||||
// Get the PPLNS N values
|
||||
K_RLOCK(optioncontrol_free);
|
||||
oc_item = find_optioncontrol(PPLNSDIFFTIMES, &(blocks->createdate),
|
||||
oc_item = find_optioncontrol(PPLNSDIFFTIMES, &(blocks->blockcreatedate),
|
||||
height);
|
||||
K_RUNLOCK(optioncontrol_free);
|
||||
if (!oc_item) {
|
||||
tv_to_buf(&(blocks->createdate), cd_buf, sizeof(cd_buf));
|
||||
tv_to_buf(&(blocks->blockcreatedate), cd_buf, sizeof(cd_buf));
|
||||
LOGEMERG("%s(): missing optioncontrol %s (%s/%"PRId32")",
|
||||
__func__, PPLNSDIFFTIMES, cd_buf, blocks->height);
|
||||
goto oku;
|
||||
@ -3376,11 +3565,11 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
diff_times = atof(optioncontrol->optionvalue);
|
||||
|
||||
K_RLOCK(optioncontrol_free);
|
||||
oc_item = find_optioncontrol(PPLNSDIFFADD, &(blocks->createdate),
|
||||
oc_item = find_optioncontrol(PPLNSDIFFADD, &(blocks->blockcreatedate),
|
||||
height);
|
||||
K_RUNLOCK(optioncontrol_free);
|
||||
if (!oc_item) {
|
||||
tv_to_buf(&(blocks->createdate), cd_buf, sizeof(cd_buf));
|
||||
tv_to_buf(&(blocks->blockcreatedate), cd_buf, sizeof(cd_buf));
|
||||
LOGEMERG("%s(): missing optioncontrol %s (%s/%"PRId32")",
|
||||
__func__, PPLNSDIFFADD, cd_buf, blocks->height);
|
||||
goto oku;
|
||||
@ -3431,7 +3620,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
end_workinfoid = sharesummary->workinfoid;
|
||||
/* Add up all sharesummaries until >= diff_want
|
||||
* also record the latest lastshare - that will be the end pplns time
|
||||
* which will be >= blocks->createdate */
|
||||
* which will be >= blocks->blockcreatedate */
|
||||
while (total_diff < diff_want && ss_item) {
|
||||
switch (sharesummary->complete[0]) {
|
||||
case SUMMARY_CONFIRM:
|
||||
@ -3584,7 +3773,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
* block - so abort
|
||||
* The fix is to create the marks and summaries needed via
|
||||
* cmd_marks() then manually trigger the payout generation
|
||||
* TODO: via cmd_payouts() ... which isn't available yet */
|
||||
* via cmd_payouts() */
|
||||
LOGEMERG("%s(): payout had < 1 (%"PRId64") workmarkers for "
|
||||
"block %"PRId32"/%"PRId64"/%s/%s/%"PRId64
|
||||
" beginwi=%"PRId64" ss=%"PRId64" diff=%.1f",
|
||||
@ -3634,6 +3823,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
bzero(payouts, sizeof(*payouts));
|
||||
payouts->height = height;
|
||||
STRNCPY(payouts->blockhash, blockhash);
|
||||
copy_tv(&(payouts->blockcreatedate), &(blocks->blockcreatedate));
|
||||
d64 = blocks->reward * 9 / 1000;
|
||||
g64 = blocks->reward - d64;
|
||||
payouts->minerreward = g64;
|
||||
@ -3805,20 +3995,8 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
pa_item = pa_item->next;
|
||||
}
|
||||
} else {
|
||||
/* Address user or normal user without a paymentaddress
|
||||
* TODO: user table needs a flag to say which it is ...
|
||||
* for now use a simple test */
|
||||
bool gotaddr = false;
|
||||
size_t len;
|
||||
|
||||
switch (users->username[0]) {
|
||||
case '1':
|
||||
case '3':
|
||||
len = strlen(users->username);
|
||||
if (len >= ADDR_MIN_LEN && len <= ADDR_MAX_LEN)
|
||||
gotaddr = true;
|
||||
}
|
||||
if (gotaddr) {
|
||||
/* Address user or normal user without a paymentaddress */
|
||||
if (users->userbits & USER_ADDRESS) {
|
||||
K_WLOCK(payments_free);
|
||||
pay_item = k_unlink_head(payments_free);
|
||||
K_WUNLOCK(payments_free);
|
||||
@ -3901,6 +4079,9 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
ss_count, wm_count, ms_count, usercount, diff_times,
|
||||
diff_add, cd_buf);
|
||||
|
||||
/* At this point the payout is complete, but it just hasn't been
|
||||
* flagged complete yet in the DB */
|
||||
|
||||
K_WLOCK(payouts_free);
|
||||
p2_item = k_unlink_head(payouts_free);
|
||||
K_WUNLOCK(payouts_free);
|
||||
@ -3909,6 +4090,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
payouts2->payoutid = payouts->payoutid;
|
||||
payouts2->height = payouts->height;
|
||||
STRNCPY(payouts2->blockhash, payouts->blockhash);
|
||||
copy_tv(&(payouts2->blockcreatedate), &(payouts->blockcreatedate));
|
||||
payouts2->minerreward = payouts->minerreward;
|
||||
payouts2->workinfoidstart = payouts->workinfoidstart;
|
||||
payouts2->workinfoidend = payouts->workinfoidend;
|
||||
@ -3926,13 +4108,20 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
|
||||
ok = payouts_add(conn, true, p2_item, &old_p2_item, (char *)by_default,
|
||||
(char *)__func__, (char *)inet_default, &now, NULL,
|
||||
false);
|
||||
|
||||
if (!ok) {
|
||||
/* All that's required is to mark the payout GENERATED
|
||||
* since it already exists in the DB and in RAM, thus a manual
|
||||
* cmd_payouts 'generated' is all that's needed to fix it */
|
||||
LOGEMERG("%s(): payout %"PRId64" for block %"PRId32"/%s "
|
||||
"NOT set generated - it needs to be set manually",
|
||||
__func__, payouts->payoutid, blocks->height,
|
||||
blocks->blockhash);
|
||||
}
|
||||
|
||||
// Flag each shift as rewarded
|
||||
reward_shifts(payouts2, true, 1);
|
||||
|
||||
CKPQDisco(&conn, conned);
|
||||
|
||||
goto oku;
|
||||
@ -4141,7 +4330,7 @@ K_ITEM *_find_markersummary(int64_t markerid, int64_t workinfoid,
|
||||
K_TREE_CTX ctx[1];
|
||||
|
||||
if (markerid == 0) {
|
||||
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED);
|
||||
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED, NULL);
|
||||
if (wm_item) {
|
||||
DATA_WORKMARKERS(wm, wm_item);
|
||||
markerid = wm->markerid;
|
||||
@ -4272,12 +4461,15 @@ cmp_t cmp_workmarkers_workinfoid(K_ITEM *a, K_ITEM *b)
|
||||
return c;
|
||||
}
|
||||
|
||||
K_ITEM *find_workmarkers(int64_t workinfoid, bool anystatus, char status)
|
||||
K_ITEM *find_workmarkers(int64_t workinfoid, bool anystatus, char status, K_TREE_CTX *ctx)
|
||||
{
|
||||
WORKMARKERS workmarkers, *wm;
|
||||
K_TREE_CTX ctx[1];
|
||||
K_TREE_CTX ctx0[1];
|
||||
K_ITEM look, *wm_item;
|
||||
|
||||
if (ctx == NULL)
|
||||
ctx = ctx0;
|
||||
|
||||
workmarkers.expirydate.tv_sec = default_expiry.tv_sec;
|
||||
workmarkers.expirydate.tv_usec = default_expiry.tv_usec;
|
||||
workmarkers.workinfoidend = workinfoid-1;
|
||||
@ -4363,8 +4555,7 @@ static bool gen_workmarkers(PGconn *conn, MARKS *stt, bool after, MARKS *fin,
|
||||
look.data = (void *)(&workinfo);
|
||||
K_RLOCK(workinfo_free);
|
||||
if (before) {
|
||||
workinfo.expirydate.tv_sec = 0;
|
||||
workinfo.expirydate.tv_usec = 0;
|
||||
DATE_ZERO(&(workinfo.expirydate));
|
||||
wi_fin_item = find_before_in_ktree(workinfo_root, &look,
|
||||
cmp_workinfo, ctx);
|
||||
while (wi_fin_item) {
|
||||
@ -4396,7 +4587,8 @@ static bool gen_workmarkers(PGconn *conn, MARKS *stt, bool after, MARKS *fin,
|
||||
* sort order and matching errors */
|
||||
if (wi_fin->workinfoid >= wi_stt->workinfoid) {
|
||||
K_RLOCK(workmarkers_free);
|
||||
old_wm_item = find_workmarkers(wi_fin->workinfoid, true, '\0');
|
||||
old_wm_item = find_workmarkers(wi_fin->workinfoid, true, '\0',
|
||||
NULL);
|
||||
K_RUNLOCK(workmarkers_free);
|
||||
DATA_WORKMARKERS_NULL(old_wm, old_wm_item);
|
||||
if (old_wm_item && (WMREADY(old_wm->status) ||
|
||||
@ -4575,6 +4767,68 @@ bool workmarkers_generate(PGconn *conn, char *err, size_t siz, char *by,
|
||||
return true;
|
||||
}
|
||||
|
||||
// delta = 1 or -1 i.e. reward or undo reward
|
||||
bool reward_shifts(PAYOUTS *payouts, bool lock, int delta)
|
||||
{
|
||||
// TODO: PPS calculations
|
||||
K_TREE_CTX ctx[1];
|
||||
K_ITEM *wm_item;
|
||||
WORKMARKERS *wm;
|
||||
bool did_one = false;
|
||||
|
||||
if (lock)
|
||||
K_WLOCK(workmarkers_free);
|
||||
|
||||
wm_item = find_workmarkers(payouts->workinfoidstart, false,
|
||||
MARKER_PROCESSED, ctx);
|
||||
while (wm_item) {
|
||||
DATA_WORKMARKERS(wm, wm_item);
|
||||
if (wm->workinfoidstart > payouts->workinfoidend)
|
||||
break;
|
||||
/* The status doesn't matter since we want the rewards passed
|
||||
* onto the PROCESSED status if it isn't already processed */
|
||||
if (CURRENT(&(wm->expirydate))) {
|
||||
wm->rewards += delta;
|
||||
did_one = true;
|
||||
}
|
||||
wm_item = next_in_ktree(ctx);
|
||||
}
|
||||
|
||||
if (lock)
|
||||
K_WUNLOCK(workmarkers_free);
|
||||
|
||||
return did_one;
|
||||
}
|
||||
|
||||
// (re)calculate rewards for a shift
|
||||
bool shift_rewards(K_ITEM *wm_item)
|
||||
{
|
||||
PAYOUTS *payouts = NULL;
|
||||
K_TREE_CTX ctx[1];
|
||||
WORKMARKERS *wm;
|
||||
K_ITEM *p_item;
|
||||
int rewards = 0;
|
||||
|
||||
DATA_WORKMARKERS(wm, wm_item);
|
||||
|
||||
// Deadlock risk since calling code should have workmarkers locked
|
||||
K_RLOCK(payouts_free);
|
||||
p_item = find_payouts_wid(wm->workinfoidend, ctx);
|
||||
DATA_PAYOUTS_NULL(payouts, p_item);
|
||||
// a workmarker should not cross a payout boundary
|
||||
while (p_item && payouts->workinfoidstart <= wm->workinfoidstart &&
|
||||
wm->workinfoidend <= payouts->workinfoidend) {
|
||||
if (CURRENT(&(payouts->expirydate)))
|
||||
rewards++;
|
||||
p_item = prev_in_ktree(ctx);
|
||||
DATA_PAYOUTS_NULL(payouts, p_item);
|
||||
}
|
||||
K_RUNLOCK(payouts_free);
|
||||
|
||||
wm->rewards = rewards;
|
||||
return (rewards > 0);
|
||||
}
|
||||
|
||||
// order by expirydate asc,workinfoid asc
|
||||
// TODO: add poolinstance
|
||||
cmp_t cmp_marks(K_ITEM *a, K_ITEM *b)
|
||||
@ -4897,7 +5151,7 @@ void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary,
|
||||
}
|
||||
|
||||
// N.B. good blocks = blocks - (orphans + rejects)
|
||||
void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock)
|
||||
void _userinfo_block(BLOCKS *blocks, enum info_type isnew, int delta, bool lock)
|
||||
{
|
||||
USERINFO *row;
|
||||
K_ITEM *item;
|
||||
@ -4907,12 +5161,12 @@ void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock)
|
||||
if (lock)
|
||||
K_WLOCK(userinfo_free);
|
||||
if (isnew == INFO_NEW) {
|
||||
row->blocks++;
|
||||
row->blocks += delta;
|
||||
copy_tv(&(row->last_block), &(blocks->createdate));
|
||||
} else if (isnew == INFO_ORPHAN)
|
||||
row->orphans++;
|
||||
row->orphans += delta;
|
||||
else if (isnew == INFO_REJECT)
|
||||
row->rejects++;
|
||||
row->rejects += delta;
|
||||
|
||||
if (lock)
|
||||
K_WUNLOCK(userinfo_free);
|
||||
|
||||
135
src/ckdb_dbio.c
135
src/ckdb_dbio.c
@ -1079,11 +1079,11 @@ K_ITEM *useratts_add(PGconn *conn, char *username, char *attname,
|
||||
else
|
||||
TXT_TO_BIGINT("attnum2", attnum2, row->attnum2);
|
||||
if (attdate == NULL || attdate[0] == '\0')
|
||||
row->attdate.tv_sec = row->attdate.tv_usec = 0L;
|
||||
DATE_ZERO(&(row->attdate));
|
||||
else
|
||||
TXT_TO_TV("attdate", attdate, row->attdate);
|
||||
if (attdate2 == NULL || attdate2[0] == '\0')
|
||||
row->attdate2.tv_sec = row->attdate2.tv_usec = 0L;
|
||||
DATE_ZERO(&(row->attdate2));
|
||||
else
|
||||
TXT_TO_TV("attdate2", attdate2, row->attdate2);
|
||||
|
||||
@ -2922,7 +2922,8 @@ bool workinfo_fill(PGconn *conn)
|
||||
if (!ok) {
|
||||
free_workinfo_data(item);
|
||||
k_add_head(workinfo_free, item);
|
||||
}
|
||||
} else
|
||||
ok = set_prevcreatedate(0);
|
||||
|
||||
//K_WUNLOCK(workinfo_free);
|
||||
PQclear(res);
|
||||
@ -2959,7 +2960,7 @@ static bool shares_process(PGconn *conn, SHARES *shares, K_TREE *trf_root)
|
||||
if (reloading && !confirm_sharesummary) {
|
||||
// We only need to know if the workmarker is processed
|
||||
wm_item = find_workmarkers(shares->workinfoid, false,
|
||||
MARKER_PROCESSED);
|
||||
MARKER_PROCESSED, NULL);
|
||||
if (wm_item) {
|
||||
LOGDEBUG("%s(): workmarker exists for wid %"PRId64
|
||||
" %"PRId64"/%s/%ld,%ld",
|
||||
@ -3260,7 +3261,7 @@ static bool shareerrors_process(PGconn *conn, SHAREERRORS *shareerrors,
|
||||
if (reloading && !confirm_sharesummary) {
|
||||
// We only need to know if the workmarker is processed
|
||||
wm_item = find_workmarkers(shareerrors->workinfoid, false,
|
||||
MARKER_PROCESSED);
|
||||
MARKER_PROCESSED, NULL);
|
||||
if (wm_item) {
|
||||
LOGDEBUG("%s(): workmarker exists for wid %"PRId64
|
||||
" %"PRId64"/%s/%ld,%ld",
|
||||
@ -4024,7 +4025,8 @@ bool _sharesummary_update(SHARES *s_row, SHAREERRORS *e_row, K_ITEM *ss_item,
|
||||
}
|
||||
|
||||
K_RLOCK(workmarkers_free);
|
||||
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED);
|
||||
wm_item = find_workmarkers(workinfoid, false, MARKER_PROCESSED,
|
||||
NULL);
|
||||
K_RUNLOCK(workmarkers_free);
|
||||
if (wm_item) {
|
||||
DATA_WORKMARKERS(wm, wm_item);
|
||||
@ -4298,6 +4300,7 @@ unparam:
|
||||
blocks_root = add_to_ktree(blocks_root, b_item, cmp_blocks);
|
||||
k_add_head(blocks_store, b_item);
|
||||
blocks_stats_rebuild = true;
|
||||
// 'confirmed' is unchanged so no need to recalc *createdate
|
||||
}
|
||||
K_WUNLOCK(blocks_free);
|
||||
|
||||
@ -4438,7 +4441,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
||||
}
|
||||
// We didn't use a Begin
|
||||
ok = true;
|
||||
userinfo_block(row, INFO_NEW);
|
||||
userinfo_block(row, INFO_NEW, 1);
|
||||
goto unparam;
|
||||
break;
|
||||
case BLOCKS_ORPHAN:
|
||||
@ -4597,10 +4600,49 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
||||
}
|
||||
|
||||
update_old = true;
|
||||
if (confirmed[0] == BLOCKS_ORPHAN)
|
||||
userinfo_block(row, INFO_ORPHAN);
|
||||
else if (confirmed[0] == BLOCKS_REJECT)
|
||||
userinfo_block(row, INFO_REJECT);
|
||||
/* handle confirmed state changes for userinfo
|
||||
* this case statement handles all possible combinations
|
||||
* even if they can't happen (yet) */
|
||||
switch (oldblocks->confirmed[0]) {
|
||||
case BLOCKS_ORPHAN:
|
||||
switch (confirmed[0]) {
|
||||
case BLOCKS_ORPHAN:
|
||||
break;
|
||||
case BLOCKS_REJECT:
|
||||
userinfo_block(row, INFO_ORPHAN, -1);
|
||||
userinfo_block(row, INFO_REJECT, 1);
|
||||
break;
|
||||
default:
|
||||
userinfo_block(row, INFO_ORPHAN, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BLOCKS_REJECT:
|
||||
switch (confirmed[0]) {
|
||||
case BLOCKS_REJECT:
|
||||
break;
|
||||
case BLOCKS_ORPHAN:
|
||||
userinfo_block(row, INFO_REJECT, -1);
|
||||
userinfo_block(row, INFO_ORPHAN, 1);
|
||||
break;
|
||||
default:
|
||||
userinfo_block(row, INFO_REJECT, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (confirmed[0]) {
|
||||
case BLOCKS_ORPHAN:
|
||||
userinfo_block(row, INFO_ORPHAN, 1);
|
||||
break;
|
||||
case BLOCKS_REJECT:
|
||||
userinfo_block(row, INFO_REJECT, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGERR("%s(): %s.failed.invalid confirm='%s'",
|
||||
@ -4638,6 +4680,9 @@ flail:
|
||||
blocks_root = add_to_ktree(blocks_root, b_item, cmp_blocks);
|
||||
k_add_head(blocks_store, b_item);
|
||||
blocks_stats_rebuild = true;
|
||||
// recalc the *createdate fields for possibly affected blocks
|
||||
set_blockcreatedate(row->height);
|
||||
set_prevcreatedate(row->height);
|
||||
}
|
||||
K_WUNLOCK(blocks_free);
|
||||
|
||||
@ -4711,6 +4756,7 @@ bool blocks_fill(PGconn *conn)
|
||||
{
|
||||
ExecStatusType rescode;
|
||||
PGresult *res;
|
||||
K_TREE_CTX ctx[1];
|
||||
K_ITEM *item;
|
||||
int n, i;
|
||||
BLOCKS *row;
|
||||
@ -4862,16 +4908,30 @@ bool blocks_fill(PGconn *conn)
|
||||
pool.height = row->height;
|
||||
}
|
||||
|
||||
if (CURRENT(&(row->expirydate))) {
|
||||
_userinfo_block(row, INFO_NEW, false);
|
||||
if (row->confirmed[0] == BLOCKS_ORPHAN)
|
||||
_userinfo_block(row, INFO_ORPHAN, false);
|
||||
else if (row->confirmed[0] == BLOCKS_REJECT)
|
||||
_userinfo_block(row, INFO_REJECT, false);
|
||||
}
|
||||
// first add all the NEW blocks
|
||||
if (row->confirmed[0] == BLOCKS_NEW)
|
||||
_userinfo_block(row, INFO_NEW, 1, false);
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
k_add_head(blocks_free, item);
|
||||
else
|
||||
ok = set_blockcreatedate(0);
|
||||
|
||||
// Now update all the CURRENT orphan/reject stats
|
||||
if (ok) {
|
||||
item = first_in_ktree(blocks_root, ctx);
|
||||
while (item) {
|
||||
DATA_BLOCKS(row, item);
|
||||
if (CURRENT(&(row->expirydate))) {
|
||||
if (row->confirmed[0] == BLOCKS_ORPHAN)
|
||||
_userinfo_block(row, INFO_ORPHAN, 1, false);
|
||||
else if (row->confirmed[0] == BLOCKS_REJECT)
|
||||
_userinfo_block(row, INFO_REJECT, 1, false);
|
||||
}
|
||||
item = next_in_ktree(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
K_WUNLOCK(blocks_free);
|
||||
PQclear(res);
|
||||
@ -5118,12 +5178,15 @@ void payouts_add_ram(bool ok, K_ITEM *p_item, K_ITEM *old_p_item, tv_t *cd)
|
||||
DATA_PAYOUTS(oldp, old_p_item);
|
||||
payouts_root = remove_from_ktree(payouts_root, old_p_item, cmp_payouts);
|
||||
payouts_id_root = remove_from_ktree(payouts_id_root, old_p_item, cmp_payouts_id);
|
||||
payouts_wid_root = remove_from_ktree(payouts_wid_root, old_p_item, cmp_payouts_wid);
|
||||
copy_tv(&(oldp->expirydate), cd);
|
||||
payouts_root = add_to_ktree(payouts_root, old_p_item, cmp_payouts);
|
||||
payouts_id_root = add_to_ktree(payouts_id_root, old_p_item, cmp_payouts_id);
|
||||
payouts_wid_root = add_to_ktree(payouts_wid_root, old_p_item, cmp_payouts_wid);
|
||||
}
|
||||
payouts_root = add_to_ktree(payouts_root, p_item, cmp_payouts);
|
||||
payouts_id_root = add_to_ktree(payouts_id_root, p_item, cmp_payouts_id);
|
||||
payouts_wid_root = add_to_ktree(payouts_wid_root, p_item, cmp_payouts_wid);
|
||||
k_add_head(payouts_store, p_item);
|
||||
}
|
||||
K_WUNLOCK(payouts_free);
|
||||
@ -5430,9 +5493,11 @@ K_ITEM *payouts_full_expire(PGconn *conn, int64_t payoutid, tv_t *now, bool lock
|
||||
DATA_PAYOUTS(payouts, po_item);
|
||||
payouts_root = remove_from_ktree(payouts_root, po_item, cmp_payouts);
|
||||
payouts_id_root = remove_from_ktree(payouts_id_root, po_item, cmp_payouts_id);
|
||||
payouts_wid_root = remove_from_ktree(payouts_wid_root, po_item, cmp_payouts_wid);
|
||||
copy_tv(&(payouts->expirydate), now);
|
||||
payouts_root = add_to_ktree(payouts_root, po_item, cmp_payouts);
|
||||
payouts_id_root = add_to_ktree(payouts_id_root, po_item, cmp_payouts_id);
|
||||
payouts_wid_root = add_to_ktree(payouts_wid_root, po_item, cmp_payouts_wid);
|
||||
|
||||
mp_item = first_miningpayouts(payoutid, mp_ctx);
|
||||
DATA_MININGPAYOUTS_NULL(mp, mp_item);
|
||||
@ -5465,6 +5530,12 @@ K_ITEM *payouts_full_expire(PGconn *conn, int64_t payoutid, tv_t *now, bool lock
|
||||
DATA_PAYMENTS_NULL(payments, pm_item);
|
||||
}
|
||||
|
||||
if (PAYGENERATED(payouts->status)) {
|
||||
// Original was generated, so undo the reward
|
||||
reward_shifts(payouts, true, -1);
|
||||
|
||||
}
|
||||
|
||||
ok = true;
|
||||
matane:
|
||||
if (begun)
|
||||
@ -5494,8 +5565,10 @@ bool payouts_fill(PGconn *conn)
|
||||
{
|
||||
ExecStatusType rescode;
|
||||
PGresult *res;
|
||||
K_ITEM *item;
|
||||
K_ITEM *item, *b_item;
|
||||
K_TREE_CTX ctx[1];
|
||||
PAYOUTS *row;
|
||||
BLOCKS *blocks;
|
||||
int n, i;
|
||||
char *field;
|
||||
char *sel;
|
||||
@ -5609,10 +5682,30 @@ bool payouts_fill(PGconn *conn)
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
// This also of course, verifies the payouts -> blocks reference
|
||||
b_item = find_blocks(row->height, row->blockhash, ctx);
|
||||
if (!b_item) {
|
||||
LOGERR("%s(): payoutid %"PRId64" references unknown "
|
||||
"block %"PRId32"/%s",
|
||||
__func__, row->payoutid, row->height,
|
||||
row->blockhash);
|
||||
ok = false;
|
||||
break;
|
||||
} else {
|
||||
// blockcreatedate will already be set
|
||||
DATA_BLOCKS(blocks, b_item);
|
||||
copy_tv(&(row->blockcreatedate),
|
||||
&(blocks->blockcreatedate));
|
||||
}
|
||||
|
||||
payouts_root = add_to_ktree(payouts_root, item, cmp_payouts);
|
||||
payouts_id_root = add_to_ktree(payouts_id_root, item, cmp_payouts_id);
|
||||
payouts_wid_root = add_to_ktree(payouts_wid_root, item, cmp_payouts_wid);
|
||||
k_add_head(payouts_store, item);
|
||||
|
||||
if (CURRENT(&(row->expirydate)) && PAYGENERATED(row->status))
|
||||
reward_shifts(row, false, 1);
|
||||
|
||||
tick();
|
||||
}
|
||||
if (!ok) {
|
||||
@ -6517,7 +6610,7 @@ bool _workmarkers_process(PGconn *conn, bool already, bool add,
|
||||
|
||||
if (markerid == 0) {
|
||||
K_RLOCK(workmarkers_free);
|
||||
old_wm_item = find_workmarkers(workinfoidend, true, '\0');
|
||||
old_wm_item = find_workmarkers(workinfoidend, true, '\0', NULL);
|
||||
K_RUNLOCK(workmarkers_free);
|
||||
} else {
|
||||
K_RLOCK(workmarkers_free);
|
||||
@ -6691,6 +6784,8 @@ unparam:
|
||||
cmp_workmarkers_workinfoid);
|
||||
}
|
||||
if (wm_item) {
|
||||
shift_rewards(wm_item);
|
||||
|
||||
workmarkers_root = add_to_ktree(workmarkers_root,
|
||||
wm_item,
|
||||
cmp_workmarkers);
|
||||
|
||||
@ -1715,7 +1715,7 @@ static void *proxy_send(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void passthrough_send(ckpool_t __maybe_unused *ckp, pass_msg_t *pm)
|
||||
static void passthrough_send(ckpool_t *ckp, pass_msg_t *pm)
|
||||
{
|
||||
int len, sent;
|
||||
|
||||
@ -1723,8 +1723,9 @@ static void passthrough_send(ckpool_t __maybe_unused *ckp, pass_msg_t *pm)
|
||||
len = strlen(pm->msg);
|
||||
sent = write_socket(pm->cs->fd, pm->msg, len);
|
||||
if (sent != len) {
|
||||
/* FIXME: Do something about this? */
|
||||
LOGWARNING("Failed to passthrough %d bytes of message %s", len, pm->msg);
|
||||
LOGWARNING("Failed to passthrough %d bytes of message %s, attempting reconnect",
|
||||
len, pm->msg);
|
||||
send_proc(ckp->generator, "reconnect");
|
||||
}
|
||||
free(pm->msg);
|
||||
free(pm);
|
||||
|
||||
10
src/ktree.c
10
src/ktree.c
@ -89,15 +89,11 @@ static void show_ktree(K_TREE *root, char *path, int pos, char *(*dsp_funct)(K_I
|
||||
|
||||
path[pos] = '\0';
|
||||
|
||||
switch(root->red)
|
||||
{
|
||||
case RED_RED:
|
||||
if (root->red == RED_RED)
|
||||
col = 'R';
|
||||
break;
|
||||
case RED_BLACK:
|
||||
else
|
||||
// if (root->red == RED_BLACK)
|
||||
col = 'B';
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" %c %s=%s\n", col, path, dsp_funct(root->data));
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user