diff --git a/pool/email.php b/pool/email.php index 9dd57ced..db4f5540 100644 --- a/pool/email.php +++ b/pool/email.php @@ -172,6 +172,45 @@ function passChanged($to, $whoip, $emailinfo) return sendnoheader($to, "Password Change", $message, $emailinfo); } # +function twofaSetup($to, $whoip, $emailinfo) +{ + global $eol; + + if (!isset($emailinfo['KWebURL'])) + return false; + + $web = $emailinfo['KWebURL']; + + $ret = emailEnd('2fa change', $whoip, $emailinfo); + if ($ret === false) + return false; + + $message = "2FA is ready to be tested.$eol"; + $message = "It will be enabled once you test it.$eol$eol"; + $message .= $ret; + + return sendnoheader($to, "2FA is Ready to be Enabled", $message, $emailinfo); +} +# +function twofaEnabled($to, $whoip, $emailinfo) +{ + global $eol; + + if (!isset($emailinfo['KWebURL'])) + return false; + + $web = $emailinfo['KWebURL']; + + $ret = emailEnd('2fa change', $whoip, $emailinfo); + if ($ret === false) + return false; + + $message = "2FA is enabled on your account.$eol$eol"; + $message .= $ret; + + return sendnoheader($to, "2FA is Enabled", $message, $emailinfo); +} +# # getOpts required for email # If they aren't all setup in the DB then email functions will return false function emailOptList() diff --git a/pool/inc.php b/pool/inc.php index dea5baf0..75d91b97 100644 --- a/pool/inc.php +++ b/pool/inc.php @@ -29,7 +29,9 @@ function gfi(c){gle(c);gst(c)} function gbd(c){gbe(c,0,0);gln(c,1,0);gln(c,1,1);gln(c,0,1);gle(c);gfl(c);gst(c)} function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av,w,cols){gtso(c,xs,ys);gss(c,'black');glw(c,1.5);gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c);glw(c,0.2);var hi=c['ctx'].measureText('M').width, wi=c['ctx'].measureText('1').width;for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')}gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left');var m=Math.round(0.5+xn/20.0);for(var i=0;i=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;j0){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;ic['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['pxe']=Math.max(Math.round(c['xm']/250),1)} +function gc2(c){var div=document.getElementById('can0');while (div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['pxe']=Math.max(Math.round(c['xm']/250),1)} +function gc(c){c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.max(Math.round(c['wx']*0.9+0.5),400);c['ym']=Math.max(Math.round(c['wy']*0.8+0.5),400);if(c['ym']>c['xm']){c['ym']=c['xm']}gc2(c)} +function gcxy(c,xm,ym){c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.min(Math.round(c['wx']*0.95),xm);c['ym']=Math.min(Math.round(c['wy']*0.95),ym);gc2(c)} function opts(t,i){var e=document.getElementById(i);if(t.checked){e.style.visibility='visible'}else{e.style.visibility='hidden'}} function ghrs(c){c['hrs']=[1,2,3,4,6,8,12,24,48];c['hln']=[1,2,3,4,6]} function ghg(c,dx){var tl=dx/(gchx(c,1)/50)/3600;for(var j=c['hrs'].length-1;j>=0;j--){if(tl diff --git a/pool/page.php b/pool/page.php index 3b9780ad..6bae844f 100644 --- a/pool/page.php +++ b/pool/page.php @@ -51,25 +51,59 @@ function addCSS($css) $page_css .= $css; } # +global $added_gbase; +$added_gbase = false; function addGBase() { - $g = GBaseJS(); - addScript($g); + global $added_gbase; + if ($added_gbase == false) + { + $added_gbase = true; + $g = GBaseJS(); + addScript($g); + } } # +global $added_tips; +$added_tips = false; function addTips() { - $t = TipsJS(); - addScript($t); - - $tcss = TipsCSS(); - addCSS($tcss); + global $added_tips; + if ($added_tips == false) + { + $added_tips = true; + $t = TipsJS(); + addScript($t); + $tcss = TipsCSS(); + addCSS($tcss); + } } # +global $added_sort; +$added_sort = false; function addSort() { - $s = SortJS(); - addScript($s); + global $added_sort; + if ($added_sort == false) + { + $added_sort = true; + $s = SortJS(); + addScript($s); + } +} +# +global $added_qr; +$added_qr = false; +function addQR() +{ + global $added_qr; + if ($added_qr == false) + { + $added_qr = true; + addGBase(); + $q = QRJS(); + addScript($q); + } } # function makeURL($page) @@ -119,20 +153,10 @@ function trm_force($html) return dotrm($html, false); } # -function isCrap() -{ - if (isset($_SERVER['HTTP_USER_AGENT'])) - return strpos($_SERVER['HTTP_USER_AGENT'],'iP'); - else - return false; -} -# function pghead($css_marker, $script_marker, $name) { global $page_title; - $iCrap = isCrap(); - $head = "\n"; $head .= "$page_title$name"; @@ -144,7 +168,7 @@ function pghead($css_marker, $script_marker, $name) $head .= HeadJS(); $head .= "\n\n"; $head .= "\n"; $head .= ''; @@ -410,26 +434,23 @@ function pgtop($info, $dotop, $user, $douser) if ($who == false) { $top .= ''; break; @@ -39,6 +50,8 @@ function set_2fa($data, $user, $tfa, $ans, $err) $sfaurl = 'otpauth://'.$ans['2fa_auth'].'/'.$ans['2fa_issuer']. ':'.htmlspecialchars($who).'?secret='.$ans['2fa_key']. '&algorithm='.$ans['2fa_hash'].'&issuer='.$ans['2fa_issuer']; + $draw = true; + addQR(); } else { @@ -46,11 +59,25 @@ function set_2fa($data, $user, $tfa, $ans, $err) $sfainfo = 'unavailable'; $sfaurl = 'unavailable'; } - $pg .= "Your 2FA Secret Key is: $key
"; + $pg .= "Your 2FA Secret Key is: $key
"; $pg .= "2FA Settings are $sfainfo

"; - $pg .= "2FA URL is Click

"; - $pg .= '2FA Value: '; - $pg .= ''; + $pg .= "To setup 2FA in your App: Click here
"; + $pg .= "or scan the qrcode/barcode below with your App:

"; + $pg .= '
'; + $pg .= 'A qrcode will show here if your browser supports html5/canvas'; + $pg .= "

"; + $pg .= 'Then enter your App 2FA Value: '; + $pg .= ''; + $pg .= ''; break; case 'ok': @@ -60,16 +87,61 @@ function set_2fa($data, $user, $tfa, $ans, $err) $pg .= 'Current 2FA Value: '; $pg .= '*

'; $pg .= '*WARNING: replacing the Secret Key will disable 2FA
'; - $pg .= 'until you successfully test the new key.

'; + $pg .= 'until you successfully test the new key,
'; + $pg .= 'thus getting a new key is effectively the same as disabling 2FA.

'; $pg .= ''; break; } - $pg .= '
'; - $top .= ' 12) + if (strlen($who) > 12) { - $who = substr($who, 0, 11); + $who = substr($who, 0, 12); $extra = '…'; } - $top .= " -".htmlspecialchars($who)."$extra 
-Hash Rate: -$uhr$u1hr
"; - $top .= makeForm('')." - -"; + $top .= "".htmlspecialchars($who)."$extra "; + $top .= makeForm(''); + $top .= ""; + $top .= "
Hash Rate:"; + $top .= "$uhr$u1hr
"; } $top .= ''; @@ -445,8 +466,6 @@ function pgtop($info, $dotop, $user, $douser) # function pgmenu($menus) { - $iCrap = isCrap(); - $ret = "\n"; $ret .= '
'; $ret .= ''; @@ -462,35 +481,27 @@ function pgmenu($menus) $side = 'r'; continue; } - if ($iCrap) + $ret .= "'; } $ret .= "
\n"; return $ret; diff --git a/pool/page_2fa.php b/pool/page_2fa.php index 0e1a8c2f..4ec7330a 100644 --- a/pool/page_2fa.php +++ b/pool/page_2fa.php @@ -1,7 +1,20 @@ "; + $app .= "Android: Google Play 'FreeOTP Authenticator' by Red Hat
"; + $app .= "Apple: App Store 'OTP Auth' by Roland Moers


"; + return $app; +} +# function set_2fa($data, $user, $tfa, $ans, $err) { + $draw = false; + $pg = '

Two Factor Authentication Settings

'; if ($err !== null and $err != '') @@ -17,12 +30,10 @@ function set_2fa($data, $user, $tfa, $ans, $err) { case '': $pg .= '
'; - $pg .= "You don't have 2FA setup yet

"; + $pg .= "You don't have Two Factor Authentication (2FA) setup yet

"; $pg .= 'To use 2FA you need an App on your phone/tablet
'; - $pg .= 'The free and recommended ones that have been tested here are:

'; - $pg .= "Android: Google Play 'FreeOTP Authenticator' by Red Hat
"; - $pg .= "Apple: App Store 'OTP Auth' by Roland Moers

"; - $pg .= 'Click here to start setting up 2FA: '; + $pg .= app_txt('ones'); + $pg .= 'Click here to begin the setup process for 2FA: '; $pg .= ''; $pg .= '
'; + $pg .= app_txt('2FA apps'); + $pg .= 'N.B. if you wish to setup 2FA on more than one device,
'; + $pg .= 'you should setup all devices before testing one of them.
'; + $pg .= 'If you have an old 2FA Secret Key in your device for this web site,
'; + $pg .= 'delete it before scanning in the new 2FA Secret Key.

'; + $pg .= 'WARNING: if you lose your 2FA device you will need to know
'; + $pg .= 'the 2FA Secret Key to manually setup a new device,
'; + $pg .= 'so your should copy it and store it somewhere securely.
'; + $pg .= 'For security reasons, the site will not show you an active 2FA Secret Key.
'; $pg .= '
'; - $pg .= ''; + + $pg .= ''; + $pg .= '2FA means that you need 2 codes to login to your account.
'; + $pg .= 'You will also need the 2FA code to modify any important settings in your account.
'; + $pg .= 'The 1st code is your current password.
'; + $pg .= 'The 2nd code is a number that your 2FA device will generate each time.
'; + $pg .= 'Your 2FA device would be, for example, your phone or tablet.

'; + $pg .= 'Each time you need a 2FA code, you use your device to generate a number
'; + $pg .= 'that you type into the "*2nd Authentication:" field on any page that has it.

