Browse Source

Merge branch 'master' into multimerge

Conflicts:
	src/connector.c
	src/generator.c
	src/libckpool.h
	src/stratifier.c
master
Con Kolivas 9 years ago
parent
commit
87ef00bca5
  1. 14
      pool/base.php
  2. 10
      pool/db.php
  3. 5
      pool/inc.php
  4. 67
      pool/page_addrmgt.php
  5. 3
      pool/page_blocks.php
  6. 197
      pool/page_luck.php
  7. 17
      pool/page_payout.php
  8. 6
      pool/page_percent.php
  9. 5
      pool/page_pplns2.php
  10. 28
      pool/page_shifts.php
  11. 25
      pool/page_workers.php
  12. 3
      pool/prime.php
  13. 8
      sql/ckdb.sql
  14. 276
      sql/rollback.sh
  15. 63
      sql/tabdump.sh
  16. 38
      sql/v1.0.2-v1.0.3.sql
  17. 26
      sql/v1.0.3-v1.0.4.sql
  18. 431
      src/ckdb.c
  19. 134
      src/ckdb.h
  20. 17
      src/ckdb_btc.c
  21. 1021
      src/ckdb_cmd.c
  22. 6
      src/ckdb_crypt.c
  23. 420
      src/ckdb_data.c
  24. 1187
      src/ckdb_dbio.c
  25. 12
      src/ckpool.c
  26. 19
      src/connector.c
  27. 453
      src/ktree.c
  28. 65
      src/ktree.h
  29. 9
      src/libckpool.c
  30. 2
      src/libckpool.h
  31. 198
      src/stratifier.c

14
pool/base.php

@ -99,7 +99,7 @@ function howlongago($sec)
return $des; return $des;
} }
# #
function howmanyhrs($tot) function howmanyhrs($tot, $days = false)
{ {
$sec = round($tot); $sec = round($tot);
if ($sec < 60) if ($sec < 60)
@ -114,6 +114,13 @@ function howmanyhrs($tot)
{ {
$hr = floor($min / 60); $hr = floor($min / 60);
$min -= $hr * 60; $min -= $hr * 60;
if ($days && $hr > 23)
{
$dy = floor($hr / 24);
$hr -= $dy * 24;
$des = $dy.'d '.$hr.'hr '.$min.'m '.$sec.'s';
}
else
$des = $hr.'hr '.$min.'m '.$sec.'s'; $des = $hr.'hr '.$min.'m '.$sec.'s';
} }
} }
@ -126,8 +133,11 @@ function btcfmt($amt)
return number_format($amt, 8); return number_format($amt, 8);
} }
# #
function utcd($when) function utcd($when, $brief = false)
{ {
if ($brief)
return gmdate('M-d H:i:s', round($when));
else
return gmdate('Y-m-d H:i:s+00', round($when)); return gmdate('Y-m-d H:i:s+00', round($when));
} }
# #

10
pool/db.php

