Browse Source

ckdb/php - dbv1.0.2, handle rejected, non-orphan blocks, update 2fa with qrcode, email, web details

master
kanoi 9 years ago
parent
commit
eafdddb8ef
  1. 39
      pool/email.php
  2. 11
      pool/inc.php
  3. 36
      pool/page.php
  4. 120
      pool/page_2fa.php
  5. 41
      pool/page_blocks.php
  6. 2
      pool/page_settings.php
  7. 3
      sql/ckdb.sql
  8. 25
      sql/v1.0.1-v1.0.2.sql
  9. 7
      src/ckdb.c
  10. 47
      src/ckdb.h
  11. 4
      src/ckdb_btc.c
  12. 120
      src/ckdb_cmd.c
  13. 63
      src/ckdb_crypt.c
  14. 32
      src/ckdb_data.c
  15. 98
      src/ckdb_dbio.c

39
pool/email.php

@ -172,6 +172,45 @@ function passChanged($to, $whoip, $emailinfo)
return sendnoheader($to, "Password Change", $message, $emailinfo); return sendnoheader($to, "Password Change", $message, $emailinfo);
} }
# #
function twofaSetup($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 is ready to be tested.$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);
}
#
function twofaEnabled($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 is enabled on your account.$eol$eol";
$message .= $ret;
return sendnoheader($to, "2FA is Enabled", $message, $emailinfo);
}
#
# getOpts required for email # getOpts required for email
# If they aren't all setup in the DB then email functions will return false # If they aren't all setup in the DB then email functions will return false
function emailOptList() function emailOptList()

11
pool/inc.php

@ -29,7 +29,9 @@ 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 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('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 sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}} function sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}}
function gc(c){var div=document.getElementById('can0');while (div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';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']}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 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)}
function gcxy(c,xm,ym){c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.min(Math.round(c['wx']*0.95),xm);c['ym']=Math.min(Math.round(c['wy']*0.95),ym);gc2(c)}
function opts(t,i){var e=document.getElementById(i);if(t.checked){e.style.visibility='visible'}else{e.style.visibility='hidden'}} function opts(t,i){var e=document.getElementById(i);if(t.checked){e.style.visibility='visible'}else{e.style.visibility='hidden'}}
function ghrs(c){c['hrs']=[1,2,3,4,6,8,12,24,48];c['hln']=[1,2,3,4,6]} 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 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}}
@ -148,4 +150,11 @@ function sotc(cn,d){var ws=gcn(cn);if(ws==''){ws=d}sotn(cn,ws)}
return $s; return $s;
} }
# #
function QRJS()
{
$q = "function qr(tw,fa,qrx,qry,qrd){if(hasCan()){gcxy(c,qrx*4,qry*4);gfs(c,'white');gss(c,'white');gbd(c);gfs(c,'black');gss(c,'black');for(var y=0;y<qry;y++){var x=0,b=0;for(var j=0;j<qrx;j+=4){var n=qrd[y].substr(b,1).charCodeAt(0)-97;for(k=0;k<4;k++){if(n & (1<<k)){gbe(c,x/qrx,1-(y/qry));gln(c,(x+1)/qrx,1-(y/qry));gln(c,(x+1)/qrx,1-((y+1)/qry));gln(c,x/qrx,1-((y+1)/qry));gle(c);gfl(c)}x++}b++}}}}
";
return $q;
}
#
?> ?>

36
pool/page.php