'; + $pg .= 'IMPORTANT: the TOTP algorithm uses the time on your device,
'; + $pg .= "so it is important that your device's clock is accurate within a few seconds.

"; + $pg .= 'IMPORTANT: you enter the value from your App at the time you submit data.
'; + $pg .= "The value is valid only once for a maximum of 30 seconds.
"; + $pg .= "In both the Apps it has a 'dial' that shows the 30 seconds running out.
"; + $pg .= "If you are close to running out, you can wait for the 30 seconds to run out
"; + $pg .= "and then enter the new value it will come up with.
"; + $pg .= "The pool checks your value using the time at the pool when you submit the data,
"; + $pg .= "it doesn't matter when you loaded the web page,
"; + $pg .= "it only matters when you clicked on the web page button to send the data to the pool.

"; + $pg .= 'WARNING: once you have successfully tested and enabled 2FA,
'; + $pg .= 'you will be unable to access or even reset your account without 2FA.
'; + $pg .= 'There is no option to recover your 2FA from the web site,
'; + $pg .= 'and you must know your 2FA code in order to be able to disable 2FA.

'; + $pg .= 'WARNING: it is important to not store your login password in your 2FA device.
'; + $pg .= 'These 2 together will give full access to your account.'; + $pg .= ''; + $pg .= ''; + if ($draw !== false) + { + $qr = shell_exec("../pool/myqr.sh '$sfaurl'"); + if ($qr !== null and strlen($qr) > 30) + { + $pg .= "\n"; + + if (strpos($qr, 'var tw=1,fa=0,qrx=') === false) + error_log("QR error for '$user' res='$qr'"); + } + else + { + if ($qr === null) + $qr = 'null'; + error_log("QR failed for '$user' res='$qr'"); + } + } + return $pg; } # @@ -77,23 +149,30 @@ function do2fa($data, $user) { $err = ''; $setup = getparam('Setup', false); + $testemail = false; if ($setup === 'Setup') { // rand() included as part of the entropy $ans = get2fa($user, 'setup', rand(1073741824,2147483647), 0); + $testemail = true; } else { $value = getparam('Value', false); - $test = getparam('Test', false); if ($test === 'Test' and $value !== null) + { $ans = get2fa($user, 'test', 0, $value); + $testemail = true; + } else { $nw = getparam('New', false); if ($nw === 'New' and $value !== null) + { $ans = get2fa($user, 'new', rand(1073741824,2147483647), $value); + $testemail = true; + } else $ans = get2fa($user, '', 0, 0); } @@ -104,6 +183,31 @@ function do2fa($data, $user) { if (isset($ans['2fa_error'])) $err = $ans['2fa_error']; + + if ($testemail and $err == '') + { + $ans2 = userSettings($user); + if ($ans2['STATUS'] != 'ok') + dbdown(); // Should be no other reason? + if (!isset($ans2['email'])) + $err = 'An error occurred, check your details below'; + else + { + $email = $ans2['email']; + $emailinfo = getOpts($user, emailOptList()); + if ($emailinfo['STATUS'] != 'ok') + $err = 'An error occurred, check your details below'; + else + { + if ($setup === 'Setup') + twofaSetup($email, zeip(), $emailinfo); + else if ($test === 'Test') + twofaEnabled($email, zeip(), $emailinfo); + else if ($nw === 'New') + twofaSetup($email, zeip(), $emailinfo); + } + } + } } if (!isset($ans['2fa_status'])) $tfa = null; diff --git a/pool/page_blocks.php b/pool/page_blocks.php index 706e3a78..68d04704 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -1,5 +1,36 @@ 255) + $grn = 255; + + if ($grn > 190) + $fg = 'blue'; + else + $fg = 'white'; + $bg = sprintf("#00%02x00", $grn); + } + else # ($erl > 0.5) + { + $red = (-0.3 - log10(1.0 - $erl)) * 255; + if ($red < 0) + $red = 0; + if ($red > 255) + $red = 255; + + $fg = 'white'; + $bg = sprintf("#%02x0000", $red); + } + + return array($fg, $bg); +} +# function pctcolour($pct) { if ($pct == 100) @@ -79,14 +110,19 @@ function doblocks($data, $user) $desc = $ans['s_desc:'.$i]; $diff = number_format(100 * $ans['s_diffratio:'.$i], 2); $mean = number_format(100 * $ans['s_diffmean:'.$i], 2); - $cdferl = number_format($ans['s_cdferl:'.$i], 4); + + $cdferl = $ans['s_cdferl:'.$i]; + list($fg, $bg) = erlcolour($cdferl); + $cdferldsp = "".number_format($cdferl, 4).''; + $bg = " bgcolor=$bg"; + $luck = number_format(100 * $ans['s_luck:'.$i], 2); $pg .= ""; $pg .= "$desc Blocks"; $pg .= "$diff%"; $pg .= "$mean%"; - $pg .= "$cdferl"; + $pg .= "$cdferldsp"; $pg .= "$luck%"; $pg .= "\n"; } @@ -137,11 +173,13 @@ function doblocks($data, $user) $pg .= "Diff"; $pg .= "Diff%"; $pg .= "CDF"; + $pg .= "B"; $pg .= "\n"; } $blktot = 0; $nettot = 0; $i = 0; + $cnt = 0; $orph = false; $csv = "Sequence,Height,Status,Timestamp,DiffAcc,NetDiff,Hash\n"; if ($ans['STATUS'] == 'ok') @@ -158,28 +196,55 @@ function doblocks($data, $user) $hifld = "$blink$hi>$hi"; $ex = ''; + $conf = $ans['confirmed:'.$i]; $stat = $ans['status:'.$i]; - if ($stat == 'Orphan') + $inf = $ans['info:'.$i]; + $tt = ''; + if ($conf == 'O' or $conf == 'R') { $ex = 's'; $orph = true; $seq = ''; + $nn = $cnt; + if ($conf == 'R') + { + addTips(); + $in = explode(':', $inf, 2); + if (trim($in[0]) != '') + $stat = trim($in[0]); + if (count($in) < 2 or trim($in[1]) == '') + { + $tip = 'Share diff was VERY close
'; + $tip .= 'so we tested it,
'; + $tip .= "but it wasn't worthy
"; + } + else + $tip = str_replace('+', '
', trim($in[1])); + + $tt = ""; + $tt .= '?'; + $tt .= ""; + $tt .= "$tip"; + } } else + { $seq = $ans['seq:'.$i]; - if ($stat == '1-Confirm') + $nn = ++$cnt; + } + if ($conf == '1') { if (isset($data['info']['lastheight'])) { - $conf = 1 + $data['info']['lastheight'] - $hi; - $stat = '+'.$conf.' Confirms'; + $confn = 1 + $data['info']['lastheight'] - $hi; + $stat = '+'.$confn.' Confirms'; } else $stat = 'Conf'; } $stara = ''; - if ($stat == 'Orphan') + if ($conf == 'O' or $conf == 'R') $stara = '*'; if (isset($ans['statsconf:'.$i])) @@ -207,7 +272,7 @@ function doblocks($data, $user) $bpct = "$approx".number_format($pct, 3).'%'; $bg = " bgcolor=$bg"; $blktot += $diffacc; - if ($stat != 'Orphan') + if ($conf != 'O' and $conf != 'R') $nettot += $netdiff; $cdfdsp = number_format($cdf, 3); @@ -228,10 +293,11 @@ function doblocks($data, $user) $pg .= "".htmlspecialchars($ans['workername:'.$i]).''; $pg .= "".btcfmt($ans['reward:'.$i]).''; $pg .= "".utcd($ans['firstcreatedate:'.$i]).''; - $pg .= "$stat"; + $pg .= "$tt$stat"; $pg .= "$stara$approx$acc"; $pg .= "$bpct"; $pg .= "$cdfdsp"; + $pg .= "$nn"; $pg .= "\n"; } else @@ -259,7 +325,7 @@ function doblocks($data, $user) else $pg .= '8'; $pg .= ' class=dc>*'; - $pg .= "Orphans count as shares but not as a block in calculations"; + $pg .= 'Orphans/Rejects count as shares but not as a block in calculations'; $pg .= ''; } $pg .= "\n"; diff --git a/pool/page_payments.php b/pool/page_payments.php index bdf66522..b9e1dbc1 100644 --- a/pool/page_payments.php +++ b/pool/page_payments.php @@ -7,14 +7,17 @@ function sortheight($a, $b) # function dopayments($data, $user) { - $bc = 'https://blockchain.info/address/'; + $btc = 'https://www.blocktrail.com/BTC/address/'; + $btcn = 'blocktrail'; $addr1 = '1KzFJddTvK9TQWsmWFKYJ9fRx9QeSATyrT'; $addr2 = '16dRhawxuR3BmdmkzdzUdgEfGAQszgmtbc'; + $addr3 = '1N6LrEDiHuFwSyJYj2GedZM2FGk7kkLjn'; $pg = '

Payments

'; - $pg .= 'The payment transactions on blockchain are here:'; - $pg .= " BTCa and"; - $pg .= " BTCb
"; + $pg .= "The payment transactions on $btcn are here:"; + $pg .= " BTCa,"; + $pg .= " BTCb and"; + $pg .= " BTCc
"; $pg .= "The payments below don't yet show when they have been sent.

"; $ans = getPayments($user); diff --git a/pool/page_reg.php b/pool/page_reg.php index c803be2d..66af608d 100644 --- a/pool/page_reg.php +++ b/pool/page_reg.php @@ -15,7 +15,14 @@ function doregres($data, $u) else $mail = ''; - $pg = '

Choose one:

'; + $pg = makeForm('')."
+ + + + +
User: Pass: 
"; + + $pg .= '

or choose one:

