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..0b72e58b 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..05ad4521 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) diff --git a/pool/page_2fa.php b/pool/page_2fa.php index 0e1a8c2f..530c9346 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 .= ''; 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 .= ''; + $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 .= ''; break; case 'ok': @@ -60,16 +87,51 @@ 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 .= ''; - $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 .= '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 +139,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 +173,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 bce95e0e..ebd76756 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -18,7 +18,7 @@ function erlcolour($erl) } else # ($erl > 0.5) { - $ref = (-0.3 - log10(1.0 - $erl)) * 255; + $red = (-0.3 - log10(1.0 - $erl)) * 255; if ($red < 0) $red = 0; if ($red > 255) @@ -194,28 +194,51 @@ 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 = ''; + 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') + 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])) @@ -243,7 +266,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); @@ -264,7 +287,7 @@ 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"; @@ -295,7 +318,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_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 c0c78bdd..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; @@ -4680,7 +4683,7 @@ static void *listener(void *arg) LOGEMERG("ABORTING"); everyone_die = true; } - return NULL; + goto sayonara; } if (!everyone_die) { @@ -4789,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 61271803..740eb604 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.211" +#define DB_VERSION "1.0.2" +#define CKDB_VERSION DB_VERSION"-1.220" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -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 */ @@ -1042,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; @@ -1461,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; @@ -1508,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 @@ -1521,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 @@ -1593,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 @@ -1993,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; @@ -2049,6 +2074,8 @@ 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); @@ -2061,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); @@ -2326,7 +2359,7 @@ extern K_ITEM *_find_create_userinfo(int64_t userid, bool lock, WHERE_FFL_ARGS); extern void _userinfo_update(SHARES *shares, SHARESUMMARY *sharesummary, 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 @@ -2459,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); @@ -2574,5 +2607,7 @@ extern K_ITEM *gen_2fa_key(K_ITEM *old_u_item, int32_t entropy, char *by, extern bool check_2fa(USERS *users, int32_t value); extern bool 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 bdedbf89..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, @@ -3976,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: @@ -4427,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: @@ -4708,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) @@ -4752,7 +4833,10 @@ 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; @@ -6164,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 ba9c82f4..d285e9ac 100644 --- a/src/ckdb_crypt.c +++ b/src/ckdb_crypt.c @@ -117,8 +117,7 @@ K_ITEM *gen_2fa_key(K_ITEM *old_u_item, int32_t entropy, char *by, char *code, u_item = k_unlink_head(users_free); K_WUNLOCK(users_free); DATA_USERS(users, u_item); - memcpy(users, old_users, sizeof(*users)); - DUP_POINTER(users_free, users->userdata, old_users->userdata); + 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, @@ -194,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; } @@ -220,8 +227,7 @@ bool tst_2fa(K_ITEM *old_u_item, int32_t value, char *by, char *code, u_item = k_unlink_head(users_free); K_WUNLOCK(users_free); DATA_USERS(users, u_item); - memcpy(users, old_users, sizeof(*users)); - DUP_POINTER(users_free, users->userdata, old_users->userdata); + 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); @@ -229,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 697e9c43..f2c491ee 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -161,6 +161,16 @@ void _free_seqset_data(K_ITEM *item, bool lock) } } +/* Data copy functions (added here as needed) + All pointers need to initialised since DUP_POINTER will free them */ + +void copy_users(USERS *newu, USERS *oldu) +{ + memcpy(newu, oldu, sizeof(*newu)); + newu->userdata = NULL; + DUP_POINTER(users_free, newu->userdata, oldu->userdata); +} + // Clear text printable version of txt up to first '\0' char *_safe_text(char *txt, bool shownull) { @@ -2645,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; } @@ -2885,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; @@ -2934,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; @@ -3327,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, @@ -4881,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; @@ -4891,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 ec7647c7..f34fab64 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -415,7 +415,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,7 +428,6 @@ bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash, STRNCPY(row->emailaddress, email); if (status) STRNCPY(row->status, status); - DUP_POINTER(users_free, row->userdata, users->userdata); HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); @@ -4193,7 +4192,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; @@ -4305,9 +4304,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) { @@ -4321,11 +4320,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__); @@ -4377,6 +4375,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); @@ -4407,6 +4406,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); @@ -4419,7 +4419,7 @@ 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 ")"; @@ -4437,10 +4437,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) { @@ -4452,7 +4453,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)); @@ -4461,16 +4461,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); } @@ -4490,8 +4511,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; @@ -4525,6 +4548,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); @@ -4532,34 +4556,34 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, params[par++] = double_to_buf(row->shareacc, NULL, 0); params[par++] = double_to_buf(row->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"; } @@ -4573,7 +4597,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'", @@ -4663,6 +4689,7 @@ flail: } break; case BLOCKS_ORPHAN: + case BLOCKS_REJECT: case BLOCKS_42: default: blk = false; @@ -4688,14 +4715,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"; @@ -4784,6 +4811,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; @@ -4830,9 +4862,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)