@ -51,26 +51,60 @@ function addCSS($css)
$page_css .= $css; $page_css .= $css;
} }
# #
global $added_gbase;
$added_gbase = false;
function addGBase() function addGBase()
{ {
global $added_gbase;
if ($added_gbase == false)
{
$added_gbase = true;
$g = GBaseJS(); $g = GBaseJS();
addScript($g); addScript($g);
} }
}
# #
global $added_tips;
$added_tips = false;
function addTips() function addTips()
{ {
global $added_tips;
if ($added_tips == false)
{
$added_tips = true;
$t = TipsJS(); $t = TipsJS();
addScript($t); addScript($t);
$tcss = TipsCSS(); $tcss = TipsCSS();
addCSS($tcss); addCSS($tcss);
} }
}
# #
global $added_sort;
$added_sort = false;
function addSort() function addSort()
{ {
global $added_sort;
if ($added_sort == false)
{
$added_sort = true;
$s = SortJS(); $s = SortJS();
addScript($s); addScript($s);
} }
}
#
global $added_qr;
$added_qr = false;
function addQR()
{
global $added_qr;
if ($added_qr == false)
{
$added_qr = true;
addGBase();
$q = QRJS();
addScript($q);
}
}
# #
function makeURL($page) function makeURL($page)
{ {

120
pool/page_2fa.php

@ -1,7 +1,20 @@
<?php <?php
# #
include_once('email.php');
#
function app_txt($ones)
{
$app = "The free and recommended $ones that ";
$app .= "have been tested here are:<br><span class=hil>";
$app .= "Android: Google Play '<b>FreeOTP Authenticator</b>' by Red Hat<br>";
$app .= "Apple: App Store '<b>OTP Auth</b>' by Roland Moers</span><br><br>";
return $app;
}
#
function set_2fa($data, $user, $tfa, $ans, $err) function set_2fa($data, $user, $tfa, $ans, $err)
{ {
$draw = false;
$pg = '<h1>Two Factor Authentication Settings</h1>'; $pg = '<h1>Two Factor Authentication Settings</h1>';
if ($err !== null and $err != '') if ($err !== null and $err != '')
@ -17,12 +30,10 @@ function set_2fa($data, $user, $tfa, $ans, $err)
{ {
case '': case '':
$pg .= '<tr class=dl><td>'; $pg .= '<tr class=dl><td>';
$pg .= "You don't have 2FA setup yet<br><br>"; $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 .= 'To use 2FA you need an App on your phone/tablet<br>';
$pg .= 'The free and recommended ones that have been tested here are:<br><br>'; $pg .= app_txt('ones');
$pg .= "Android: Google Play 'FreeOTP Authenticator' by Red Hat<br>"; $pg .= 'Click here to begin the setup process for 2FA: ';
$pg .= "Apple: App Store 'OTP Auth' by Roland Moers<br><br>";
$pg .= 'Click here to start setting up 2FA: ';
$pg .= '<input type=submit name=Setup value=Setup>'; $pg .= '<input type=submit name=Setup value=Setup>';
$pg .= '</td></tr>'; $pg .= '</td></tr>';
break; break;
@ -39,6 +50,8 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$sfaurl = 'otpauth://'.$ans['2fa_auth'].'/'.$ans['2fa_issuer']. $sfaurl = 'otpauth://'.$ans['2fa_auth'].'/'.$ans['2fa_issuer'].
':'.htmlspecialchars($who).'?secret='.$ans['2fa_key']. ':'.htmlspecialchars($who).'?secret='.$ans['2fa_key'].
'&algorithm='.$ans['2fa_hash'].'&issuer='.$ans['2fa_issuer']; '&algorithm='.$ans['2fa_hash'].'&issuer='.$ans['2fa_issuer'];
$draw = true;
addQR();
} }
else else
{ {
@ -46,11 +59,25 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$sfainfo = 'unavailable'; $sfainfo = 'unavailable';
$sfaurl = 'unavailable'; $sfaurl = 'unavailable';
} }
$pg .= "Your 2FA Secret Key is: $key<br>"; $pg .= "Your <span class=urg>2FA Secret Key</span> is: $key<br>";
$pg .= "2FA Settings are $sfainfo<br><br>"; $pg .= "2FA Settings are $sfainfo<br><br>";
$pg .= "2FA URL is <a href='$sfaurl'>Click</a><br><br>"; $pg .= "To setup 2FA in your App: <a href='$sfaurl'>Click here</a><br>";
$pg .= '2FA Value: <input name=Value value="" size=10> '; $pg .= "or scan the qrcode/barcode below with your App:<br><br>";
$pg .= '<input type=submit name=Test value=Test>'; $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 .= 'Then enter your App 2FA Value: <input name=Value value="" size=10> ';
$pg .= '<input type=submit name=Test value=Test></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>';
$pg .= 'you should setup all devices before testing one of them.<br>';
$pg .= 'If you have an old <span class=urg>2FA Secret Key</span> in your device for this web site,<br>';
$pg .= 'delete it before scanning in the new <span class=urg>2FA Secret Key</span>.<br><br>';
$pg .= '<span class=urg>WARNING:</span> if you lose your 2FA device you will need to know<br>';
$pg .= 'the <span class=urg>2FA Secret Key</span> to manually setup a new device,<br>';
$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 .= '</td></tr>';
break; break;
case 'ok': case 'ok':
@ -60,16 +87,51 @@ function set_2fa($data, $user, $tfa, $ans, $err)
$pg .= 'Current 2FA Value: <input name=Value value="" size=10> '; $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><br><br>';
$pg .= '<span class=st1>*</span>WARNING: replacing the Secret Key will disable 2FA<br>'; $pg .= '<span class=st1>*</span>WARNING: replacing the Secret Key will disable 2FA<br>';
$pg .= 'until you successfully test the new key.<br><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 .= '</td></tr>';
break; break;
} }
$pg .= '</table></form>'; $pg .= '</table></form>';
$pg .= '</center></td></tr>'; $pg .= '</center></td></tr>';
$pg .= '<tr class=dl><td>';
$pg .= '2FA means that you need 2 codes to login to your account.<br>';
$pg .= 'You will also need the 2FA code to modify any important settings in your account.<br>';
$pg .= 'The 1st code is your current password.<br>';
$pg .= 'The 2nd code is a number that your 2FA device will generate each time.<br>';
$pg .= 'Your 2FA device would be, for example, your phone or tablet.<br><br>';
$pg .= 'Each time you need a 2FA code, you use your device to generate a number<br>';
$pg .= 'that you type into the "<span class=st1>*</span>2nd Authentication:" field on any page that has it.<br><br>';
$pg .= '<span class=urg>WARNING:</span> once you have successfully tested and enabled 2FA,<br>';
$pg .= 'you will be unable to access or even reset your account without 2FA.<br>';
$pg .= 'There is no option to recover your 2FA from the web site,<br>';
$pg .= 'and you must know your 2FA code in order to be able to disable 2FA.<br><br>';
$pg .= '<span class=urg>WARNING:</span> it is important to <b>not</b> store your login password in your 2FA device.<br>';
$pg .= 'These 2 together will give full access to your account.';
$pg .= '</td></tr>';
$pg .= '</table>'; $pg .= '</table>';
if ($draw !== false)
{
$qr = shell_exec("../pool/myqr.sh '$sfaurl'");
if ($qr !== null and strlen($qr) > 30)
{
$pg .= "<script type='text/javascript'>\n";
$pg .= "${qr}qr(tw,fa,qrx,qry,qrd);</script>\n";
if (strpos($qr, 'var tw=1,fa=0,qrx=') === false)
error_log("QR error for '$user' res='$qr'");
}
else
{
if ($qr === null)
$qr = 'null';
error_log("QR failed for '$user' res='$qr'");
}
}
return $pg; return $pg;
} }
# #
@ -77,23 +139,30 @@ function do2fa($data, $user)
{ {
$err = ''; $err = '';
$setup = getparam('Setup', false); $setup = getparam('Setup', false);
$testemail = false;
if ($setup === 'Setup') if ($setup === 'Setup')
{ {
// rand() included as part of the entropy // rand() included as part of the entropy
$ans = get2fa($user, 'setup', rand(1073741824,2147483647), 0); $ans = get2fa($user, 'setup', rand(1073741824,2147483647), 0);
$testemail = true;
} }
else else
{ {
$value = getparam('Value', false); $value = getparam('Value', false);
$test = getparam('Test', false); $test = getparam('Test', false);
if ($test === 'Test' and $value !== null) if ($test === 'Test' and $value !== null)
{
$ans = get2fa($user, 'test', 0, $value); $ans = get2fa($user, 'test', 0, $value);
$testemail = true;
}
else else
{ {
$nw = getparam('New', false); $nw = getparam('New', false);
if ($nw === 'New' and $value !== null) if ($nw === 'New' and $value !== null)
{
$ans = get2fa($user, 'new', rand(1073741824,2147483647), $value); $ans = get2fa($user, 'new', rand(1073741824,2147483647), $value);
$testemail = true;
}
else else
$ans = get2fa($user, '', 0, 0); $ans = get2fa($user, '', 0, 0);
} }
@ -104,6 +173,31 @@ function do2fa($data, $user)
{ {
if (isset($ans['2fa_error'])) if (isset($ans['2fa_error']))
$err = $ans['2fa_error']; $err = $ans['2fa_error'];
if ($testemail and $err == '')
{
$ans2 = userSettings($user);
if ($ans2['STATUS'] != 'ok')
dbdown(); // Should be no other reason?
if (!isset($ans2['email']))
$err = 'An error occurred, check your details below';
else
{
$email = $ans2['email'];
$emailinfo = getOpts($user, emailOptList());
if ($emailinfo['STATUS'] != 'ok')
$err = 'An error occurred, check your details below';
else
{
if ($setup === 'Setup')
twofaSetup($email, zeip(), $emailinfo);
else if ($test === 'Test')
twofaEnabled($email, zeip(), $emailinfo);
else if ($nw === 'New')
twofaSetup($email, zeip(), $emailinfo);
}
}
}
} }
if (!isset($ans['2fa_status'])) if (!isset($ans['2fa_status']))
$tfa = null; $tfa = null;

41
pool/page_blocks.php

@ -18,7 +18,7 @@ function erlcolour($erl)
} }
else # ($erl > 0.5) else # ($erl > 0.5)
{ {
$ref = (-0.3 - log10(1.0 - $erl)) * 255; $red = (-0.3 - log10(1.0 - $erl)) * 255;
if ($red < 0) if ($red < 0)
$red = 0; $red = 0;
if ($red > 255) if ($red > 255)
@ -194,28 +194,51 @@ function doblocks($data, $user)
$hifld = "$blink$hi>$hi</a>"; $hifld = "$blink$hi>$hi</a>";
$ex = ''; $ex = '';
$conf = $ans['confirmed:'.$i];
$stat = $ans['status:'.$i]; $stat = $ans['status:'.$i];
if ($stat == 'Orphan') $inf = $ans['info:'.$i];
$tt = '';
if ($conf == 'O' or $conf == 'R')
{ {
$ex = 's'; $ex = 's';
$orph = true; $orph = true;
$seq = ''; $seq = '';
if ($conf == 'R')
{
addTips();
$in = explode(':', $inf, 2);
if (trim($in[0]) != '')
$stat = trim($in[0]);
if (count($in) < 2 or trim($in[1]) == '')
{
$tip = 'Share diff was VERY close<br>';
$tip .= 'so we tested it,<br>';
$tip .= "but it wasn't worthy<br>";
}
else
$tip = str_replace('+', '<br>', trim($in[1]));
$tt = "<span class=q onclick='tip(\"btip$i\",6000)'>";
$tt .= '?</span><span class=tip0>';
$tt .= "<span class=notip id=btip$i>";
$tt .= "$tip</span></span>";
}
} }
else else
$seq = $ans['seq:'.$i]; $seq = $ans['seq:'.$i];
if ($stat == '1-Confirm') if ($conf == '1')
{ {
if (isset($data['info']['lastheight'])) if (isset($data['info']['lastheight']))
{ {
$conf = 1 + $data['info']['lastheight'] - $hi; $confn = 1 + $data['info']['lastheight'] - $hi;
$stat = '+'.$conf.' Confirms'; $stat = '+'.$confn.' Confirms';
} }
else else
$stat = 'Conf'; $stat = 'Conf';
} }
$stara = ''; $stara = '';
if ($stat == 'Orphan') if ($conf == 'O' or $conf == 'R')
$stara = '<span class=st1>*</span>'; $stara = '<span class=st1>*</span>';
if (isset($ans['statsconf:'.$i])) if (isset($ans['statsconf:'.$i]))
@ -243,7 +266,7 @@ function doblocks($data, $user)
$bpct = "<font color=$fg>$approx".number_format($pct, 3).'%</font>'; $bpct = "<font color=$fg>$approx".number_format($pct, 3).'%</font>';
$bg = " bgcolor=$bg"; $bg = " bgcolor=$bg";
$blktot += $diffacc; $blktot += $diffacc;
if ($stat != 'Orphan') if ($conf != 'O' and $conf != 'R')
$nettot += $netdiff; $nettot += $netdiff;
$cdfdsp = number_format($cdf, 3); $cdfdsp = number_format($cdf, 3);
@ -264,7 +287,7 @@ function doblocks($data, $user)
$pg .= "<td class=dl$ex>".htmlspecialchars($ans['workername:'.$i]).'</td>'; $pg .= "<td class=dl$ex>".htmlspecialchars($ans['workername:'.$i]).'</td>';
$pg .= "<td class=dr$ex>".btcfmt($ans['reward:'.$i]).'</td>'; $pg .= "<td class=dr$ex>".btcfmt($ans['reward:'.$i]).'</td>';
$pg .= "<td class=dl$ex>".utcd($ans['firstcreatedate:'.$i]).'</td>'; $pg .= "<td class=dl$ex>".utcd($ans['firstcreatedate:'.$i]).'</td>';
$pg .= "<td class=dr$ex>$stat</td>"; $pg .= "<td class=dr$ex>$tt$stat</td>";
$pg .= "<td class=dr>$stara$approx$acc</td>"; $pg .= "<td class=dr>$stara$approx$acc</td>";
$pg .= "<td class=dr$bg>$bpct</td>"; $pg .= "<td class=dr$bg>$bpct</td>";
$pg .= "<td class=dr>$cdfdsp</td>"; $pg .= "<td class=dr>$cdfdsp</td>";
@ -295,7 +318,7 @@ function doblocks($data, $user)
else else
$pg .= '8'; $pg .= '8';
$pg .= ' class=dc><font size=-1><span class=st1>*</span>'; $pg .= ' class=dc><font size=-1><span class=st1>*</span>';
$pg .= "Orphans count as shares but not as a block in calculations"; $pg .= 'Orphans/Rejects count as shares but not as a block in calculations';
$pg .= '</font></td></tr>'; $pg .= '</font></td></tr>';
} }
$pg .= "</table>\n"; $pg .= "</table>\n";

2
pool/page_settings.php

@ -218,7 +218,7 @@ function dosettings($data, $user)
$old = $_SESSION['old_set_email']; $old = $_SESSION['old_set_email'];
else else
$old = null; $old = null;
# emailAddressChanged($email, zeip(), $emailinfo, $old); emailAddressChanged($email, zeip(), $emailinfo, $old);
break; break;
case 'Address': case 'Address':
payoutAddressChanged($email, zeip(), $emailinfo); payoutAddressChanged($email, zeip(), $emailinfo);

3
sql/ckdb.sql

@ -336,6 +336,7 @@ CREATE TABLE blocks (
nonce character varying(64) NOT NULL, nonce character varying(64) NOT NULL,
reward bigint NOT NULL, -- satoshis reward bigint NOT NULL, -- satoshis
confirmed char DEFAULT '' NOT NULL, confirmed char DEFAULT '' NOT NULL,
info character varying(64) DEFAULT ''::character varying NOT NULL,
diffacc float DEFAULT 0 NOT NULL, diffacc float DEFAULT 0 NOT NULL,
diffinv float DEFAULT 0 NOT NULL, diffinv float DEFAULT 0 NOT NULL,
shareacc float DEFAULT 0 NOT NULL, shareacc float DEFAULT 0 NOT NULL,
@ -463,4 +464,4 @@ CREATE TABLE version (
PRIMARY KEY (vlock) PRIMARY KEY (vlock)
); );
insert into version (vlock,version) values (1,'1.0.1'); insert into version (vlock,version) values (1,'1.0.2');

25
sql/v1.0.1-v1.0.2.sql

@ -0,0 +1,25 @@
SET SESSION AUTHORIZATION 'postgres';
BEGIN transaction;
DO $$
DECLARE ver TEXT;
BEGIN
UPDATE version set version='1.0.2' where vlock=1 and version='1.0.1';
IF found THEN
RETURN;
END IF;
SELECT version into ver from version
WHERE vlock=1;
RAISE EXCEPTION 'Wrong DB version - expect "1.0.1" - found "%"', ver;
END $$;
ALTER TABLE ONLY blocks
ADD COLUMN info character varying(64) DEFAULT ''::character varying NOT NULL;
END transaction;

7
src/ckdb.c

@ -165,6 +165,8 @@ const char *hashpatt = "^[A-Fa-f0-9]*$";
* and with a simple test must be ADDR_MIN_LEN to ADDR_MAX_LEN (ckdb.h) * and with a simple test must be ADDR_MIN_LEN to ADDR_MAX_LEN (ckdb.h)
* bitcoind is used to fully validate them when required */ * bitcoind is used to fully validate them when required */
const char *addrpatt = "^[13][A-HJ-NP-Za-km-z1-9]*$"; const char *addrpatt = "^[13][A-HJ-NP-Za-km-z1-9]*$";
// Strings in socket transfer: space to '~' excluding '='
const char *strpatt = "^[ -<>-~]*$";
// So the records below have the same 'name' as the klist // So the records below have the same 'name' as the klist
const char Transfer[] = "Transfer"; const char Transfer[] = "Transfer";
@ -423,6 +425,7 @@ const char *blocks_new = "New";
const char *blocks_confirm = "1-Confirm"; const char *blocks_confirm = "1-Confirm";
const char *blocks_42 = "Matured"; const char *blocks_42 = "Matured";
const char *blocks_orphan = "Orphan"; const char *blocks_orphan = "Orphan";
const char *blocks_reject = "Unworthy";
const char *blocks_unknown = "?Unknown?"; const char *blocks_unknown = "?Unknown?";
K_TREE *blocks_root; K_TREE *blocks_root;
@ -4680,7 +4683,7 @@ static void *listener(void *arg)
LOGEMERG("ABORTING"); LOGEMERG("ABORTING");
everyone_die = true; everyone_die = true;
} }
return NULL; goto sayonara;
} }
if (!everyone_die) { if (!everyone_die) {
@ -4789,6 +4792,8 @@ static void *listener(void *arg)
} }
} }
sayonara:
listener_using_data = false; listener_using_data = false;
if (conn) if (conn)