'; $pg .= '
'; diff --git a/pool/page_settings.php b/pool/page_settings.php index 886cc3ed..21ad6915 100644 --- a/pool/page_settings.php +++ b/pool/page_settings.php @@ -218,7 +218,7 @@ function dosettings($data, $user) $old = $_SESSION['old_set_email']; else $old = null; -# emailAddressChanged($email, zeip(), $emailinfo, $old); + emailAddressChanged($email, zeip(), $emailinfo, $old); break; case 'Address': payoutAddressChanged($email, zeip(), $emailinfo); diff --git a/sql/ckdb.sql b/sql/ckdb.sql index deed4f5a..f7d9775b 100644 --- a/sql/ckdb.sql +++ b/sql/ckdb.sql @@ -336,6 +336,7 @@ CREATE TABLE blocks ( nonce character varying(64) NOT NULL, reward bigint NOT NULL, -- satoshis confirmed char DEFAULT '' NOT NULL, + info character varying(64) DEFAULT ''::character varying NOT NULL, diffacc float DEFAULT 0 NOT NULL, diffinv float DEFAULT 0 NOT NULL, shareacc float DEFAULT 0 NOT NULL, @@ -463,4 +464,4 @@ CREATE TABLE version ( PRIMARY KEY (vlock) ); -insert into version (vlock,version) values (1,'1.0.1'); +insert into version (vlock,version) values (1,'1.0.2'); diff --git a/sql/v1.0.1-v1.0.2.sql b/sql/v1.0.1-v1.0.2.sql new file mode 100644 index 00000000..9719fce2 --- /dev/null +++ b/sql/v1.0.1-v1.0.2.sql @@ -0,0 +1,25 @@ +SET SESSION AUTHORIZATION 'postgres'; + +BEGIN transaction; + +DO $$ +DECLARE ver TEXT; +BEGIN + + UPDATE version set version='1.0.2' where vlock=1 and version='1.0.1'; + + IF found THEN + RETURN; + END IF; + + SELECT version into ver from version + WHERE vlock=1; + + RAISE EXCEPTION 'Wrong DB version - expect "1.0.1" - found "%"', ver; + +END $$; + +ALTER TABLE ONLY blocks + ADD COLUMN info character varying(64) DEFAULT ''::character varying NOT NULL; + +END transaction; diff --git a/src/ckdb.c b/src/ckdb.c index 041e3cc6..263b4b70 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -165,6 +165,8 @@ const char *hashpatt = "^[A-Fa-f0-9]*$"; * and with a simple test must be ADDR_MIN_LEN to ADDR_MAX_LEN (ckdb.h) * bitcoind is used to fully validate them when required */ const char *addrpatt = "^[13][A-HJ-NP-Za-km-z1-9]*$"; +// Strings in socket transfer: space to '~' excluding '=' +const char *strpatt = "^[ -<>-~]*$"; // So the records below have the same 'name' as the klist const char Transfer[] = "Transfer"; @@ -423,6 +425,7 @@ const char *blocks_new = "New"; const char *blocks_confirm = "1-Confirm"; const char *blocks_42 = "Matured"; const char *blocks_orphan = "Orphan"; +const char *blocks_reject = "Unworthy"; const char *blocks_unknown = "?Unknown?"; K_TREE *blocks_root; @@ -1320,7 +1323,9 @@ static void dealloc_storage() FREE_ALL(auths); FREE_TREE(payouts_id); - FREE_ALL(payouts); + FREE_TREE(payouts); + FREE_STORE_DATA(payouts); + FREE_LIST_DATA(payouts); FREE_ALL(miningpayouts); FREE_ALL(blocks); @@ -1400,7 +1405,9 @@ static void dealloc_storage() FREE_ALL(useratts); FREE_TREE(userid); - FREE_ALL(users); + FREE_TREE(users); + FREE_STORE_DATA(users); + FREE_LIST_DATA(users); LOGWARNING("%s() transfer/heartbeatqueue/workqueue ...", __func__); @@ -4676,7 +4683,7 @@ static void *listener(void *arg) LOGEMERG("ABORTING"); everyone_die = true; } - return NULL; + goto sayonara; } if (!everyone_die) { @@ -4785,6 +4792,8 @@ static void *listener(void *arg) } } +sayonara: + listener_using_data = false; if (conn) diff --git a/src/ckdb.h b/src/ckdb.h index 76a45dd6..a1f713bc 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -54,8 +54,8 @@ */ #define DB_VLOCK "1" -#define DB_VERSION "1.0.1" -#define CKDB_VERSION DB_VERSION"-1.200" +#define DB_VERSION "1.0.2" +#define CKDB_VERSION DB_VERSION"-1.222" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -67,13 +67,6 @@ #define STRINT(x) STRINT2(x) #define STRINT2(x) #x -#define FREENULL(mem) do { \ - if (mem) { \ - free(mem); \ - mem = NULL; \ - } \ - } while (0) - // So they can fit into a 1 byte flag field #define TRUE_STR "Y" #define FALSE_STR "N" @@ -105,6 +98,13 @@ extern int switch_state; #define BLANK " " extern char *EMPTY; +#define FREENULL(mem) do { \ + if ((mem) && (void *)(mem) != (void *)EMPTY) { \ + free(mem); \ + mem = NULL; \ + } \ + } while (0) + // To ensure there's space for the ticker #define TICK_PREFIX " " @@ -115,6 +115,7 @@ extern const char *idpatt; extern const char *intpatt; extern const char *hashpatt; extern const char *addrpatt; +extern const char *strpatt; /* If a trimmed username is like an address but this many or more characters, * disallow it */ @@ -450,17 +451,21 @@ enum cmd_values { } while (0) #define LIST_MEM_ADD(_list, _fld) do { \ - size_t __siz; \ - __siz = strlen(_fld) + 1; \ - LIST_MEM_ADD_SIZ(_list, __siz); \ + if ((_fld) && (_fld) != EMPTY) { \ + size_t __siz; \ + __siz = strlen(_fld) + 1; \ + LIST_MEM_ADD_SIZ(_list, __siz); \ + } \ } while (0) #define LIST_MEM_SUB(_list, _fld) do { \ - size_t __siz; \ - __siz = strlen(_fld) + 1; \ - if (__siz % MEMBASE) \ - __siz += MEMBASE - (__siz % MEMBASE); \ - _list->ram -= (int)__siz; \ + if ((_fld) && (_fld) != EMPTY) { \ + size_t __siz; \ + __siz = strlen(_fld) + 1; \ + if (__siz % MEMBASE) \ + __siz += MEMBASE - (__siz % MEMBASE); \ + _list->ram -= (int)__siz; \ + } \ } while (0) #define SET_POINTER(_list, _fld, _val, _def) do { \ @@ -479,11 +484,28 @@ enum cmd_values { LIST_MEM_ADD(_list, _val); \ _fld = strdup(_val); \ if (!(_fld)) \ - quithere(1, "malloc OOM"); \ + quithere(1, "strdup OOM"); \ } \ } \ } while (0) +#define DUP_POINTER(_list, _fld, _val) do { \ + if ((_fld) && ((_fld) != EMPTY)) { \ + if (_list) \ + LIST_MEM_SUB(_list, _fld); \ + free(_fld); \ + } \ + if (!(_val) || !(*(_val))) \ + (_fld) = EMPTY; \ + else { \ + if (_list) \ + LIST_MEM_ADD(_list, _val); \ + _fld = strdup(_val); \ + if (!(_fld)) \ + quithere(1, "strdup OOM"); \ + } \ + } while (0) + #define SET_CREATEBY(_list, _fld, _val) SET_POINTER(_list, _fld, _val, by_default) #define SET_CREATECODE(_list, _fld, _val) SET_POINTER(_list, _fld, _val, EMPTY) #define SET_CREATEINET(_list, _fld, _val) SET_POINTER(_list, _fld, _val, inet_default) @@ -1021,6 +1043,7 @@ typedef struct users { char *userdata; int64_t databits; // non-DB field, Bitmask of userdata content int64_t userbits; // Bitmask of user attributes + int32_t lastvalue; // non-DB field HISTORYDATECONTROLFIELDS; } USERS; @@ -1440,6 +1463,8 @@ typedef struct blocks { char nonce[TXT_SML+1]; int64_t reward; char confirmed[TXT_FLAG+1]; + // block Short:Description to use vs default for 'R' in page_blocks.php + char info[TXT_SML+1]; double diffacc; double diffinv; double shareacc; @@ -1487,6 +1512,15 @@ typedef struct blocks { #define BLOCKS_42_VALUE 101 #define BLOCKS_ORPHAN 'O' #define BLOCKS_ORPHAN_STR "O" +#define BLOCKS_REJECT 'R' +#define BLOCKS_REJECT_STR "R" + +#define BLOCKS_N_C_STR BLOCKS_NEW_STR " or " BLOCKS_CONFIRM_STR +#define BLOCKS_N_C_O_STR BLOCKS_NEW_STR ", " BLOCKS_CONFIRM_STR " or " \ + BLOCKS_ORPHAN_STR +#define BLOCKS_N_C_O_R_STR BLOCKS_NEW_STR ", " BLOCKS_CONFIRM_STR ", " \ + BLOCKS_ORPHAN_STR " or " BLOCKS_REJECT_STR + /* Block height difference required before checking if it's orphaned * TODO: add a cmd_blockstatus option to un-orphan a block */ #define BLOCKS_ORPHAN_CHECK 1 @@ -1500,6 +1534,7 @@ extern const char *blocks_new; extern const char *blocks_confirm; extern const char *blocks_42; extern const char *blocks_orphan; +extern const char *blocks_reject; extern const char *blocks_unknown; #define KANO -27972 @@ -1572,6 +1607,10 @@ extern cklock_t process_pplns_lock; #define PAYOUTS_ORPHAN 'O' #define PAYOUTS_ORPHAN_STR "O" #define PAYORPHAN(_status) ((_status)[0] == PAYOUTS_ORPHAN) +// A rejected payout must be ignored +#define PAYOUTS_REJECT 'R' +#define PAYOUTS_REJECT_STR "R" +#define PAYREJECT(_status) ((_status)[0] == PAYOUTS_REJECT) // Default number of shifts (payouts) to display on web #define SHIFTS_DEFAULT 99 @@ -1972,12 +2011,19 @@ extern const char *marktype_shift_end_skip; #define MARK_USED_STR "u" #define MUSED(_status) (tolower((_status)[0]) == MARK_USED) +enum info_type { + INFO_NEW, + INFO_ORPHAN, + INFO_REJECT +}; + // USERINFO from various incoming data typedef struct userinfo { int64_t userid; char username[TXT_BIG+1]; int blocks; int orphans; // How many blocks are orphans + int rejects; // How many blocks are rejects tv_t last_block; // For all time double diffacc; @@ -2028,9 +2074,13 @@ extern void sequence_report(bool lock); #define REWARDOVERRIDE "MinerReward" // Data free functions (first) +#define FREE_ITEM(item) do { } while(0) +// TODO: make a macro for all other to use above macro extern void free_msgline_data(K_ITEM *item, bool t_lock, bool t_cull); +extern void free_users_data(K_ITEM *item); extern void free_workinfo_data(K_ITEM *item); extern void free_sharesummary_data(K_ITEM *item); +extern void free_payouts_data(K_ITEM *item); extern void free_optioncontrol_data(K_ITEM *item); extern void free_markersummary_data(K_ITEM *item); extern void free_workmarkers_data(K_ITEM *item); @@ -2038,6 +2088,12 @@ extern void free_marks_data(K_ITEM *item); #define free_seqset_data(_item) _free_seqset_data(_item, false) extern void _free_seqset_data(K_ITEM *item, bool lock); +// Data copy functions +#define COPY_DATA(_new, _old) memcpy(_new, _old, sizeof(*(_new))) + +extern void copy_users(USERS *newu, USERS *oldu); +#define copy_blocks(_newb, _oldb) COPY_DATA(_newb, _oldb) + #define safe_text(_txt) _safe_text(_txt, true) #define safe_text_nonull(_txt) _safe_text(_txt, false) extern char *_safe_text(char *txt, bool shownull); @@ -2270,7 +2326,7 @@ extern K_ITEM *find_markersummary_userid(int64_t userid, char *workername, _find_markersummary(_markerid, 0, KANO, EMPTY, true) #define POOL_MS(_row) do { \ (_row)->userid = KANO; \ - (_row)->workername = strdup(EMPTY); \ + (_row)->workername = EMPTY; \ } while (0) extern K_ITEM *_find_markersummary(int64_t markerid, int64_t workinfoid, int64_t userid, char *workername, bool pool); @@ -2303,7 +2359,7 @@ extern K_ITEM *_find_create_userinfo(int64_t userid, bool lock, WHERE_FFL_ARGS); extern void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary, MARKERSUMMARY *markersummary, bool ss_sub, bool lock); #define userinfo_block(_blocks, _isnew) _userinfo_block(_blocks, _isnew, true) -extern void _userinfo_block(BLOCKS *blocks, bool isnew, bool lock); +extern void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock); // *** // *** PostgreSQL functions ckdb_dbio.c @@ -2436,9 +2492,9 @@ extern bool blocks_stats(PGconn *conn, int32_t height, char *blockhash, double shareinv, int64_t elapsed, char *by, char *code, char *inet, tv_t *cd); extern bool blocks_add(PGconn *conn, char *height, char *blockhash, - char *confirmed, char *workinfoid, char *username, - char *workername, char *clientid, char *enonce1, - char *nonce2, char *nonce, char *reward, + char *confirmed, char *info, char *workinfoid, + char *username, char *workername, char *clientid, + char *enonce1, char *nonce2, char *nonce, char *reward, char *by, char *code, char *inet, tv_t *cd, bool igndup, char *id, K_TREE *trf_root); extern bool blocks_fill(PGconn *conn); @@ -2551,5 +2607,7 @@ extern K_ITEM *gen_2fa_key(K_ITEM *old_u_item, int32_t entropy, char *by, extern bool check_2fa(USERS *users, int32_t value); extern bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root); +extern K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by, + char *code, char *inet, tv_t *cd, K_TREE *trf_root); #endif diff --git a/src/ckdb_btc.c b/src/ckdb_btc.c index 0523b164..44105190 100644 --- a/src/ckdb_btc.c +++ b/src/ckdb_btc.c @@ -355,7 +355,7 @@ void btc_blockstatus(BLOCKS *blocks) ok = blocks_add(NULL, height_str, blocks->blockhash, - BLOCKS_ORPHAN_STR, + BLOCKS_ORPHAN_STR, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, by_default, (char *)__func__, inet_default, @@ -378,7 +378,7 @@ void btc_blockstatus(BLOCKS *blocks) ok = blocks_add(NULL, height_str, blocks->blockhash, - BLOCKS_42_STR, + BLOCKS_42_STR, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, by_default, (char *)__func__, inet_default, diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 798cc6c4..774a018c 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -325,6 +325,24 @@ static char *cmd_2fa(__maybe_unused PGconn *conn, char *cmd, char *id, DATA_USERS(users, u_item); } } + } else if (strcmp(action, "remove") == 0) { + // Can't remove if 2FA isn't already present + if (!(users->databits & (USER_TOTPAUTH | USER_TEST2FA))) + goto dame; + value = (int32_t)atoi(transfer_data(i_value)); + if (!check_2fa(users, value)) { + sfa_error = "Invalid code"; + // Report sfa_error to web + ok = true; + } else { + u_new = remove_2fa(u_item, value, by, code, + inet, now, trf_root); + if (u_new) { + ok = true; + sfa_status = EMPTY; + key = false; + } + } } if (key) { char *keystr, *issuer = "Kano"; @@ -1132,7 +1150,8 @@ redo: while (b_item) { DATA_BLOCKS(blocks, b_item); if (CURRENT(&(blocks->expirydate))) { - if (blocks->confirmed[0] != BLOCKS_ORPHAN) + if (blocks->confirmed[0] != BLOCKS_ORPHAN && + blocks->confirmed[0] != BLOCKS_REJECT) tot++; } b_item = next_in_ktree(ctx); @@ -1149,10 +1168,14 @@ redo: copy_tv(&first_cd, &(blocks->createdate)); } if (CURRENT(&(blocks->expirydate))) { - if (blocks->confirmed[0] == BLOCKS_ORPHAN) { + if (blocks->confirmed[0] == BLOCKS_ORPHAN || + blocks->confirmed[0] == BLOCKS_REJECT) { snprintf(tmp, sizeof(tmp), - "seq:%d=o%c", - rows, FLDSEP); + "seq:%d=%c%c", + rows, + blocks->confirmed[0] == BLOCKS_ORPHAN ? + 'o' : 'r', + FLDSEP); APPEND_REALLOC(buf, off, len, tmp); } else { snprintf(tmp, sizeof(tmp), @@ -1191,10 +1214,16 @@ redo: APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), - "status:%d=%s%c", rows, + "confirmed:%d=%s%cstatus:%d=%s%c", rows, + blocks->confirmed, FLDSEP, rows, blocks_confirmed(blocks->confirmed), FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + snprintf(tmp, sizeof(tmp), + "info:%d=%s%c", rows, + blocks->info, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + snprintf(tmp, sizeof(tmp), "statsconf:%d=%s%c", rows, blocks->statsconfirmed, FLDSEP); @@ -1248,7 +1277,8 @@ redo: while (b_item) { DATA_BLOCKS(blocks, b_item); if (CURRENT(&(blocks->expirydate)) && - blocks->confirmed[0] != BLOCKS_ORPHAN) { + blocks->confirmed[0] != BLOCKS_ORPHAN && + blocks->confirmed[0] != BLOCKS_REJECT) { desc = NULL; if (seq == 1) { snprintf(desc_buf, sizeof(desc_buf), @@ -1314,8 +1344,9 @@ redo: "rows=%d%cflds=%s%c", rows, FLDSEP, "seq,height,blockhash,nonce,reward,workername,first"CDTRF"," - CDTRF",status,statsconf,diffacc,diffinv,shareacc," - "shareinv,elapsed,netdiff,diffratio,cdf,luck", FLDSEP); + CDTRF",confirmed,status,info,statsconf,diffacc,diffinv," + "shareacc,shareinv,elapsed,netdiff,diffratio,cdf,luck", + FLDSEP); APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks,BlockStats", FLDSEP, ",s"); @@ -1329,13 +1360,13 @@ static char *cmd_blockstatus(__maybe_unused PGconn *conn, char *cmd, char *id, tv_t *now, char *by, char *code, char *inet, __maybe_unused tv_t *cd, K_TREE *trf_root) { - K_ITEM *i_height, *i_blockhash, *i_action; + K_ITEM *i_height, *i_blockhash, *i_action, *i_info; char reply[1024] = ""; size_t siz = sizeof(reply); K_ITEM *b_item; BLOCKS *blocks; int32_t height; - char *action; + char *action, *info, *tmp; bool ok = false; LOGDEBUG("%s(): cmd '%s'", __func__, cmd); @@ -1368,13 +1399,57 @@ static char *cmd_blockstatus(__maybe_unused PGconn *conn, char *cmd, char *id, DATA_BLOCKS(blocks, b_item); + // Default to previous value + info = blocks->info; + if (strcasecmp(action, "orphan") == 0) { switch (blocks->confirmed[0]) { case BLOCKS_NEW: case BLOCKS_CONFIRM: ok = blocks_add(conn, transfer_data(i_height), blocks->blockhash, - BLOCKS_ORPHAN_STR, + BLOCKS_ORPHAN_STR, info, + EMPTY, EMPTY, EMPTY, EMPTY, + EMPTY, EMPTY, EMPTY, EMPTY, + by, code, inet, now, false, id, + trf_root); + if (!ok) { + snprintf(reply, siz, + "DBE.action '%s'", + action); + LOGERR("%s.%s", id, reply); + return strdup(reply); + } + // TODO: reset the share counter? + break; + default: + snprintf(reply, siz, + "ERR.invalid action '%.*s%s' for block state '%s'", + CMD_SIZ, action, + (strlen(action) > CMD_SIZ) ? "..." : "", + blocks_confirmed(blocks->confirmed)); + LOGERR("%s.%s", id, reply); + return strdup(reply); + } + } else if (strcasecmp(action, "reject") == 0) { + i_info = require_name(trf_root, "info", 0, (char *)strpatt, + reply, siz); + if (!i_info) + return strdup(reply); + tmp = transfer_data(i_info); + /* Override if not empty + * Thus you can't blank it out if current has a value */ + if (tmp && *tmp) + info = tmp; + + switch (blocks->confirmed[0]) { + case BLOCKS_NEW: + case BLOCKS_CONFIRM: + case BLOCKS_ORPHAN: + case BLOCKS_REJECT: + ok = blocks_add(conn, transfer_data(i_height), + blocks->blockhash, + BLOCKS_REJECT_STR, info, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, by, code, inet, now, false, id, @@ -1403,7 +1478,7 @@ static char *cmd_blockstatus(__maybe_unused PGconn *conn, char *cmd, char *id, case BLOCKS_NEW: ok = blocks_add(conn, transfer_data(i_height), blocks->blockhash, - BLOCKS_CONFIRM_STR, + BLOCKS_CONFIRM_STR, info, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, by, code, inet, now, false, id, @@ -2596,6 +2671,7 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, ok = blocks_add(conn, transfer_data(i_height), transfer_data(i_blockhash), transfer_data(i_confirmed), + EMPTY, transfer_data(i_workinfoid), transfer_data(i_username), transfer_data(i_workername), @@ -2612,6 +2688,7 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by, ok = blocks_add(conn, transfer_data(i_height), transfer_data(i_blockhash), transfer_data(i_confirmed), + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, by, code, inet, cd, igndup, id, @@ -3794,9 +3871,8 @@ static char *cmd_setopts(PGconn *conn, char *cmd, char *id, gotvalue = false; } if (strcmp(dot, "value") == 0) { - optioncontrol->optionvalue = strdup(data); - if (!(optioncontrol->optionvalue)) - quithere(1, "malloc (%d) OOM", (int)strlen(data)); + DUP_POINTER(optioncontrol_free, + optioncontrol->optionvalue, data); gotvalue = true; } else if (strcmp(dot, "date") == 0) { att_to_date(&(optioncontrol->activationdate), data, now); @@ -3977,6 +4053,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id, block_extra = "Can't be paid out yet"; break; case BLOCKS_ORPHAN: + case BLOCKS_REJECT: block_extra = "Can't be paid out"; break; default: @@ -4428,6 +4505,7 @@ static char *cmd_pplns2(__maybe_unused PGconn *conn, char *cmd, char *id, block_extra = "Can't be paid out yet"; break; case BLOCKS_ORPHAN: + case BLOCKS_REJECT: block_extra = "Can't be paid out"; break; default: @@ -4694,7 +4772,7 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, payouts2->diffused = payouts->diffused; payouts2->shareacc = payouts->shareacc; copy_tv(&(payouts2->lastshareacc), &(payouts->lastshareacc)); - payouts2->stats = strdup(payouts->stats); + DUP_POINTER(payouts_free, payouts2->stats, payouts->stats); ok = payouts_add(conn, true, p2_item, &old_p2_item, by, code, inet, now, NULL, false); @@ -4709,12 +4787,14 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, "%"PRId32"/%s", payoutid, old_payouts2->status, payouts2->status, payouts2->height, payouts2->blockhash); - } else if (strcasecmp(action, "orphan") == 0) { + } else if (strcasecmp(action, "orphan") == 0 || + strcasecmp(action, "reject") == 0) { /* Change the status of a generated payout to orphaned + * or rejected * Require payoutid - * Use this if the orphan process didn't automatically - * update a generated payout to orphaned - * TODO: get orphaned blocks to automatically do this */ + * Use this if the orphan or reject process didn't + * automatically update a generated payout + * TODO: get orphaned and rejected blocks to automatically do this */ i_payoutid = require_name(trf_root, "payoutid", 1, (char *)intpatt, reply, siz); if (!i_payoutid) @@ -4753,12 +4833,15 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, payouts2->workinfoidstart = payouts->workinfoidstart; payouts2->workinfoidend = payouts->workinfoidend; payouts2->elapsed = payouts->elapsed; - STRNCPY(payouts2->status, PAYOUTS_ORPHAN_STR); + if (strcasecmp(action, "orphan") == 0) + STRNCPY(payouts2->status, PAYOUTS_ORPHAN_STR); + else + STRNCPY(payouts2->status, PAYOUTS_REJECT_STR); payouts2->diffwanted = payouts->diffwanted; payouts2->diffused = payouts->diffused; payouts2->shareacc = payouts->shareacc; copy_tv(&(payouts2->lastshareacc), &(payouts->lastshareacc)); - payouts2->stats = strdup(payouts->stats); + DUP_POINTER(payouts_free, payouts2->stats, payouts->stats); ok = payouts_add(conn, true, p2_item, &old_p2_item, by, code, inet, now, NULL, false); @@ -5410,8 +5493,7 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id, APPEND_REALLOC_INIT(buf, off, len); APPEND_REALLOC(buf, off, len, "ok."); -// Doesn't include blob memory -// - average transactiontree length of ~119k I have is ~28k (>3.3GB) +// FYI average transactiontree length of the ~119k I have is ~28k (>3.3GB) #define USEINFO(_obj, _stores, _trees) \ klist = _obj ## _free; \ ram = sizeof(K_LIST) + _stores * sizeof(K_STORE) + \ @@ -6166,7 +6248,9 @@ static char *cmd_userinfo(__maybe_unused PGconn *conn, char *cmd, char *id, APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), "blocks:%d=%d%c", rows, - userinfo->blocks - userinfo->orphans, FLDSEP); + userinfo->blocks - + (userinfo->orphans + userinfo->rejects), + FLDSEP); APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), "orphans:%d=%d%c", rows, diff --git a/src/ckdb_crypt.c b/src/ckdb_crypt.c index 360ba93a..d285e9ac 100644 --- a/src/ckdb_crypt.c +++ b/src/ckdb_crypt.c @@ -117,12 +117,7 @@ K_ITEM *gen_2fa_key(K_ITEM *old_u_item, int32_t entropy, char *by, char *code, u_item = k_unlink_head(users_free); K_WUNLOCK(users_free); DATA_USERS(users, u_item); - memcpy(users, old_users, sizeof(*users)); - if (users->userdata != EMPTY) { - users->userdata = strdup(users->userdata); - if (!users->userdata) - quithere(1, "strdup OOM"); - } + copy_users(users, old_users); users_userdata_add_bin(users, USER_TOTPAUTH_NAME, USER_TOTPAUTH, key, sizeof(key)); users_userdata_add_txt(users, USER_TEST2FA_NAME, @@ -198,15 +193,23 @@ bool check_2fa(USERS *users, int32_t value) otp %= 1000000; - LOGDEBUG("%s() '%s/%s offset=%d otp=%"PRId32" value=%"PRId32, + LOGDEBUG("%s() '%s/%s offset=%d otp=%"PRId32" value=%"PRId32 + " lastvalue=%"PRId32, __func__, st = safe_text_nonull(users->username), - USER_TOTPAUTH_NAME, offset, otp, value); + USER_TOTPAUTH_NAME, offset, otp, value, users->lastvalue); FREENULL(st); FREENULL(hash); - if (otp == value) + /* Disallow 0 since that's the default value + * If it is 0, that means wait another TOTPAUTH_TIME and try again + * 0 is only one in a million tests for all users + * For security reasons, we can't allow using the same value twice, + * N.B. a ckdb restart will forget lastvalue, but a restart should + * take long enough to resolve that issue */ + if (otp == value && otp != 0 && otp != users->lastvalue) { + users->lastvalue = otp; return true; - else + } else return false; } @@ -224,12 +227,7 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, u_item = k_unlink_head(users_free); K_WUNLOCK(users_free); DATA_USERS(users, u_item); - memcpy(users, old_users, sizeof(*users)); - if (users->userdata != EMPTY) { - users->userdata = strdup(users->userdata); - if (!users->userdata) - quithere(1, "strdup OOM"); - } + copy_users(users, old_users); users_userdata_del(users, USER_TEST2FA_NAME, USER_TEST2FA); ok = users_replace(NULL, u_item, old_u_item, by, code, inet, cd, trf_root); @@ -237,3 +235,44 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, } return ok; } + +K_ITEM *remove_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, + char *inet, tv_t *cd, K_TREE *trf_root) +{ + K_ITEM *u_item = NULL; + USERS *old_users, *users; + bool ok, did = false; + + DATA_USERS(old_users, old_u_item); + ok = check_2fa(old_users, value); + if (ok) { + K_WLOCK(users_free); + u_item = k_unlink_head(users_free); + K_WUNLOCK(users_free); + DATA_USERS(users, u_item); + copy_users(users, old_users); + if (users->databits & USER_TEST2FA) { + users_userdata_del(users, USER_TEST2FA_NAME, USER_TEST2FA); + did = true; + } + if (users->databits & USER_TOTPAUTH) { + users_userdata_del(users, USER_TOTPAUTH_NAME, USER_TOTPAUTH); + did = true; + } + if (did) { + ok = users_replace(NULL, u_item, old_u_item, by, code, inet, cd, + trf_root); + if (!ok) { + // u_item was cleaned up in user_replace() + u_item = NULL; + } + } else { + K_WLOCK(users_free); + free_users_data(u_item); + k_add_head(users_free, u_item); + K_WUNLOCK(users_free); + u_item = NULL; + } + } + return u_item; +} diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 18e780fd..f2c491ee 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -44,15 +44,33 @@ void free_msgline_data(K_ITEM *item, bool t_lock, bool t_cull) FREENULL(msgline->msg); } +void free_users_data(K_ITEM *item) +{ + USERS *users; + + DATA_USERS(users, item); + LIST_MEM_SUB(users_free, users->userdata); + FREENULL(users->userdata); +} + void free_workinfo_data(K_ITEM *item) { WORKINFO *workinfo; DATA_WORKINFO(workinfo, item); - if (workinfo->transactiontree) - FREENULL(workinfo->transactiontree); - if (workinfo->merklehash) - FREENULL(workinfo->merklehash); + LIST_MEM_SUB(workinfo_free, workinfo->transactiontree); + FREENULL(workinfo->transactiontree); + LIST_MEM_SUB(workinfo_free, workinfo->merklehash); + FREENULL(workinfo->merklehash); +} + +void free_payouts_data(K_ITEM *item) +{ + PAYOUTS *payouts; + + DATA_PAYOUTS(payouts, item); + LIST_MEM_SUB(payouts_free, payouts->stats); + FREENULL(payouts->stats); } void free_sharesummary_data(K_ITEM *item) @@ -60,10 +78,8 @@ void free_sharesummary_data(K_ITEM *item) SHARESUMMARY *sharesummary; DATA_SHARESUMMARY(sharesummary, item); - if (sharesummary->workername) { - LIST_MEM_SUB(sharesummary_free, sharesummary->workername); - FREENULL(sharesummary->workername); - } + LIST_MEM_SUB(sharesummary_free, sharesummary->workername); + FREENULL(sharesummary->workername); SET_CREATEBY(sharesummary_free, sharesummary->createby, EMPTY); SET_CREATECODE(sharesummary_free, sharesummary->createcode, EMPTY); SET_CREATEINET(sharesummary_free, sharesummary->createinet, EMPTY); @@ -77,8 +93,8 @@ void free_optioncontrol_data(K_ITEM *item) OPTIONCONTROL *optioncontrol; DATA_OPTIONCONTROL(optioncontrol, item); - if (optioncontrol->optionvalue) - FREENULL(optioncontrol->optionvalue); + LIST_MEM_SUB(optioncontrol_free, optioncontrol->optionvalue); + FREENULL(optioncontrol->optionvalue); } void free_markersummary_data(K_ITEM *item) @@ -86,8 +102,8 @@ void free_markersummary_data(K_ITEM *item) MARKERSUMMARY *markersummary; DATA_MARKERSUMMARY(markersummary, item); - if (markersummary->workername) - FREENULL(markersummary->workername); + LIST_MEM_SUB(markersummary_free, markersummary->workername); + FREENULL(markersummary->workername); SET_CREATEBY(markersummary_free, markersummary->createby, EMPTY); SET_CREATECODE(markersummary_free, markersummary->createcode, EMPTY); SET_CREATEINET(markersummary_free, markersummary->createinet, EMPTY); @@ -101,10 +117,10 @@ void free_workmarkers_data(K_ITEM *item) WORKMARKERS *workmarkers; DATA_WORKMARKERS(workmarkers, item); - if (workmarkers->poolinstance) - FREENULL(workmarkers->poolinstance); - if (workmarkers->description) - FREENULL(workmarkers->description); + LIST_MEM_SUB(workmarkers_free, workmarkers->poolinstance); + FREENULL(workmarkers->poolinstance); + LIST_MEM_SUB(workmarkers_free, workmarkers->description); + FREENULL(workmarkers->description); } void free_marks_data(K_ITEM *item) @@ -112,12 +128,12 @@ void free_marks_data(K_ITEM *item) MARKS *marks; DATA_MARKS(marks, item); - if (marks->poolinstance && marks->poolinstance != EMPTY) - FREENULL(marks->poolinstance); - if (marks->description && marks->description != EMPTY) - FREENULL(marks->description); - if (marks->extra && marks->extra != EMPTY) - FREENULL(marks->extra); + LIST_MEM_SUB(marks_free, marks->poolinstance); + FREENULL(marks->poolinstance); + LIST_MEM_SUB(marks_free, marks->description); + FREENULL(marks->description); + LIST_MEM_SUB(marks_free, marks->extra); + FREENULL(marks->extra); } void _free_seqset_data(K_ITEM *item, bool lock) @@ -145,6 +161,16 @@ void _free_seqset_data(K_ITEM *item, bool lock) } } +/* Data copy functions (added here as needed) + All pointers need to initialised since DUP_POINTER will free them */ + +void copy_users(USERS *newu, USERS *oldu) +{ + memcpy(newu, oldu, sizeof(*newu)); + newu->userdata = NULL; + DUP_POINTER(users_free, newu->userdata, oldu->userdata); +} + // Clear text printable version of txt up to first '\0' char *_safe_text(char *txt, bool shownull) { @@ -2629,6 +2655,8 @@ const char *blocks_confirmed(char *confirmed) return blocks_42; case BLOCKS_ORPHAN: return blocks_orphan; + case BLOCKS_REJECT: + return blocks_reject; } return blocks_unknown; } @@ -2869,7 +2897,8 @@ bool check_update_blocks_stats(tv_t *stats) DATA_BLOCKS(blocks, b_item); if (CURRENT(&(blocks->expirydate))) { pending += blocks->diffacc; - if (blocks->confirmed[0] == BLOCKS_ORPHAN) + if (blocks->confirmed[0] == BLOCKS_ORPHAN || + blocks->confirmed[0] == BLOCKS_REJECT) blocks->diffcalc = 0.0; else { blocks->diffcalc = pending; @@ -2918,10 +2947,11 @@ bool check_update_blocks_stats(tv_t *stats) else blocks->blockluck = 1.0 / blocks->blockdiffratio; - /* Orphans are treated as +diffacc but no block + /* Orphans/Rejects are treated as +diffacc but no block * i.e. they simply add shares to the later block * and have running stats set to zero */ - if (blocks->confirmed[0] == BLOCKS_ORPHAN) { + if (blocks->confirmed[0] == BLOCKS_ORPHAN || + blocks->confirmed[0] == BLOCKS_REJECT) { blocks->diffratio = 0.0; blocks->diffmean = 0.0; blocks->cdferl = 0.0; @@ -3311,6 +3341,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd) switch (blocks->confirmed[0]) { case BLOCKS_NEW: case BLOCKS_ORPHAN: + case BLOCKS_REJECT: LOGERR("%s(): can't process block %"PRId32"/%" PRId64"/%s/%"PRId64" status: %s/%s", __func__, blocks->height, blocks->workinfoid, @@ -3656,7 +3687,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd) diff_times, FLDSEP, diff_add, FLDSEP, total_share_count, FLDSEP, ss_count, FLDSEP, wm_count, FLDSEP, ms_count, FLDSEP, cd_buf); - payouts->stats = buf; + DUP_POINTER(payouts_free, payouts->stats, &buf[0]); conned = CKPQConn(&conn); begun = CKPQBegin(conn); @@ -3870,9 +3901,6 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd) ss_count, wm_count, ms_count, usercount, diff_times, diff_add, cd_buf); - // convert the stack memory to heap memeory - payouts->stats = strdup(payouts->stats); - K_WLOCK(payouts_free); p2_item = k_unlink_head(payouts_free); K_WUNLOCK(payouts_free); @@ -3890,7 +3918,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd) payouts2->diffused = payouts->diffused; payouts2->shareacc = payouts->shareacc; copy_tv(&(payouts2->lastshareacc), &(payouts->lastshareacc)); - payouts2->stats = strdup(payouts->stats); + DUP_POINTER(payouts_free, payouts2->stats, payouts->stats); setnow(&now); /* N.B. the PROCESSING payouts could have expirydate = createdate @@ -3918,6 +3946,7 @@ shazbot: if (p_item) { K_WLOCK(payouts_free); + free_payouts_data(p_item); k_add_head(payouts_free, p_item); K_WUNLOCK(payouts_free); } @@ -4867,8 +4896,8 @@ void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary, } } -// N.B. good blocks = blocks - orphans -void _userinfo_block(BLOCKS *blocks, bool isnew, bool lock) +// N.B. good blocks = blocks - (orphans + rejects) +void _userinfo_block(BLOCKS *blocks, enum info_type isnew, bool lock) { USERINFO *row; K_ITEM *item; @@ -4877,11 +4906,14 @@ void _userinfo_block(BLOCKS *blocks, bool isnew, bool lock) DATA_USERINFO(row, item); if (lock) K_WLOCK(userinfo_free); - if (isnew) { + if (isnew == INFO_NEW) { row->blocks++; copy_tv(&(row->last_block), &(blocks->createdate)); - } else + } else if (isnew == INFO_ORPHAN) row->orphans++; + else if (isnew == INFO_REJECT) + row->rejects++; + if (lock) K_WUNLOCK(userinfo_free); } diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index 07117a82..f2927d9e 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -181,6 +181,7 @@ char *pqerrmsg(PGconn *conn) #define PQPARAM17 PQPARAM16 ",$17" #define PQPARAM18 PQPARAM16 ",$17,$18" #define PQPARAM22 PQPARAM16 ",$17,$18,$19,$20,$21,$22" +#define PQPARAM23 PQPARAM16 ",$17,$18,$19,$20,$21,$22,$23" #define PQPARAM26 PQPARAM22 ",$23,$24,$25,$26" #define PQPARAM27 PQPARAM26 ",$27" @@ -415,7 +416,7 @@ bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash, K_WUNLOCK(users_free); DATA_USERS(row, item); - memcpy(row, users, sizeof(*row)); + copy_users(row, users); // Update each one supplied if (hash) { @@ -428,11 +429,6 @@ bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash, STRNCPY(row->emailaddress, email); if (status) STRNCPY(row->status, status); - if (row->userdata != EMPTY) { - row->userdata = strdup(users->userdata); - if (!row->userdata) - quithere(1, "strdup OOM"); - } HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); @@ -514,8 +510,7 @@ unparam: K_WLOCK(users_free); if (!ok) { - if (row->userdata != EMPTY) - FREENULL(row->userdata); + free_users_data(item); k_add_head(users_free, item); } else { users_root = remove_from_ktree(users_root, u_item, cmp_users); @@ -649,9 +644,10 @@ unparam: free(params[n]); unitem: K_WLOCK(users_free); - if (!ok) + if (!ok) { + free_users_data(item); k_add_head(users_free, item); - else { + } else { users_root = add_to_ktree(users_root, item, cmp_users); userid_root = add_to_ktree(userid_root, item, cmp_userid); k_add_head(users_store, item); @@ -761,8 +757,7 @@ unparam: K_WLOCK(users_free); if (!ok) { // cleanup done here - if (users->userdata != EMPTY) - FREENULL(users->userdata); + free_users_data(u_item); k_add_head(users_free, u_item); } else { users_root = remove_from_ktree(users_root, old_u_item, cmp_users); @@ -892,8 +887,10 @@ bool users_fill(PGconn *conn) userid_root = add_to_ktree(userid_root, item, cmp_userid); k_add_head(users_store, item); } - if (!ok) + if (!ok) { + free_users_data(item); k_add_head(users_free, item); + } K_WUNLOCK(users_free); PQclear(res); @@ -1429,7 +1426,7 @@ bool workers_update(PGconn *conn, K_ITEM *item, char *difficultydefault, WORKERS *row; char *upd, *ins; bool ok = false; - char *params[6 + HISTORYDATECOUNT]; + char *params[7 + HISTORYDATECOUNT]; int n, par = 0; int32_t diffdef; char idlenot; @@ -2341,7 +2338,7 @@ K_ITEM *optioncontrol_item_add(PGconn *conn, K_ITEM *oc_item, tv_t *cd, bool beg K_TREE_CTX ctx[1]; PGresult *res; K_ITEM *old_item, look; - OPTIONCONTROL *row, *optioncontrol; + OPTIONCONTROL *row; char *upd, *ins; bool ok = false; char *params[4 + HISTORYDATECOUNT]; @@ -2444,16 +2441,15 @@ nostart: K_WLOCK(optioncontrol_free); if (!ok) { // Cleanup item passed in - FREENULL(row->optionvalue); + free_optioncontrol_data(oc_item); k_add_head(optioncontrol_free, oc_item); } else { // Discard old if (old_item) { - DATA_OPTIONCONTROL(optioncontrol, old_item); optioncontrol_root = remove_from_ktree(optioncontrol_root, old_item, cmp_optioncontrol); k_unlink_item(optioncontrol_store, old_item); - FREENULL(optioncontrol->optionvalue); + free_optioncontrol_data(old_item); k_add_head(optioncontrol_free, old_item); } optioncontrol_root = add_to_ktree(optioncontrol_root, oc_item, cmp_optioncontrol); @@ -2600,7 +2596,7 @@ bool optioncontrol_fill(PGconn *conn) } } if (!ok) { - FREENULL(row->optionvalue); + free_optioncontrol_data(item); k_add_head(optioncontrol_free, item); } @@ -2648,14 +2644,8 @@ int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstance, TXT_TO_BIGINT("workinfoid", workinfoidstr, row->workinfoid); STRNCPY(row->poolinstance, poolinstance); - row->transactiontree = strdup(transactiontree); - if (!(row->transactiontree)) - quithere(1, "malloc (%d) OOM", (int)strlen(transactiontree)); - LIST_MEM_ADD(workinfo_free, row->transactiontree); - row->merklehash = strdup(merklehash); - if (!(row->merklehash)) - quithere(1, "malloc (%d) OOM", (int)strlen(merklehash)); - LIST_MEM_ADD(workinfo_free, row->merklehash); + DUP_POINTER(workinfo_free, row->transactiontree, transactiontree); + DUP_POINTER(workinfo_free, row->merklehash, merklehash); STRNCPY(row->prevhash, prevhash); STRNCPY(row->coinbase1, coinbase1); STRNCPY(row->coinbase2, coinbase2); @@ -2670,11 +2660,8 @@ int64_t workinfo_add(PGconn *conn, char *workinfoidstr, char *poolinstance, K_WLOCK(workinfo_free); if (find_in_ktree(workinfo_root, item, cmp_workinfo, ctx)) { - LIST_MEM_SUB(workinfo_free, row->transactiontree); - FREENULL(row->transactiontree); - LIST_MEM_SUB(workinfo_free, row->merklehash); - FREENULL(row->merklehash); workinfoid = row->workinfoid; + free_workinfo_data(item); k_add_head(workinfo_free, item); K_WUNLOCK(workinfo_free); @@ -2735,19 +2722,12 @@ unparam: K_WLOCK(workinfo_free); if (workinfoid == -1) { - LIST_MEM_SUB(workinfo_free, row->transactiontree); - FREENULL(row->transactiontree); - LIST_MEM_SUB(workinfo_free, row->merklehash); - FREENULL(row->merklehash); + free_workinfo_data(item); k_add_head(workinfo_free, item); } else { - if (row->transactiontree && *(row->transactiontree)) { - // Not currently needed in RAM - LIST_MEM_SUB(workinfo_free, row->transactiontree); - free(row->transactiontree); - row->transactiontree = strdup(EMPTY); - LIST_MEM_ADD(workinfo_free, row->transactiontree); - } + // Not currently needed in RAM + LIST_MEM_SUB(workinfo_free, row->transactiontree); + FREENULL(row->transactiontree); hex2bin(ndiffbin, row->bits, 4); current_ndiff = diff_from_nbits(ndiffbin); @@ -2870,9 +2850,9 @@ bool workinfo_fill(PGconn *conn) if (!ok) break; TXT_TO_BLOB("transactiontree", field, row->transactiontree); -*/ - row->transactiontree = strdup(EMPTY); LIST_MEM_ADD(workinfo_free, row->transactiontree); +*/ + row->transactiontree = EMPTY; PQ_GET_FLD(res, i, "merklehash", field, ok); if (!ok) @@ -2940,8 +2920,7 @@ bool workinfo_fill(PGconn *conn) tick(); } if (!ok) { - //FREENULL(row->transactiontree); - FREENULL(row->merklehash); + free_workinfo_data(item); k_add_head(workinfo_free, item); } @@ -3690,9 +3669,11 @@ bool sharesummaries_to_markersummaries(PGconn *conn, WORKMARKERS *workmarkers, bzero(markersummary, sizeof(*markersummary)); markersummary->markerid = workmarkers->markerid; markersummary->userid = sharesummary->userid; - markersummary->workername = strdup(sharesummary->workername); - LIST_MEM_ADD(markersummary_free, markersummary->workername); - ms_root = add_to_ktree(ms_root, ms_item, cmp_markersummary); + DUP_POINTER(markersummary_free, + markersummary->workername, + sharesummary->workername); + ms_root = add_to_ktree(ms_root, ms_item, + cmp_markersummary); LOGDEBUG("%s() new ms %"PRId64"/%"PRId64"/%s", shortname, markersummary->markerid, @@ -3830,7 +3811,6 @@ flail: bzero(p_markersummary, sizeof(*p_markersummary)); p_markersummary->markerid = markersummary->markerid; POOL_MS(p_markersummary); - LIST_MEM_ADD(markersummary_free, p_markersummary->workername); markersummary_pool_root = add_to_ktree(markersummary_pool_root, p_ms_item, cmp_markersummary); @@ -4075,8 +4055,8 @@ bool _sharesummary_update(SHARES *s_row, SHAREERRORS *e_row, K_ITEM *ss_item, DATA_SHARESUMMARY(row, item); bzero(row, sizeof(*row)); row->userid = userid; - row->workername = strdup(workername); - LIST_MEM_ADD(sharesummary_free, row->workername); + DUP_POINTER(sharesummary_free, row->workername, + workername); row->workinfoid = workinfoid; } @@ -4146,7 +4126,6 @@ bool _sharesummary_update(SHARES *s_row, SHAREERRORS *e_row, K_ITEM *ss_item, DATA_SHARESUMMARY(p_row, p_item); bzero(p_row, sizeof(*p_row)); POOL_SS(p_row); - LIST_MEM_ADD(sharesummary_free, p_row->workername); p_row->workinfoid = workinfoid; } @@ -4214,7 +4193,7 @@ bool blocks_stats(PGconn *conn, int32_t height, char *blockhash, K_WUNLOCK(blocks_free); DATA_BLOCKS(row, b_item); - memcpy(row, oldblocks, sizeof(*row)); + copy_blocks(row, oldblocks); row->diffacc = diffacc; row->diffinv = diffinv; row->shareacc = shareacc; @@ -4326,9 +4305,9 @@ unparam: } bool blocks_add(PGconn *conn, char *height, char *blockhash, - char *confirmed, char *workinfoid, char *username, - char *workername, char *clientid, char *enonce1, - char *nonce2, char *nonce, char *reward, + char *confirmed, char *info, char *workinfoid, + char *username, char *workername, char *clientid, + char *enonce1, char *nonce2, char *nonce, char *reward, char *by, char *code, char *inet, tv_t *cd, bool igndup, char *id, K_TREE *trf_root) { @@ -4342,11 +4321,10 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, BLOCKS *row, *oldblocks; USERS *users; char *upd, *ins; - char *params[17 + HISTORYDATECOUNT]; + char *params[18 + HISTORYDATECOUNT]; bool ok = false, update_old = false; int n, par = 0; - char want = '?'; - char *st = NULL; + char *want = NULL, *st = NULL; LOGDEBUG("%s(): add", __func__); @@ -4398,6 +4376,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, } STRNCPY(row->confirmed, confirmed); + STRNCPY(row->info, info); TXT_TO_BIGINT("workinfoid", workinfoid, row->workinfoid); STRNCPY(row->workername, workername); TXT_TO_INT("clientid", clientid, row->clientid); @@ -4428,6 +4407,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, params[par++] = str_to_buf(row->nonce, NULL, 0); params[par++] = bigint_to_buf(row->reward, NULL, 0); params[par++] = str_to_buf(row->confirmed, NULL, 0); + params[par++] = str_to_buf(row->info, NULL, 0); params[par++] = double_to_buf(row->diffacc, NULL, 0); params[par++] = double_to_buf(row->diffinv, NULL, 0); params[par++] = double_to_buf(row->shareacc, NULL, 0); @@ -4440,9 +4420,9 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, ins = "insert into blocks " "(height,blockhash,workinfoid,userid,workername," "clientid,enonce1,nonce2,nonce,reward,confirmed," - "diffacc,diffinv,shareacc,shareinv,elapsed," + "info,diffacc,diffinv,shareacc,shareinv,elapsed," "statsconfirmed" - HISTORYDATECONTROL ") values (" PQPARAM22 ")"; + HISTORYDATECONTROL ") values (" PQPARAM23 ")"; if (conn == NULL) { conn = dbconnect(); @@ -4458,10 +4438,11 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, } // We didn't use a Begin ok = true; - userinfo_block(row, true); + userinfo_block(row, INFO_NEW); goto unparam; break; case BLOCKS_ORPHAN: + case BLOCKS_REJECT: case BLOCKS_42: // These shouldn't be possible until startup completes if (!startup_complete) { @@ -4473,7 +4454,6 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, height, hash_dsp, cd_buf); goto flail; } - want = BLOCKS_CONFIRM; case BLOCKS_CONFIRM: if (!old_b_item) { tv_to_buf(cd, cd_buf, sizeof(cd_buf)); @@ -4482,16 +4462,37 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, height, hash_dsp, cd_buf); goto flail; } - if (confirmed[0] == BLOCKS_CONFIRM) - want = BLOCKS_NEW; - if (oldblocks->confirmed[0] != want) { + switch (confirmed[0]) { + case BLOCKS_CONFIRM: + if (oldblocks->confirmed[0] != BLOCKS_NEW) + want = BLOCKS_NEW_STR; + break; + case BLOCKS_42: + if (oldblocks->confirmed[0] != BLOCKS_CONFIRM) + want = BLOCKS_CONFIRM_STR; + break; + case BLOCKS_ORPHAN: + if (oldblocks->confirmed[0] != BLOCKS_NEW && + oldblocks->confirmed[0] != BLOCKS_CONFIRM) + want = BLOCKS_N_C_STR; + break; + case BLOCKS_REJECT: + if (oldblocks->confirmed[0] != BLOCKS_NEW && + oldblocks->confirmed[0] != BLOCKS_CONFIRM && + oldblocks->confirmed[0] != BLOCKS_ORPHAN && + oldblocks->confirmed[0] != BLOCKS_REJECT) + want = BLOCKS_N_C_O_R_STR; + break; + } + if (want) { // No mismatch messages during startup if (startup_complete) { tv_to_buf(cd, cd_buf, sizeof(cd_buf)); - LOGERR("%s(): New Status: %s requires Status: %c. " - "Ignored: Status: %s, Block: %s/...%s/%s", + LOGERR("%s(): New Status: (%s)%s requires Status: %s. " + "Ignored: Status: (%s)%s, Block: %s/...%s/%s", __func__, - blocks_confirmed(confirmed), want, + confirmed, blocks_confirmed(confirmed), + want, oldblocks->confirmed, blocks_confirmed(oldblocks->confirmed), height, hash_dsp, cd_buf); } @@ -4511,8 +4512,10 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, } // New is mostly a copy of the old - memcpy(row, oldblocks, sizeof(*row)); + copy_blocks(row, oldblocks); STRNCPY(row->confirmed, confirmed); + if (info && *info) + STRNCPY(row->info, info); if (confirmed[0] == BLOCKS_CONFIRM) { row->diffacc = pool.diffacc; row->diffinv = pool.diffinv; @@ -4546,6 +4549,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, params[par++] = str_to_buf(row->blockhash, NULL, 0); params[par++] = tv_to_buf(cd, NULL, 0); params[par++] = str_to_buf(row->confirmed, NULL, 0); + params[par++] = str_to_buf(row->info, NULL, 0); if (confirmed[0] == BLOCKS_CONFIRM) { params[par++] = double_to_buf(row->diffacc, NULL, 0); @@ -4553,34 +4557,34 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, params[par++] = double_to_buf(row->shareacc, NULL, 0); params[par++] = double_to_buf(row->shareinv, NULL, 0); HISTORYDATEPARAMS(params, par, row); - PARCHKVAL(par, 7 + HISTORYDATECOUNT, params); // 12 as per ins + PARCHKVAL(par, 8 + HISTORYDATECOUNT, params); // 13 as per ins ins = "insert into blocks " "(height,blockhash,workinfoid,userid,workername," "clientid,enonce1,nonce2,nonce,reward,confirmed," - "diffacc,diffinv,shareacc,shareinv,elapsed," + "info,diffacc,diffinv,shareacc,shareinv,elapsed," "statsconfirmed" HISTORYDATECONTROL ") select " "height,blockhash,workinfoid,userid,workername," "clientid,enonce1,nonce2,nonce,reward," - "$3,$4,$5,$6,$7,elapsed,statsconfirmed," - "$8,$9,$10,$11,$12 from blocks where " + "$3,$4,$5,$6,$7,$8,elapsed,statsconfirmed," + "$9,$10,$11,$12,$13 from blocks where " "blockhash=$1 and "EDDB"=$2"; } else { HISTORYDATEPARAMS(params, par, row); - PARCHKVAL(par, 3 + HISTORYDATECOUNT, params); // 8 as per ins + PARCHKVAL(par, 4 + HISTORYDATECOUNT, params); // 9 as per ins ins = "insert into blocks " "(height,blockhash,workinfoid,userid,workername," "clientid,enonce1,nonce2,nonce,reward,confirmed," - "diffacc,diffinv,shareacc,shareinv,elapsed," + "info,diffacc,diffinv,shareacc,shareinv,elapsed," "statsconfirmed" HISTORYDATECONTROL ") select " "height,blockhash,workinfoid,userid,workername," "clientid,enonce1,nonce2,nonce,reward," - "$3,diffacc,diffinv,shareacc,shareinv,elapsed," + "$3,$4,diffacc,diffinv,shareacc,shareinv,elapsed," "statsconfirmed," - "$4,$5,$6,$7,$8 from blocks where " + "$5,$6,$7,$8,$9 from blocks where " "blockhash=$1 and "EDDB"=$2"; } @@ -4594,7 +4598,9 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, update_old = true; if (confirmed[0] == BLOCKS_ORPHAN) - userinfo_block(row, false); + userinfo_block(row, INFO_ORPHAN); + else if (confirmed[0] == BLOCKS_REJECT) + userinfo_block(row, INFO_REJECT); break; default: LOGERR("%s(): %s.failed.invalid confirm='%s'", @@ -4684,6 +4690,7 @@ flail: } break; case BLOCKS_ORPHAN: + case BLOCKS_REJECT: case BLOCKS_42: default: blk = false; @@ -4709,14 +4716,14 @@ bool blocks_fill(PGconn *conn) BLOCKS *row; char *field; char *sel; - int fields = 17; + int fields = 18; bool ok; LOGDEBUG("%s(): select", __func__); sel = "select " "height,blockhash,workinfoid,userid,workername," - "clientid,enonce1,nonce2,nonce,reward,confirmed," + "clientid,enonce1,nonce2,nonce,reward,confirmed,info," "diffacc,diffinv,shareacc,shareinv,elapsed,statsconfirmed" HISTORYDATECONTROL " from blocks"; @@ -4805,6 +4812,11 @@ bool blocks_fill(PGconn *conn) break; TXT_TO_STR("confirmed", field, row->confirmed); + PQ_GET_FLD(res, i, "info", field, ok); + if (!ok) + break; + TXT_TO_STR("info", field, row->info); + PQ_GET_FLD(res, i, "diffacc", field, ok); if (!ok) break; @@ -4851,9 +4863,11 @@ bool blocks_fill(PGconn *conn) } if (CURRENT(&(row->expirydate))) { - _userinfo_block(row, true, false); + _userinfo_block(row, INFO_NEW, false); if (row->confirmed[0] == BLOCKS_ORPHAN) - _userinfo_block(row, false, false); + _userinfo_block(row, INFO_ORPHAN, false); + else if (row->confirmed[0] == BLOCKS_REJECT) + _userinfo_block(row, INFO_REJECT, false); } } if (!ok) @@ -5097,6 +5111,7 @@ void payouts_add_ram(bool ok, K_ITEM *p_item, K_ITEM *old_p_item, tv_t *cd) K_WLOCK(payouts_free); if (!ok) { // Cleanup for the calling function + free_payouts_data(p_item); k_add_head(payouts_free, p_item); } else { if (old_p_item) { @@ -5601,7 +5616,7 @@ bool payouts_fill(PGconn *conn) tick(); } if (!ok) { - FREENULL(row->stats); + free_payouts_data(item); k_add_head(payouts_free, item); } @@ -6425,7 +6440,6 @@ bool markersummary_fill(PGconn *conn) bzero(p_row, sizeof(*p_row)); p_row->markerid = row->markerid; POOL_MS(p_row); - LIST_MEM_ADD(markersummary_free, p_row->workername); markersummary_pool_root = add_to_ktree(markersummary_pool_root, p_item, cmp_markersummary); @@ -6448,7 +6462,7 @@ bool markersummary_fill(PGconn *conn) tick(); } if (!ok) { - FREENULL(row->workername); + free_markersummary_data(item); k_add_head(markersummary_free, item); } @@ -6605,12 +6619,10 @@ bool _workmarkers_process(PGconn *conn, bool already, bool add, } } - row->poolinstance = strdup(poolinstance); - LIST_MEM_ADD(workmarkers_free, poolinstance); + DUP_POINTER(workmarkers_free, row->poolinstance, poolinstance); row->workinfoidend = workinfoidend; row->workinfoidstart = workinfoidstart; - row->description = strdup(description); - LIST_MEM_ADD(workmarkers_free, description); + DUP_POINTER(workmarkers_free, row->description, description); STRNCPY(row->status, status); HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); @@ -6658,23 +6670,7 @@ unparam: K_WLOCK(workmarkers_free); if (!ok) { if (wm_item) { - DATA_WORKMARKERS(row, wm_item); - if (row->poolinstance) { - if (row->poolinstance != EMPTY) { - LIST_MEM_SUB(workmarkers_free, - row->poolinstance); - free(row->poolinstance); - } - row->poolinstance = NULL; - } - if (row->description) { - if (row->description != EMPTY) { - LIST_MEM_SUB(workmarkers_free, - row->description); - free(row->description); - } - row->description = NULL; - } + free_workmarkers_data(wm_item); k_add_head(workmarkers_free, wm_item); } } @@ -6820,8 +6816,10 @@ bool workmarkers_fill(PGconn *conn) tick(); } - if (!ok) + if (!ok) { + free_workmarkers_data(item); k_add_head(workmarkers_free, item); + } K_WUNLOCK(workmarkers_free); PQclear(res); @@ -6920,13 +6918,10 @@ bool _marks_process(PGconn *conn, bool add, char *poolinstance, K_WUNLOCK(marks_free); DATA_MARKS(row, m_item); bzero(row, sizeof(*row)); - row->poolinstance = strdup(poolinstance); - LIST_MEM_ADD(marks_free, poolinstance); + DUP_POINTER(marks_free, row->poolinstance, poolinstance); row->workinfoid = workinfoid; - row->description = strdup(description); - LIST_MEM_ADD(marks_free, description); - row->extra = strdup(extra); - LIST_MEM_ADD(marks_free, extra); + DUP_POINTER(marks_free, row->description, description); + DUP_POINTER(marks_free, row->extra, extra); STRNCPY(row->marktype, marktype); STRNCPY(row->status, status); HISTORYDATEINIT(row, cd, by, code, inet); @@ -6991,32 +6986,10 @@ unparam: K_WLOCK(marks_free); if (!ok) { if (m_item) { - DATA_MARKS(row, m_item); - if (row->poolinstance) { - if (row->poolinstance != EMPTY) { - LIST_MEM_SUB(marks_free, row->poolinstance); - free(row->poolinstance); - } - row->poolinstance = NULL; - } - if (row->description) { - if (row->description != EMPTY) { - LIST_MEM_SUB(marks_free, row->description); - free(row->description); - } - row->description = NULL; - } - if (row->extra) { - if (row->extra != EMPTY) { - LIST_MEM_SUB(marks_free, row->extra); - free(row->extra); - } - row->extra = NULL; - } + free_marks_data(m_item); k_add_head(marks_free, m_item); } - } - else { + } else { if (old_m_item) { marks_root = remove_from_ktree(marks_root, old_m_item, cmp_marks); copy_tv(&(oldmarks->expirydate), cd); @@ -7123,8 +7096,10 @@ bool marks_fill(PGconn *conn) tick(); } - if (!ok) + if (!ok) { + free_marks_data(item); k_add_head(marks_free, item); + } K_WUNLOCK(marks_free); PQclear(res);