@ -139,13 +139,15 @@ function msgEncode($cmd, $id, $fields, $user)
{ {
global $send_sep, $fld_sep, $val_sep; global $send_sep, $fld_sep, $val_sep;
$t = time() % 10000; $now = time();
$t = $now % 10000;
$msg = $cmd . $send_sep . $id.$t . $send_sep; $msg = $cmd . $send_sep . $id.$t . $send_sep;
foreach ($fields as $name => $value) foreach ($fields as $name => $value)
$msg .= $name . $val_sep . $value . $fld_sep; $msg .= $name . $val_sep . $value . $fld_sep;
$msg .= 'createcode' . $val_sep . 'php' . $fld_sep; $msg .= 'createcode' . $val_sep . 'php' . $fld_sep;
$msg .= 'createby' . $val_sep . $user . $fld_sep; $msg .= 'createby' . $val_sep . $user . $fld_sep;
$msg .= 'createinet' . $val_sep . zeip(); $msg .= 'createinet' . $val_sep . zeip(). $fld_sep;
$msg .= 'webtime' . $val_sep . $now;
adm($user, $msg); adm($user, $msg);
return $msg; return $msg;
} }
@ -240,6 +242,7 @@ function userReg($user, $email, $pass)
# #
function userSettings($user, $email = null, $addr = null, $pass = null, $twofa = null) function userSettings($user, $email = null, $addr = null, $pass = null, $twofa = null)
{ {
global $fld_sep;
$tmo = false; $tmo = false;
$flds = array('username' => $user); $flds = array('username' => $user);
if ($email != null) if ($email != null)
@ -251,6 +254,9 @@ function userSettings($user, $email = null, $addr = null, $pass = null, $twofa =
foreach ($addr as $ar) foreach ($addr as $ar)
{ {
$flds['address:'.$i] = $ar['addr']; $flds['address:'.$i] = $ar['addr'];
// optional - missing = blank
if (isset($ar['payname']))
$flds['payname:'.$i] = str_replace($fld_sep, ' ', trim($ar['payname']));
// optional - missing = use default // optional - missing = use default
if (isset($ar['ratio'])) if (isset($ar['ratio']))
$flds['ratio:'.$i] = $ar['ratio']; $flds['ratio:'.$i] = $ar['ratio'];

5
pool/inc.php

@ -5,6 +5,7 @@ function GBaseJS()
$g = "function hasCan(){var c0=document.getElementById('can0');c=document.getElementById('can');return !!(c0 && c && c.getContext && c.getContext('2d'))} $g = "function hasCan(){var c0=document.getElementById('can0');c=document.getElementById('can');return !!(c0 && c && c.getContext && c.getContext('2d'))}
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 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 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 dfmtm(c,e){var d=new Date(e*1000);var M,DD,HH;var MMM=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];if(c['utc']){M=MMM[d.getUTCMonth()];DD=d.getUTCDate();HH=d.getUTCHours()}else{M=MMM[d.getMonth()];DD=d.getDate();HH=d.getHours()}var ans=''+M+'-';if(DD<10){ans += '0'}ans += ''+DD+'/';if(HH<10){ans += '0'}ans += ''+HH;return ans}
function ccb(c,n){var e=document.getElementById(n);c[n]=(e&&e.checked)} 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 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 gch(z,zm){if(z<0.5){return 0.5}if(z>(zm-0.5)){return(zm-0.5)}return z}
@ -28,13 +29,13 @@ function gfl(c){c['ctx'].fill()}
function gst(c){c['ctx'].stroke()} function gst(c){c['ctx'].stroke()}
function gfi(c){gle(c);gst(c)} 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('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 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 n,l=0;tpos=2.7;if(c['over']){tpos=1.5}for(var i=xhr;i>=x0;i-=hrs){var xo=(i-x0)/(x1-x0);if(c['hrs'][c['hr']]<=48){n=dfmt(c,i)}else{n=dfmtm(c,i)}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 i,dsp;i=c['hrs'][c['hr']];if(i < 24){dsp=''+i+'h'}else{dsp=''+(i/24)+'d'}gfz(c,1,0,c['xo']-c['pxe'],hi,dsp,'red','end');i=c['hln'][c['hl']];gfz(c,1,0,c['xo']-c['pxe'],hi*3,''+i,'red','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 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 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 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 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,168,336,672,1344,2688];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}}
function gopt(c,cbx){for(var i=0;i<cbx.length;i++){ccb(c,cbx[i])}} 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 gsh(c,w){for(var i=1;i<w.length;i++){ccbd(c,'lin'+i,true)}}

67
pool/page_addrmgt.php

@ -10,15 +10,21 @@ function addrmgtuser($data, $user, $err)
$pg .= makeForm('addrmgt'); $pg .= makeForm('addrmgt');
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n"; $pg .= "<table callpadding=0 cellspacing=0 border=0>\n";
$pg .= '<tr class=title>'; $pg .= '<tr class=title>';
$pg .= '<td class=dc>#</td>';
$pg .= '<td class=dl>Address</td>'; $pg .= '<td class=dl>Address</td>';
$pg .= '<td class=dl>ID</td>';
$pg .= '<td class=dr>Ratio</td>'; $pg .= '<td class=dr>Ratio</td>';
$pg .= '<td class=dr>%</td>'; $pg .= '<td class=dr>%</td>';
$pg .= '</tr>'; $pg .= '</tr>';
# new row template for '+' # new row template for '+'
$pg .= '<tr class=hid id=bs>'; $pg .= '<tr class=hid id=bs>';
$pg .= '<td class=dc> </td>';
$pg .= '<td class=dl>'; $pg .= '<td class=dl>';
$pg .= "<input type=text size=42 name='addr:' value=''>"; $pg .= "<input type=text size=36 name='addr:' value=''>";
$pg .= '</td>';
$pg .= '<td class=dl>';
$pg .= "<input type=text size=16 name='payname:' value=''>";
$pg .= '</td>'; $pg .= '</td>';
$pg .= '<td class=dr>'; $pg .= '<td class=dr>';
$pg .= "<input type=text size=6 name='ratio:' value='0' id=rat onchange='repc()'>"; $pg .= "<input type=text size=6 name='ratio:' value='0' id=rat onchange='repc()'>";
@ -34,7 +40,12 @@ function addrmgtuser($data, $user, $err)
$count = 0; $count = 0;
if ($ans['STATUS'] == 'ok') if ($ans['STATUS'] == 'ok')
{ {
if (isset($ans['limit']))
$limit = $ans['limit'];
else
$limit = 1;
$count = $ans['rows']; $count = $ans['rows'];
# this will output any DB rows > limit but DB update will ignore extras
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
{ {
if ((($offset) % 2) == 0) if ((($offset) % 2) == 0)
@ -44,8 +55,13 @@ function addrmgtuser($data, $user, $err)
$pg .= "<tr class=$row>"; $pg .= "<tr class=$row>";
$addr = $ans['addr:'.$i]; $addr = $ans['addr:'.$i];
$pg .= '<td class=dc>'.($i+1).'</td>';
$pg .= '<td class=dl>';
$pg .= "<input type=text size=36 name='addr:$i' value='$addr'>";
$pg .= '</td>';
$nam = htmlspecialchars($ans['payname:'.$i]);
$pg .= '<td class=dl>'; $pg .= '<td class=dl>';
$pg .= "<input type=text size=42 name='addr:$i' value='$addr'>"; $pg .= "<input type=text size=16 name='payname:$i' value='$nam'>";
$pg .= '</td>'; $pg .= '</td>';
$ratio = intval($ans['ratio:'.$i]); $ratio = intval($ans['ratio:'.$i]);
$pg .= '<td class=dr>'; $pg .= '<td class=dr>';
@ -58,49 +74,57 @@ function addrmgtuser($data, $user, $err)
$offset++; $offset++;
} }
if ($offset < $limit) {
if ((($offset++) % 2) == 0) if ((($offset++) % 2) == 0)
$row = 'even'; $row = 'even';
else else
$row = 'odd'; $row = 'odd';
$pg .= "<tr class=$row id=plus>"; $pg .= "<tr class=$row id=plus><td class=dc>";
$pg .= '<td colspan=3 class=dl>'; $pg .= "<input type=button value='+' onclick='return adrw($limit);'>";
$pg .= "<input type=button value='+' onclick='return adrw();'>"; $pg .= "</td><td colspan=4 class=dl><font size=-1>limit $limit</font></td></tr>";
$pg .= '</td></tr>'; }
if ((($offset++) % 2) == 0) if ((($offset++) % 2) == 0)
$row = 'even'; $row = 'even';
else else
$row = 'odd'; $row = 'odd';
$pg .= "<tr class=$row>"; $pg .= "<tr class=$row>";
$pg .= '<td class=dr>'; $pg .= '<td class=dr>&nbsp;</td>';
$pg .= 'Password: <input type=password name=pass size=20>'; $pg .= '<td class=dr>Password:</td>';
$pg .= '</td><td colspan=2>&nbsp;</td></tr>'; $pg .= '<td class=dl><input type=password name=pass size=20></td>';
$pg .= '<td colspan=2>&nbsp;</td></tr>';
if ((($offset++) % 2) == 0) if ((($offset++) % 2) == 0)
$row = 'even'; $row = 'even';
else else
$row = 'odd'; $row = 'odd';
$pg .= "<tr class=$row>"; $pg .= "<tr class=$row>";
$pg .= '<td class=dr>'; $pg .= '<td class=dr>&nbsp;</td>';
$pg .= '<span class=st1>*</span>2nd Authentication: <input type=password name=2fa size=10>'; $pg .= '<td class=dr><span class=st1>*</span>2nd Authentication:</td>';
$pg .= '</td><td colspan=2 class=dl><input type=submit name=OK value=Save></td></tr>'; $pg .= '<td class=dl><input type=password name=2fa size=10>';
$pg .= ' <input type=submit name=OK value=Save></td>';
$pg .= '<td colspan=3 class=dl>&nbsp;</td></tr>';
$pg .= "<tr><td colspan=3 class=dc><font size=-1>"; $pg .= '<tr><td colspan=5 class=dc><font size=-1>';
$pg .= "<span class=st1>*</span>Leave blank if you haven't enabled it<br>"; $pg .= "<span class=st1>*</span>Leave blank if you haven't enabled it<br>";
$pg .= 'You must enter your password to save changes<br>'; $pg .= 'You must enter your password to save changes<br>';
$pg .= 'A ratio of 0, will remove the address from the payouts</font></td></tr>'; $pg .= 'A ratio of 0, will remove the address from the payouts</td></tr>';
} }
$pg .= "</table><input type=hidden name=rows value=$count id=rows></form>\n"; $pg .= "</table><input type=hidden name=rows value=$count id=rows></form>\n";
# TODO - adrw() update the odd/even class for the new row and rows below it
# TODO - move the js functions into inc.php
$pg .= "<script type='text/javascript'>\n"; $pg .= "<script type='text/javascript'>\n";
$pg .= "function adrw(){var p=document.getElementById('plus');"; $pg .= "function adrw(l){var p=document.getElementById('plus');";
$pg .= "var r=document.getElementById('rows');var c=parseInt(r.value);"; $pg .= "var r=document.getElementById('rows');var c=parseInt(r.value);";
$pg .= "var bs=document.getElementById('bs');var n=bs.cloneNode(true);n.id='z';"; $pg .= "var bs=document.getElementById('bs');var n=bs.cloneNode(true);n.id='z';";
$pg .= "n.className='odd';var ia=n.childNodes[0].firstChild;ia.name='addr:'+c;ia.value='';"; $pg .= "var ia=n.childNodes[1].firstChild;ia.name='addr:'+c;ia.value='';";
$pg .= "var ir=n.childNodes[1].firstChild;ir.id='rat'+c;ir.name='ratio:'+c;ir.value='0';"; $pg .= "var ipn=n.childNodes[2].firstChild;ipn.name='payname:'+c;ipn.value='';";
$pg .= "var ip=n.childNodes[2].firstChild;ip.id='per'+c;ip.innerHTML='0.00%';"; $pg .= "var ir=n.childNodes[3].firstChild;ir.id='rat'+c;ir.name='ratio:'+c;ir.value='0';";
$pg .= "var ip=n.childNodes[4].firstChild;ip.id='per'+c;ip.innerHTML='0.00%';";
$pg .= "p.parentNode.insertBefore(n, p);"; $pg .= "p.parentNode.insertBefore(n, p);";
$pg .= "c++;r.value=c;return true}\n"; $pg .= "c++;r.value=c;if(c>=l){p.parentNode.removeChild(p)}";
$pg .= "n.childNodes[0].innerHTML=''+c;n.className='odd';return true}\n";
$pg .= "function repc(){var c=parseInt(document.getElementById('rows').value);"; $pg .= "function repc(){var c=parseInt(document.getElementById('rows').value);";
$pg .= "if(!isNaN(c)&&c>0&&c<1000){var v=[],tot=0;for(i=0;i<c;i++){"; $pg .= "if(!isNaN(c)&&c>0&&c<1000){var v=[],tot=0;for(i=0;i<c;i++){";
$pg .= "var o=document.getElementById('rat'+i);var ov=parseInt(o.value);if(!isNaN(ov)&&ov>0)"; $pg .= "var o=document.getElementById('rat'+i);var ov=parseInt(o.value);if(!isNaN(ov)&&ov>0)";
@ -127,9 +151,12 @@ function doaddrmgt($data, $user)
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
{ {
$addr = getparam('addr:'.$i, false); $addr = getparam('addr:'.$i, false);
$nam = getparam('payname:'.$i, false);
if (nuem($nam))
$nam = '';
$ratio = getparam('ratio:'.$i, false); $ratio = getparam('ratio:'.$i, false);
if (!nuem($addr) && !nuem($ratio)) if (!nuem($addr) && !nuem($ratio))
$addrarr[] = array('addr' => $addr, 'ratio' => $ratio); $addrarr[] = array('addr' => $addr, 'payname' => $nam, 'ratio' => $ratio);
} }
$ans = userSettings($user, null, $addrarr, $pass, $twofa); $ans = userSettings($user, null, $addrarr, $pass, $twofa);
if ($ans['STATUS'] != 'ok') if ($ans['STATUS'] != 'ok')

3
pool/page_blocks.php

@ -94,6 +94,7 @@ function doblocks($data, $user)
$pg .= "<tr class=title>"; $pg .= "<tr class=title>";
$pg .= "<td class=dl>Description</td>"; $pg .= "<td class=dl>Description</td>";
$pg .= "<td class=dr>Time</td>"; $pg .= "<td class=dr>Time</td>";
$pg .= "<td class=dr>MeanTx%</td>";
$pg .= "<td class=dr>Diff%</td>"; $pg .= "<td class=dr>Diff%</td>";
$pg .= "<td class=dr>Mean%</td>"; $pg .= "<td class=dr>Mean%</td>";
$pg .= "<td class=dr>CDF[Erl]</td>"; $pg .= "<td class=dr>CDF[Erl]</td>";
@ -121,10 +122,12 @@ function doblocks($data, $user)
$bg = " bgcolor=$bg"; $bg = " bgcolor=$bg";
$luck = number_format(100 * $ans['s_luck:'.$i], 2); $luck = number_format(100 * $ans['s_luck:'.$i], 2);
$txm = number_format(100 * $ans['s_txmean:'.$i], 1);
$pg .= "<tr class=$row>"; $pg .= "<tr class=$row>";
$pg .= "<td class=dl>$desc Blocks</td>"; $pg .= "<td class=dl>$desc Blocks</td>";
$pg .= "<td class=dr>$age</td>"; $pg .= "<td class=dr>$age</td>";
$pg .= "<td class=dr>$txm%</td>";
$pg .= "<td class=dr>$diff%</td>"; $pg .= "<td class=dr>$diff%</td>";
$pg .= "<td class=dr>$mean%</td>"; $pg .= "<td class=dr>$mean%</td>";
$pg .= "<td class=dr$bg>$cdferldsp</td>"; $pg .= "<td class=dr$bg>$cdferldsp</td>";

197
pool/page_luck.php

@ -0,0 +1,197 @@
<?php
#
function lckg($nc, $av)
{
$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=0,ymax=0,xmin=-1,xmax=0,tlk=[];
var w=d['arp'].split(',');var cols=d['cols'].split(',');
gsh(c,w);
for(var j=1;j<w.length;j++){tlk[j-1]=$av}
for(var i=0;i<rows;i++){var s=parseFloat(d['firstcreatedate:'+i]);d['vx:'+i]=s;if(xmin==-1||xmin>s){xmin=s}if(xmax<s){xmax=s}
for(var j=1;j<w.length;j++){var pre=w[j];var lk=0,nam=pre+'luck:'+i;if(d[nam]){lk=parseFloat(d[nam])}if(lk>ymax)ymax=lk}
}
if(ymax>500){ymax=500}
ghg(c,xmax-xmin);
ggr(c,0.90,0.90,'Luck%',rows,xmin,xmax,ymin,ymax,d,'seq:','vx:','luck:',tlk,w,cols)}
c={};
function dodrw(data,cbx){if(hasCan()){gdrw(c,sep(data),cbx)}}
function gact(t){if(t.checked){scnv(t.id,1)}else{scnv(t.id,0)}godrw(0)}";
return $g;
}
#
function doluck($data, $user)
{
global $fld_sep, $val_sep;
if ($user === null)
$ans = getBlocks('Anon');
else
$ans = getBlocks($user);
$pg = '<h1>Pool Avg Block Luck History</h1><br>';
if ($ans['STATUS'] == 'ok' and isset($ans['rows']) and $ans['rows'] > 0)
{
$count = $ans['s_rows'] - 1;
$av = number_format(100 * $ans['s_luck:'.$count], 3);
for ($i = 0; $i < $count; $i++)
// This also defines how many lines there are
$cols = array('#0000c0', '#00dd00', '#e06020', '#b020e0');
$nams = array(1, 5, 15, 25);
$nc = count($cols);
addGBase();
$cbx = array('skey' => 'block key', 'slines' => 'block lines',
'tkey' => 'time key', 'tlines' => 'time lines',
'over' => 'key overlap', 'smooth' => 'smooth',
'utc' => 'utc');
$xon = array('skey' => 1, 'tkey' => 1, 'tlines' => 1, 'utc' => 1);
$pg .= '<div>';
foreach ($cbx as $nam => $txt)
{
$pg .= ' <span class=nb>';
$pg .= "<input type=checkbox id=$nam onclick='gact(this)'>";
$pg .= "$txt&nbsp;</span>";
}
$pg .= '</div><div>';
$i = 1;
$datacols = '';
foreach ($cols as $col)
{
if ($i != 1)
$pg .= '&nbsp;&nbsp;';
if ($i == 2 || $i == 4)
$chk = ' checked';
else
$chk = '';
$pg .= "<span class=nb><font color=$col>";
$pg .= "<input type=checkbox id=lin$i$chk onclick='godrw(0)'>: ";
if ($nams[$i-1] == 1)
$avs = '';
else
$avs = ' Avg';
$pg .= $nams[$i-1]." Block Luck$avs</font></span>";
if ($i > 1)
$datacols .= ',';
$datacols .= $col;
$i++;
}
$pg .= '</div>';
$pg .= '<div id=can0><canvas id=can width=1 height=1>';
$pg .= 'A graph will show here if your browser supports html5/canvas';
$pg .= "</canvas></div>\n";
$count = $ans['rows'];
# add the orphan/reject ratios to the subsequent blocks
$dr = 0;
for ($i = $count-1; $i >= 0; $i--)
{
$conf = $ans["confirmed:$i"];
if ($conf == '1' or $conf == 'F')
{
$ans["diffratio:$i"] += $dr;
$dr = 0;
}
else
$dr += $ans["diffratio:$i"];
}
# $ans blocks are 0->rows-1 highest->lowest
# build an array of valid block offsets (reversed lowest->highest)
$off = array();
for ($i = $count-1; $i >= 0; $i--)
{
$conf = $ans["confirmed:$i"];
if ($conf == '1' or $conf == 'F')
$off[] = $i;
}
$data = '';
$count = count($off);
$avg = 0;
# each valid block offset number (lowest->highest)
for ($j = 0; $j < $count; $j++)
{
$i = $off[$j];
$data .= $fld_sep . "height:$j$val_sep";
$data .= $ans["height:$i"];
$data .= $fld_sep . "seq:$j$val_sep";
$data .= $ans["seq:$i"];
$data .= $fld_sep . "firstcreatedate:$j$val_sep";
$data .= $ans["firstcreatedate:$i"];
$data .= $fld_sep . "0_luck:$j$val_sep";
$data .= number_format(100 * $ans['luck:'.$i], 3);
$avg += $ans["diffratio:$i"];
$l5c = $l15c = $l25c = 1;
$l5 = $l15 = $l25 = $ans['diffratio:'.$i];
# +/- offset from j (12 is the max for 25)
for ($k = 1; $k <= 12; $k++)
{
# we want the (n-1)/2 on each side of the offset number
foreach (array(-1, 1) as $s)
{
$o = $j + ($s * $k);
if (0 <= $o && $o < $count)
{
$dr = $ans['diffratio:'.$off[$o]];
if ($k <= 2) # (5-1)/2
{
$l5 += $dr;
$l5c++;
}
if ($k < 7) # (15-1)/2
{
$l15 += $dr;
$l15c++;
}
$l25 += $dr;
$l25c++;
}
}
}
# luck is 1/(mean diffratio)
$data .= $fld_sep . "1_luck:$j$val_sep";
$data .= number_format(100 * $l5c / $l5, 3);
$data .= $fld_sep . "2_luck:$j$val_sep";
$data .= number_format(100 * $l15c / $l15, 3);
$data .= $fld_sep . "3_luck:$j$val_sep";
$data .= number_format(100 * $l25c / $l25, 3);
}
$data .= $fld_sep . 'rows' . $val_sep . $count;
$data .= $fld_sep . 'arp' . $val_sep . ',0_,1_,2_,3_';
$data .= $fld_sep . 'cols' . $val_sep . $datacols;
$pg .= "<script type='text/javascript'>\n";
$pg .= lckg($nc, 100*$count/$avg);
$pg .= "\nfunction godrw(f){var cbx=[";
$comma = '';
foreach ($cbx as $nam => $txt)
{
$pg .= "$comma'$nam'";
$comma = ',';
}
$pg .= '];if(f){var xon={};';
foreach ($xon as $nam => $val)
$pg .= "xon['$nam']=1;";
$pg .= "doinit(cbx,xon)}dodrw('$data',cbx)};godrw(1);</script>\n";
}
return $pg;
}
#
function show_luck($info, $page, $menu, $name, $user)
{
gopage($info, NULL, 'doluck', $page, $menu, $name, $user);
}
#
?>

17
pool/page_payout.php

@ -2,9 +2,10 @@
# #
function dopayout($data, $user) function dopayout($data, $user)
{ {
$t = '<span class=nn>5</span>'; $N = 5;
$ot = '<span class=nn>1/5</span>'; $t = "<span class=nn>$N</span>";
$n = '<span class=nn>5Nd</span>'; $ot = "<span class=nn>1/$N</span>";
$n = "<span class=nn>${N}Nd</span>";
$n1 = '<span class=nn>N</span>'; $n1 = '<span class=nn>N</span>';
$n1d = '<span class=nn>Nd</span>'; $n1d = '<span class=nn>Nd</span>';
$bc = '+101 Confirms'; $bc = '+101 Confirms';
@ -13,7 +14,7 @@ function dopayout($data, $user)
if (isset($data['info']['currndiff'])) if (isset($data['info']['currndiff']))
$nd = $data['info']['currndiff']; $nd = $data['info']['currndiff'];
$nv = number_format($nd, 1); $nv = number_format($nd, 1);
$nv5 = number_format(5.0*$nd, 1); $nvx = number_format($N*$nd, 1);
$pg = "<h1>Payouts</h1> $pg = "<h1>Payouts</h1>
<table width=75% cellpadding=0 cellspacing=0 border=0><tr><td> <table width=75% cellpadding=0 cellspacing=0 border=0><tr><td>
@ -41,11 +42,13 @@ Shifts are ~50min or less in length.<br>
Aproximately every 30s, the pool generates new work and sends that to all the miners.<br> Aproximately every 30s, the pool generates new work and sends that to all the miners.<br>
The pool also sends new work every time a block is found on the Bitcoin network.<br> The pool also sends new work every time a block is found on the Bitcoin network.<br>
A shift summarises all the shares submitted to the pool for 100 work changes.<br> A shift summarises all the shares submitted to the pool for 100 work changes.<br>
However, when we find pool blocks, the current shift ends at the work in which the block was found.<br> However, when we find pool blocks, the current shift ends at the work in which the block was found<br>
A ckpool restart will also end the current shift and start a new one.<br><br> and a new shift starts.<br>
A ckpool restart will also end the current shift and start a new shift.<br>
A network difficulty change will also end the current shift and start a new shift.<br><br>
<span class=hdr>So, what's the $n value?</span><br><br> <span class=hdr>So, what's the $n value?</span><br><br>
The current Bitcoin network value for $n1d is $nv and thus $n is <b>$nv5</b><br> The current Bitcoin network value for $n1d is $nv and thus $n is <b>$nvx</b><br>
Bitcoin adjusts the $n1d value every 2016 blocks, which is about every 2 weeks.<br><br> Bitcoin adjusts the $n1d value every 2016 blocks, which is about every 2 weeks.<br><br>
When a block is found, the reward process counts back shifts until the total share difficulty included is $n.<br> When a block is found, the reward process counts back shifts until the total share difficulty included is $n.<br>
Since shares are summarised into shifts, it will include the full shift at the end of the range counting backwards,<br> Since shares are summarised into shifts, it will include the full shift at the end of the range counting backwards,<br>

6
pool/page_percent.php

@ -4,6 +4,7 @@ function pertitle($data, $user)
{ {
$pg = '<tr class=title>'; $pg = '<tr class=title>';
$pg .= '<td class=dl>Address</td>'; $pg .= '<td class=dl>Address</td>';
$pg .= '<td class=dl>ID</td>';
$pg .= '<td class=dr>Shares</td>'; $pg .= '<td class=dr>Shares</td>';
$pg .= '<td class=dr>Diff</td>'; $pg .= '<td class=dr>Diff</td>';
$pg .= '<td class=dr>Invalid</td>'; $pg .= '<td class=dr>Invalid</td>';
@ -40,6 +41,7 @@ function peruser($data, $user, &$offset, &$totshare, &$totdiff,
$all[] = array('payaddress' => $ans['payaddress:'.$i], $all[] = array('payaddress' => $ans['payaddress:'.$i],
'payratio' => $ans['payratio:'.$i], 'payratio' => $ans['payratio:'.$i],
'paypercent' => $ans['paypercent:'.$i], 'paypercent' => $ans['paypercent:'.$i],
'payname' => $ans['payname:'.$i],
'p_shareacc' => $ans['p_shareacc:'.$i], 'p_shareacc' => $ans['p_shareacc:'.$i],
'p_diffacc' => $ans['p_diffacc:'.$i], 'p_diffacc' => $ans['p_diffacc:'.$i],
'p_diffinv' => $ans['p_diffinv:'.$i], 'p_diffinv' => $ans['p_diffinv:'.$i],
@ -58,6 +60,7 @@ function peruser($data, $user, &$offset, &$totshare, &$totdiff,
$pg .= "<tr class=$row>"; $pg .= "<tr class=$row>";
$pg .= '<td class=dl>'.$all[$i]['payaddress'].'</td>'; $pg .= '<td class=dl>'.$all[$i]['payaddress'].'</td>';
$pg .= '<td class=dl>'.$all[$i]['payname'].'</td>';
$shareacc = number_format($all[$i]['p_shareacc'], 0); $shareacc = number_format($all[$i]['p_shareacc'], 0);
$totshare += $all[$i]['p_shareacc']; $totshare += $all[$i]['p_shareacc'];
@ -113,6 +116,7 @@ function pertotal($offset, $totshare, $totdiff, $totinvalid, $totrate, $blockacc
else else
$row = 'odd'; $row = 'odd';
$pg .= "<tr class=$row><td class=dl>Total:</td>"; $pg .= "<tr class=$row><td class=dl>Total:</td>";
$pg .= "<td class=dl>&nbsp;</td>";
$shareacc = number_format($totshare, 0); $shareacc = number_format($totshare, 0);
$pg .= "<td class=dr>$shareacc</td>"; $pg .= "<td class=dr>$shareacc</td>";
$diffacc = number_format($totdiff, 0); $diffacc = number_format($totdiff, 0);
@ -156,7 +160,7 @@ function dopercent($data, $user)
if ($blockacc > 0 && $blockreward > 0) if ($blockacc > 0 && $blockreward > 0)
{ {
$btc = btcfmt($totdiff / $blockacc * $blockreward); $btc = btcfmt($totdiff / $blockacc * $blockreward);
$pg .= '<tr><td colspan=8 class=dc>'; $pg .= '<tr><td colspan=9 class=dc>';
$pg .= "<br>Payout est if block found at 100%: ~$btc BTC"; $pg .= "<br>Payout est if block found at 100%: ~$btc BTC";
$pg .= '</td></tr>'; $pg .= '</td></tr>';
} }

5
pool/page_pplns2.php

@ -121,6 +121,9 @@ function fmtdata($code, $val)
case '.': case '.':
$ret = number_format($val, 1); $ret = number_format($val, 1);
break; break;
case '@':
$ret = howmanyhrs($val, true);
break;
default: default:
$ret = $val; $ret = $val;
} }
@ -186,6 +189,7 @@ Block: <input type=text name=blk size=10 value='$blkuse'>
'PPLNS Wanted' => '.diff_want', 'PPLNS Wanted' => '.diff_want',
'PPLNS Used' => '.diffacc_total', 'PPLNS Used' => '.diffacc_total',
'Elapsed Seconds' => ',pplns_elapsed', 'Elapsed Seconds' => ',pplns_elapsed',
'Elapsed Time' => '@pplns_elapsed',
'Users' => 'rows', 'Users' => 'rows',
'Oldest Workinfoid' => 'begin_workinfoid', 'Oldest Workinfoid' => 'begin_workinfoid',
'Oldest Time' => 'begin_stamp', 'Oldest Time' => 'begin_stamp',
@ -241,6 +245,7 @@ Block: <input type=text name=blk size=10 value='$blkuse'>
{ {
case ',': case ',':
case '.': case '.':
case '@':
$nm = substr($name, 1); $nm = substr($name, 1);
$fmt = fmtdata($name[0], $ans[$nm]); $fmt = fmtdata($name[0], $ans[$nm]);
break; break;

28
pool/page_shifts.php

@ -4,10 +4,11 @@ function doshifts($data, $user)
{ {
$ans = getShifts($user); $ans = getShifts($user);
$pg = "<table callpadding=0 cellspacing=0 border=0>\n"; $pg = "Click <a href='#payoutmark'>here</a> to jump to the start of the last payout<br><br>";
$pg .= "<table callpadding=0 cellspacing=0 border=0>\n";
$pg .= "<tr class=title>"; $pg .= "<tr class=title>";
$pg .= "<td class=dl>Shift</td>"; $pg .= "<td class=dl>Shift</td>";
$pg .= "<td class=dl>Start</td>"; $pg .= "<td class=dl>Start UTC</td>";
$pg .= "<td class=dr>Length</td>"; $pg .= "<td class=dr>Length</td>";
$pg .= "<td class=dr>Your Diff</td>"; $pg .= "<td class=dr>Your Diff</td>";
$pg .= "<td class=dr>Inv Diff</td>"; $pg .= "<td class=dr>Inv Diff</td>";
@ -15,6 +16,8 @@ function doshifts($data, $user)
$pg .= "<td class=dr>Shares</td>"; $pg .= "<td class=dr>Shares</td>";
$pg .= "<td class=dr>Avg Share</td>"; $pg .= "<td class=dr>Avg Share</td>";
$pg .= "<td class=dr>Rewards</td>"; $pg .= "<td class=dr>Rewards</td>";
$pg .= "<td class=dr>Rewarded<span class=st1>*</span></td>";
$pg .= "<td class=dr>PPS%</td>";
$pg .= "</tr>\n"; $pg .= "</tr>\n";
if (($ans['STATUS'] != 'ok') || !isset($ans['prefix_all'])) if (($ans['STATUS'] != 'ok') || !isset($ans['prefix_all']))
@ -28,9 +31,13 @@ function doshifts($data, $user)
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
{ {
$u = ''; $u = '';
$mark = '';
if (isset($ans['lastpayoutstart:'.$i]) if (isset($ans['lastpayoutstart:'.$i])
&& $ans['lastpayoutstart:'.$i] != '') && $ans['lastpayoutstart:'.$i] != '')
{
$u = 'u'; $u = 'u';
$mark = '<a name=payoutmark></a>';
}
if (($i % 2) == 0) if (($i % 2) == 0)
$row = "even$u"; $row = "even$u";
else else
@ -52,9 +59,9 @@ function doshifts($data, $user)
$btc = ' <img src=/BTCSym.png border=0>'; $btc = ' <img src=/BTCSym.png border=0>';
else else
$btc = ''; $btc = '';
$pg .= "<td class=dl>$shif$btc</td>"; $pg .= "<td class=dl>$shif$btc$mark</td>";
$start = $ans['start:'.$i]; $start = $ans['start:'.$i];
$pg .= '<td class=dl>'.utcd($start).'</td>'; $pg .= '<td class=dl>'.utcd($start, true).'</td>';
$nd = $ans['end:'.$i]; $nd = $ans['end:'.$i];
$elapsed = $nd - $start; $elapsed = $nd - $start;
$pg .= '<td class=dr>'.howmanyhrs($elapsed).'</td>'; $pg .= '<td class=dr>'.howmanyhrs($elapsed).'</td>';
@ -72,10 +79,23 @@ function doshifts($data, $user)
$avgsh = 0; $avgsh = 0;
$pg .= '<td class=dr>'.number_format($avgsh, 2).'</td>'; $pg .= '<td class=dr>'.number_format($avgsh, 2).'</td>';
$pg .= '<td class=dr>'.$ans['rewards:'.$i].'</td>'; $pg .= '<td class=dr>'.$ans['rewards:'.$i].'</td>';
$ppsr = (float)$ans['ppsrewarded:'.$i];
if ($ppsr > 0)
$ppsd = sprintf('%.5f', $ppsr);
else
$ppsd = '0';
$pg .= "<td class=dr>$ppsd</td>";
$ppsv = (float)$ans['ppsvalue:'.$i];
if ($ppsv > 0)
$pgot = number_format(100.0 * $ppsr / $ppsv, 2).'%';
else
$pgot = '?';
$pg .= "<td class=dr>$pgot</td>";
$pg .= "</tr>\n"; $pg .= "</tr>\n";
} }
} }
$pg .= "</table>\n"; $pg .= "</table>\n";
$pg .= "<span class=st1>*</span> The Rewarded value unit is satoshis per 1diff share<br>";
return $pg; return $pg;
} }

25
pool/page_workers.php

@ -11,9 +11,10 @@ function worktitle($data, $user)
$pg .= '<td class=dr>Shares</td>'; $pg .= '<td class=dr>Shares</td>';
$pg .= "<td class=dr><span class=nb><$r id=srtdiff data-sf=r4>:Diff</span></td>"; $pg .= "<td class=dr><span class=nb><$r id=srtdiff data-sf=r4>:Diff</span></td>";
$pg .= "<td class=dr><span class=nb><$r id=srtshrate data-sf=r5>:Share Rate</span></td>"; $pg .= "<td class=dr><span class=nb><$r id=srtshrate data-sf=r5>:Share Rate</span></td>";
$pg .= "<td class=dr><span class=nb><$r id=srtinv data-sf=r6>:Invalid</span></td>"; $pg .= '<td class=dr>&laquo;Elapsed</td>';
$pg .= "<td class=dr><span class=nb><$r id=srtinv data-sf=r7>:Invalid</span></td>";
$pg .= '<td class=dr>Block %</td>'; $pg .= '<td class=dr>Block %</td>';
$pg .= "<td class=dr><span class=nb><$r id=srtrate data-sf=r8>:Hash</span> Rate</td>"; $pg .= "<td class=dr><span class=nb><$r id=srtrate data-sf=r9>:Hash</span> Rate</td>";
$pg .= "</tr>\n"; $pg .= "</tr>\n";
return $pg; return $pg;
} }
@ -46,9 +47,10 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
} }
$all = array(); $all = array();
$count = $ans['rows']; $count = $ans['rows'];
$now = $ans['STAMP'];
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
{ {
$lst = $ans['STAMP'] - $ans['w_lastshare:'.$i]; $lst = $now - $ans['w_lastshare:'.$i];
if ($old !== false && $lst > $old) if ($old !== false && $lst > $old)
continue; continue;
@ -59,6 +61,7 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
$all[] = array('workername' => $ans['workername:'.$i], $all[] = array('workername' => $ans['workername:'.$i],
'w_lastshare' => $ans['w_lastshare:'.$i], 'w_lastshare' => $ans['w_lastshare:'.$i],
'w_lastshareacc' => $ans['w_lastshareacc:'.$i],
'w_lastdiff' => $ans['w_lastdiff:'.$i], 'w_lastdiff' => $ans['w_lastdiff:'.$i],
'w_shareacc' => $ans['w_shareacc:'.$i], 'w_shareacc' => $ans['w_shareacc:'.$i],
'w_diffacc' => $ans['w_diffacc:'.$i], 'w_diffacc' => $ans['w_diffacc:'.$i],
@ -74,10 +77,12 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
for ($i = 0; $i < $count; $i++) for ($i = 0; $i < $count; $i++)
{ {
$lst = $ans['STAMP'] - $all[$i]['w_lastshare']; $lst = $now - $all[$i]['w_lastshare'];
if ($old !== false && $lst > $old) if ($old !== false && $lst > $old)
continue; continue;
$lstacc = $now - $all[$i]['w_lastshareacc'];
if ((($offset) % 2) == 0) if ((($offset) % 2) == 0)
$row = 'even'; $row = 'even';
else else
@ -91,7 +96,7 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
$ld = '&nbsp;'; $ld = '&nbsp;';
$pg .= "<td class=dr>$ld</td>"; $pg .= "<td class=dr>$ld</td>";
$pg .= "<td class=dr data-srt=$lst>".howlongago($lst).'</td>'; $pg .= "<td class=dr data-srt=$lstacc>".howlongago($lstacc).'</td>';
$shareacc = number_format($all[$i]['w_shareacc'], 0); $shareacc = number_format($all[$i]['w_shareacc'], 0);
$totshare += $all[$i]['w_shareacc']; $totshare += $all[$i]['w_shareacc'];
@ -105,9 +110,12 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
$acthr = '0'; $acthr = '0';
$acthrv = 0; $acthrv = 0;
$actstt = $all[$i]['w_active_start']; $actstt = $all[$i]['w_active_start'];
if ($actstt > 0) if ($actstt <= 0 || ($now - $actstt) < 0)
$actsin = '&nbsp;';
else
{ {
$elapsed = $ans['STAMP'] - $actstt; $actsin = howmanyhrs($now - $actstt);
$elapsed = $now - $actstt;
if ($elapsed > 0) if ($elapsed > 0)
{ {
$acthrv = $all[$i]['w_active_diffacc'] * $acthrv = $all[$i]['w_active_diffacc'] *
@ -117,6 +125,7 @@ function workuser($data, $user, &$offset, &$totshare, &$totdiff,
} }
} }
$pg .= "<td class=dr data-srt=$acthrv>$acthr</td>"; $pg .= "<td class=dr data-srt=$acthrv>$acthr</td>";
$pg .= "<td class=dr>$actsin</td>";
$dinv = $all[$i]['w_diffinv']; $dinv = $all[$i]['w_diffinv'];
$dtot = $dacc + $dinv; $dtot = $dacc + $dinv;
@ -178,7 +187,7 @@ function worktotal($offset, $totshare, $totdiff, $totshrate, $totinvalid,
$pg .= "<td class=dr>$shareacc</td>"; $pg .= "<td class=dr>$shareacc</td>";
$diffacc = number_format($totdiff, 0); $diffacc = number_format($totdiff, 0);
$pg .= "<td class=dr>$diffacc</td>"; $pg .= "<td class=dr>$diffacc</td>";
$pg .= "<td class=dr>$totshrate</td>"; $pg .= "<td class=dr>$totshrate</td><td>&nbsp;</td>";
$dtot = $totdiff + $totinvalid; $dtot = $totdiff + $totinvalid;
if ($dtot > 0) if ($dtot > 0)
$rej = number_format(100.0 * $totinvalid / $dtot, 3); $rej = number_format(100.0 * $totinvalid / $dtot, 3);

3
pool/prime.php

@ -86,7 +86,8 @@ function check()
'Stats' => 'stats', 'Stats' => 'stats',
'Blocks' => 'blocks', 'Blocks' => 'blocks',
'Graph' => 'psperf', 'Graph' => 'psperf',
'Acclaim' => 'userinfo' 'Acclaim' => 'userinfo',
'Luck' => 'luck'
), ),
'Admin' => NULL, 'Admin' => NULL,
'gap' => array( # options not shown 'gap' => array( # options not shown

8
sql/ckdb.sql

@ -75,6 +75,8 @@ CREATE TABLE paymentaddresses (
userid bigint NOT NULL, userid bigint NOT NULL,
payaddress character varying(256) DEFAULT ''::character varying NOT NULL, payaddress character varying(256) DEFAULT ''::character varying NOT NULL,
payratio integer DEFAULT 1000000 NOT NULL, payratio integer DEFAULT 1000000 NOT NULL,
payname character varying(64) DEFAULT ''::character varying NOT NULL,
status char DEFAULT ' ' NOT NULL,
createdate timestamp with time zone NOT NULL, createdate timestamp with time zone NOT NULL,
createby character varying(64) DEFAULT ''::character varying NOT NULL, createby character varying(64) DEFAULT ''::character varying NOT NULL,
createcode character varying(128) DEFAULT ''::character varying NOT NULL, createcode character varying(128) DEFAULT ''::character varying NOT NULL,
@ -247,6 +249,8 @@ CREATE TABLE sharesummary ( -- per workinfo for each user+worker
errorcount bigint NOT NULL, errorcount bigint NOT NULL,
firstshare timestamp with time zone NOT NULL, firstshare timestamp with time zone NOT NULL,
lastshare timestamp with time zone NOT NULL, lastshare timestamp with time zone NOT NULL,
firstshareacc timestamp with time zone NOT NULL,
lastshareacc timestamp with time zone NOT NULL,
lastdiffacc float NOT NULL, lastdiffacc float NOT NULL,
complete char NOT NULL, complete char NOT NULL,
createdate timestamp with time zone NOT NULL, createdate timestamp with time zone NOT NULL,
@ -311,6 +315,8 @@ CREATE TABLE markersummary ( -- sum of sharesummary for a workinfo range
errorcount bigint NOT NULL, errorcount bigint NOT NULL,
firstshare timestamp with time zone NOT NULL, firstshare timestamp with time zone NOT NULL,
lastshare timestamp with time zone NOT NULL, lastshare timestamp with time zone NOT NULL,
firstshareacc timestamp with time zone NOT NULL,
lastshareacc timestamp with time zone NOT NULL,
lastdiffacc float NOT NULL, lastdiffacc float NOT NULL,
createdate timestamp with time zone NOT NULL, createdate timestamp with time zone NOT NULL,
createby character varying(64) NOT NULL, createby character varying(64) NOT NULL,
@ -464,4 +470,4 @@ CREATE TABLE version (
PRIMARY KEY (vlock) PRIMARY KEY (vlock)
); );
insert into version (vlock,version) values (1,'1.0.2'); insert into version (vlock,version) values (1,'1.0.4');

276
sql/rollback.sh

@ -0,0 +1,276 @@
#!/bin/bash
#
# WARNING!!!
# 1) Don't use this
# 2) If you do use this, only use it if your "ckpool's ckdb logfiles"
# (CCLs) are 100% certainly OK
# Data in the DB will be lost if the rollback requires reloading
# data that is missing from the CCLs
# 3) If you do use this, make sure ckdb is NOT running
# 4) The rollback is only for the tables that are generated from the CCLs
# If you need data from other tables, see tabdump.sql
# 5) If you need to reload missing data that may or may not be in the CCLs
# then you need to convince Kano to update the ckdb -y option to handle
# that, with the current db, and also add code to the -y option to
# update the DB
# i.e. the ckdb -y options/code need updating
# 6) Blocks commands manually entered using ckpmsg (confirm,orphan,reject,etc)
# will not be automatically restored if you use -b, you'll need to redo
# them again manually
#
# The basic use of this script is for when something goes wrong with the
# database and the CCLs are OK - so you can roll back to before the
# database problem and reload all the data
#
# It may be unnecessary to delete/expire blocks records since the reload will
# attempt to load all old and new blocks records in the CCLs being
# reloaded, no matter what
# Also, deleting blocks history will lose all manual block changes
# done with confirms, orphans, rejects, etc
# However, if the block summarisations are wrong or the blocks table is
# corrupt, you will need to delete/expire them to correct them and then
# redo the manual blocks changes after reloading
#
# Deleting markersummaries would only be an option if you know for sure
# that all data is in the CCLs
# It would be ideal to do a markersummary table dump before a rollback
# However, -e will be OK if the CCLs aren't missing anything reqired for
# the reload
#
# In all cases, if data is missing between the start and end of the
# rollback, then the reload SEQ checking will report it, unless ...
# by coincidence the missing data is at the end of a ckpool sequence
# and no gaps exist in the data before the truncation point
# e.g. seqall goes from N..M then a new SEQ starts at 0..
# however if there actually was data after M, but all missing exactly up
# to before the SEQ restart 0 point, then ckdb couldn't know this unless
# the data was inconsistent
#
# -c will show you record counts but not change anything
#
# -e will of course allow you to compare all but markersummary, before and
# after rolling back, by manually comparing the expired record with the
# new replacement unexpired record - but it deletes the markersummary data
# -e is untidy simply because it leaves around unnecesary data, if the
# reload after the rollback is not missing anything and succeeds
# -e deletes all the records that were already expired so you will lose
# the original DB history of those records, however a reload should
# regenerate a similar history
#
# -m is the same as -e except it doesn't touch markersummary at all
# -m will probably cause duplicate markersummary issues for ckdb
#
# -r ... use at your own risk :) - but is the best option if nothing is
# missing from your CCLs
# it simply deletes all reload data back to the specified point and
# that data should all reappear with a successful reload
#
usAge()
{
echo "usAge: `basename $0` [-b] [-n] -c|-e|-r|-m workinfoid"
echo " Preferred option is just -e as long as you aren't missing reload data"
echo " The order of options must match the usAge order"
echo
echo " -b = include blocks when deleting/expiring (otherwise left untouched)"
echo
echo " -n = use 'now()' instead of the date timestamp of now, for expiry date"
echo
echo " -c = report the counts of rows that would be affected, but don't do it"
echo
echo " -e = rollback by deleteing expired data and expiring unexpired data,"
echo " but deleting markersummary"
echo
echo " -r = rollback by deleting all relevant data (expired or unexpired)"
echo " -m = rollback by deleteing expired data and expiring unexpired data,"
echo " but don't touch markersummary"
echo " N.B. -m is expected to cause problems with ckdb"
echo
echo " generates the sql on stdout, that you would feed into pgsql"
echo
echo " Read `basename $0` for a more detailed explanation"
exit 1
}
#
idctl()
{
echo "\\echo 'update idcontrol $1'
update idcontrol
set lastid=(select max($1) from $2),
modifydate=$n,modifyby='$idn',
modifycode='$mc',modifyinet='$mi'
where idname='$1';"
}
#
process()
{
# so all stamps are exactly the same
now="`date +%s`"
idn="rollback_${wi}_`date -d "@$now" '+%Y%m%d%H%M%S%:::z'`"
mc="`basename $0`"
mi="127.0.0.1"
if [ "$usenow" ] ; then
n="now()"
else
n="'`date -u -d "@$now" '+%Y-%m-%d %H:%M:%S+00'`'"
fi
ex="expirydate = $n"
unex="expirydate > '6666-06-01'"
oldex="expirydate < '6666-06-01'"
#
if [ "$opt" = "-c" ] ; then
echo "\\echo 'count markersummary'"
echo "select count(*),min(markerid) as min_markerid,max(markerid) as max_markerid,"
echo " sum(diffacc) as sum_diffacc,min(firstshare) as min_firstshare,"
echo " max(lastshareacc) as max_lastshareacc,max(lastshare) as max_lastshare"
echo " from markersummary where markerid in"
echo " (select distinct markerid from workmarkers where workinfoidend >= $wi);"
fi
if [ "$opt" = "-r" -o "$opt" = "-e" ] ; then
echo "\\echo 'delete markersummary'"
echo "delete from markersummary where markerid in"
echo " (select distinct markerid from workmarkers where workinfoidend >= $wi);"
fi
#
if [ "$opt" = "-c" ] ; then
echo "\\echo 'count marks'"
echo "select count(*),min(workinfoid) as min_workinfoid,"
echo " max(workinfoid) as max_workinfoid"
echo " from marks where workinfoid >= $wi;"
echo "\\echo 'count workmarkers'"
echo "select count(*),min(workinfoidstart) as min_workinfoidstart,"
echo " max(workinfoidend) as max_workinfoidend"
echo " from workmarkers where workinfoidend >= $wi;"
fi
if [ "$opt" = "-r" ] ; then
echo "\\echo 'delete marks'"
echo "delete from marks where workinfoid >= $wi;"
echo "\\echo 'delete workmarkers'"
echo "delete from workmarkers where workinfoidend >= $wi;"
fi
if [ "$opt" = "-e" -o "$opt" = "-m" ] ; then
echo "\\echo 'delete/update marks'"
echo "delete from marks where $oldex and workinfoid >= $wi;"
echo "update marks set $ex where $unex and workinfoid >= $wi;"
echo "\\echo 'delete/update workmarkers'"
echo "delete from workmarkers where $oldex and workinfoidend >= $wi;"
echo "update workmarkers set $ex where $unex and workinfoidend >= $wi;"
fi
#
if [ "$opt" = "-c" ] ; then
echo "\\echo 'count blocks'"
echo "select count(*),min(height) as min_height,max(height) as max_height,"
echo " min(workinfoid) as min_workinfoid,max(workinfoid) as max_workinfoid"
echo " from blocks where workinfoid >= $wi;"
echo "\\echo 'count workinfo'"
echo "select count(*),min(workinfoid) as min_workinfoid,"
echo " max(workinfoid) as max_workinfoid,min(reward) as min_reward,"
echo " max(reward) as max_reward,max(length(transactiontree)) as max_tree,"
echo " min(createdate) as min_createdate,max(createdate) as max_createdate"
echo " from workinfo where workinfoid >= $wi;"
fi
if [ "$opt" = "-r" ] ; then
if [ "$deblk" ] ; then
echo "\\echo 'delete blocks'"
echo "delete from blocks where workinfoid >= $wi;"
fi
echo "\\echo 'delete workinfo'"
echo "delete from workinfo where workinfoid >= $wi;"
fi
if [ "$opt" = "-e" -o "$opt" = "-m" ] ; then
if [ "$deblk" ] ; then
echo "\\echo 'delete/update blocks'"
echo "delete from blocks where $oldex and workinfoid >= $wi;"
echo "update blocks set $ex where $unex and workinfoid >= $wi;"
fi
echo "\\echo 'delete/update workinfo'"
echo "delete from workinfo where $oldex and workinfoid >= $wi;"
echo "update workinfo set $ex where $unex and workinfoid >= $wi;"
fi
#
if [ "$opt" = "-c" ] ; then
echo "\\echo 'count miningpayouts'"
echo "select count(*),min(payoutid) as min_payoutid,"
echo " max(payoutid) as max_payoutid"
echo " from miningpayouts where payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "\\echo 'count payments'"
echo "select count(*),min(payoutid) as min_payoutid,"
echo " max(payoutid) as max_payoutid"
echo " from payments where payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "\\echo 'count payouts'"
echo "select count(*),min(workinfoidstart) as min_workinfoidstart,"
echo " max(workinfoidend) as max_workinfoidend"
echo " from payouts where workinfoidend >= $wi;"
fi
if [ "$opt" = "-r" ] ; then
echo "\\echo 'delete miningpayouts'"
echo "delete from miningpayouts where payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "\\echo 'delete payments'"
echo "delete from payments where payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "\\echo 'delete payouts'"
echo "delete from payouts where workinfoidend >= $wi;"
fi
if [ "$opt" = "-e" -o "$opt" = "-m" ] ; then
echo "\\echo 'delete/update miningpayouts'"
echo "delete from miningpayouts where $oldex and payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "update miningpayouts set $ex where $unex and payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "\\echo 'delete/update payments'"
echo "delete from payments where $oldex and payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "update payments set $ex where $unex and payoutid in"
echo " (select distinct payoutid from payouts where workinfoidend >= $wi);"
echo "\\echo 'delete/update payouts'"
echo "delete from payouts where $oldex and workinfoidend >= $wi;"
echo "update payouts set $ex where workinfoidend >= $wi and $unex;"
fi
#
if [ "$opt" = "-e" -o "$opt" = "-m" -o "$opt" = "-r" ] ; then
idctl markerid workmarkers
idctl paymentid payments
idctl payoutid payouts
# this makes sure the worker data is consistent - don't remove this
idctl workerid workers
fi
}
#
if [ -z "$1" ] ; then
usAge
fi
#
if [ "$1" = "-?" -o "$1" = "-h" -o "$1" = "-help" -o "$1" = "--help" ] ; then
usAge
fi
#
deblk=""
if [ "$1" = "-b" ] ; then
deblk="y"
shift
fi
#
usenow=""
if [ "$1" = "-n" ] ; then
usenow="y"
shift
fi
#
if [ "$1" != "-c" -a "$1" != "-e" -a "$1" != "-r" -a "$1" != "-m" ] ; then
echo "ERR: Unknown p1='$1'"
usAge
fi
#
opt="$1"
shift
#
if [ -z "$1" ] ; then
echo "ERR: missing workinfoid"
usAge
fi
#
wi="$1"
#
process

63
sql/tabdump.sh

@ -0,0 +1,63 @@
#!/bin/bash
#
# idcontrol is updated after the rows are loaded
# for users, paymentaddresses and workers
#
# note that this doesn't save idcontrol since it
# would cause a consistency problem with the reload
# Instead it generates it based on the current DB
#
# Obviously ... don't run the output file when CKDB is running
#
# initid.sh would also be useful to create any missing idcontrol
# records, before using this to update them
#
t0="optioncontrol paymentaddresses useratts users workers version"
#
usAge()
{
echo "usAge: `basename $0` -r > log.sql"
echo " -r = do it"
echo " dump tables not part of the reload"
exit 1
}
#
idctl()
{
echo "
update idcontrol
set lastid=(select max($1) from $2),
modifydate=now(),modifyby='$idn',
modifycode='$mc',modifyinet='$mi'
where idname='$1';"
}
#
process()
{
t=""
for i in $t0 ; do
t="$t -t $i"
echo "delete from $i;"
done
pg_dump -a $t ckdb
#
idn="tabdump-`date "+%Y%m%d%H%M%S"`"
mc="`basename $0`"
mi="127.0.0.1"
#
idctl userid users
idctl workerid workers
idctl paymentaddressid paymentaddresses
# these below are just to make sure the DB is consistent
idctl markerid workmarkers
idctl paymentid payments
idctl payoutid payouts
}
#
if [ "$1" != "-r" ] ; then
echo "Missing -r"
usAge
fi
#
process

38
sql/v1.0.2-v1.0.3.sql

@ -0,0 +1,38 @@
SET SESSION AUTHORIZATION 'postgres';
BEGIN transaction;
DO $$
DECLARE ver TEXT;
BEGIN
UPDATE version set version='1.0.3' where vlock=1 and version='1.0.2';
IF found THEN
RETURN;
END IF;
SELECT version into ver from version
WHERE vlock=1;
RAISE EXCEPTION 'Wrong DB version - expect "1.0.2" - found "%"', ver;
END $$;
ALTER TABLE ONLY markersummary
ADD COLUMN firstshareacc timestamp with time zone DEFAULT '1970-01-01 00:00:00+00' NOT NULL,
ADD COLUMN lastshareacc timestamp with time zone DEFAULT '1970-01-01 00:00:00+00' NOT NULL;
ALTER TABLE ONLY markersummary
ALTER COLUMN firstshareacc DROP DEFAULT,
ALTER COLUMN lastshareacc DROP DEFAULT;
ALTER TABLE ONLY sharesummary
ADD COLUMN firstshareacc timestamp with time zone DEFAULT '1970-01-01 00:00:00+00' NOT NULL,
ADD COLUMN lastshareacc timestamp with time zone DEFAULT '1970-01-01 00:00:00+00' NOT NULL;
ALTER TABLE ONLY sharesummary
ALTER COLUMN firstshareacc DROP DEFAULT,
ALTER COLUMN lastshareacc DROP DEFAULT;
END transaction;

26
sql/v1.0.3-v1.0.4.sql

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

431
src/ckdb.c

File diff suppressed because it is too large Load Diff

134
src/ckdb.h

@ -54,8 +54,8 @@
*/ */
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "1.0.2" #define DB_VERSION "1.0.4"
#define CKDB_VERSION DB_VERSION"-1.241" #define CKDB_VERSION DB_VERSION"-1.505"
#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__
@ -95,6 +95,21 @@ extern int switch_state;
#define SWITCH_STATE_AUTHWORKERS 1 #define SWITCH_STATE_AUTHWORKERS 1
#define SWITCH_STATE_ALL 666666 #define SWITCH_STATE_ALL 666666
extern bool genpayout_auto;
extern bool markersummary_auto;
enum free_modes {
FREE_MODE_ALL,
FREE_MODE_NONE,
FREE_MODE_FAST
};
#define FREE_MODE_ALL_STR "all"
#define FREE_MODE_NONE_STR "none"
#define FREE_MODE_FAST_STR "fast"
extern enum free_modes free_mode;
#define BLANK " " #define BLANK " "
extern char *EMPTY; extern char *EMPTY;
@ -135,6 +150,7 @@ typedef struct loadstatus {
tv_t newest_createdate_workinfo; tv_t newest_createdate_workinfo;
tv_t newest_createdate_poolstats; tv_t newest_createdate_poolstats;
tv_t newest_createdate_blocks; tv_t newest_createdate_blocks;
int32_t newest_height_blocks;
} LOADSTATUS; } LOADSTATUS;
extern LOADSTATUS dbstatus; extern LOADSTATUS dbstatus;
@ -312,6 +328,7 @@ extern bool everyone_die;
extern tv_t last_heartbeat; extern tv_t last_heartbeat;
extern tv_t last_workinfo; extern tv_t last_workinfo;
extern tv_t last_share; extern tv_t last_share;
extern tv_t last_share_acc;
extern tv_t last_share_inv; extern tv_t last_share_inv;
extern tv_t last_auth; extern tv_t last_auth;
extern cklock_t last_lock; extern cklock_t last_lock;
@ -406,6 +423,7 @@ enum cmd_values {
CMD_SHSTA, CMD_SHSTA,
CMD_USERINFO, CMD_USERINFO,
CMD_BTCSET, CMD_BTCSET,
CMD_QUERY,
CMD_END CMD_END
}; };
@ -438,8 +456,8 @@ enum cmd_values {
// CCLs are every ... // CCLs are every ...
#define ROLL_S 3600 #define ROLL_S 3600
#define LOGQUE(_msg) log_queue_message(_msg) #define LOGQUE(_msg, _db) log_queue_message(_msg, _db)
#define LOGFILE(_msg) rotating_log_nolock(_msg) #define LOGFILE(_msg, _prefix) rotating_log_nolock(_msg, _prefix)
#define LOGDUP "dup." #define LOGDUP "dup."
// *** // ***
@ -711,6 +729,7 @@ enum cmd_values {
// LOGQUEUE // LOGQUEUE
typedef struct logqueue { typedef struct logqueue {
char *msg; char *msg;
bool db;
} LOGQUEUE; } LOGQUEUE;
#define ALLOC_LOGQUEUE 1024 #define ALLOC_LOGQUEUE 1024
@ -1122,6 +1141,9 @@ extern K_STORE *useratts_store;
// This att means the user uses multiple % based payout addresses // This att means the user uses multiple % based payout addresses
#define USER_MULTI_PAYOUT "PayAddresses" #define USER_MULTI_PAYOUT "PayAddresses"
// If they have multi, then: the default address limit if the useratt num < 1
#define USER_ADDR_LIMIT 2
#define USER_OLD_WORKERS "OldWorkersDays" #define USER_OLD_WORKERS "OldWorkersDays"
#define USER_OLD_WORKERS_DEFAULT 7 #define USER_OLD_WORKERS_DEFAULT 7
@ -1179,6 +1201,7 @@ typedef struct paymentaddresses {
int64_t userid; int64_t userid;
char payaddress[TXT_BIG+1]; char payaddress[TXT_BIG+1];
int32_t payratio; int32_t payratio;
char payname[TXT_SML+1];
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
bool match; // non-DB field bool match; // non-DB field
} PAYMENTADDRESSES; } PAYMENTADDRESSES;
@ -1294,6 +1317,7 @@ typedef struct optioncontrol {
// Value it must default to (to work properly) // Value it must default to (to work properly)
#define OPTIONCONTROL_HEIGHT 1 #define OPTIONCONTROL_HEIGHT 1
#define MAX_HEIGHT 999999999
// Test it here rather than obscuring the #define elsewhere // Test it here rather than obscuring the #define elsewhere
#if ((OPTIONCONTROL_HEIGHT+1) != START_POOL_HEIGHT) #if ((OPTIONCONTROL_HEIGHT+1) != START_POOL_HEIGHT)
@ -1324,6 +1348,8 @@ typedef struct workinfo {
char bits[TXT_SML+1]; char bits[TXT_SML+1];
char ntime[TXT_SML+1]; char ntime[TXT_SML+1];
int64_t reward; int64_t reward;
int32_t height; // non-DB field
double diff_target; // non-DB field
HISTORYDATECONTROLFIELDS; HISTORYDATECONTROLFIELDS;
} WORKINFO; } WORKINFO;
@ -1346,6 +1372,13 @@ extern tv_t last_bc;
// current network diff // current network diff
extern double current_ndiff; extern double current_ndiff;
// Offset in binary coinbase1 of the block number
#define BLOCKNUM_OFFSET 42
// Initial block reward (satoshi)
#define REWARD_BASE 5000000000.0
// How many blocks per halving
#define REWARD_HALVE 210000.0
// SHARES shares.id.json={...} // SHARES shares.id.json={...}
typedef struct shares { typedef struct shares {
int64_t workinfoid; int64_t workinfoid;
@ -1381,6 +1414,17 @@ extern K_STORE *shares_early_store;
check for it's workinfoid and then be discarded */ check for it's workinfoid and then be discarded */
#define EARLYSHARESLIMIT 60.0 #define EARLYSHARESLIMIT 60.0
/* All shares this % less than beng a block, or higher,
will be reported on the console */
#define DIFF_PERCENT_DEFAULT 5
// OptionControl can override it, > 100 means don't do it
#define DIFF_PERCENT_NAME "ShareDiffPercent"
// int diff % -> ratio
#define DIFF_VAL(_v) (1.0 - ((double)(_v) / 100.0))
extern double diff_percent;
// SHAREERRORS shareerrors.id.json={...} // SHAREERRORS shareerrors.id.json={...}
typedef struct shareerrors { typedef struct shareerrors {
int64_t workinfoid; int64_t workinfoid;
@ -1426,6 +1470,8 @@ typedef struct sharesummary {
int64_t errorcount; int64_t errorcount;
tv_t firstshare; tv_t firstshare;
tv_t lastshare; tv_t lastshare;
tv_t firstshareacc;
tv_t lastshareacc;
double lastdiffacc; double lastdiffacc;
char complete[TXT_FLAG+1]; char complete[TXT_FLAG+1];
MODIFYDATECONTROLPOINTERS; MODIFYDATECONTROLPOINTERS;
@ -1497,6 +1543,9 @@ typedef struct blocks {
double cdferl; double cdferl;
double luck; double luck;
// Mean reward ratio per block from last to this
double txmean;
// To save looking them up when needed // To save looking them up when needed
tv_t prevcreatedate; // non-DB field tv_t prevcreatedate; // non-DB field
tv_t blockcreatedate; // non-DB field tv_t blockcreatedate; // non-DB field
@ -1821,7 +1870,8 @@ typedef struct workerstatus {
char workername[TXT_BIG+1]; char workername[TXT_BIG+1];
tv_t last_auth; tv_t last_auth;
tv_t last_share; tv_t last_share;
double last_diff; tv_t last_share_acc;
double last_diff_acc;
tv_t last_stats; tv_t last_stats;
tv_t last_idle; tv_t last_idle;
// Below gets reset on each block // Below gets reset on each block
@ -1881,6 +1931,8 @@ typedef struct markersummary {
int64_t errorcount; int64_t errorcount;
tv_t firstshare; tv_t firstshare;
tv_t lastshare; tv_t lastshare;
tv_t firstshareacc;
tv_t lastshareacc;
double lastdiffacc; double lastdiffacc;
MODIFYDATECONTROLPOINTERS; MODIFYDATECONTROLPOINTERS;
} MARKERSUMMARY; } MARKERSUMMARY;
@ -2090,6 +2142,8 @@ extern void sequence_report(bool lock);
#define REWARDOVERRIDE "MinerReward" #define REWARDOVERRIDE "MinerReward"
#define PPSOVERRIDE "PPSValue"
// Data free functions (first) // Data free functions (first)
#define FREE_ITEM(item) do { } while(0) #define FREE_ITEM(item) do { } while(0)
// TODO: make a macro for all other to use above macro // TODO: make a macro for all other to use above macro
@ -2190,16 +2244,17 @@ extern K_ITEM *_optional_name(K_TREE *trf_root, char *name, int len, char *patt,
extern K_ITEM *_require_name(K_TREE *trf_root, char *name, int len, char *patt, extern K_ITEM *_require_name(K_TREE *trf_root, char *name, int len, char *patt,
char *reply, size_t siz, WHERE_FFL_ARGS); char *reply, size_t siz, WHERE_FFL_ARGS);
extern cmp_t cmp_workerstatus(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_workerstatus(K_ITEM *a, K_ITEM *b);
extern K_ITEM *get_workerstatus(int64_t userid, char *workername); extern K_ITEM *get_workerstatus(bool lock, int64_t userid, char *workername);
#define find_create_workerstatus(_u, _w, _file, _func, _line) \ #define find_create_workerstatus(_l, _u, _w, _file, _func, _line) \
_find_create_workerstatus(_u, _w, true, _file, _func, _line, WHERE_FFL_HERE) _find_create_workerstatus(_l, _u, _w, true, _file, _func, _line, WHERE_FFL_HERE)
#define find_workerstatus(_u, _w, _file, _func, _line) \ #define find_workerstatus(_l, _u, _w, _file, _func, _line) \
_find_create_workerstatus(_u, _w, false, _file, _func, _line, WHERE_FFL_HERE) _find_create_workerstatus(_l, _u, _w, false, _file, _func, _line, WHERE_FFL_HERE)
extern K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, extern K_ITEM *_find_create_workerstatus(bool lock, int64_t userid,
bool create, const char *file2, char *workername, bool create,
const char *func2, const int line2, const char *file2, const char *func2,
WHERE_FFL_ARGS); const int line2, WHERE_FFL_ARGS);
extern void zero_all_active(tv_t *when);
extern void workerstatus_ready(); extern void workerstatus_ready();
#define workerstatus_update(_auths, _shares, _userstats) \ #define workerstatus_update(_auths, _shares, _userstats) \
_workerstatus_update(_auths, _shares, _userstats, WHERE_FFL_HERE) _workerstatus_update(_auths, _shares, _userstats, WHERE_FFL_HERE)
@ -2264,14 +2319,13 @@ extern K_ITEM *find_first_paypayid(int64_t userid, int64_t payoutid, K_TREE_CTX
extern cmp_t cmp_accountbalance(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_accountbalance(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_accountbalance(int64_t userid); extern K_ITEM *find_accountbalance(int64_t userid);
extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height); extern K_ITEM *find_optioncontrol(char *optionname, const tv_t *now, int32_t height);
#define sys_setting(_name, _def, _now) user_sys_setting(0, _name, _def, _now)
extern int64_t user_sys_setting(int64_t userid, char *setting_name, extern int64_t user_sys_setting(int64_t userid, char *setting_name,
int64_t setting_default, tv_t *now); int64_t setting_default, const tv_t *now);
extern cmp_t cmp_workinfo(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_workinfo(K_ITEM *a, K_ITEM *b);
#define coinbase1height(_cb1) _coinbase1height(_cb1, WHERE_FFL_HERE) #define coinbase1height(_wi) _coinbase1height(_wi, WHERE_FFL_HERE)
extern int32_t _coinbase1height(char *coinbase1, WHERE_FFL_ARGS); extern int32_t _coinbase1height(WORKINFO *wi, WHERE_FFL_ARGS);
#define cmp_height(_cb1a, _cb1b) _cmp_height(_cb1a, _cb1b, WHERE_FFL_HERE)
extern cmp_t _cmp_height(char *coinbase1a, char *coinbase1b, WHERE_FFL_ARGS);
extern cmp_t cmp_workinfo_height(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_workinfo_height(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_workinfo(int64_t workinfoid, K_TREE_CTX *ctx); extern K_ITEM *find_workinfo(int64_t workinfoid, K_TREE_CTX *ctx);
extern K_ITEM *next_workinfo(int64_t workinfoid, K_TREE_CTX *ctx); extern K_ITEM *next_workinfo(int64_t workinfoid, K_TREE_CTX *ctx);
@ -2279,12 +2333,14 @@ extern bool workinfo_age(int64_t workinfoid, char *poolinstance, char *by,
char *code, char *inet, tv_t *cd, tv_t *ss_first, char *code, char *inet, tv_t *cd, tv_t *ss_first,
tv_t *ss_last, int64_t *ss_count, int64_t *s_count, tv_t *ss_last, int64_t *ss_count, int64_t *s_count,
int64_t *s_diff); int64_t *s_diff);
extern double coinbase_reward(int32_t height);
extern double workinfo_pps(K_ITEM *w_item, int64_t workinfoid, bool lock);
extern cmp_t cmp_shares(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_shares(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_shareerrors(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_shareerrors(K_ITEM *a, K_ITEM *b);
extern void dsp_sharesummary(K_ITEM *item, FILE *stream); extern void dsp_sharesummary(K_ITEM *item, FILE *stream);
extern cmp_t cmp_sharesummary(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_sharesummary(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_sharesummary_workinfoid(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_sharesummary_workinfoid(K_ITEM *a, K_ITEM *b);
extern void zero_sharesummary(SHARESUMMARY *row, tv_t *cd, double diff); extern void zero_sharesummary(SHARESUMMARY *row);
#define find_sharesummary(_userid, _workername, _workinfoid) \ #define find_sharesummary(_userid, _workername, _workinfoid) \
_find_sharesummary(_userid, _workername, _workinfoid, false) _find_sharesummary(_userid, _workername, _workinfoid, false)
#define find_sharesummary_p(_workinfoid) \ #define find_sharesummary_p(_workinfoid) \
@ -2309,9 +2365,9 @@ extern double _blockhash_diff(char *hash, WHERE_FFL_ARGS);
extern void dsp_blocks(K_ITEM *item, FILE *stream); extern void dsp_blocks(K_ITEM *item, FILE *stream);
extern cmp_t cmp_blocks(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_blocks(K_ITEM *a, K_ITEM *b);
extern K_ITEM *find_blocks(int32_t height, char *blockhash, K_TREE_CTX *ctx); extern K_ITEM *find_blocks(int32_t height, char *blockhash, K_TREE_CTX *ctx);
extern K_ITEM *find_prev_blocks(int32_t height); extern K_ITEM *find_prev_blocks(int32_t height, K_TREE_CTX *ctx);
extern const char *blocks_confirmed(char *confirmed); extern const char *blocks_confirmed(char *confirmed);
extern void zero_on_new_block(); extern void zero_on_new_block(bool lock);
extern void set_block_share_counters(); extern void set_block_share_counters();
extern bool check_update_blocks_stats(tv_t *stats); extern bool check_update_blocks_stats(tv_t *stats);
#define set_blockcreatedate(_h) _set_blockcreatedate(_h, WHERE_FFL_HERE) #define set_blockcreatedate(_h) _set_blockcreatedate(_h, WHERE_FFL_HERE)
@ -2328,6 +2384,7 @@ 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_id(K_ITEM *a, K_ITEM *b);
extern cmp_t cmp_payouts_wid(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_payouts(int32_t height, char *blockhash);
extern K_ITEM *first_payouts(int32_t height, K_TREE_CTX *ctx);
extern K_ITEM *find_last_payouts(); extern K_ITEM *find_last_payouts();
extern K_ITEM *find_payoutid(int64_t payoutid); extern K_ITEM *find_payoutid(int64_t payoutid);
extern K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx); extern K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx);
@ -2459,8 +2516,9 @@ extern K_ITEM *useratts_add(PGconn *conn, char *username, char *attname,
bool begun); bool begun);
extern bool useratts_item_expire(PGconn *conn, K_ITEM *ua_item, tv_t *cd); extern bool useratts_item_expire(PGconn *conn, K_ITEM *ua_item, tv_t *cd);
extern bool useratts_fill(PGconn *conn); extern bool useratts_fill(PGconn *conn);
extern K_ITEM *workers_add(PGconn *conn, int64_t userid, char *workername, extern K_ITEM *workers_add(PGconn *conn, bool lock, int64_t userid,
char *difficultydefault, char *idlenotificationenabled, char *workername, char *difficultydefault,
char *idlenotificationenabled,
char *idlenotificationtime, char *by, char *idlenotificationtime, char *by,
char *code, char *inet, tv_t *cd, K_TREE *trf_root); char *code, char *inet, tv_t *cd, K_TREE *trf_root);
extern bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, extern bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault,
@ -2504,19 +2562,24 @@ extern bool shareerrors_add(PGconn *conn, char *workinfoid, char *username,
extern bool sharesummaries_to_markersummaries(PGconn *conn, WORKMARKERS *workmarkers, extern bool sharesummaries_to_markersummaries(PGconn *conn, WORKMARKERS *workmarkers,
char *by, char *code, char *inet, char *by, char *code, char *inet,
tv_t *cd, K_TREE *trf_root); tv_t *cd, K_TREE *trf_root);
extern bool delete_markersummaries(PGconn *conn, WORKMARKERS *wm);
extern char *ooo_status(char *buf, size_t siz); extern char *ooo_status(char *buf, size_t siz);
#define sharesummary_update(_s_row, _e_row, _ss_item, _by, _code, _inet, _cd) \ #define sharesummary_update(_s_row, _e_row, _by, _code, _inet, _cd) \
_sharesummary_update(_s_row, _e_row, _ss_item, _by, _code, _inet, _cd, \ _sharesummary_update(_s_row, _e_row, _by, _code, _inet, _cd, \
WHERE_FFL_HERE) WHERE_FFL_HERE)
extern bool _sharesummary_update(SHARES *s_row, SHAREERRORS *e_row, K_ITEM *ss_item, extern bool _sharesummary_update(SHARES *s_row, SHAREERRORS *e_row, char *by,
char *by, char *code, char *inet, tv_t *cd, char *code, char *inet, tv_t *cd,
WHERE_FFL_ARGS); WHERE_FFL_ARGS);
#define sharesummary_age(_ss_item, _by, _code, _inet, _cd) \
_sharesummary_age(_ss_item, _by, _code, _inet, _cd, WHERE_FFL_HERE)
extern bool _sharesummary_age(K_ITEM *ss_item, char *by, char *code, char *inet,
tv_t *cd, WHERE_FFL_ARGS);
extern bool sharesummary_fill(PGconn *conn); extern bool sharesummary_fill(PGconn *conn);
extern bool blocks_stats(PGconn *conn, int32_t height, char *blockhash, extern bool blocks_stats(PGconn *conn, int32_t height, char *blockhash,
double diffacc, double diffinv, double shareacc, double diffacc, double diffinv, double shareacc,
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, int32_t height, char *blockhash,
char *confirmed, char *info, char *workinfoid, char *confirmed, char *info, char *workinfoid,
char *username, char *workername, char *clientid, char *username, char *workername, char *clientid,
char *enonce1, char *nonce2, char *nonce, char *reward, char *enonce1, char *nonce2, char *nonce, char *reward,
@ -2597,6 +2660,13 @@ extern bool check_db_version(PGconn *conn);
// *** ckdb_cmd.c // *** ckdb_cmd.c
// *** // ***
// TODO: limit access by having seperate sockets for each
#define ACCESS_POOL (1 << 0)
#define ACCESS_SYSTEM (1 << 1)
#define ACCESS_WEB (1 << 2)
#define ACCESS_PROXY (1 << 3)
#define ACCESS_CKDB (1 << 4)
struct CMDS { struct CMDS {
enum cmd_values cmd_val; enum cmd_values cmd_val;
char *cmd_str; char *cmd_str;
@ -2605,7 +2675,7 @@ struct CMDS {
char *(*func)(PGconn *, char *, char *, tv_t *, char *, char *, char *(*func)(PGconn *, char *, char *, tv_t *, char *, char *,
char *, tv_t *, K_TREE *); char *, tv_t *, K_TREE *);
enum seq_num seq; enum seq_num seq;
char *access; int access;
}; };
extern struct CMDS ckdb_cmds[]; extern struct CMDS ckdb_cmds[];

17
src/ckdb_btc.c

@ -308,7 +308,6 @@ bool btc_valid_address(char *addr)
void btc_blockstatus(BLOCKS *blocks) void btc_blockstatus(BLOCKS *blocks)
{ {
char hash[TXT_BIG+1]; char hash[TXT_BIG+1];
char height_str[32];
char *blockhash; char *blockhash;
int32_t confirms; int32_t confirms;
size_t len; size_t len;
@ -348,14 +347,12 @@ void btc_blockstatus(BLOCKS *blocks)
return; return;
if (strcmp(blockhash, hash) != 0) { if (strcmp(blockhash, hash) != 0) {
snprintf(height_str, sizeof(height_str), "%d", blocks->height); LOGERR("%s() flagging block %d as %s pool=%s btc=%s",
LOGERR("%s() flagging block %d(%s) as %s pool=%s btc=%s", __func__, blocks->height,
__func__,
blocks->height, height_str,
blocks_confirmed(BLOCKS_ORPHAN_STR), blocks_confirmed(BLOCKS_ORPHAN_STR),
hash, blockhash); hash, blockhash);
ok = blocks_add(NULL, height_str, ok = blocks_add(NULL, blocks->height,
blocks->blockhash, blocks->blockhash,
BLOCKS_ORPHAN_STR, EMPTY, BLOCKS_ORPHAN_STR, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
@ -371,14 +368,12 @@ void btc_blockstatus(BLOCKS *blocks)
confirms = btc_confirms(hash); confirms = btc_confirms(hash);
if (confirms >= BLOCKS_42_VALUE) { if (confirms >= BLOCKS_42_VALUE) {
snprintf(height_str, sizeof(height_str), "%d", blocks->height); LOGERR("%s() flagging block %d as %s confirms=%d(%d)",
LOGERR("%s() flagging block %d(%s) as %s confirms=%d(%d)", __func__, blocks->height,
__func__,
blocks->height, height_str,
blocks_confirmed(BLOCKS_42_STR), blocks_confirmed(BLOCKS_42_STR),
confirms, BLOCKS_42_VALUE); confirms, BLOCKS_42_VALUE);
ok = blocks_add(NULL, height_str, ok = blocks_add(NULL, blocks->height,
blocks->blockhash, blocks->blockhash,
BLOCKS_42_STR, EMPTY, BLOCKS_42_STR, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,

1021
src/ckdb_cmd.c

File diff suppressed because it is too large Load Diff

6
src/ckdb_crypt.c

@ -36,7 +36,7 @@ char *_tob32(USERS *users, unsigned char *bin, size_t len, char *name,
if (osiz != olen) { if (osiz != olen) {
LOGEMERG("%s() of '%s' data for '%s' invalid olen=%d != osiz=%d" LOGEMERG("%s() of '%s' data for '%s' invalid olen=%d != osiz=%d"
WHERE_FFL, WHERE_FFL,
__func__, name, safe_text_nonull(users->username), __func__, name, st = safe_text_nonull(users->username),
(int)olen, (int)osiz, WHERE_FFL_PASS); (int)olen, (int)osiz, WHERE_FFL_PASS);
FREENULL(st); FREENULL(st);
olen = osiz; olen = osiz;
@ -59,8 +59,8 @@ char *_tob32(USERS *users, unsigned char *bin, size_t len, char *name,
"ch=%d, i=%d j=%d bits=%d bin=0x%s len=%d " "ch=%d, i=%d j=%d bits=%d bin=0x%s len=%d "
"olen=%d" WHERE_FFL, "olen=%d" WHERE_FFL,
__func__, name, __func__, name,
safe_text_nonull(users->username), ch, i, j, st = safe_text_nonull(users->username),
bits, binstr, (int)len, (int)olen, ch, i, j, bits, binstr, (int)len, (int)olen,
WHERE_FFL_PASS); WHERE_FFL_PASS);
FREENULL(st); FREENULL(st);
FREENULL(binstr); FREENULL(binstr);

420
src/ckdb_data.c

File diff suppressed because it is too large Load Diff

1187
src/ckdb_dbio.c

File diff suppressed because it is too large Load Diff

12
src/ckpool.c

@ -1551,7 +1551,8 @@ static bool send_recv_path(const char *path, const char *msg)
ret = true; ret = true;
LOGWARNING("Received: %s in response to %s request", response, msg); LOGWARNING("Received: %s in response to %s request", response, msg);
dealloc(response); dealloc(response);
} } else
LOGWARNING("Received not response to %s request", msg);
Close(sockd); Close(sockd);
return ret; return ret;
} }
@ -1802,6 +1803,7 @@ int main(int argc, char **argv)
if (send_recv_path(path, "ping")) { if (send_recv_path(path, "ping")) {
for (i = 0; i < ckp.serverurls; i++) { for (i = 0; i < ckp.serverurls; i++) {
char oldurl[INET6_ADDRSTRLEN], oldport[8];
char getfd[16]; char getfd[16];
int sockd; int sockd;
@ -1813,11 +1815,17 @@ int main(int argc, char **argv)
break; break;
ckp.oldconnfd[i] = get_fd(sockd); ckp.oldconnfd[i] = get_fd(sockd);
Close(sockd); Close(sockd);
if (!ckp.oldconnfd[i]) sockd = ckp.oldconnfd[i];
if (!sockd)
break; break;
if (url_from_socket(sockd, oldurl, oldport)) {
LOGWARNING("Inherited old server socket %d url %s:%s !",
i, oldurl, oldport);
} else {
LOGWARNING("Inherited old server socket %d with new file descriptor %d!", LOGWARNING("Inherited old server socket %d with new file descriptor %d!",
i, ckp.oldconnfd[i]); i, ckp.oldconnfd[i]);
} }
}
send_recv_path(path, "reject"); send_recv_path(path, "reject");
send_recv_path(path, "reconnect"); send_recv_path(path, "reconnect");
send_recv_path(path, "shutdown"); send_recv_path(path, "shutdown");

19
src/connector.c

@ -64,6 +64,9 @@ struct client_instance {
/* Linked list of shares in redirector mode.*/ /* Linked list of shares in redirector mode.*/
share_t *shares; share_t *shares;
/* Time this client started blocking, 0 when not blocked */
time_t blocked_time;
}; };
struct sender_send { struct sender_send {
@ -635,6 +638,7 @@ out:
static bool send_sender_send(ckpool_t *ckp, cdata_t *cdata, sender_send_t *sender_send) static bool send_sender_send(ckpool_t *ckp, cdata_t *cdata, sender_send_t *sender_send)
{ {
client_instance_t *client = sender_send->client; client_instance_t *client = sender_send->client;
time_t now_t;
if (unlikely(client->invalid)) if (unlikely(client->invalid))
goto out_true; goto out_true;
@ -642,14 +646,26 @@ static bool send_sender_send(ckpool_t *ckp, cdata_t *cdata, sender_send_t *sende
/* Make sure we only send one message at a time to each client */ /* Make sure we only send one message at a time to each client */
if (unlikely(client->sending && client->sending != sender_send)) if (unlikely(client->sending && client->sending != sender_send))
return false; return false;
client->sending = sender_send; client->sending = sender_send;
now_t = time(NULL);
while (sender_send->len) { while (sender_send->len) {
int ret = write(client->fd, sender_send->buf + sender_send->ofs, sender_send->len); int ret = write(client->fd, sender_send->buf + sender_send->ofs, sender_send->len);
if (unlikely(ret < 1)) { if (unlikely(ret < 1)) {
if (errno == EAGAIN || errno == EWOULDBLOCK || !ret) /* Invalidate clients that block for more than 60 seconds */
if (unlikely(client->blocked_time && now_t - client->blocked_time >= 60)) {
LOGNOTICE("Client id %"PRId64" fd %d blocked for >60 seconds, disconnecting",
client->id, client->fd);
invalidate_client(ckp, cdata, client);
goto out_true;
}
if (errno == EAGAIN || errno == EWOULDBLOCK || !ret) {
if (!client->blocked_time)
client->blocked_time = now_t;
return false; return false;
}
LOGINFO("Client id %"PRId64" fd %d disconnected with write errno %d:%s", LOGINFO("Client id %"PRId64" fd %d disconnected with write errno %d:%s",
client->id, client->fd, errno, strerror(errno)); client->id, client->fd, errno, strerror(errno));
invalidate_client(ckp, cdata, client); invalidate_client(ckp, cdata, client);
@ -657,6 +673,7 @@ static bool send_sender_send(ckpool_t *ckp, cdata_t *cdata, sender_send_t *sende
} }
sender_send->ofs += ret; sender_send->ofs += ret;
sender_send->len -= ret; sender_send->len -= ret;
client->blocked_time = 0;
} }
out_true: out_true:
client->sending = NULL; client->sending = NULL;

453
src/ktree.c

@ -1,5 +1,5 @@
/* /*
* Copyright 1995-2014 Andrew Smith * Copyright 1995-2015 Andrew Smith
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free * under the terms of the GNU General Public License as published by the Free
@ -23,42 +23,56 @@ static const int dbg = 0;
#define Yo true #define Yo true
#define No false #define No false
static K_TREE nil[1] = { { Yo, RED_BLACK, NULL, NULL, NULL, NULL, 0 } }; static K_NODE nil[1] = { { Yo, RED_BLACK, NULL, NULL, NULL, NULL, 0 } };
K_TREE *_new_ktree(KTREE_FFL_ARGS) static K_NODE *_new_knode(KTREE_FFL_ARGS)
{ {
K_TREE *ktree = (K_TREE *)malloc(sizeof(*ktree)); K_NODE *node = (K_NODE *)malloc(sizeof(*node));
if (ktree == NULL) if (node == NULL)
FAIL("%s", "OOM"); FAIL("%s", "node OOM");
ktree->isNil = Yo; node->isNil = Yo;
ktree->red = RED_BLACK; node->red = RED_BLACK;
ktree->parent = nil; node->parent = nil;
ktree->left = nil; node->left = nil;
ktree->right = nil; node->right = nil;
ktree->data = NULL; node->data = NULL;
ktree->test = 0; node->test = 0;
return ktree; return node;
} }
static K_TREE *new_data(K_ITEM *data, KTREE_FFL_ARGS) K_TREE *_new_ktree(cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS)
{ {
K_TREE *ktree = (K_TREE *)malloc(sizeof(*ktree)); K_TREE *tree = (K_TREE *)malloc(sizeof(*tree));
if (tree == NULL)
FAIL("%s", "tree OOM");
tree->root = _new_knode(KTREE_FFL_PASS);
if (ktree == NULL) tree->cmp_funct = cmp_funct;
return tree;
}
static K_NODE *new_data(K_ITEM *data, KTREE_FFL_ARGS)
{
K_NODE *knode = (K_NODE *)malloc(sizeof(*knode));
if (knode == NULL)
FAIL("%s", "OOM"); FAIL("%s", "OOM");
ktree->isNil = No; knode->isNil = No;
ktree->red = RED_RED; knode->red = RED_RED;
ktree->parent = nil; knode->parent = nil;
ktree->left = nil; knode->left = nil;
ktree->right = nil; knode->right = nil;
ktree->data = data; knode->data = data;
ktree->test = 0; knode->test = 0;
return ktree; return knode;
} }
static int bCount = 0; static int bCount = 0;
@ -73,54 +87,54 @@ static long getTestValue()
return ++testValue; return ++testValue;
} }
static void show_ktree(K_TREE *root, char *path, int pos, char *(*dsp_funct)(K_ITEM *)) static void show_ktree(K_NODE *node, char *path, int pos, char *(*dsp_funct)(K_ITEM *))
{ {
char col; char col;
if (root->isNil == Yo) if (node->isNil == Yo)
return; return;
if (root->left->isNil == No) if (node->left->isNil == No)
{ {
path[pos] = 'L'; path[pos] = 'L';
path[pos+1] = '\0'; path[pos+1] = '\0';
show_ktree(root->left, path, pos+1, dsp_funct); show_ktree(node->left, path, pos+1, dsp_funct);
} }
path[pos] = '\0'; path[pos] = '\0';
if (root->red == RED_RED) if (node->red == RED_RED)
col = 'R'; col = 'R';
else else
// if (root->red == RED_BLACK) // if (node->red == RED_BLACK)
col = 'B'; col = 'B';
printf(" %c %s=%s\n", col, path, dsp_funct(root->data)); printf(" %c %s=%s\n", col, path, dsp_funct(node->data));
if (root->right->isNil == No) if (node->right->isNil == No)
{ {
path[pos] = 'R'; path[pos] = 'R';
path[pos+1] = '\0'; path[pos+1] = '\0';
show_ktree(root->right, path, pos+1, dsp_funct); show_ktree(node->right, path, pos+1, dsp_funct);
} }
} }
void _dump_ktree(K_TREE *root, char *(*dsp_funct)(K_ITEM *), KTREE_FFL_ARGS) void _dump_ktree(K_TREE *tree, char *(*dsp_funct)(K_ITEM *), KTREE_FFL_ARGS)
{ {
char buf[42424]; char buf[42424];
printf("dump:\n"); printf("dump:\n");
if (root->isNil == No) if (tree->root->isNil == No)
{ {
buf[0] = 'T'; buf[0] = 'T';
buf[1] = '\0'; buf[1] = '\0';
show_ktree(root, buf, 1, dsp_funct); show_ktree(tree->root, buf, 1, dsp_funct);
} }
else else
printf(" Empty ktree\n"); printf(" Empty tree\n");
} }
void _dsp_ktree(K_LIST *list, K_TREE *root, char *filename, char *msg, KTREE_FFL_ARGS) void _dsp_ktree(K_LIST *list, K_TREE *tree, char *filename, char *msg, KTREE_FFL_ARGS)
{ {
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
K_ITEM *item; K_ITEM *item;
@ -154,11 +168,11 @@ void _dsp_ktree(K_LIST *list, K_TREE *root, char *filename, char *msg, KTREE_FFL
if (msg) if (msg)
fprintf(stream, "%s %s\n", stamp, msg); fprintf(stream, "%s %s\n", stamp, msg);
else else
fprintf(stream, "%s Dump of ktree '%s':\n", stamp, list->name); fprintf(stream, "%s Dump of tree '%s':\n", stamp, list->name);
if (root->isNil == No) if (tree->root->isNil == No)
{ {
item = first_in_ktree(root, ctx); item = first_in_ktree(tree, ctx);
while (item) while (item)
{ {
list->dsp_func(item, stream); list->dsp_func(item, stream);
@ -172,7 +186,7 @@ void _dsp_ktree(K_LIST *list, K_TREE *root, char *filename, char *msg, KTREE_FFL
fclose(stream); fclose(stream);
} }
static int nilTest(K_TREE *node, char *msg, int depth, int count, K_TREE *nil2, KTREE_FFL_ARGS) static int nilTest(K_NODE *node, char *msg, int depth, int count, K_NODE *nil2, KTREE_FFL_ARGS)
{ {
if (node->isNil == Yo || node == nil2) if (node->isNil == Yo || node == nil2)
{ {
@ -231,7 +245,7 @@ static int nilTest(K_TREE *node, char *msg, int depth, int count, K_TREE *nil2,
return(count); return(count);
} }
static void bTest(K_TREE *root, K_TREE *cur, char *msg, int count, KTREE_FFL_ARGS) static void bTest(K_NODE *cur, char *msg, int count, KTREE_FFL_ARGS)
{ {
if (cur->red != RED_RED) if (cur->red != RED_RED)
count++; count++;
@ -259,108 +273,118 @@ static void bTest(K_TREE *root, K_TREE *cur, char *msg, int count, KTREE_FFL_ARG
else else
FAIL("BTESTVALUE '%s' count=%d", msg, count); FAIL("BTESTVALUE '%s' count=%d", msg, count);
bTest(root, cur->left, msg, count, KTREE_FFL_PASS); bTest(cur->left, msg, count, KTREE_FFL_PASS);
bTest(root, cur->right, msg, count, KTREE_FFL_PASS); bTest(cur->right, msg, count, KTREE_FFL_PASS);
} }
} }
static void bTestInit(K_TREE *root, char *msg, KTREE_FFL_ARGS) static void bTestInit(K_TREE *tree, char *msg, KTREE_FFL_ARGS)
{ {
bCount = 0; bCount = 0;
bTestValue = getTestValue(); bTestValue = getTestValue();
bTest(root, root, msg, 0, KTREE_FFL_PASS); bTest(tree->root, msg, 0, KTREE_FFL_PASS);
} }
static void lrpTest(K_TREE *top, char *msg, KTREE_FFL_ARGS) static void lrpTest(K_NODE *node, char *msg, KTREE_FFL_ARGS)
{ {
if (top->test != lrpTestValue) if (node->test != lrpTestValue)
top->test = lrpTestValue; node->test = lrpTestValue;
else else
FAIL("LRPTESTVALUE '%s'", msg); FAIL("LRPTESTVALUE '%s'", msg);
if (top->left->isNil == No) if (node->left->isNil == No)
{ {
if (top->left->parent != top) if (node->left->parent != node)
FAIL("LRPTESTL '%s'", msg); FAIL("LRPTESTL '%s'", msg);
lrpTest(top->left, msg, KTREE_FFL_PASS); lrpTest(node->left, msg, KTREE_FFL_PASS);
} }
if (top->right->isNil == No) if (node->right->isNil == No)
{ {
if (top->right->parent != top) if (node->right->parent != node)
FAIL("LRPTESTR '%s'", msg); FAIL("LRPTESTR '%s'", msg);
lrpTest(top->right, msg, KTREE_FFL_PASS); lrpTest(node->right, msg, KTREE_FFL_PASS);
} }
} }
static __maybe_unused void check_ktree(K_TREE *root, char *msg, K_TREE *nil2, int debugNil, int debugLRP, int debugColor, KTREE_FFL_ARGS) static __maybe_unused void check_ktree(K_TREE *tree, char *msg, K_NODE *nil2, int debugNil, int debugLRP, int debugColor, KTREE_FFL_ARGS)
{ {
if (root->isNil == Yo) if (tree->root->isNil == Yo)
return; return;
if (debugNil) if (debugNil)
{ {
nilTestValue = getTestValue(); nilTestValue = getTestValue();
nilTest(root, msg, 1, 0, nil2, KTREE_FFL_PASS); nilTest(tree->root, msg, 1, 0, nil2, KTREE_FFL_PASS);
} }
if (debugLRP && root->isNil == No) if (debugLRP && tree->root->isNil == No)
{ {
lrpTestValue = getTestValue(); lrpTestValue = getTestValue();
lrpTest(root, msg, KTREE_FFL_PASS); lrpTest(tree->root, msg, KTREE_FFL_PASS);
} }
if (debugColor && root->isNil == No) if (debugColor && tree->root->isNil == No)
bTestInit(root, msg, KTREE_FFL_PASS); bTestInit(tree, msg, KTREE_FFL_PASS);
} }
K_ITEM *_first_in_ktree(K_TREE *root, K_TREE_CTX *ctx, KTREE_FFL_ARGS) static K_ITEM *_first_in_knode(K_NODE *node, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
if (root->isNil == No) if (node->isNil == No)
{ {
while (root->left->isNil == No) while (node->left->isNil == No)
root = root->left; node = node->left;
*ctx = root; *ctx = node;
return(root->data); return(node->data);
} }
*ctx = NULL; *ctx = NULL;
return(NULL); return(NULL);
} }
K_ITEM *_last_in_ktree(K_TREE *root, K_TREE_CTX *ctx, KTREE_FFL_ARGS) K_ITEM *_first_in_ktree(K_TREE *tree, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
if (root->isNil == No) return _first_in_knode(tree->root, ctx, KTREE_FFL_PASS);
}
static K_ITEM *_last_in_knode(K_NODE *node, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
while (root->right->isNil == No) if (node->isNil == No)
root = root->right; {
while (node->right->isNil == No)
node = node->right;
*ctx = root; *ctx = node;
return(root->data); return(node->data);
} }
*ctx = NULL; *ctx = NULL;
return(NULL); return(NULL);
} }
K_ITEM *_last_in_ktree(K_TREE *tree, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{
return _last_in_knode(tree->root, ctx, KTREE_FFL_PASS);
}
K_ITEM *_next_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS) K_ITEM *_next_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
K_TREE *parent; K_NODE *parent;
K_TREE *ktree = (K_TREE *)(*ctx); K_NODE *knode = (K_NODE *)(*ctx);
if (ktree->isNil == No) if (knode->isNil == No)
{ {
if (ktree->right->isNil == No) if (knode->right->isNil == No)
return(first_in_ktree(ktree->right, ctx)); return(_first_in_knode(knode->right, ctx, KTREE_FFL_PASS));
else else
{ {
parent = ktree->parent; parent = knode->parent;
while (parent->isNil == No && ktree == parent->right) while (parent->isNil == No && knode == parent->right)
{ {
ktree = parent; knode = parent;
parent = parent->parent; parent = parent->parent;
} }
if (parent->isNil == No) if (parent->isNil == No)
@ -377,19 +401,19 @@ K_ITEM *_next_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS)
K_ITEM *_prev_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS) K_ITEM *_prev_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
K_TREE *parent; K_NODE *parent;
K_TREE *ktree = (K_TREE *)(*ctx); K_NODE *knode = (K_NODE *)(*ctx);
if (ktree->isNil == No) if (knode->isNil == No)
{ {
if (ktree->left->isNil == No) if (knode->left->isNil == No)
return(last_in_ktree(ktree->left, ctx)); return(_last_in_knode(knode->left, ctx, KTREE_FFL_PASS));
else else
{ {
parent = ktree->parent; parent = knode->parent;
while (parent->isNil == No && ktree == parent->left) while (parent->isNil == No && knode == parent->left)
{ {
ktree = parent; knode = parent;
parent = parent->parent; parent = parent->parent;
} }
if (parent->isNil == No) if (parent->isNil == No)
@ -404,9 +428,9 @@ K_ITEM *_prev_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS)
return(NULL); return(NULL);
} }
static K_TREE *left_rotate(K_TREE *root, K_TREE *about) static K_NODE *left_rotate(K_NODE *root, K_NODE *about)
{ {
K_TREE *rotate; K_NODE *rotate;
rotate = about->right; rotate = about->right;
about->right = rotate->left; about->right = rotate->left;
@ -432,9 +456,9 @@ static K_TREE *left_rotate(K_TREE *root, K_TREE *about)
return(root); return(root);
} }
static K_TREE *right_rotate(K_TREE *root, K_TREE *about) static K_NODE *right_rotate(K_NODE *root, K_NODE *about)
{ {
K_TREE *rotate; K_NODE *rotate;
rotate = about->left; rotate = about->left;
about->left = rotate->right; about->left = rotate->right;
@ -458,50 +482,50 @@ static K_TREE *right_rotate(K_TREE *root, K_TREE *about)
return(root); return(root);
} }
K_TREE *_add_to_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS) void _add_to_ktree(K_TREE *tree, K_ITEM *data, KTREE_FFL_ARGS)
{ {
K_TREE *ktree; K_NODE *knode;
K_TREE *x, *y; K_NODE *x, *y;
K_TREE *pp; K_NODE *pp;
cmp_t cmp; cmp_t cmp;
if (root == NULL) if (tree == NULL)
FAIL("%s", "ADDNULL add ktree is NULL"); FAIL("%s", "ADDNULL add tree is NULL");
//check_ktree(root, ">add", NULL, 1, 1, 1, KTREE_FFL_PASS); //check_ktree(tree, ">add", NULL, 1, 1, 1, KTREE_FFL_PASS);
if (root->parent != nil && root->parent != NULL) if (tree->root->parent != nil && tree->root->parent != NULL)
FAIL("%s", "ADDROOT add root isn't the root"); FAIL("%s", "ADDROOT add tree->root isn't the root");
ktree = new_data(data, KTREE_FFL_PASS); knode = new_data(data, KTREE_FFL_PASS);
if (root->isNil == Yo) if (tree->root->isNil == Yo)
{ {
if (root != nil) if (tree->root != nil)
free(root); free(tree->root);
root = ktree; tree->root = knode;
} }
else else
{ {
x = root; x = tree->root;
y = nil; y = nil;
while (x->isNil == No) while (x->isNil == No)
{ {
y = x; y = x;
if ((cmp = (*cmp_funct)(ktree->data, x->data)) < 0) if ((cmp = tree->cmp_funct(knode->data, x->data)) < 0)
x = x->left; x = x->left;
else else
x = x->right; x = x->right;
} }
ktree->parent = y; knode->parent = y;
if (cmp < 0) if (cmp < 0)
y->left = ktree; y->left = knode;
else else
y->right = ktree; y->right = knode;
x = ktree; x = knode;
while (x != root && x->parent->red == RED_RED) while (x != tree->root && x->parent->red == RED_RED)
{ {
pp = x->parent->parent; pp = x->parent->parent;
if (x->parent == pp->left) if (x->parent == pp->left)
@ -519,12 +543,12 @@ K_TREE *_add_to_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K
if (x == x->parent->right) if (x == x->parent->right)
{ {
x = x->parent; x = x->parent;
root = left_rotate(root, x); tree->root = left_rotate(tree->root, x);
pp = x->parent->parent; pp = x->parent->parent;
} }
x->parent->red = RED_BLACK; x->parent->red = RED_BLACK;
pp->red = RED_RED; pp->red = RED_RED;
root = right_rotate(root, pp); tree->root = right_rotate(tree->root, pp);
} }
} }
else else
@ -542,45 +566,49 @@ K_TREE *_add_to_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K
if (x == x->parent->left) if (x == x->parent->left)
{ {
x = x->parent; x = x->parent;
root = right_rotate(root, x); tree->root = right_rotate(tree->root, x);
pp = x->parent->parent; pp = x->parent->parent;
} }
x->parent->red = RED_BLACK; x->parent->red = RED_BLACK;
pp->red = RED_RED; pp->red = RED_RED;
root = left_rotate(root, pp); tree->root = left_rotate(tree->root, pp);
} }
} }
} }
} }
root->red = RED_BLACK; tree->root->red = RED_BLACK;
//check_ktree(root, "<add", NULL, 1, 1, 1, KTREE_FFL_PASS); //check_ktree(tree, "<add", NULL, 1, 1, 1, KTREE_FFL_PASS);
return(root);
} }
K_ITEM *_find_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) K_ITEM *_find_in_ktree(K_TREE *tree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
K_NODE *knode;
cmp_t cmp = -1; cmp_t cmp = -1;
if (ktree == NULL) if (tree == NULL)
FAIL("%s", "FINDNULL find ktree is NULL"); FAIL("%s", "FINDNULL find tree is NULL");
while (ktree->isNil == No && cmp != 0) if (tree->root == NULL)
FAIL("%s", "FINDNULL find tree->root is NULL");
knode = tree->root;
while (knode->isNil == No && cmp != 0)
{ {
if ((cmp = (*cmp_funct)(ktree->data, data))) if ((cmp = tree->cmp_funct(knode->data, data)))
{ {
if (cmp > 0) if (cmp > 0)
ktree = ktree->left; knode = knode->left;
else else
ktree = ktree->right; knode = knode->right;
} }
} }
if (ktree->isNil == No) if (knode->isNil == No)
{ {
*ctx = ktree; *ctx = knode;
return(ktree->data); return(knode->data);
} }
else else
{ {
@ -589,30 +617,35 @@ K_ITEM *_find_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *,
} }
} }
K_ITEM *_find_after_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) K_ITEM *_find_after_in_ktree(K_TREE *tree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
K_TREE *old = NULL; K_NODE *knode, *old = NULL;
cmp_t cmp = -1, oldcmp = -1; cmp_t cmp = -1, oldcmp = -1;
if (ktree == NULL) if (tree == NULL)
FAIL("%s", "FINDNULL find_after ktree is NULL"); FAIL("%s", "FINDNULL find_after tree is NULL");
if (tree->root == NULL)
FAIL("%s", "FINDNULL find_after tree->root is NULL");
knode = tree->root;
while (ktree->isNil == No && cmp != 0) while (knode->isNil == No && cmp != 0)
{ {
if ((cmp = (*cmp_funct)(ktree->data, data))) if ((cmp = tree->cmp_funct(knode->data, data)))
{ {
old = ktree; old = knode;
oldcmp = cmp; oldcmp = cmp;
if (cmp > 0) if (cmp > 0)
ktree = ktree->left; knode = knode->left;
else else
ktree = ktree->right; knode = knode->right;
} }
} }
if (ktree->isNil == No) if (knode->isNil == No)
{ {
*ctx = ktree; *ctx = knode;
return next_in_ktree(ctx); return next_in_ktree(ctx);
} }
else else
@ -634,30 +667,35 @@ K_ITEM *_find_after_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_I
} }
} }
K_ITEM *_find_before_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) K_ITEM *_find_before_in_ktree(K_TREE *tree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
K_TREE *old = NULL; K_NODE *knode, *old = NULL;
cmp_t cmp = 1, oldcmp = 1; cmp_t cmp = 1, oldcmp = 1;
if (ktree == NULL) if (tree == NULL)
FAIL("%s", "FINDNULL find_before ktree is NULL"); FAIL("%s", "FINDNULL find_before tree is NULL");
while (ktree->isNil == No && cmp != 0) if (tree->root == NULL)
FAIL("%s", "FINDNULL find_before tree->root is NULL");
knode = tree->root;
while (knode->isNil == No && cmp != 0)
{ {
if ((cmp = (*cmp_funct)(ktree->data, data))) if ((cmp = tree->cmp_funct(knode->data, data)))
{ {
old = ktree; old = knode;
oldcmp = cmp; oldcmp = cmp;
if (cmp > 0) if (cmp > 0)
ktree = ktree->left; knode = knode->left;
else else
ktree = ktree->right; knode = knode->right;
} }
} }
if (ktree->isNil == No) if (knode->isNil == No)
{ {
*ctx = ktree; *ctx = knode;
return prev_in_ktree(ctx); return prev_in_ktree(ctx);
} }
else else
@ -679,9 +717,9 @@ K_ITEM *_find_before_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_
} }
} }
static K_TREE *removeFixup(K_TREE *root, K_TREE *fix) static K_NODE *removeFixup(K_NODE *root, K_NODE *fix)
{ {
K_TREE *w = NULL; K_NODE *w = NULL;
while (fix != root && fix->red != RED_RED) while (fix != root && fix->red != RED_RED)
{ {
@ -758,37 +796,40 @@ static K_TREE *removeFixup(K_TREE *root, K_TREE *fix)
return root; return root;
} }
// Does this work OK when you remove the last element in the ktree? // Does this work OK when you remove the last element in the tree?
// It should return the root as 'nil' // It should return the root as 'nil'
K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS) void _remove_from_ktree(K_TREE *tree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS)
{ {
K_TREE_CTX tmpctx[1]; K_TREE_CTX tmpctx[1];
K_TREE *found; K_NODE *found;
K_ITEM *fdata; K_ITEM *fdata;
K_TREE *x, *y, *nil2; K_NODE *x, *y, *nil2;
// cmp_t cmp; // cmp_t cmp;
int yred; int yred;
//check_ktree(root, ">remove", NULL, 1, 1, 1, KTREE_FFL_PASS); //check_ktree(tree, ">remove", NULL, 1, 1, 1, KTREE_FFL_PASS);
if (root == NULL) if (tree == NULL)
FAIL("%s", "REMNULL remove ktree is NULL"); FAIL("%s", "REMNULL remove tree is NULL");
if (root->isNil == Yo) if (tree->root == NULL)
FAIL("%s", "REMNULL remove tree->root is NULL");
if (tree->root->isNil == Yo)
{ {
*ctx = NULL; *ctx = NULL;
return(root); return;
} }
if (root->parent->isNil == No) if (tree->root->parent->isNil == No)
FAIL("%s", "REMROOT remove root isn't the root"); FAIL("%s", "REMROOT remove tree->root isn't the root");
fdata = find_in_ktree(root, data, cmp_funct, ctx); fdata = find_in_ktree(tree, data, ctx);
if (fdata == NULL) if (fdata == NULL)
return(root); return;
if (cmp_funct(fdata, data) != 0) if (tree->cmp_funct(fdata, data) != 0)
FAIL("%s", "BADFIND cmp(found, remove) != 0"); FAIL("%s", "BADFIND cmp(found, remove) != 0");
found = *ctx; found = *ctx;
@ -819,14 +860,14 @@ K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM
nil2 = NULL; nil2 = NULL;
else else
{ {
nil2 = new_ktree(); nil2 = _new_knode(KTREE_FFL_PASS);
x = nil2; x = nil2;
} }
x->parent = y->parent; x->parent = y->parent;
if (x->parent->isNil == Yo) if (x->parent->isNil == Yo)
root = x; tree->root = x;
else else
{ {
if (x->parent->left == y) if (x->parent->left == y)
@ -837,8 +878,8 @@ K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM
if (y != found) if (y != found)
{ {
if (root == found) if (tree->root == found)
root = y; tree->root = y;
if (x == found) if (x == found)
x = y; x = y;
@ -864,7 +905,7 @@ K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM
} }
if (yred != RED_RED) if (yred != RED_RED)
root = removeFixup(root, x); tree->root = removeFixup(tree->root, x);
if (nil2 != NULL) if (nil2 != NULL)
{ {
@ -874,8 +915,8 @@ K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM
if (nil2->parent->isNil == No && nil2->parent->right == nil2) if (nil2->parent->isNil == No && nil2->parent->right == nil2)
nil2->parent->right = nil; nil2->parent->right = nil;
if (root == nil2) if (tree->root == nil2)
root = nil; tree->root = nil;
/* /*
if (dbg != 0) if (dbg != 0)
@ -889,24 +930,24 @@ DBG("@remove nil2->left wasn't nil!!!\n");
DBG("@remove nil2->right wasn't nil!!!\n"); DBG("@remove nil2->right wasn't nil!!!\n");
} }
cmp = 0; cmp = 0;
fdata = first_in_ktree(root, tmpctx);; fdata = first_in_ktree(tree, tmpctx);;
while (fdata != NULL) while (fdata != NULL)
{ {
cmp++; cmp++;
x = *tmpctx; x = *tmpctx;
if (x == nil2) if (x == nil2)
{ {
DBG("@remove found nil2 in ktree %f!!!\n", cmp); DBG("@remove found nil2 in ktree %d!!!\n", (int)cmp);
} }
else else
if (x->left == nil2) if (x->left == nil2)
{ {
DBG("@remove found nil2 in ktree(left) %f!!!\n", cmp); DBG("@remove found nil2 in ktree(left) %d!!!\n", (int)cmp);
} }
else else
if (x->right == nil2) if (x->right == nil2)
{ {
DBG("@remove found nil2 in ktree(right) %f!!!\n", cmp); DBG("@remove found nil2 in ktree(right) %d!!!\n", (int)cmp);
} }
fdata = next_in_ktree(tmpctx);; fdata = next_in_ktree(tmpctx);;
@ -920,10 +961,10 @@ DBG("@remove found nil2 in ktree(right) %f!!!\n", cmp);
if (dbg != 0) if (dbg != 0)
{ {
cmp = 0; cmp = 0;
fdata = first_in_ktree(root, tmpctx);; fdata = first_in_ktree(tree, tmpctx);;
while (fdata != NULL) while (fdata != NULL)
{ {
if (cmp_funct(fdata, root->data) < 0) if (tree->cmp_funct(fdata, tree->root->data) < 0)
cmp--; cmp--;
else else
cmp++; cmp++;
@ -932,52 +973,48 @@ if (dbg != 0)
} }
if (cmp < -10 || cmp > 10) if (cmp < -10 || cmp > 10)
{ {
DBG("@remove after balance=%f :(\n", cmp); DBG("@remove after balance=%d :(\n", (int)cmp);
} }
} }
*/ */
//check_ktree(root, "<remove", NULL, 1, 1, 1, KTREE_FFL_PASS); //check_ktree(tree, "<remove", NULL, 1, 1, 1, KTREE_FFL_PASS);
return root; return;
} }
K_TREE *_remove_from_ktree_free(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS) void _remove_from_ktree_free(K_TREE *root, K_ITEM *data, KTREE_FFL_ARGS)
{ {
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1];
root = _remove_from_ktree(root, data, cmp_funct, ctx, KTREE_FFL_PASS); _remove_from_ktree(root, data, ctx, KTREE_FFL_PASS);
if (*ctx) if (*ctx)
free(*ctx); free(*ctx);
return root;
} }
static void free_ktree_sub(K_TREE *ktree, void (*free_funct)(void *)) static void free_ktree_sub(K_NODE *knode, void (*free_funct)(void *))
{ {
if (ktree != NULL && ktree != nil) if (knode != NULL && knode != nil)
{ {
if (ktree->data != NULL && free_funct) if (knode->data != NULL && free_funct)
(*free_funct)(ktree->data); free_funct(knode->data);
free_ktree_sub(ktree->left, free_funct); free_ktree_sub(knode->left, free_funct);
free_ktree_sub(ktree->right, free_funct); free_ktree_sub(knode->right, free_funct);
free(ktree); free(knode);
} }
} }
K_TREE *_free_ktree(K_TREE *ktree, void (*free_funct)(void *), KTREE_FFL_ARGS) void _free_ktree(K_TREE *tree, void (*free_funct)(void *), KTREE_FFL_ARGS)
{ {
if (ktree == NULL) if (tree == NULL)
FAIL("%s", "FREENULL free NULL ktree"); FAIL("%s", "FREENULL free NULL tree");
if (ktree->parent != NULL && ktree->parent != nil)
FAIL("%s", "FREENOTROOT free ktree not root");
free_ktree_sub(ktree, free_funct); if (tree->root->parent != NULL && tree->root->parent != nil)
FAIL("%s", "FREENOTROOT free tree->root not root");
return(nil); free_ktree_sub(tree->root, free_funct);
} }

65
src/ktree.h

@ -1,5 +1,5 @@
/* /*
* Copyright 1995-2014 Andrew Smith * Copyright 1995-2015 Andrew Smith
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free * under the terms of the GNU General Public License as published by the Free
@ -34,45 +34,54 @@
#define CMP_BIGINT CMP_BIG #define CMP_BIGINT CMP_BIG
#define CMP_DOUBLE CMP_BIG #define CMP_DOUBLE CMP_BIG
typedef struct ktree typedef struct knode
{ {
bool isNil; bool isNil;
bool red; bool red;
struct ktree *parent; struct knode *parent;
struct ktree *left; struct knode *left;
struct ktree *right; struct knode *right;
K_ITEM *data; K_ITEM *data;
long test; long test;
} K_NODE;
typedef struct ktree
{
K_NODE *root;
cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *);
} K_TREE; } K_TREE;
typedef void *K_TREE_CTX; typedef void *K_TREE_CTX;
extern K_TREE *_new_ktree(KTREE_FFL_ARGS); extern K_TREE *_new_ktree(cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS);
#define new_ktree() _new_ktree(KLIST_FFL_HERE) #define new_ktree(_cmp_funct) _new_ktree(_cmp_funct, KLIST_FFL_HERE)
extern void _dump_ktree(K_TREE *root, char *(*dsp_funct)(K_ITEM *), KTREE_FFL_ARGS); extern void _dump_ktree(K_TREE *tree, char *(*dsp_funct)(K_ITEM *), KTREE_FFL_ARGS);
#define dump_ktree(_root, _dsp_funct) _dump_ktree(_root, _dsp_funct, KLIST_FFL_HERE) #define dump_ktree(_tree, _dsp_funct) _dump_ktree(_tree, _dsp_funct, KLIST_FFL_HERE)
extern void _dsp_ktree(K_LIST *list, K_TREE *root, char *filename, char *msg, KTREE_FFL_ARGS); extern void _dsp_ktree(K_LIST *list, K_TREE *tree, char *filename, char *msg, KTREE_FFL_ARGS);
#define dsp_ktree(_list, _root, _filename, _msg) _dsp_ktree(_list, _root, _filename, _msg, KLIST_FFL_HERE) #define dsp_ktree(_list, _tree, _filename, _msg) _dsp_ktree(_list, _tree, _filename, _msg, KLIST_FFL_HERE)
extern K_ITEM *_first_in_ktree(K_TREE *root, K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_first_in_ktree(K_TREE *tree, K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define first_in_ktree(_root, _ctx) _first_in_ktree(_root, _ctx, KLIST_FFL_HERE) #define first_in_ktree(_tree, _ctx) _first_in_ktree(_tree, _ctx, KLIST_FFL_HERE)
extern K_ITEM *_last_in_ktree(K_TREE *root, K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_last_in_ktree(K_TREE *tree, K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define last_in_ktree(_root, _ctx) _last_in_ktree(_root, _ctx, KLIST_FFL_HERE) #define last_in_ktree(_tree, _ctx) _last_in_ktree(_tree, _ctx, KLIST_FFL_HERE)
extern K_ITEM *_next_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_next_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define next_in_ktree(_ctx) _next_in_ktree(_ctx, KLIST_FFL_HERE) #define next_in_ktree(_ctx) _next_in_ktree(_ctx, KLIST_FFL_HERE)
extern K_ITEM *_prev_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_prev_in_ktree(K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define prev_in_ktree(_ctx) _prev_in_ktree(_ctx, KLIST_FFL_HERE) #define prev_in_ktree(_ctx) _prev_in_ktree(_ctx, KLIST_FFL_HERE)
extern K_TREE *_add_to_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_func)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS); extern void _add_to_ktree(K_TREE *tree, K_ITEM *data, KTREE_FFL_ARGS);
#define add_to_ktree(_root, _data, _cmp_func) _add_to_ktree(_root, _data, _cmp_func, KLIST_FFL_HERE) #define add_to_ktree(_tree, _data) _add_to_ktree(_tree, _data, KLIST_FFL_HERE)
extern K_ITEM *_find_in_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_find_in_ktree(K_TREE *tree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define find_in_ktree(_root, _data, _cmp_funct, _ctx) _find_in_ktree(_root, _data, _cmp_funct, _ctx, KLIST_FFL_HERE) #define find_in_ktree(_tree, _data, _ctx) _find_in_ktree(_tree, _data, _ctx, KLIST_FFL_HERE)
extern K_ITEM *_find_after_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_find_after_in_ktree(K_TREE *ktree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define find_after_in_ktree(_ktree, _data, _cmp_funct, _ctx) _find_after_in_ktree(_ktree, _data, _cmp_funct, _ctx, KLIST_FFL_HERE) #define find_after_in_ktree(_ktree, _data, _ctx) _find_after_in_ktree(_ktree, _data, _ctx, KLIST_FFL_HERE)
extern K_ITEM *_find_before_in_ktree(K_TREE *ktree, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern K_ITEM *_find_before_in_ktree(K_TREE *ktree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS);
#define find_before_in_ktree(_ktree, _data, _cmp_funct, _ctx) _find_before_in_ktree(_ktree, _data, _cmp_funct, _ctx, KLIST_FFL_HERE) #define find_before_in_ktree(_ktree, _data, _ctx) _find_before_in_ktree(_ktree, _data, _ctx, KLIST_FFL_HERE)
extern K_TREE *_remove_from_ktree(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx, KTREE_FFL_ARGS); extern void _remove_from_ktree(K_TREE *tree, K_ITEM *data, K_TREE_CTX *ctx, KTREE_FFL_ARGS);
extern K_TREE *_remove_from_ktree_free(K_TREE *root, K_ITEM *data, cmp_t (*cmp_funct)(K_ITEM *, K_ITEM *), KTREE_FFL_ARGS); extern void _remove_from_ktree_free(K_TREE *tree, K_ITEM *data, KTREE_FFL_ARGS);
#define remove_from_ktree(_root, _data, _cmp_funct) _remove_from_ktree_free(_root, _data, _cmp_funct, KLIST_FFL_HERE) #define remove_from_ktree(_tree, _data) _remove_from_ktree_free(_tree, _data, KLIST_FFL_HERE)
extern K_TREE *_free_ktree(K_TREE *root, void (*free_funct)(void *), KTREE_FFL_ARGS); extern void _free_ktree(K_TREE *tree, void (*free_funct)(void *), KTREE_FFL_ARGS);
#define free_ktree(_root, _free_funct) _free_ktree(_root, _free_funct, KLIST_FFL_HERE) #define free_ktree(_tree, _free_funct) do { \
_free_ktree(_tree, _free_funct, KLIST_FFL_HERE); \
_tree = NULL; \
} while (0)
#endif #endif

9
src/libckpool.c

@ -570,14 +570,15 @@ out:
* INET6_ADDRSTRLEN size, port at least a string of 6 bytes */ * INET6_ADDRSTRLEN size, port at least a string of 6 bytes */
bool url_from_socket(const int sockd, char *url, char *port) bool url_from_socket(const int sockd, char *url, char *port)
{ {
socklen_t addrlen = sizeof(struct sockaddr); struct sockaddr_storage storage;
struct sockaddr addr; socklen_t addrlen = sizeof(struct sockaddr_storage);
struct sockaddr *addr = (struct sockaddr *)&storage;
if (sockd < 1) if (sockd < 1)
return false; return false;
if (getsockname(sockd, &addr, &addrlen)) if (getsockname(sockd, addr, &addrlen))
return false; return false;
if (!url_from_sockaddr(&addr, url, port)) if (!url_from_sockaddr(addr, url, port))
return false; return false;
return true; return true;
} }

2
src/libckpool.h

@ -192,7 +192,7 @@ static inline void flip_80(void *dest_p, const void *src_p)
void logmsg(int loglevel, const char *fmt, ...); void logmsg(int loglevel, const char *fmt, ...);
#define DEFLOGBUFSIZ 1024 #define DEFLOGBUFSIZ 1000
#define LOGMSGBUF(__lvl, __buf) do { \ #define LOGMSGBUF(__lvl, __buf) do { \
logmsg(__lvl, "%s", __buf); \ logmsg(__lvl, "%s", __buf); \

198
src/stratifier.c

@ -29,6 +29,14 @@
#include "utlist.h" #include "utlist.h"
#include "api.h" #include "api.h"
#define MIN1 60
#define MIN5 300
#define MIN15 900
#define HOUR 3600
#define HOUR6 21600
#define DAY 86400
#define WEEK 604800
/* Consistent across all pool instances */ /* Consistent across all pool instances */
static const char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"; static const char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000";
static const char *scriptsig_header = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff"; static const char *scriptsig_header = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff";
@ -174,12 +182,14 @@ struct user_instance {
double best_diff; /* Best share found by this user */ double best_diff; /* Best share found by this user */
int64_t shares;
double dsps1; /* Diff shares per second, 1 minute rolling average */ double dsps1; /* Diff shares per second, 1 minute rolling average */
double dsps5; /* ... 5 minute ... */ double dsps5; /* ... 5 minute ... */
double dsps60;/* etc */ double dsps60;/* etc */
double dsps1440; double dsps1440;
double dsps10080; double dsps10080;
tv_t last_share; tv_t last_share;
tv_t last_decay;
tv_t last_update; tv_t last_update;
bool authorised; /* Has this username ever been authorised? */ bool authorised; /* Has this username ever been authorised? */
@ -197,11 +207,14 @@ struct worker_instance {
worker_instance_t *next; worker_instance_t *next;
worker_instance_t *prev; worker_instance_t *prev;
int64_t shares;
double dsps1; double dsps1;
double dsps5; double dsps5;
double dsps60; double dsps60;
double dsps1440; double dsps1440;
double dsps10080;
tv_t last_share; tv_t last_share;
tv_t last_decay;
tv_t last_update; tv_t last_update;
time_t start_time; time_t start_time;
@ -246,6 +259,7 @@ struct stratum_instance {
int ssdc; /* Shares since diff change */ int ssdc; /* Shares since diff change */
tv_t first_share; tv_t first_share;
tv_t last_share; tv_t last_share;
tv_t last_decay;
time_t first_invalid; /* Time of first invalid in run of non stale rejects */ time_t first_invalid; /* Time of first invalid in run of non stale rejects */
time_t start_time; time_t start_time;
@ -2242,12 +2256,12 @@ static void reset_bestshares(sdata_t *sdata)
static void block_solve(ckpool_t *ckp, const char *blockhash) static void block_solve(ckpool_t *ckp, const char *blockhash)
{ {
ckmsg_t *block, *tmp, *found = NULL; ckmsg_t *block, *tmp, *found = NULL;
char *msg, *workername = NULL;
sdata_t *sdata = ckp->data; sdata_t *sdata = ckp->data;
char cdfield[64]; char cdfield[64];
int height = 0; int height = 0;
ts_t ts_now; ts_t ts_now;
json_t *val; json_t *val;
char *msg;
update_base(ckp, GEN_PRIORITY); update_base(ckp, GEN_PRIORITY);
@ -2266,6 +2280,7 @@ static void block_solve(ckpool_t *ckp, const char *blockhash)
} }
if (!strcmp(solvehash, blockhash)) { if (!strcmp(solvehash, blockhash)) {
dealloc(solvehash); dealloc(solvehash);
json_get_string(&workername, val, "workername");
found = block; found = block;
DL_DELETE(sdata->block_solves, block); DL_DELETE(sdata->block_solves, block);
break; break;
@ -2287,11 +2302,16 @@ static void block_solve(ckpool_t *ckp, const char *blockhash)
ckdbq_add(ckp, ID_BLOCK, val); ckdbq_add(ckp, ID_BLOCK, val);
free(found); free(found);
ASPRINTF(&msg, "Block %d solved by %s!", height, ckp->name); if (unlikely(!workername))
workername = strdup("");
ASPRINTF(&msg, "Block %d solved by %s @ %s!", height, workername, ckp->name);
stratum_broadcast_message(sdata, msg); stratum_broadcast_message(sdata, msg);
free(msg); free(msg);
LOGWARNING("Solved and confirmed block %d", height); LOGWARNING("Solved and confirmed block %d by %s", height, workername);
free(workername);
reset_bestshares(sdata); reset_bestshares(sdata);
} }
@ -2994,7 +3014,7 @@ retry:
LOGDEBUG("%ds elapsed in strat_loop, updating gbt base", LOGDEBUG("%ds elapsed in strat_loop, updating gbt base",
ckp->update_interval); ckp->update_interval);
update_base(ckp, GEN_NORMAL); update_base(ckp, GEN_NORMAL);
} else { } else if (!ckp->passthrough) {
LOGDEBUG("%ds elapsed in strat_loop, pinging miners", LOGDEBUG("%ds elapsed in strat_loop, pinging miners",
ckp->update_interval); ckp->update_interval);
broadcast_ping(sdata); broadcast_ping(sdata);
@ -3498,6 +3518,52 @@ static double dsps_from_key(json_t *val, const char *key)
return ret; return ret;
} }
/* Sanity check to prevent clock adjustments backwards from screwing up stats */
static double sane_tdiff(tv_t *end, tv_t *start)
{
double tdiff = tvdiff(end, start);
if (unlikely(tdiff < 0.001))
tdiff = 0.001;
return tdiff;
}
static void decay_client(stratum_instance_t *client, double diff, tv_t *now_t)
{
double tdiff = sane_tdiff(now_t, &client->last_decay);
decay_time(&client->dsps1, diff, tdiff, MIN1);
decay_time(&client->dsps5, diff, tdiff, MIN5);
decay_time(&client->dsps60, diff, tdiff, HOUR);
decay_time(&client->dsps1440, diff, tdiff, DAY);
decay_time(&client->dsps10080, diff, tdiff, WEEK);
copy_tv(&client->last_decay, now_t);
}
static void decay_worker(worker_instance_t *worker, double diff, tv_t *now_t)
{
double tdiff = sane_tdiff(now_t, &worker->last_decay);
decay_time(&worker->dsps1, diff, tdiff, MIN1);
decay_time(&worker->dsps5, diff, tdiff, MIN5);
decay_time(&worker->dsps60, diff, tdiff, HOUR);
decay_time(&worker->dsps1440, diff, tdiff, DAY);
decay_time(&worker->dsps10080, diff, tdiff, WEEK);
copy_tv(&worker->last_decay, now_t);
}
static void decay_user(user_instance_t *user, double diff, tv_t *now_t)
{
double tdiff = sane_tdiff(now_t, &user->last_decay);
decay_time(&user->dsps1, diff, tdiff, MIN1);
decay_time(&user->dsps5, diff, tdiff, MIN5);
decay_time(&user->dsps60, diff, tdiff, HOUR);
decay_time(&user->dsps1440, diff, tdiff, DAY);
decay_time(&user->dsps10080, diff, tdiff, WEEK);
copy_tv(&user->last_decay, now_t);
}
/* Enter holding a reference count */ /* Enter holding a reference count */
static void read_userstats(ckpool_t *ckp, user_instance_t *user) static void read_userstats(ckpool_t *ckp, user_instance_t *user)
{ {
@ -3528,12 +3594,14 @@ static void read_userstats(ckpool_t *ckp, user_instance_t *user)
tv_time(&now); tv_time(&now);
copy_tv(&user->last_share, &now); copy_tv(&user->last_share, &now);
copy_tv(&user->last_decay, &now);
user->dsps1 = dsps_from_key(val, "hashrate1m"); user->dsps1 = dsps_from_key(val, "hashrate1m");
user->dsps5 = dsps_from_key(val, "hashrate5m"); user->dsps5 = dsps_from_key(val, "hashrate5m");
user->dsps60 = dsps_from_key(val, "hashrate1hr"); user->dsps60 = dsps_from_key(val, "hashrate1hr");
user->dsps1440 = dsps_from_key(val, "hashrate1d"); user->dsps1440 = dsps_from_key(val, "hashrate1d");
user->dsps10080 = dsps_from_key(val, "hashrate7d"); user->dsps10080 = dsps_from_key(val, "hashrate7d");
json_get_int64(&user->last_update.tv_sec, val, "lastupdate"); json_get_int64(&user->last_update.tv_sec, val, "lastupdate");
json_get_int64(&user->shares, val, "shares");
json_get_double(&user->best_diff, val, "bestshare"); json_get_double(&user->best_diff, val, "bestshare");
LOGINFO("Successfully read user %s stats %f %f %f %f %f %f", user->username, LOGINFO("Successfully read user %s stats %f %f %f %f %f %f", user->username,
user->dsps1, user->dsps5, user->dsps60, user->dsps1440, user->dsps1, user->dsps5, user->dsps60, user->dsps1440,
@ -3544,11 +3612,7 @@ static void read_userstats(ckpool_t *ckp, user_instance_t *user)
if (tvsec_diff > 60) { if (tvsec_diff > 60) {
LOGINFO("Old user stats indicate not logged for %d seconds, decaying stats", LOGINFO("Old user stats indicate not logged for %d seconds, decaying stats",
tvsec_diff); tvsec_diff);
decay_time(&user->dsps1, 0, tvsec_diff, 60); decay_user(user, 0, &now);
decay_time(&user->dsps5, 0, tvsec_diff, 300);
decay_time(&user->dsps60, 0, tvsec_diff, 3600);
decay_time(&user->dsps1440, 0, tvsec_diff, 86400);
decay_time(&user->dsps10080, 0, tvsec_diff, 604800);
} }
} }
@ -3582,12 +3646,15 @@ static void read_workerstats(ckpool_t *ckp, worker_instance_t *worker)
tv_time(&now); tv_time(&now);
copy_tv(&worker->last_share, &now); copy_tv(&worker->last_share, &now);
copy_tv(&worker->last_decay, &now);
worker->dsps1 = dsps_from_key(val, "hashrate1m"); worker->dsps1 = dsps_from_key(val, "hashrate1m");
worker->dsps5 = dsps_from_key(val, "hashrate5m"); worker->dsps5 = dsps_from_key(val, "hashrate5m");
worker->dsps60 = dsps_from_key(val, "hashrate1d"); worker->dsps60 = dsps_from_key(val, "hashrate1d");
worker->dsps1440 = dsps_from_key(val, "hashrate1d"); worker->dsps1440 = dsps_from_key(val, "hashrate1d");
worker->dsps10080 = dsps_from_key(val, "hashrate7d");
json_get_double(&worker->best_diff, val, "bestshare"); json_get_double(&worker->best_diff, val, "bestshare");
json_get_int64(&worker->last_update.tv_sec, val, "lastupdate"); json_get_int64(&worker->last_update.tv_sec, val, "lastupdate");
json_get_int64(&worker->shares, val, "shares");
LOGINFO("Successfully read worker %s stats %f %f %f %f %f", worker->workername, LOGINFO("Successfully read worker %s stats %f %f %f %f %f", worker->workername,
worker->dsps1, worker->dsps5, worker->dsps60, worker->dsps1440, worker->best_diff); worker->dsps1, worker->dsps5, worker->dsps60, worker->dsps1440, worker->best_diff);
json_decref(val); json_decref(val);
@ -3596,10 +3663,7 @@ static void read_workerstats(ckpool_t *ckp, worker_instance_t *worker)
if (tvsec_diff > 60) { if (tvsec_diff > 60) {
LOGINFO("Old worker stats indicate not logged for %d seconds, decaying stats", LOGINFO("Old worker stats indicate not logged for %d seconds, decaying stats",
tvsec_diff); tvsec_diff);
decay_time(&worker->dsps1, 0, tvsec_diff, 60); decay_worker(worker, 0, &now);
decay_time(&worker->dsps5, 0, tvsec_diff, 300);
decay_time(&worker->dsps60, 0, tvsec_diff, 3600);
decay_time(&worker->dsps1440, 0, tvsec_diff, 86400);
} }
} }
@ -4030,16 +4094,6 @@ static double time_bias(const double tdiff, const double period)
return 1.0 - 1.0 / exp(dexp); return 1.0 - 1.0 / exp(dexp);
} }
/* Sanity check to prevent clock adjustments backwards from screwing up stats */
static double sane_tdiff(tv_t *end, tv_t *start)
{
double tdiff = tvdiff(end, start);
if (unlikely(tdiff < 0.001))
tdiff = 0.001;
return tdiff;
}
/* Needs to be entered with client holding a ref count. */ /* Needs to be entered with client holding a ref count. */
static void add_submit(ckpool_t *ckp, stratum_instance_t *client, const int diff, const bool valid, static void add_submit(ckpool_t *ckp, stratum_instance_t *client, const int diff, const bool valid,
const bool submit) const bool submit)
@ -4060,7 +4114,10 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, const int diff
mutex_unlock(&ckp_sdata->stats_lock); mutex_unlock(&ckp_sdata->stats_lock);
/* Count only accepted and stale rejects in diff calculation. */ /* Count only accepted and stale rejects in diff calculation. */
if (!valid && !submit) if (valid) {
worker->shares += diff;
user->shares += diff;
} else if (!submit)
return; return;
tv_time(&now_t); tv_time(&now_t);
@ -4078,28 +4135,14 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, const int diff
copy_tv(&client->ldc, &now_t); copy_tv(&client->ldc, &now_t);
} }
tdiff = sane_tdiff(&now_t, &client->last_share); decay_client(client, diff, &now_t);
decay_time(&client->dsps1, diff, tdiff, 60);
decay_time(&client->dsps5, diff, tdiff, 300);
decay_time(&client->dsps60, diff, tdiff, 3600);
decay_time(&client->dsps1440, diff, tdiff, 86400);
decay_time(&client->dsps10080, diff, tdiff, 604800);
copy_tv(&client->last_share, &now_t); copy_tv(&client->last_share, &now_t);
tdiff = sane_tdiff(&now_t, &worker->last_share); decay_worker(worker, diff, &now_t);
decay_time(&worker->dsps1, diff, tdiff, 60);
decay_time(&worker->dsps5, diff, tdiff, 300);
decay_time(&worker->dsps60, diff, tdiff, 3600);
decay_time(&worker->dsps1440, diff, tdiff, 86400);
copy_tv(&worker->last_share, &now_t); copy_tv(&worker->last_share, &now_t);
worker->idle = false; worker->idle = false;
tdiff = sane_tdiff(&now_t, &user->last_share); decay_user(user, diff, &now_t);
decay_time(&user->dsps1, diff, tdiff, 60);
decay_time(&user->dsps5, diff, tdiff, 300);
decay_time(&user->dsps60, diff, tdiff, 3600);
decay_time(&user->dsps1440, diff, tdiff, 86400);
decay_time(&user->dsps10080, diff, tdiff, 604800);
copy_tv(&user->last_share, &now_t); copy_tv(&user->last_share, &now_t);
client->idle = false; client->idle = false;
@ -5513,11 +5556,7 @@ static void *statsupdate(void *arg)
/* Decay times per connected instance */ /* Decay times per connected instance */
if (per_tdiff > 60) { if (per_tdiff > 60) {
/* No shares for over a minute, decay to 0 */ /* No shares for over a minute, decay to 0 */
decay_time(&client->dsps1, 0, per_tdiff, 60); decay_client(client, 0, &now);
decay_time(&client->dsps5, 0, per_tdiff, 300);
decay_time(&client->dsps60, 0, per_tdiff, 3600);
decay_time(&client->dsps1440, 0, per_tdiff, 86400);
decay_time(&client->dsps10080, 0, per_tdiff, 604800);
idle_workers++; idle_workers++;
if (per_tdiff > 600) if (per_tdiff > 600)
client->idle = true; client->idle = true;
@ -5536,10 +5575,7 @@ static void *statsupdate(void *arg)
DL_FOREACH(user->worker_instances, worker) { DL_FOREACH(user->worker_instances, worker) {
per_tdiff = tvdiff(&now, &worker->last_share); per_tdiff = tvdiff(&now, &worker->last_share);
if (per_tdiff > 60) { if (per_tdiff > 60) {
decay_time(&worker->dsps1, 0, per_tdiff, 60); decay_worker(worker, 0, &now);
decay_time(&worker->dsps5, 0, per_tdiff, 300);
decay_time(&worker->dsps60, 0, per_tdiff, 3600);
decay_time(&worker->dsps1440, 0, per_tdiff, 86400);
worker->idle = true; worker->idle = true;
} }
ghs = worker->dsps1 * nonces; ghs = worker->dsps1 * nonces;
@ -5554,14 +5590,19 @@ static void *statsupdate(void *arg)
ghs = worker->dsps1440 * nonces; ghs = worker->dsps1440 * nonces;
suffix_string(ghs, suffix1440, 16, 0); suffix_string(ghs, suffix1440, 16, 0);
ghs = worker->dsps10080 * nonces;
suffix_string(ghs, suffix10080, 16, 0);
copy_tv(&worker->last_update, &now); copy_tv(&worker->last_update, &now);
JSON_CPACK(val, "{ss,ss,ss,ss,si,sf}", JSON_CPACK(val, "{ss,ss,ss,ss,ss,si,sI,sf}",
"hashrate1m", suffix1, "hashrate1m", suffix1,
"hashrate5m", suffix5, "hashrate5m", suffix5,
"hashrate1hr", suffix60, "hashrate1hr", suffix60,
"hashrate1d", suffix1440, "hashrate1d", suffix1440,
"hashrate7d", suffix10080,
"lastupdate", now.tv_sec, "lastupdate", now.tv_sec,
"shares", worker->shares,
"bestshare", worker->best_diff); "bestshare", worker->best_diff);
ASPRINTF(&fname, "%s/workers/%s", ckp->logdir, worker->workername); ASPRINTF(&fname, "%s/workers/%s", ckp->logdir, worker->workername);
@ -5573,11 +5614,7 @@ static void *statsupdate(void *arg)
/* Decay times per user */ /* Decay times per user */
per_tdiff = tvdiff(&now, &user->last_share); per_tdiff = tvdiff(&now, &user->last_share);
if (per_tdiff > 60) { if (per_tdiff > 60) {
decay_time(&user->dsps1, 0, per_tdiff, 60); decay_user(user, 0, &now);
decay_time(&user->dsps5, 0, per_tdiff, 300);
decay_time(&user->dsps60, 0, per_tdiff, 3600);
decay_time(&user->dsps1440, 0, per_tdiff, 86400);
decay_time(&user->dsps10080, 0, per_tdiff, 604800);
idle = true; idle = true;
} }
ghs = user->dsps1 * nonces; ghs = user->dsps1 * nonces;
@ -5597,7 +5634,7 @@ static void *statsupdate(void *arg)
copy_tv(&user->last_update, &now); copy_tv(&user->last_update, &now);
JSON_CPACK(val, "{ss,ss,ss,ss,ss,si,si,sf}", JSON_CPACK(val, "{ss,ss,ss,ss,ss,si,si,sI,sf}",
"hashrate1m", suffix1, "hashrate1m", suffix1,
"hashrate5m", suffix5, "hashrate5m", suffix5,
"hashrate1hr", suffix60, "hashrate1hr", suffix60,
@ -5605,6 +5642,7 @@ static void *statsupdate(void *arg)
"hashrate7d", suffix10080, "hashrate7d", suffix10080,
"lastupdate", now.tv_sec, "lastupdate", now.tv_sec,
"workers", user->workers, "workers", user->workers,
"shares", user->shares,
"bestshare", user->best_diff); "bestshare", user->best_diff);
ASPRINTF(&fname, "%s/users/%s", ckp->logdir, user->username); ASPRINTF(&fname, "%s/users/%s", ckp->logdir, user->username);
@ -5766,18 +5804,18 @@ static void *statsupdate(void *arg)
stats->accounted_diff_shares += stats->unaccounted_diff_shares; stats->accounted_diff_shares += stats->unaccounted_diff_shares;
stats->accounted_rejects += stats->unaccounted_rejects; stats->accounted_rejects += stats->unaccounted_rejects;
decay_time(&stats->sps1, stats->unaccounted_shares, 1.875, 60); decay_time(&stats->sps1, stats->unaccounted_shares, 1.875, MIN1);
decay_time(&stats->sps5, stats->unaccounted_shares, 1.875, 300); decay_time(&stats->sps5, stats->unaccounted_shares, 1.875, MIN5);
decay_time(&stats->sps15, stats->unaccounted_shares, 1.875, 900); decay_time(&stats->sps15, stats->unaccounted_shares, 1.875, MIN15);
decay_time(&stats->sps60, stats->unaccounted_shares, 1.875, 3600); decay_time(&stats->sps60, stats->unaccounted_shares, 1.875, HOUR);
decay_time(&stats->dsps1, stats->unaccounted_diff_shares, 1.875, 60); decay_time(&stats->dsps1, stats->unaccounted_diff_shares, 1.875, MIN1);
decay_time(&stats->dsps5, stats->unaccounted_diff_shares, 1.875, 300); decay_time(&stats->dsps5, stats->unaccounted_diff_shares, 1.875, MIN5);
decay_time(&stats->dsps15, stats->unaccounted_diff_shares, 1.875, 900); decay_time(&stats->dsps15, stats->unaccounted_diff_shares, 1.875, MIN15);
decay_time(&stats->dsps60, stats->unaccounted_diff_shares, 1.875, 3600); decay_time(&stats->dsps60, stats->unaccounted_diff_shares, 1.875, HOUR);
decay_time(&stats->dsps360, stats->unaccounted_diff_shares, 1.875, 21600); decay_time(&stats->dsps360, stats->unaccounted_diff_shares, 1.875, HOUR6);
decay_time(&stats->dsps1440, stats->unaccounted_diff_shares, 1.875, 86400); decay_time(&stats->dsps1440, stats->unaccounted_diff_shares, 1.875, DAY);
decay_time(&stats->dsps10080, stats->unaccounted_diff_shares, 1.875, 604800); decay_time(&stats->dsps10080, stats->unaccounted_diff_shares, 1.875, WEEK);
stats->unaccounted_shares = stats->unaccounted_shares =
stats->unaccounted_diff_shares = stats->unaccounted_diff_shares =
@ -5896,18 +5934,18 @@ static void read_poolstats(ckpool_t *ckp)
if (tvsec_diff > 60) { if (tvsec_diff > 60) {
LOGNOTICE("Old pool stats indicate pool down for %d seconds, decaying stats", LOGNOTICE("Old pool stats indicate pool down for %d seconds, decaying stats",
tvsec_diff); tvsec_diff);
decay_time(&stats->sps1, 0, tvsec_diff, 60); decay_time(&stats->sps1, 0, tvsec_diff, MIN1);
decay_time(&stats->sps5, 0, tvsec_diff, 300); decay_time(&stats->sps5, 0, tvsec_diff, MIN5);
decay_time(&stats->sps15, 0, tvsec_diff, 900); decay_time(&stats->sps15, 0, tvsec_diff, MIN15);
decay_time(&stats->sps60, 0, tvsec_diff, 3600); decay_time(&stats->sps60, 0, tvsec_diff, HOUR);
decay_time(&stats->dsps1, 0, tvsec_diff, 60); decay_time(&stats->dsps1, 0, tvsec_diff, MIN1);
decay_time(&stats->dsps5, 0, tvsec_diff, 300); decay_time(&stats->dsps5, 0, tvsec_diff, MIN5);
decay_time(&stats->dsps15, 0, tvsec_diff, 900); decay_time(&stats->dsps15, 0, tvsec_diff, MIN15);
decay_time(&stats->dsps60, 0, tvsec_diff, 3600); decay_time(&stats->dsps60, 0, tvsec_diff, HOUR);
decay_time(&stats->dsps360, 0, tvsec_diff, 21600); decay_time(&stats->dsps360, 0, tvsec_diff, HOUR6);
decay_time(&stats->dsps1440, 0, tvsec_diff, 86400); decay_time(&stats->dsps1440, 0, tvsec_diff, DAY);
decay_time(&stats->dsps10080, 0, tvsec_diff, 604800); decay_time(&stats->dsps10080, 0, tvsec_diff, WEEK);
} }
} }

Loading…
Cancel
Save