47
src/ckdb.h

@ -54,8 +54,8 @@
*/ */
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "1.0.1" #define DB_VERSION "1.0.2"
#define CKDB_VERSION DB_VERSION"-1.211" #define CKDB_VERSION DB_VERSION"-1.220"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -115,6 +115,7 @@ extern const char *idpatt;
extern const char *intpatt; extern const char *intpatt;
extern const char *hashpatt; extern const char *hashpatt;
extern const char *addrpatt; extern const char *addrpatt;
extern const char *strpatt;
/* If a trimmed username is like an address but this many or more characters, /* If a trimmed username is like an address but this many or more characters,
* disallow it */ * disallow it */
@ -1042,6 +1043,7 @@ typedef struct users {
char *userdata; char *userdata;
int64_t databits; // non-DB field, Bitmask of userdata content int64_t databits; // non-DB field, Bitmask of userdata content
int64_t userbits; // Bitmask of user attributes int64_t userbits; // Bitmask of user attributes
int32_t lastvalue; // non-DB field
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
} USERS; } USERS;
@ -1461,6 +1463,8 @@ typedef struct blocks {
char nonce[TXT_SML+1]; char nonce[TXT_SML+1];
int64_t reward; int64_t reward;
char confirmed[TXT_FLAG+1]; char confirmed[TXT_FLAG+1];
// block Short:Description to use vs default for 'R' in page_blocks.php
char info[TXT_SML+1];
double diffacc; double diffacc;
double diffinv; double diffinv;
double shareacc; double shareacc;
@ -1508,6 +1512,15 @@ typedef struct blocks {
#define BLOCKS_42_VALUE 101 #define BLOCKS_42_VALUE 101
#define BLOCKS_ORPHAN 'O' #define BLOCKS_ORPHAN 'O'
#define BLOCKS_ORPHAN_STR "O" #define BLOCKS_ORPHAN_STR "O"
#define BLOCKS_REJECT 'R'
#define BLOCKS_REJECT_STR "R"
#define BLOCKS_N_C_STR BLOCKS_NEW_STR " or " BLOCKS_CONFIRM_STR
#define BLOCKS_N_C_O_STR BLOCKS_NEW_STR ", " BLOCKS_CONFIRM_STR " or " \
BLOCKS_ORPHAN_STR
#define BLOCKS_N_C_O_R_STR BLOCKS_NEW_STR ", " BLOCKS_CONFIRM_STR ", " \
BLOCKS_ORPHAN_STR " or " BLOCKS_REJECT_STR
/* Block height difference required before checking if it's orphaned /* Block height difference required before checking if it's orphaned
* TODO: add a cmd_blockstatus option to un-orphan a block */ * TODO: add a cmd_blockstatus option to un-orphan a block */
#define BLOCKS_ORPHAN_CHECK 1 #define BLOCKS_ORPHAN_CHECK 1
@ -1521,6 +1534,7 @@ extern const char *blocks_new;
extern const char *blocks_confirm; extern const char *blocks_confirm;
extern const char *blocks_42; extern const char *blocks_42;
extern const char *blocks_orphan; extern const char *blocks_orphan;
extern const char *blocks_reject;
extern const char *blocks_unknown; extern const char *blocks_unknown;
#define KANO -27972 #define KANO -27972
@ -1593,6 +1607,10 @@ extern cklock_t process_pplns_lock;
#define PAYOUTS_ORPHAN 'O' #define PAYOUTS_ORPHAN 'O'
#define PAYOUTS_ORPHAN_STR "O" #define PAYOUTS_ORPHAN_STR "O"
#define PAYORPHAN(_status) ((_status)[0] == PAYOUTS_ORPHAN) #define PAYORPHAN(_status) ((_status)[0] == PAYOUTS_ORPHAN)
// A rejected payout must be ignored
#define PAYOUTS_REJECT 'R'
#define PAYOUTS_REJECT_STR "R"
#define PAYREJECT(_status) ((_status)[0] == PAYOUTS_REJECT)
// Default number of shifts (payouts) to display on web // Default number of shifts (payouts) to display on web
#define SHIFTS_DEFAULT 99 #define SHIFTS_DEFAULT 99
@ -1993,12 +2011,19 @@ extern const char *marktype_shift_end_skip;
#define MARK_USED_STR "u" #define MARK_USED_STR "u"
#define MUSED(_status) (tolower((_status)[0]) == MARK_USED) #define MUSED(_status) (tolower((_status)[0]) == MARK_USED)
enum info_type {
INFO_NEW,
INFO_ORPHAN,
INFO_REJECT
};
// USERINFO from various incoming data // USERINFO from various incoming data
typedef struct userinfo { typedef struct userinfo {
int64_t userid; int64_t userid;
char username[TXT_BIG+1]; char username[TXT_BIG+1];
int blocks; int blocks;
int orphans; // How many blocks are orphans int orphans; // How many blocks are orphans
int rejects; // How many blocks are rejects
tv_t last_block; tv_t last_block;
// For all time // For all time
double diffacc; double diffacc;
@ -2049,6 +2074,8 @@ extern void sequence_report(bool lock);
#define REWARDOVERRIDE "MinerReward" #define REWARDOVERRIDE "MinerReward"
// Data free functions (first) // Data free functions (first)
#define FREE_ITEM(item) do { } while(0)
// TODO: make a macro for all other to use above macro
extern void free_msgline_data(K_ITEM *item, bool t_lock, bool t_cull); extern void free_msgline_data(K_ITEM *item, bool t_lock, bool t_cull);
extern void free_users_data(K_ITEM *item); extern void free_users_data(K_ITEM *item);
extern void free_workinfo_data(K_ITEM *item); extern void free_workinfo_data(K_ITEM *item);
@ -2061,6 +2088,12 @@ extern void free_marks_data(K_ITEM *item);
#define free_seqset_data(_item) _free_seqset_data(_item, false) #define free_seqset_data(_item) _free_seqset_data(_item, false)
extern void _free_seqset_data(K_ITEM *item, bool lock); extern void _free_seqset_data(K_ITEM *item, bool lock);
// Data copy functions
#define COPY_DATA(_new, _old) memcpy(_new, _old, sizeof(*(_new)))
extern void copy_users(USERS *newu, USERS *oldu);
#define copy_blocks(_newb, _oldb) COPY_DATA(_newb, _oldb)
#define safe_text(_txt) _safe_text(_txt, true) #define safe_text(_txt) _safe_text(_txt, true)
#define safe_text_nonull(_txt) _safe_text(_txt, false) #define safe_text_nonull(_txt) _safe_text(_txt, false)
extern char *_safe_text(char *txt, bool shownull); extern char *_safe_text(char *txt, bool shownull);
@ -2326,7 +2359,7 @@ extern K_ITEM *_find_create_userinfo(int64_t userid, bool lock, WHERE_FFL_ARGS);
extern void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary, extern void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary,
MARKERSUMMARY *markersummary, bool ss_sub, bool lock); MARKERSUMMARY *markersummary, bool ss_sub, bool lock);
#define userinfo_block(_blocks, _isnew) _userinfo_block(_blocks, _isnew, true) #define userinfo_block(_blocks, _isnew) _userinfo_block(_blocks, _isnew, true)
extern void _userinfo_block(BLOCKS *blocks, bool isnew, bool lock); extern void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock);
// *** // ***
// *** PostgreSQL functions ckdb_dbio.c // *** PostgreSQL functions ckdb_dbio.c
@ -2459,9 +2492,9 @@ extern bool blocks_stats(PGconn *conn, int32_t height, char *blockhash,
double shareinv, int64_t elapsed, double shareinv, int64_t elapsed,
char *by, char *code, char *inet, tv_t *cd); char *by, char *code, char *inet, tv_t *cd);
extern bool blocks_add(PGconn *conn, char *height, char *blockhash, extern bool blocks_add(PGconn *conn, char *height, char *blockhash,
char *confirmed, char *workinfoid, char *username, char *confirmed, char *info, char *workinfoid,
char *workername, char *clientid, char *enonce1, char *username, char *workername, char *clientid,
char *nonce2, char *nonce, char *reward, char *enonce1, char *nonce2, char *nonce, char *reward,
char *by, char *code, char *inet, tv_t *cd, char *by, char *code, char *inet, tv_t *cd,
bool igndup, char *id, K_TREE *trf_root); bool igndup, char *id, K_TREE *trf_root);
extern bool blocks_fill(PGconn *conn); extern bool blocks_fill(PGconn *conn);
@ -2574,5 +2607,7 @@ extern K_ITEM *gen_2fa_key(K_ITEM *old_u_item, int32_t entropy, char *by,
extern bool check_2fa(USERS *users, int32_t value); 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, 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); 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);
#endif #endif

4
src/ckdb_btc.c

@ -355,7 +355,7 @@ void btc_blockstatus(BLOCKS *blocks)
ok = blocks_add(NULL, height_str, ok = blocks_add(NULL, height_str,
blocks->blockhash, blocks->blockhash,
BLOCKS_ORPHAN_STR, BLOCKS_ORPHAN_STR, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
by_default, (char *)__func__, inet_default, by_default, (char *)__func__, inet_default,
@ -378,7 +378,7 @@ void btc_blockstatus(BLOCKS *blocks)
ok = blocks_add(NULL, height_str, ok = blocks_add(NULL, height_str,
blocks->blockhash, blocks->blockhash,
BLOCKS_42_STR, BLOCKS_42_STR, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
by_default, (char *)__func__, inet_default, by_default, (char *)__func__, inet_default,

120
src/ckdb_cmd.c

@ -325,6 +325,24 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id,
DATA_USERS(users, u_item); DATA_USERS(users, u_item);
} }
} }
} else if (strcmp(action, "remove") == 0) {
// Can't remove if 2FA isn't already present
if (!(users->databits & (USER_TOTPAUTH | USER_TEST2FA)))
goto dame;
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 {
u_new = remove_2fa(u_item, value, by, code,
inet, now, trf_root);
if (u_new) {
ok = true;
sfa_status = EMPTY;
key = false;
}
}
} }
if (key) { if (key) {
char *keystr, *issuer = "Kano"; char *keystr, *issuer = "Kano";
@ -1132,7 +1150,8 @@ redo:
while (b_item) { while (b_item) {
DATA_BLOCKS(blocks, b_item); DATA_BLOCKS(blocks, b_item);
if (CURRENT(&(blocks->expirydate))) { if (CURRENT(&(blocks->expirydate))) {
if (blocks->confirmed[0] != BLOCKS_ORPHAN) if (blocks->confirmed[0] != BLOCKS_ORPHAN &&
blocks->confirmed[0] != BLOCKS_REJECT)
tot++; tot++;
} }
b_item = next_in_ktree(ctx); b_item = next_in_ktree(ctx);
@ -1149,10 +1168,14 @@ redo:
copy_tv(&first_cd, &(blocks->createdate)); copy_tv(&first_cd, &(blocks->createdate));
} }
if (CURRENT(&(blocks->expirydate))) { if (CURRENT(&(blocks->expirydate))) {
if (blocks->confirmed[0] == BLOCKS_ORPHAN) { if (blocks->confirmed[0] == BLOCKS_ORPHAN ||
blocks->confirmed[0] == BLOCKS_REJECT) {
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"seq:%d=o%c", "seq:%d=%c%c",
rows, FLDSEP); rows,
blocks->confirmed[0] == BLOCKS_ORPHAN ?
'o' : 'r',
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
} else { } else {
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
@ -1191,10 +1214,16 @@ redo:
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"status:%d=%s%c", rows, "confirmed:%d=%s%cstatus:%d=%s%c", rows,
blocks->confirmed, FLDSEP, rows,
blocks_confirmed(blocks->confirmed), FLDSEP); blocks_confirmed(blocks->confirmed), FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp),
"info:%d=%s%c", rows,
blocks->info, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), snprintf(tmp, sizeof(tmp),
"statsconf:%d=%s%c", rows, "statsconf:%d=%s%c", rows,
blocks->statsconfirmed, FLDSEP); blocks->statsconfirmed, FLDSEP);
@ -1248,7 +1277,8 @@ redo:
while (b_item) { while (b_item) {
DATA_BLOCKS(blocks, b_item); DATA_BLOCKS(blocks, b_item);
if (CURRENT(&(blocks->expirydate)) && if (CURRENT(&(blocks->expirydate)) &&
blocks->confirmed[0] != BLOCKS_ORPHAN) { blocks->confirmed[0] != BLOCKS_ORPHAN &&
blocks->confirmed[0] != BLOCKS_REJECT) {
desc = NULL; desc = NULL;
if (seq == 1) { if (seq == 1) {
snprintf(desc_buf, sizeof(desc_buf), snprintf(desc_buf, sizeof(desc_buf),
@ -1314,8 +1344,9 @@ redo:
"rows=%d%cflds=%s%c", "rows=%d%cflds=%s%c",
rows, FLDSEP, rows, FLDSEP,
"seq,height,blockhash,nonce,reward,workername,first"CDTRF"," "seq,height,blockhash,nonce,reward,workername,first"CDTRF","
CDTRF",status,statsconf,diffacc,diffinv,shareacc," CDTRF",confirmed,status,info,statsconf,diffacc,diffinv,"
"shareinv,elapsed,netdiff,diffratio,cdf,luck", FLDSEP); "shareacc,shareinv,elapsed,netdiff,diffratio,cdf,luck",
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks,BlockStats", FLDSEP, ",s"); snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks,BlockStats", FLDSEP, ",s");
@ -1329,13 +1360,13 @@ static char *cmd_blockstatus(__maybe_unused PGconn *conn, char *cmd, char *id,
tv_t *now, char *by, char *code, char *inet, tv_t *now, char *by, char *code, char *inet,
__maybe_unused tv_t *cd, K_TREE *trf_root) __maybe_unused tv_t *cd, K_TREE *trf_root)
{ {
K_ITEM *i_height, *i_blockhash, *i_action; K_ITEM *i_height, *i_blockhash, *i_action, *i_info;
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
K_ITEM *b_item; K_ITEM *b_item;
BLOCKS *blocks; BLOCKS *blocks;
int32_t height; int32_t height;
char *action; char *action, *info, *tmp;
bool ok = false; bool ok = false;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -1368,13 +1399,57 @@ static char *cmd_blockstatus(__maybe_unused PGconn *conn, char *cmd, char *id,
DATA_BLOCKS(blocks, b_item); DATA_BLOCKS(blocks, b_item);
// Default to previous value
info = blocks->info;
if (strcasecmp(action, "orphan") == 0) { if (strcasecmp(action, "orphan") == 0) {
switch (blocks->confirmed[0]) { switch (blocks->confirmed[0]) {
case BLOCKS_NEW: case BLOCKS_NEW:
case BLOCKS_CONFIRM: case BLOCKS_CONFIRM:
ok = blocks_add(conn, transfer_data(i_height), ok = blocks_add(conn, transfer_data(i_height),
blocks->blockhash, blocks->blockhash,
BLOCKS_ORPHAN_STR, BLOCKS_ORPHAN_STR, info,
EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY,
by, code, inet, now, false, id,
trf_root);
if (!ok) {
snprintf(reply, siz,
"DBE.action '%s'",
action);
LOGERR("%s.%s", id, reply);
return strdup(reply);
}
// TODO: reset the share counter?
break;
default:
snprintf(reply, siz,
"ERR.invalid action '%.*s%s' for block state '%s'",
CMD_SIZ, action,
(strlen(action) > CMD_SIZ) ? "..." : "",
blocks_confirmed(blocks->confirmed));
LOGERR("%s.%s", id, reply);
return strdup(reply);
}
} else if (strcasecmp(action, "reject") == 0) {
i_info = require_name(trf_root, "info", 0, (char *)strpatt,
reply, siz);
if (!i_info)
return strdup(reply);
tmp = transfer_data(i_info);
/* Override if not empty
* Thus you can't blank it out if current has a value */
if (tmp && *tmp)
info = tmp;
switch (blocks->confirmed[0]) {
case BLOCKS_NEW:
case BLOCKS_CONFIRM:
case BLOCKS_ORPHAN:
case BLOCKS_REJECT:
ok = blocks_add(conn, transfer_data(i_height),
blocks->blockhash,
BLOCKS_REJECT_STR, info,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
by, code, inet, now, false, id, by, code, inet, now, false, id,
@ -1403,7 +1478,7 @@ static char *cmd_blockstatus(__maybe_unused PGconn *conn, char *cmd, char *id,
case BLOCKS_NEW: case BLOCKS_NEW:
ok = blocks_add(conn, transfer_data(i_height), ok = blocks_add(conn, transfer_data(i_height),
blocks->blockhash, blocks->blockhash,
BLOCKS_CONFIRM_STR, BLOCKS_CONFIRM_STR, info,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
by, code, inet, now, false, id, by, code, inet, now, false, id,
@ -2596,6 +2671,7 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by,
ok = blocks_add(conn, transfer_data(i_height), ok = blocks_add(conn, transfer_data(i_height),
transfer_data(i_blockhash), transfer_data(i_blockhash),
transfer_data(i_confirmed), transfer_data(i_confirmed),
EMPTY,
transfer_data(i_workinfoid), transfer_data(i_workinfoid),
transfer_data(i_username), transfer_data(i_username),
transfer_data(i_workername), transfer_data(i_workername),
@ -2612,6 +2688,7 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by,
ok = blocks_add(conn, transfer_data(i_height), ok = blocks_add(conn, transfer_data(i_height),
transfer_data(i_blockhash), transfer_data(i_blockhash),
transfer_data(i_confirmed), transfer_data(i_confirmed),
EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
by, code, inet, cd, igndup, id, by, code, inet, cd, igndup, id,
@ -3976,6 +4053,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
block_extra = "Can't be paid out yet"; block_extra = "Can't be paid out yet";
break; break;
case BLOCKS_ORPHAN: case BLOCKS_ORPHAN:
case BLOCKS_REJECT:
block_extra = "Can't be paid out"; block_extra = "Can't be paid out";
break; break;
default: default:
@ -4427,6 +4505,7 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id,
block_extra = "Can't be paid out yet"; block_extra = "Can't be paid out yet";
break; break;
case BLOCKS_ORPHAN: case BLOCKS_ORPHAN:
case BLOCKS_REJECT:
block_extra = "Can't be paid out"; block_extra = "Can't be paid out";
break; break;
default: default:
@ -4708,12 +4787,14 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
"%"PRId32"/%s", "%"PRId32"/%s",
payoutid, old_payouts2->status, payouts2->status, payoutid, old_payouts2->status, payouts2->status,
payouts2->height, payouts2->blockhash); payouts2->height, payouts2->blockhash);
} else if (strcasecmp(action, "orphan") == 0) { } else if (strcasecmp(action, "orphan") == 0 ||
strcasecmp(action, "reject") == 0) {
/* Change the status of a generated payout to orphaned /* Change the status of a generated payout to orphaned
* or rejected
* Require payoutid * Require payoutid
* Use this if the orphan process didn't automatically * Use this if the orphan or reject process didn't
* update a generated payout to orphaned * automatically update a generated payout
* TODO: get orphaned blocks to automatically do this */ * TODO: get orphaned and rejected blocks to automatically do this */
i_payoutid = require_name(trf_root, "payoutid", 1, i_payoutid = require_name(trf_root, "payoutid", 1,
(char *)intpatt, reply, siz); (char *)intpatt, reply, siz);
if (!i_payoutid) if (!i_payoutid)
@ -4752,7 +4833,10 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
payouts2->workinfoidstart = payouts->workinfoidstart; payouts2->workinfoidstart = payouts->workinfoidstart;
payouts2->workinfoidend = payouts->workinfoidend; payouts2->workinfoidend = payouts->workinfoidend;
payouts2->elapsed = payouts->elapsed; payouts2->elapsed = payouts->elapsed;
if (strcasecmp(action, "orphan") == 0)
STRNCPY(payouts2->status, PAYOUTS_ORPHAN_STR); STRNCPY(payouts2->status, PAYOUTS_ORPHAN_STR);
else
STRNCPY(payouts2->status, PAYOUTS_REJECT_STR);
payouts2->diffwanted = payouts->diffwanted; payouts2->diffwanted = payouts->diffwanted;
payouts2->diffused = payouts->diffused; payouts2->diffused = payouts->diffused;
payouts2->shareacc = payouts->shareacc; payouts2->shareacc = payouts->shareacc;
@ -6164,7 +6248,9 @@ static char *cmd_userinfo(__maybe_unused PGconn *conn, char *cmd, char *id,
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "blocks:%d=%d%c", rows, snprintf(tmp, sizeof(tmp), "blocks:%d=%d%c", rows,
userinfo->blocks - userinfo->orphans, FLDSEP); userinfo->blocks -
(userinfo->orphans + userinfo->rejects),
FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "orphans:%d=%d%c", rows, snprintf(tmp, sizeof(tmp), "orphans:%d=%d%c", rows,

63
src/ckdb_crypt.c

@ -117,8 +117,7 @@ K_ITEM *gen_2fa_key(K_ITEM *old_u_item, int32_t entropy, char *by, char *code,
u_item = k_unlink_head(users_free); u_item = k_unlink_head(users_free);
K_WUNLOCK(users_free); K_WUNLOCK(users_free);
DATA_USERS(users, u_item); DATA_USERS(users, u_item);
memcpy(users, old_users, sizeof(*users)); copy_users(users, old_users);
DUP_POINTER(users_free, users->userdata, old_users->userdata);
users_userdata_add_bin(users, USER_TOTPAUTH_NAME, users_userdata_add_bin(users, USER_TOTPAUTH_NAME,
USER_TOTPAUTH, key, sizeof(key)); USER_TOTPAUTH, key, sizeof(key));
users_userdata_add_txt(users, USER_TEST2FA_NAME, users_userdata_add_txt(users, USER_TEST2FA_NAME,
@ -194,15 +193,23 @@ bool check_2fa(USERS *users, int32_t value)
otp %= 1000000; otp %= 1000000;
LOGDEBUG("%s() '%s/%s offset=%d otp=%"PRId32" value=%"PRId32, LOGDEBUG("%s() '%s/%s offset=%d otp=%"PRId32" value=%"PRId32
" lastvalue=%"PRId32,
__func__, st = safe_text_nonull(users->username), __func__, st = safe_text_nonull(users->username),
USER_TOTPAUTH_NAME, offset, otp, value); USER_TOTPAUTH_NAME, offset, otp, value, users->lastvalue);
FREENULL(st); FREENULL(st);
FREENULL(hash); FREENULL(hash);
if (otp == value) /* Disallow 0 since that's the default value
* If it is 0, that means wait another TOTPAUTH_TIME and try again
* 0 is only one in a million tests for all users
* For security reasons, we can't allow using the same value twice,
* N.B. a ckdb restart will forget lastvalue, but a restart should
* take long enough to resolve that issue */
if (otp == value && otp != 0 && otp != users->lastvalue) {
users->lastvalue = otp;
return true; return true;
else } else
return false; return false;
} }
@ -220,8 +227,7 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
u_item = k_unlink_head(users_free); u_item = k_unlink_head(users_free);
K_WUNLOCK(users_free); K_WUNLOCK(users_free);
DATA_USERS(users, u_item); DATA_USERS(users, u_item);
memcpy(users, old_users, sizeof(*users)); copy_users(users, old_users);
DUP_POINTER(users_free, users->userdata, old_users->userdata);
users_userdata_del(users, USER_TEST2FA_NAME, USER_TEST2FA); users_userdata_del(users, USER_TEST2FA_NAME, USER_TEST2FA);
ok = users_replace(NULL, u_item, old_u_item, by, code, inet, cd, ok = users_replace(NULL, u_item, old_u_item, by, code, inet, cd,
trf_root); trf_root);
@ -229,3 +235,44 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code,
} }
return ok; return ok;
} }
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)
{
K_ITEM *u_item = NULL;
USERS *old_users, *users;
bool ok, did = false;
DATA_USERS(old_users, old_u_item);
ok = check_2fa(old_users, value);
if (ok) {
K_WLOCK(users_free);
u_item = k_unlink_head(users_free);
K_WUNLOCK(users_free);
DATA_USERS(users, u_item);
copy_users(users, old_users);
if (users->databits & USER_TEST2FA) {
users_userdata_del(users, USER_TEST2FA_NAME, USER_TEST2FA);
did = true;
}
if (users->databits & USER_TOTPAUTH) {
users_userdata_del(users, USER_TOTPAUTH_NAME, USER_TOTPAUTH);
did = true;
}
if (did) {
ok = users_replace(NULL, u_item, old_u_item, by, code, inet, cd,
trf_root);
if (!ok) {
// u_item was cleaned up in user_replace()
u_item = NULL;
}
} else {
K_WLOCK(users_free);
free_users_data(u_item);
k_add_head(users_free, u_item);
K_WUNLOCK(users_free);
u_item = NULL;
}
}
return u_item;
}

32
src/ckdb_data.c

@ -161,6 +161,16 @@ void _free_seqset_data(K_ITEM *item, bool lock)
} }
} }
/* Data copy functions (added here as needed)
All pointers need to initialised since DUP_POINTER will free them */
void copy_users(USERS *newu, USERS *oldu)
{
memcpy(newu, oldu, sizeof(*newu));
newu->userdata = NULL;
DUP_POINTER(users_free, newu->userdata, oldu->userdata);
}
// Clear text printable version of txt up to first '\0' // Clear text printable version of txt up to first '\0'
char *_safe_text(char *txt, bool shownull) char *_safe_text(char *txt, bool shownull)
{ {
@ -2645,6 +2655,8 @@ const char *blocks_confirmed(char *confirmed)
return blocks_42; return blocks_42;
case BLOCKS_ORPHAN: case BLOCKS_ORPHAN:
return blocks_orphan; return blocks_orphan;
case BLOCKS_REJECT:
return blocks_reject;
} }
return blocks_unknown; return blocks_unknown;
} }
@ -2885,7 +2897,8 @@ bool check_update_blocks_stats(tv_t *stats)
DATA_BLOCKS(blocks, b_item); DATA_BLOCKS(blocks, b_item);
if (CURRENT(&(blocks->expirydate))) { if (CURRENT(&(blocks->expirydate))) {
pending += blocks->diffacc; pending += blocks->diffacc;
if (blocks->confirmed[0] == BLOCKS_ORPHAN) if (blocks->confirmed[0] == BLOCKS_ORPHAN ||
blocks->confirmed[0] == BLOCKS_REJECT)
blocks->diffcalc = 0.0; blocks->diffcalc = 0.0;
else { else {
blocks->diffcalc = pending; blocks->diffcalc = pending;
@ -2934,10 +2947,11 @@ bool check_update_blocks_stats(tv_t *stats)
else else
blocks->blockluck = 1.0 / blocks->blockdiffratio; blocks->blockluck = 1.0 / blocks->blockdiffratio;
/* Orphans are treated as +diffacc but no block /* Orphans/Rejects are treated as +diffacc but no block
* i.e. they simply add shares to the later block * i.e. they simply add shares to the later block
* and have running stats set to zero */ * and have running stats set to zero */
if (blocks->confirmed[0] == BLOCKS_ORPHAN) { if (blocks->confirmed[0] == BLOCKS_ORPHAN ||
blocks->confirmed[0] == BLOCKS_REJECT) {
blocks->diffratio = 0.0; blocks->diffratio = 0.0;
blocks->diffmean = 0.0; blocks->diffmean = 0.0;
blocks->cdferl = 0.0; blocks->cdferl = 0.0;
@ -3327,6 +3341,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
switch (blocks->confirmed[0]) { switch (blocks->confirmed[0]) {
case BLOCKS_NEW: case BLOCKS_NEW:
case BLOCKS_ORPHAN: case BLOCKS_ORPHAN:
case BLOCKS_REJECT:
LOGERR("%s(): can't process block %"PRId32"/%" LOGERR("%s(): can't process block %"PRId32"/%"
PRId64"/%s/%"PRId64" status: %s/%s", PRId64"/%s/%"PRId64" status: %s/%s",
__func__, blocks->height, blocks->workinfoid, __func__, blocks->height, blocks->workinfoid,
@ -4881,8 +4896,8 @@ void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary,
} }
} }
// N.B. good blocks = blocks - orphans // N.B. good blocks = blocks - (orphans + rejects)
void _userinfo_block(BLOCKS *blocks, bool isnew, bool lock) void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock)
{ {
USERINFO *row; USERINFO *row;
K_ITEM *item; K_ITEM *item;
@ -4891,11 +4906,14 @@ void _userinfo_block(BLOCKS *blocks, bool isnew, bool lock)
DATA_USERINFO(row, item); DATA_USERINFO(row, item);
if (lock) if (lock)
K_WLOCK(userinfo_free); K_WLOCK(userinfo_free);
if (isnew) { if (isnew == INFO_NEW) {
row->blocks++; row->blocks++;
copy_tv(&(row->last_block), &(blocks->createdate)); copy_tv(&(row->last_block), &(blocks->createdate));
} else } else if (isnew == INFO_ORPHAN)
row->orphans++; row->orphans++;
else if (isnew == INFO_REJECT)
row->rejects++;
if (lock) if (lock)
K_WUNLOCK(userinfo_free); K_WUNLOCK(userinfo_free);
} }

98
src/ckdb_dbio.c

@ -415,7 +415,7 @@ bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash,
K_WUNLOCK(users_free); K_WUNLOCK(users_free);
DATA_USERS(row, item); DATA_USERS(row, item);
memcpy(row, users, sizeof(*row)); copy_users(row, users);
// Update each one supplied // Update each one supplied
if (hash) { if (hash) {
@ -428,7 +428,6 @@ bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash,
STRNCPY(row->emailaddress, email); STRNCPY(row->emailaddress, email);
if (status) if (status)
STRNCPY(row->status, status); STRNCPY(row->status, status);
DUP_POINTER(users_free, row->userdata, users->userdata);
HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row); HISTORYDATETRANSFER(trf_root, row);
@ -4193,7 +4192,7 @@ bool blocks_stats(PGconn *conn, int32_t height, char *blockhash,
K_WUNLOCK(blocks_free); K_WUNLOCK(blocks_free);
DATA_BLOCKS(row, b_item); DATA_BLOCKS(row, b_item);
memcpy(row, oldblocks, sizeof(*row)); copy_blocks(row, oldblocks);
row->diffacc = diffacc; row->diffacc = diffacc;
row->diffinv = diffinv; row->diffinv = diffinv;
row->shareacc = shareacc; row->shareacc = shareacc;
@ -4305,9 +4304,9 @@ unparam:
} }
bool blocks_add(PGconn *conn, char *height, char *blockhash, bool blocks_add(PGconn *conn, char *height, char *blockhash,
char *confirmed, char *workinfoid, char *username, char *confirmed, char *info, char *workinfoid,
char *workername, char *clientid, char *enonce1, char *username, char *workername, char *clientid,
char *nonce2, char *nonce, char *reward, char *enonce1, char *nonce2, char *nonce, char *reward,
char *by, char *code, char *inet, tv_t *cd, char *by, char *code, char *inet, tv_t *cd,
bool igndup, char *id, K_TREE *trf_root) bool igndup, char *id, K_TREE *trf_root)
{ {
@ -4321,11 +4320,10 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
BLOCKS *row, *oldblocks; BLOCKS *row, *oldblocks;
USERS *users; USERS *users;
char *upd, *ins; char *upd, *ins;
char *params[17 + HISTORYDATECOUNT]; char *params[18 + HISTORYDATECOUNT];
bool ok = false, update_old = false; bool ok = false, update_old = false;
int n, par = 0; int n, par = 0;
char want = '?'; char *want = NULL, *st = NULL;
char *st = NULL;
LOGDEBUG("%s(): add", __func__); LOGDEBUG("%s(): add", __func__);
@ -4377,6 +4375,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
} }
STRNCPY(row->confirmed, confirmed); STRNCPY(row->confirmed, confirmed);
STRNCPY(row->info, info);
TXT_TO_BIGINT("workinfoid", workinfoid, row->workinfoid); TXT_TO_BIGINT("workinfoid", workinfoid, row->workinfoid);
STRNCPY(row->workername, workername); STRNCPY(row->workername, workername);
TXT_TO_INT("clientid", clientid, row->clientid); TXT_TO_INT("clientid", clientid, row->clientid);
@ -4407,6 +4406,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
params[par++] = str_to_buf(row->nonce, NULL, 0); params[par++] = str_to_buf(row->nonce, NULL, 0);
params[par++] = bigint_to_buf(row->reward, NULL, 0); params[par++] = bigint_to_buf(row->reward, NULL, 0);
params[par++] = str_to_buf(row->confirmed, NULL, 0); params[par++] = str_to_buf(row->confirmed, NULL, 0);
params[par++] = str_to_buf(row->info, NULL, 0);
params[par++] = double_to_buf(row->diffacc, NULL, 0); params[par++] = double_to_buf(row->diffacc, NULL, 0);
params[par++] = double_to_buf(row->diffinv, NULL, 0); params[par++] = double_to_buf(row->diffinv, NULL, 0);
params[par++] = double_to_buf(row->shareacc, NULL, 0); params[par++] = double_to_buf(row->shareacc, NULL, 0);
@ -4419,7 +4419,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
ins = "insert into blocks " ins = "insert into blocks "
"(height,blockhash,workinfoid,userid,workername," "(height,blockhash,workinfoid,userid,workername,"
"clientid,enonce1,nonce2,nonce,reward,confirmed," "clientid,enonce1,nonce2,nonce,reward,confirmed,"
"diffacc,diffinv,shareacc,shareinv,elapsed," "info,diffacc,diffinv,shareacc,shareinv,elapsed,"
"statsconfirmed" "statsconfirmed"
HISTORYDATECONTROL ") values (" PQPARAM22 ")"; HISTORYDATECONTROL ") values (" PQPARAM22 ")";
@ -4437,10 +4437,11 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
} }
// We didn't use a Begin // We didn't use a Begin
ok = true; ok = true;
userinfo_block(row, true); userinfo_block(row, INFO_NEW);
goto unparam; goto unparam;
break; break;
case BLOCKS_ORPHAN: case BLOCKS_ORPHAN:
case BLOCKS_REJECT:
case BLOCKS_42: case BLOCKS_42:
// These shouldn't be possible until startup completes // These shouldn't be possible until startup completes
if (!startup_complete) { if (!startup_complete) {
@ -4452,7 +4453,6 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
height, hash_dsp, cd_buf); height, hash_dsp, cd_buf);
goto flail; goto flail;
} }
want = BLOCKS_CONFIRM;
case BLOCKS_CONFIRM: case BLOCKS_CONFIRM:
if (!old_b_item) { if (!old_b_item) {
tv_to_buf(cd, cd_buf, sizeof(cd_buf)); tv_to_buf(cd, cd_buf, sizeof(cd_buf));
@ -4461,16 +4461,37 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
height, hash_dsp, cd_buf); height, hash_dsp, cd_buf);
goto flail; goto flail;
} }
if (confirmed[0] == BLOCKS_CONFIRM) switch (confirmed[0]) {
want = BLOCKS_NEW; case BLOCKS_CONFIRM:
if (oldblocks->confirmed[0] != want) { if (oldblocks->confirmed[0] != BLOCKS_NEW)
want = BLOCKS_NEW_STR;
break;
case BLOCKS_42:
if (oldblocks->confirmed[0] != BLOCKS_CONFIRM)
want = BLOCKS_CONFIRM_STR;
break;
case BLOCKS_ORPHAN:
if (oldblocks->confirmed[0] != BLOCKS_NEW &&
oldblocks->confirmed[0] != BLOCKS_CONFIRM)
want = BLOCKS_N_C_STR;
break;
case BLOCKS_REJECT:
if (oldblocks->confirmed[0] != BLOCKS_NEW &&
oldblocks->confirmed[0] != BLOCKS_CONFIRM &&
oldblocks->confirmed[0] != BLOCKS_ORPHAN &&
oldblocks->confirmed[0] != BLOCKS_REJECT)
want = BLOCKS_N_C_O_R_STR;
break;
}
if (want) {
// No mismatch messages during startup // No mismatch messages during startup
if (startup_complete) { if (startup_complete) {
tv_to_buf(cd, cd_buf, sizeof(cd_buf)); tv_to_buf(cd, cd_buf, sizeof(cd_buf));
LOGERR("%s(): New Status: %s requires Status: %c. " LOGERR("%s(): New Status: (%s)%s requires Status: %s. "
"Ignored: Status: %s, Block: %s/...%s/%s", "Ignored: Status: (%s)%s, Block: %s/...%s/%s",
__func__, __func__,
blocks_confirmed(confirmed), want, confirmed, blocks_confirmed(confirmed),
want, oldblocks->confirmed,
blocks_confirmed(oldblocks->confirmed), blocks_confirmed(oldblocks->confirmed),
height, hash_dsp, cd_buf); height, hash_dsp, cd_buf);
} }
@ -4490,8 +4511,10 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
} }
// New is mostly a copy of the old // New is mostly a copy of the old
memcpy(row, oldblocks, sizeof(*row)); copy_blocks(row, oldblocks);
STRNCPY(row->confirmed, confirmed); STRNCPY(row->confirmed, confirmed);
if (info && *info)
STRNCPY(row->info, info);
if (confirmed[0] == BLOCKS_CONFIRM) { if (confirmed[0] == BLOCKS_CONFIRM) {
row->diffacc = pool.diffacc; row->diffacc = pool.diffacc;
row->diffinv = pool.diffinv; row->diffinv = pool.diffinv;
@ -4525,6 +4548,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
params[par++] = str_to_buf(row->blockhash, NULL, 0); params[par++] = str_to_buf(row->blockhash, NULL, 0);
params[par++] = tv_to_buf(cd, NULL, 0); params[par++] = tv_to_buf(cd, NULL, 0);
params[par++] = str_to_buf(row->confirmed, NULL, 0); params[par++] = str_to_buf(row->confirmed, NULL, 0);
params[par++] = str_to_buf(row->info, NULL, 0);
if (confirmed[0] == BLOCKS_CONFIRM) { if (confirmed[0] == BLOCKS_CONFIRM) {
params[par++] = double_to_buf(row->diffacc, NULL, 0); params[par++] = double_to_buf(row->diffacc, NULL, 0);
@ -4532,34 +4556,34 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
params[par++] = double_to_buf(row->shareacc, NULL, 0); params[par++] = double_to_buf(row->shareacc, NULL, 0);
params[par++] = double_to_buf(row->shareinv, NULL, 0); params[par++] = double_to_buf(row->shareinv, NULL, 0);
HISTORYDATEPARAMS(params, par, row); HISTORYDATEPARAMS(params, par, row);
PARCHKVAL(par, 7 + HISTORYDATECOUNT, params); // 12 as per ins PARCHKVAL(par, 8 + HISTORYDATECOUNT, params); // 13 as per ins
ins = "insert into blocks " ins = "insert into blocks "
"(height,blockhash,workinfoid,userid,workername," "(height,blockhash,workinfoid,userid,workername,"
"clientid,enonce1,nonce2,nonce,reward,confirmed," "clientid,enonce1,nonce2,nonce,reward,confirmed,"
"diffacc,diffinv,shareacc,shareinv,elapsed," "info,diffacc,diffinv,shareacc,shareinv,elapsed,"
"statsconfirmed" "statsconfirmed"
HISTORYDATECONTROL ") select " HISTORYDATECONTROL ") select "
"height,blockhash,workinfoid,userid,workername," "height,blockhash,workinfoid,userid,workername,"
"clientid,enonce1,nonce2,nonce,reward," "clientid,enonce1,nonce2,nonce,reward,"
"$3,$4,$5,$6,$7,elapsed,statsconfirmed," "$3,$4,$5,$6,$7,$8,elapsed,statsconfirmed,"
"$8,$9,$10,$11,$12 from blocks where " "$9,$10,$11,$12,$13 from blocks where "
"blockhash=$1 and "EDDB"=$2"; "blockhash=$1 and "EDDB"=$2";
} else { } else {
HISTORYDATEPARAMS(params, par, row); HISTORYDATEPARAMS(params, par, row);
PARCHKVAL(par, 3 + HISTORYDATECOUNT, params); // 8 as per ins PARCHKVAL(par, 4 + HISTORYDATECOUNT, params); // 9 as per ins
ins = "insert into blocks " ins = "insert into blocks "
"(height,blockhash,workinfoid,userid,workername," "(height,blockhash,workinfoid,userid,workername,"
"clientid,enonce1,nonce2,nonce,reward,confirmed," "clientid,enonce1,nonce2,nonce,reward,confirmed,"
"diffacc,diffinv,shareacc,shareinv,elapsed," "info,diffacc,diffinv,shareacc,shareinv,elapsed,"
"statsconfirmed" "statsconfirmed"
HISTORYDATECONTROL ") select " HISTORYDATECONTROL ") select "
"height,blockhash,workinfoid,userid,workername," "height,blockhash,workinfoid,userid,workername,"
"clientid,enonce1,nonce2,nonce,reward," "clientid,enonce1,nonce2,nonce,reward,"
"$3,diffacc,diffinv,shareacc,shareinv,elapsed," "$3,$4,diffacc,diffinv,shareacc,shareinv,elapsed,"
"statsconfirmed," "statsconfirmed,"
"$4,$5,$6,$7,$8 from blocks where " "$5,$6,$7,$8,$9 from blocks where "
"blockhash=$1 and "EDDB"=$2"; "blockhash=$1 and "EDDB"=$2";
} }
@ -4573,7 +4597,9 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash,
update_old = true; update_old = true;
if (confirmed[0] == BLOCKS_ORPHAN) if (confirmed[0] == BLOCKS_ORPHAN)
userinfo_block(row, false); userinfo_block(row, INFO_ORPHAN);
else if (confirmed[0] == BLOCKS_REJECT)
userinfo_block(row, INFO_REJECT);
break; break;
default: default:
LOGERR("%s(): %s.failed.invalid confirm='%s'", LOGERR("%s(): %s.failed.invalid confirm='%s'",
@ -4663,6 +4689,7 @@ flail:
} }
break; break;
case BLOCKS_ORPHAN: case BLOCKS_ORPHAN:
case BLOCKS_REJECT:
case BLOCKS_42: case BLOCKS_42:
default: default:
blk = false; blk = false;
@ -4688,14 +4715,14 @@ bool blocks_fill(PGconn *conn)
BLOCKS *row; BLOCKS *row;
char *field; char *field;
char *sel; char *sel;
int fields = 17; int fields = 18;
bool ok; bool ok;
LOGDEBUG("%s(): select", __func__); LOGDEBUG("%s(): select", __func__);
sel = "select " sel = "select "
"height,blockhash,workinfoid,userid,workername," "height,blockhash,workinfoid,userid,workername,"
"clientid,enonce1,nonce2,nonce,reward,confirmed," "clientid,enonce1,nonce2,nonce,reward,confirmed,info,"
"diffacc,diffinv,shareacc,shareinv,elapsed,statsconfirmed" "diffacc,diffinv,shareacc,shareinv,elapsed,statsconfirmed"
HISTORYDATECONTROL HISTORYDATECONTROL
" from blocks"; " from blocks";
@ -4784,6 +4811,11 @@ bool blocks_fill(PGconn *conn)
break; break;
TXT_TO_STR("confirmed", field, row->confirmed); TXT_TO_STR("confirmed", field, row->confirmed);
PQ_GET_FLD(res, i, "info", field, ok);
if (!ok)
break;
TXT_TO_STR("info", field, row->info);
PQ_GET_FLD(res, i, "diffacc", field, ok); PQ_GET_FLD(res, i, "diffacc", field, ok);
if (!ok) if (!ok)
break; break;
@ -4830,9 +4862,11 @@ bool blocks_fill(PGconn *conn)
} }
if (CURRENT(&(row->expirydate))) { if (CURRENT(&(row->expirydate))) {
_userinfo_block(row, true, false); _userinfo_block(row, INFO_NEW, false);
if (row->confirmed[0] == BLOCKS_ORPHAN) if (row->confirmed[0] == BLOCKS_ORPHAN)
_userinfo_block(row, false, false); _userinfo_block(row, INFO_ORPHAN, false);
else if (row->confirmed[0] == BLOCKS_REJECT)
_userinfo_block(row, INFO_REJECT, false);
} }
} }
if (!ok) if (!ok)

Loading…
Cancel
Save