diff --git a/CHANGELOG.md b/CHANGELOG.md index dc04771102..36a8d9d113 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,38 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [5.0.2.0] 2020-10-08, leisure +### Added + - trivial: Add and update copyright headers in Gridcoin files #1897 (@cyrossignol) + - refactor: port chainparams #1878 (@div72) + - gui: Update default font to Inter-Regular and console font to Inconsolata (@opsinphark, @jamescowens) + - gui: Add "review beacon verification" button to wizard summary page #1912 (@cyrossignol) + - rpc, wallet: Implement liststakes #1909 (@jamescowens) + - rpc: Add "getlaststake" RPC function #1913 (@cyrossignol) + - gui: Install bold variant of Inter font #1914 (@cyrossignol) + +### Changed + - refactor: Consolidate Gridcoin-specific code #1894 (@cyrossignol) + - script: Setup improvements #1895 (@nathanielcwm) + - gui: Diagnostics refresh #1899 (@jamescowens) + - superblock: Optimize superblock size calculation #1906 (@cyrossignol) + - gui: Adjust stylesheets and scale icons to improve HiDPI side toolbar display #1911 (@jamescowens) + - doc: Tell user to disable win32 application support in WSL (for building) #1917 (@nathanielcwm) + - rpc: Revise and expand help for beaconconvergence rpc call #1918 (@jamescowens) + - scheduler: Increase default update check interval to 5 days #1920 (@cyrossignol) + - gui: Prevent multiple dialogs from being open at the same time #1922 (@scribblemaniac) + +### Removed + - refactor: Clean up remaining legacy timer code #1892 (@cyrossignol) + +### Fixed + - build: Add --without-brotli option to curl.mk #1902 (@G_UK) + - test: Remove fs_tests... file after the fs test #1903 (@div72) + - util, gui: Fix shutdown segfault and repair broken overview page staking status #1901 (@jamescowens) + - scraper: Fix order of destruction for global scraper objects #1904 (@cyrossignol) + - scraper: Fix global object destruction order for MacOS #1905 (@cyrossignol) + - util: Decouple out-of-sync state from block acceptance #1921 (@cyrossignol) + ## [5.0.1.0] 2020-09-20, leisure ### Added - wallet, rpc: Implement backup file management functionality #1735 (@jamescowens) diff --git a/configure.ac b/configure.ac index 38339ccfd9..abf8bf21f9 100755 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 5) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 1) +define(_CLIENT_VERSION_REVISION, 2) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/depends/packages/curl.mk b/depends/packages/curl.mk index b99403aea9..d9ed3ea56e 100755 --- a/depends/packages/curl.mk +++ b/depends/packages/curl.mk @@ -9,6 +9,7 @@ $(package)_dependencies=openssl define $(package)_set_vars $(package)_config_opts=--disable-shared $(package)_config_opts+= --enable-static + $(package)_config_opts+= --without-brotli $(package)_config_opts_release+=--disable-debug-mode $(package)_config_opts_linux+=--with-pic # Disable OpenSSL for Windows and use native SSL stack (SSPI/Schannel): diff --git a/doc/build-windows.md b/doc/build-windows.md index d02eb0f439..9da9905bdc 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -64,6 +64,9 @@ First, install the general dependencies: A host toolchain (`build-essential`) is necessary because some dependency packages need to build host utilities that are used in the build process. +If you want to build the windows installer with `make deploy` you need [NSIS](https://nsis.sourceforge.io/Main_Page): + + sudo apt install nsis Acquire the source in the usual way: @@ -87,15 +90,22 @@ Note that for WSL the Gridcoin source path MUST be somewhere in the default moun example /usr/src/Gridcoin-Research, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. This means you cannot use a directory that is located directly on the host Windows file system to perform the build. +Additional WSL Note: WSL support for [launching Win32 applications](https://docs.microsoft.com/en-us/archive/blogs/wsl/windows-and-ubuntu-interoperability#launching-win32-applications-from-within-wsl) +results in `Autoconf` configure scripts being able to execute Windows Portable Executable files. This can cause +unexpected behaviour during the build, such as Win32 error dialogs for missing libraries. The recommended approach +is to temporarily disable WSL support for Win32 applications. + Build using: PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var + sudo bash -c "echo 0 > /proc/sys/fs/binfmt_misc/status" # Disable WSL support for Win32 applications. cd depends make HOST=x86_64-w64-mingw32 cd .. ./autogen.sh # not required when building from tarball CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/ make + sudo bash -c "echo 1 > /proc/sys/fs/binfmt_misc/status" # Enable WSL support for Win32 applications. ## Building for 32-bit Windows @@ -117,12 +127,14 @@ For WSL use: Then build using: + sudo bash -c "echo 0 > /proc/sys/fs/binfmt_misc/status" # Disable WSL support for Win32 applications. cd depends make HOST=i686-w64-mingw32 cd .. ./autogen.sh # not required when building from tarball CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site ./configure --prefix=/ make + sudo bash -c "echo 1 > /proc/sys/fs/binfmt_misc/status" # Enable WSL support for Win32 applications. ## Depends system @@ -137,3 +149,6 @@ as they appear in the release `.zip` archive. This can be done in the following way. This will install to `c:\workspace\Gridcoin-Research`, for example: make install DESTDIR=/mnt/c/workspace/Gridcoin-Research +You can also create an installer using: + + make deploy diff --git a/share/pixmaps/GrcInstallBanner.jpg b/share/pixmaps/GrcInstallBanner.jpg deleted file mode 100644 index 2c4fdbad11..0000000000 Binary files a/share/pixmaps/GrcInstallBanner.jpg and /dev/null differ diff --git a/share/pixmaps/addressbook16.bmp b/share/pixmaps/addressbook16.bmp deleted file mode 100644 index 16f1988dd5..0000000000 Binary files a/share/pixmaps/addressbook16.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook16mask.bmp b/share/pixmaps/addressbook16mask.bmp deleted file mode 100644 index d3a478d1ad..0000000000 Binary files a/share/pixmaps/addressbook16mask.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook20.bmp b/share/pixmaps/addressbook20.bmp deleted file mode 100644 index ad10547144..0000000000 Binary files a/share/pixmaps/addressbook20.bmp and /dev/null differ diff --git a/share/pixmaps/addressbook20mask.bmp b/share/pixmaps/addressbook20mask.bmp deleted file mode 100644 index 56ce6125db..0000000000 Binary files a/share/pixmaps/addressbook20mask.bmp and /dev/null differ diff --git a/share/pixmaps/check.ico b/share/pixmaps/check.ico deleted file mode 100644 index 0c4e6e8147..0000000000 Binary files a/share/pixmaps/check.ico and /dev/null differ diff --git a/share/pixmaps/favicon.ico b/share/pixmaps/favicon.ico deleted file mode 100644 index 0d1d0fe46a..0000000000 Binary files a/share/pixmaps/favicon.ico and /dev/null differ diff --git a/share/pixmaps/gradient75.png b/share/pixmaps/gradient75.png deleted file mode 100644 index 7bc0c995ec..0000000000 Binary files a/share/pixmaps/gradient75.png and /dev/null differ diff --git a/share/pixmaps/gradientmiddle.png b/share/pixmaps/gradientmiddle.png deleted file mode 100644 index 383bccb3c0..0000000000 Binary files a/share/pixmaps/gradientmiddle.png and /dev/null differ diff --git a/share/pixmaps/grc-small.png b/share/pixmaps/grc-small.png deleted file mode 100644 index c6030b6c52..0000000000 Binary files a/share/pixmaps/grc-small.png and /dev/null differ diff --git a/share/pixmaps/grc.png b/share/pixmaps/grc.png deleted file mode 100644 index a0b87c4a73..0000000000 Binary files a/share/pixmaps/grc.png and /dev/null differ diff --git a/share/pixmaps/grclogo.png b/share/pixmaps/grclogo.png deleted file mode 100644 index 1cf93e91f7..0000000000 Binary files a/share/pixmaps/grclogo.png and /dev/null differ diff --git a/share/pixmaps/grcsimple - Copy.png b/share/pixmaps/grcsimple - Copy.png deleted file mode 100644 index 7e2412be78..0000000000 Binary files a/share/pixmaps/grcsimple - Copy.png and /dev/null differ diff --git a/share/pixmaps/grcsm.png b/share/pixmaps/grcsm.png deleted file mode 100644 index 0335628c3d..0000000000 Binary files a/share/pixmaps/grcsm.png and /dev/null differ diff --git a/share/pixmaps/gridcoin horizontal green.png b/share/pixmaps/gridcoin horizontal green.png deleted file mode 100644 index 274246445f..0000000000 Binary files a/share/pixmaps/gridcoin horizontal green.png and /dev/null differ diff --git a/share/pixmaps/gridcoin horizontal.jpg b/share/pixmaps/gridcoin horizontal.jpg deleted file mode 100644 index 8073a33d29..0000000000 Binary files a/share/pixmaps/gridcoin horizontal.jpg and /dev/null differ diff --git a/share/pixmaps/gridcoin horizontal.png b/share/pixmaps/gridcoin horizontal.png deleted file mode 100644 index 1cf93e91f7..0000000000 Binary files a/share/pixmaps/gridcoin horizontal.png and /dev/null differ diff --git a/share/pixmaps/gridcoin-bc.ico b/share/pixmaps/gridcoin-bc.ico deleted file mode 100644 index 0d1d0fe46a..0000000000 Binary files a/share/pixmaps/gridcoin-bc.ico and /dev/null differ diff --git a/share/pixmaps/gridcoin.ico b/share/pixmaps/gridcoin.ico index 0d1d0fe46a..3e87a68de1 100644 Binary files a/share/pixmaps/gridcoin.ico and b/share/pixmaps/gridcoin.ico differ diff --git a/share/pixmaps/gridcoin.png b/share/pixmaps/gridcoin.png deleted file mode 100644 index 495c999216..0000000000 Binary files a/share/pixmaps/gridcoin.png and /dev/null differ diff --git a/share/pixmaps/gridcoin128.png b/share/pixmaps/gridcoin128.png deleted file mode 100644 index d8f9f22e11..0000000000 Binary files a/share/pixmaps/gridcoin128.png and /dev/null differ diff --git a/share/pixmaps/gridcoin16.ico b/share/pixmaps/gridcoin16.ico deleted file mode 100644 index 8d11ce2f69..0000000000 Binary files a/share/pixmaps/gridcoin16.ico and /dev/null differ diff --git a/share/pixmaps/gridcoin256.png b/share/pixmaps/gridcoin256.png deleted file mode 100644 index 69493c6a68..0000000000 Binary files a/share/pixmaps/gridcoin256.png and /dev/null differ diff --git a/share/pixmaps/gridcoin32.ico b/share/pixmaps/gridcoin32.ico deleted file mode 100644 index 0d1d0fe46a..0000000000 Binary files a/share/pixmaps/gridcoin32.ico and /dev/null differ diff --git a/share/pixmaps/gridcoin32.png b/share/pixmaps/gridcoin32.png deleted file mode 100644 index 096340dac2..0000000000 Binary files a/share/pixmaps/gridcoin32.png and /dev/null differ diff --git a/share/pixmaps/gridcoin64.ico b/share/pixmaps/gridcoin64.ico deleted file mode 100644 index 3c8ece7085..0000000000 Binary files a/share/pixmaps/gridcoin64.ico and /dev/null differ diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp index e6e33b402b..168b7a886f 100644 Binary files a/share/pixmaps/nsis-header.bmp and b/share/pixmaps/nsis-header.bmp differ diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp index 3b1e243e14..68a5e1082a 100644 Binary files a/share/pixmaps/nsis-wizard.bmp and b/share/pixmaps/nsis-wizard.bmp differ diff --git a/share/pixmaps/nsis-wizard.png b/share/pixmaps/nsis-wizard.png deleted file mode 100644 index 808258f12e..0000000000 Binary files a/share/pixmaps/nsis-wizard.png and /dev/null differ diff --git a/share/pixmaps/send16.bmp b/share/pixmaps/send16.bmp deleted file mode 100644 index 4097463034..0000000000 Binary files a/share/pixmaps/send16.bmp and /dev/null differ diff --git a/share/pixmaps/send16mask.bmp b/share/pixmaps/send16mask.bmp deleted file mode 100644 index 06c747f934..0000000000 Binary files a/share/pixmaps/send16mask.bmp and /dev/null differ diff --git a/share/pixmaps/send16masknoshadow.bmp b/share/pixmaps/send16masknoshadow.bmp deleted file mode 100644 index faf24e0d8a..0000000000 Binary files a/share/pixmaps/send16masknoshadow.bmp and /dev/null differ diff --git a/share/pixmaps/send20.bmp b/share/pixmaps/send20.bmp deleted file mode 100644 index 334b1abf38..0000000000 Binary files a/share/pixmaps/send20.bmp and /dev/null differ diff --git a/share/pixmaps/send20mask.bmp b/share/pixmaps/send20mask.bmp deleted file mode 100644 index f124d0da08..0000000000 Binary files a/share/pixmaps/send20mask.bmp and /dev/null differ diff --git a/share/pixmaps/splash.jpg b/share/pixmaps/splash.jpg deleted file mode 100644 index d6bc96307a..0000000000 Binary files a/share/pixmaps/splash.jpg and /dev/null differ diff --git a/share/pixmaps/splash.png b/share/pixmaps/splash.png deleted file mode 100644 index a3b3b546f0..0000000000 Binary files a/share/pixmaps/splash.png and /dev/null differ diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 5770d79dc3..6648d248ae 100644 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -17,6 +17,7 @@ SetCompressor /SOLID lzma !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_RIGHT !define MUI_HEADERIMAGE_BITMAP "${ICONDIR}\nsis-header.bmp" +!define MUI_WELCOMEFINISHPAGE_BITMAP "${ICONDIR}\nsis-wizard.bmp" !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM !define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY} @@ -161,13 +162,21 @@ Function .onInit ${If} ${RunningX64} ; disable registry redirection (enable access to 64-bit portion of registry) SetRegView 64 + ReadRegStr $INSTDIR HKCU "${REGKEY}" "Path" + StrCmp $INSTDIR "" 0 rununin + StrCpy $INSTDIR $PROGRAMFILES64\GridcoinResearch ${Else} MessageBox MB_OK|MB_ICONSTOP "Cannot install 64-bit version on a 32-bit system." Abort ${EndIf} +!else + ReadRegStr $INSTDIR HKCU "${REGKEY}" "Path" + StrCmp $INSTDIR "" 0 rununin + StrCpy $INSTDIR $PROGRAMFILES\GridcoinResearch !endif - Exec $INSTDIR\uninst.exe - Delete $INSTDIR\*" + rununin: + Exec $INSTDIR\uninst.exe + Delete $INSTDIR\*" FunctionEnd # Uninstaller functions diff --git a/src/Makefile.am b/src/Makefile.am index 801dcae4bf..5d0757ebe9 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,47 +60,60 @@ GRIDCOIN_CORE_H = \ addrdb.h \ addrman.h \ alert.h \ - appcache.h \ arith_uint256.h \ attributes.h \ - backup.h \ banman.h \ base58.h \ bignum.h \ - block.h \ - boinc.h \ + chainparams.h \ + chainparamsbase.h \ checkpoints.h \ compat.h \ compat/byteswap.h \ compat/endian.h \ + consensus/consensus.h \ + consensus/params.h \ crypter.h \ - enumbytes.h \ - filehash.h \ fs.h \ fwd.h \ - global_objects.hpp \ - global_objects_noui.hpp \ - gridcoin.h \ gridcoin/account.h \ gridcoin/accrual/computer.h \ gridcoin/accrual/newbie.h \ gridcoin/accrual/null.h \ gridcoin/accrual/research_age.h \ gridcoin/accrual/snapshot.h \ + gridcoin/appcache.h \ + gridcoin/backup.h \ gridcoin/beacon.h \ + gridcoin/boinc.h \ gridcoin/claim.h \ gridcoin/contract/contract.h \ gridcoin/contract/handler.h \ gridcoin/contract/message.h \ gridcoin/contract/payload.h \ gridcoin/cpid.h \ + gridcoin/gridcoin.h \ gridcoin/magnitude.h \ gridcoin/project.h \ gridcoin/quorum.h \ gridcoin/researcher.h \ + gridcoin/scraper/fwd.h \ + gridcoin/scraper/http.h \ + gridcoin/scraper/scraper.h \ + gridcoin/scraper/scraper_net.h \ + gridcoin/staking/difficulty.h \ + gridcoin/staking/exceptions.h \ + gridcoin/staking/kernel.h \ + gridcoin/staking/reward.h \ + gridcoin/staking/status.h \ gridcoin/superblock.h \ + gridcoin/support/block_finder.h \ + gridcoin/support/enumbytes.h \ + gridcoin/support/filehash.h \ + gridcoin/support/xml.h \ gridcoin/tally.h \ gridcoin/tx_message.h \ + gridcoin/upgrade.h \ gridcoin/voting/builders.h \ gridcoin/voting/claims.h \ gridcoin/voting/fwd.h \ @@ -111,7 +124,6 @@ GRIDCOIN_CORE_H = \ gridcoin/voting/vote.h \ hash.h \ init.h \ - kernel.h \ key.h \ keystore.h \ logging.h \ @@ -128,10 +140,6 @@ GRIDCOIN_CORE_H = \ rpcprotocol.h \ rpcserver.h \ scheduler.h \ - scraper_net.h \ - scraper/fwd.h \ - scraper/http.h \ - scraper/scraper.h \ script.h \ scrypt.h \ serialize.h \ @@ -148,7 +156,6 @@ GRIDCOIN_CORE_H = \ txdb-leveldb.h \ ui_interface.h \ uint256.h \ - upgrade.h \ util/memory.h \ util/reverse_iterator.h \ util/strencodings.h \ @@ -165,26 +172,37 @@ GRIDCOIN_CORE_H = \ GRIDCOIN_CORE_CPP = addrdb.cpp \ addrman.cpp \ alert.cpp \ - appcache.cpp \ arith_uint256.cpp \ - backup.cpp \ banman.cpp \ - block.cpp \ - boinc.cpp \ + chainparams.cpp \ + chainparamsbase.cpp \ checkpoints.cpp \ crypter.cpp \ fs.cpp \ - gridcoin.cpp \ + gridcoin/appcache.cpp \ + gridcoin/backup.cpp \ gridcoin/beacon.cpp \ + gridcoin/boinc.cpp \ gridcoin/claim.cpp \ gridcoin/contract/contract.cpp \ gridcoin/contract/message.cpp \ gridcoin/cpid.cpp \ + gridcoin/gridcoin.cpp \ gridcoin/project.cpp \ gridcoin/quorum.cpp \ gridcoin/researcher.cpp \ + gridcoin/scraper/http.cpp \ + gridcoin/scraper/scraper.cpp \ + gridcoin/scraper/scraper_net.cpp \ + gridcoin/staking/difficulty.cpp \ + gridcoin/staking/exceptions.cpp \ + gridcoin/staking/kernel.cpp \ + gridcoin/staking/reward.cpp \ + gridcoin/staking/status.cpp \ gridcoin/superblock.cpp \ + gridcoin/support/block_finder.cpp \ gridcoin/tally.cpp \ + gridcoin/upgrade.cpp \ gridcoin/voting/builders.cpp \ gridcoin/voting/claims.cpp \ gridcoin/voting/poll.cpp \ @@ -192,7 +210,6 @@ GRIDCOIN_CORE_CPP = addrdb.cpp \ gridcoin/voting/result.cpp \ gridcoin/voting/vote.cpp \ init.cpp \ - kernel.cpp \ key.cpp \ keystore.cpp \ logging.cpp \ @@ -213,9 +230,6 @@ GRIDCOIN_CORE_CPP = addrdb.cpp \ rpcrawtransaction.cpp \ rpcserver.cpp \ rpcvoting.cpp \ - scraper_net.cpp \ - scraper/http.cpp \ - scraper/scraper.cpp \ script.cpp \ scrypt.cpp \ scrypt-x86_64.S \ @@ -226,7 +240,6 @@ GRIDCOIN_CORE_CPP = addrdb.cpp \ sync.cpp \ txdb-leveldb.cpp \ uint256.cpp \ - upgrade.cpp \ util/strencodings.cpp \ util/threadnames.cpp \ util/time.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index c896caf586..ab29d9f147 100755 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -379,6 +379,11 @@ RES_IMAGES = \ qt/res/images/ic_solo_inactive.svg \ qt/res/images/splash3.png +RES_FONTS = \ + qt/res/fonts/Inconsolata-Regular.ttf \ + qt/res/fonts/Inter-Bold.ttf \ + qt/res/fonts/Inter-Regular.ttf + RES_STYLESHEETS = \ qt/res/stylesheets/light_stylesheet.qss \ qt/res/stylesheets/native_stylesheet.qss \ @@ -403,7 +408,7 @@ qt_libgridcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(GRIDCOIN_INCLUDES) $(GRIDCOIN_QT_ qt_libgridcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_libgridcoinqt_a_SOURCES = $(GRIDCOINRESEARCH_QT_CPP) $(GRIDCOINRESEARCH_QT_H) $(QT_FORMS_UI) \ - $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES) $(RES_STYLESHEETS) + $(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_FONTS) $(RES_MOVIES) $(RES_STYLESHEETS) if TARGET_WINDOWS qt_libgridcoinqt_a_SOURCES += $(GRIDCOIN_CORE_H) $(GRIDCOIN_CORE_CPP) @@ -462,7 +467,7 @@ $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ @rm $(@D)/temp_$( $@ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 76fed185ff..81053f2fc1 100755 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -23,7 +23,6 @@ OTHER_TEST_FILES = \ # test_n binary # GRIDCOIN_TESTS =\ - test/appcache_tests.cpp \ test/checkpoints_tests.cpp \ test/dos_tests.cpp \ test/accounting_tests.cpp \ @@ -32,15 +31,16 @@ GRIDCOIN_TESTS =\ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bignum_tests.cpp \ - test/block_tests.cpp \ - test/enumbytes.cpp \ test/fs_tests.cpp \ test/getarg_tests.cpp \ test/gridcoin_tests.cpp \ + test/gridcoin/appcache_tests.cpp \ + test/gridcoin/block_finder_tests.cpp \ test/gridcoin/beacon_tests.cpp \ test/gridcoin/claim_tests.cpp \ test/gridcoin/contract_tests.cpp \ test/gridcoin/cpid_tests.cpp \ + test/gridcoin/enumbytes_tests.cpp \ test/gridcoin/magnitude_tests.cpp \ test/gridcoin/project_tests.cpp \ test/gridcoin/researcher_tests.cpp \ diff --git a/src/alert.cpp b/src/alert.cpp index 164179eaff..8c6fb0ff9f 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -9,6 +9,7 @@ #include #include "alert.h" +#include "chainparams.h" #include "key.h" #include "net.h" #include "streams.h" @@ -21,15 +22,6 @@ using namespace std; map mapAlerts; CCriticalSection cs_mapAlerts; -// same as master project key now -static const char* pszMainKey = "049ac003b3318d9fe28b2830f6a95a2624ce2a69fb0c0c7ac0b513efcc1e93a6a6e8eba84481155dd82f2f1104e0ff62c69d662b0094639b7106abc5d84f948c0a"; - -// TestNet alerts pubKey -static const char* pszTestKey = "0471dc165db490094d35cde15b1f5d755fa6ad6f2b5ed0f340e3f17f57389c3c2af113a8cbcc885bde73305a553b5640c83021128008ddf882e856336269080496"; - -// TestNet alerts private key -// "308201130201010420b665cff1884e53da26376fd1b433812c9a5a8a4d5221533b15b9629789bb7e42a081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a1440342000471dc165db490094d35cde15b1f5d755fa6ad6f2b5ed0f340e3f17f57389c3c2af113a8cbcc885bde73305a553b5640c83021128008ddf882e856336269080496" - void CUnsignedAlert::SetNull() { nVersion = 1; @@ -153,7 +145,7 @@ bool CAlert::RelayTo(CNode* pnode) const bool CAlert::CheckSignature() const { CKey key; - if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey))) + if (!key.SetPubKey(Params().AlertKey())) return error("CAlert::CheckSignature() : SetPubKey failed"); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CAlert::CheckSignature() : verify signature failed"); diff --git a/src/boinc.cpp b/src/boinc.cpp deleted file mode 100644 index c501b5745a..0000000000 --- a/src/boinc.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "boinc.h" -#include "util.h" - -fs::path GetBoincDataDir(){ - - std::string path = GetArgument("boincdatadir", ""); - if (!path.empty()){ - return fs::path(std::move(path)); - } - - #ifdef WIN32 - HKEY hKey; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup\\", - 0, - KEY_READ|KEY_WOW64_64KEY, - &hKey) == ERROR_SUCCESS){ - - wchar_t szPath[MAX_PATH]; - DWORD dwSize = sizeof(szPath); - - if (RegQueryValueEx(hKey, - L"DATADIR", - NULL, - NULL, - (LPBYTE)&szPath, - &dwSize) == ERROR_SUCCESS){ - RegCloseKey(hKey); - - fs::path path = std::wstring(szPath); - - if (fs::exists(path)){ - return path; - } else { - LogPrintf("Cannot find BOINC data dir %s.", path.string()); - } - } - RegCloseKey(hKey); - } - - if (fs::exists("C:\\ProgramData\\BOINC\\")){ - return "C:\\ProgramData\\BOINC\\"; - } - else if(fs::exists("C:\\Documents and Settings\\All Users\\Application Data\\BOINC\\")){ - return "C:\\Documents and Settings\\All Users\\Application Data\\BOINC\\"; - } - #endif - - #ifdef __linux__ - if (fs::exists("/var/lib/boinc-client/")){ - return "/var/lib/boinc-client/"; - } - else if (fs::exists("/var/lib/boinc/")){ - return "/var/lib/boinc/"; - } - #endif - - #ifdef __APPLE__ - if (fs::exists("/Library/Application Support/BOINC Data/")){ - return "/Library/Application Support/BOINC Data/"; - } - #endif - - LogPrintf("ERROR: Cannot find BOINC data dir"); - return ""; -} diff --git a/src/boinc.h b/src/boinc.h deleted file mode 100644 index 47243f2588..0000000000 --- a/src/boinc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef GRIDCOIN_BOINC_H -#define GRIDCOIN_BOINC_H - -#include - -fs::path GetBoincDataDir(); - -#endif diff --git a/src/chainparams.cpp b/src/chainparams.cpp new file mode 100644 index 0000000000..24e92fce05 --- /dev/null +++ b/src/chainparams.cpp @@ -0,0 +1,196 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparams.h" + +#include "tinyformat.h" +#include "util/strencodings.h" + +#include + +#include +#include + +/* TODO: Uncomment this when CBlock is moved from main.h +static CBlock CreateGenesisBlock(const char* pszTimestamp, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion) +{ + CMutableTransaction txNew; + txNew.nVersion = 1; + txNew.nTime = nTime; + txNew.vin.resize(1); + txNew.vout.resize(1); + txNew.vin[0].scriptSig = CScript() << 0 << CBigNum(42) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vout[0].SetEmpty(); + + CBlock genesis; + genesis.nTime = nTime; + genesis.nBits = nBits; + genesis.nNonce = nNonce; + genesis.nVersion = nVersion; + genesis.vtx.push_back(txNew); + genesis.hashPrevBlock.SetNull(); + genesis.hashMerkleRoot = genesis.BuildMerkleTree(); + return genesis; +} */ + +/** + * Build the genesis block. Note that the output of its generation + * transaction cannot be spent since it did not originally exist in the + * database. + * + * CBlock(hash=00000f762f698b5962aa81e38926c3a3f1f03e0b384850caed34cd9164b7f990, ver=1, + * hashPrevBlock=0000000000000000000000000000000000000000000000000000000000000000, + * hashMerkleRoot=0bd65ac9501e8079a38b5c6f558a99aea0c1bcff478b8b3023d09451948fe841, nTime=1413149999, nBits=1e0fffff, nNonce=1572771, vtx=1, vchBlockSig=) +static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion) +{ + const char* pszTimestamp = "10/11/14 Andrea Rossi Industrial Heat vindicated with LENR validation"; + return CreateGenesisBlock(pszTimestamp, nTime, nNonce, nBits, nVersion); +} */ + +/** + * Main network + */ +class CMainParams : public CChainParams { +public: + CMainParams() { + strNetworkID = CBaseChainParams::MAIN; + consensus.ProtocolV2Height = 85400; + consensus.ResearchAgeHeight = 364501; + consensus.BlockV8Height = 1010000; + consensus.BlockV9Height = 1144000; + consensus.BlockV9TallyHeight = 1144120; + consensus.BlockV10Height = 1420000; + consensus.BlockV11Height = 2053000; + /** + * The message start string is designed to be unlikely to occur in normal data. + * The characters are rarely used upper ASCII, not valid as UTF-8, and produce + * a large 32-bit integer with any alignment. + */ + pchMessageStart[0] = 0x70; + pchMessageStart[1] = 0x35; + pchMessageStart[2] = 0x22; + pchMessageStart[3] = 0x05; + vAlertPubKey = ParseHex("049ac003b3318d9fe28b2830f6a95a2624ce2a69fb0c0c7ac0b513efcc1e93a6a6e8eba84481155dd82f2f1104e0ff62c69d662b0094639b7106abc5d84f948c0a"); + nDefaultPort = 32749; + m_assumed_blockchain_size = 4; + + /* genesis = CreateGenesisBlock(1413033777, 130208, 0x1e0fffff, 1); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x000005a247b397eadfefa58e872bc967c2614797bdc8d4d0e6b09fea5c191599")); + assert(genesis.hashMerkleRoot == uint256S("0x5109d5782a26e6a5a5eb76c7867f3e8ddae2bff026632c36afec5dc32ed8ce9f")); */ + + + base58Prefix[PUBKEY_ADDRESS] = 62; + base58Prefix[SCRIPT_ADDRESS] = 85; + + m_is_test_chain = false; + m_is_mockable_chain = false; + + checkpointData = { + { + { 40, uint256S("0x0000002c305541bceb763e6f7fce2f111cb752acf9777e64c6f02fab5ef4778c")}, + { 50, uint256S("0x000000415ff618b8e72eda69e87dc2f2ff8798a5032babbef36b089da0ae2278")}, + { 6000, uint256S("0x5976ff9d0da7626badf301a9e038ec05d776e5e50839e2505357512945d53b04")}, + { 17000, uint256S("0x92fe9bafd6c9c1acbe8565ade79460505a70180ac5c3b360489037ef7a4aed42")}, + { 27000, uint256S("0x1521cd45d0564cb016e816581dd6e2d030f6333a1dac5b79bea71ca8b0186e8d")}, + { 36500, uint256S("0xcf26a63e66ca95bc7c0189a5239128fd983ef978088f187bd30817aebb2c8424")}, + { 67000, uint256S("0x429a4ed792c6270a263fa679946ff2c510e55e9a3b7234fa789d66bacd3068a0")}, + { 70000, uint256S("0x829c215851d7cdf756e7ba9e2c8eeef61e503b15488ffa4becab77c7961d30c5")}, + { 71000, uint256S("0x708c3319912b19c3547fd9a9a2aa6426c3a4543e84f972b3070a24200bd4fcd3")}, + { 85000, uint256S("0x928f0669b1f036561a2d53b7588b10c5ea2fcb9e2960a9be593b508a7fcceec1")}, + { 91000, uint256S("0x8ed361fa50f6c16fbda4f2c7454dd818f2278151987324825bc1ec1eacfa9be2")}, + {101000, uint256S("0x578efd18f7cd5191be3463a2b0db985375f48ee6e8a8940cc6b91d6847fa3614")}, + {118000, uint256S("0x8f8ea6eaeae707ab935b517f1c334e6324df75ad8e5f9fbc4d9fb3cc7aa2e69f")}, + {120000, uint256S("0xe64d19e39d564cc66e931e88c03207c19e4c9a873ca68ccef16ad712830da726")}, + {122000, uint256S("0xb35d4f385bba3c3cb3f9b6914edd6621bde8f78c8c42f58ec47131ed6aac82a9")}, + {124392, uint256S("0x1496cd55d7adad1ada774542165a04102a91f8f80c6e894c05f1d0c2ff7e5a39")}, + {145000, uint256S("0x99f5d7166ad55d6d0e1ac5c7fffaee1d1dd1ff1409738e0d4f13ac1ae38234cc")}, + {278000, uint256S("0x8066e63198c44b9840f664e795b0315d9b752773b267d6212f35593bc0e3b6f4")}, + {361800, uint256S("0x801981d8a8f5809e34a2881ea97600259e1d9d778fa21752a5f6cff4defcd08d")}, + {500000, uint256S("0x3916b53eaa0eb392ce5d7e4eaf7db4f745187743f167539ffa4dc1a30c06acbd")}, + {700000, uint256S("0x2e45c8a834675b505b96792d198c2dc970f560429c635479c347204044acc59b")}, + {770000, uint256S("0xfc13a63162bc0a5a09acc3f284cf959d6812a027bb54b342a0e1ccaaca8627ce")}, + {850000, uint256S("0xc78b15f25ad990d02256907fab92ab37301d129eaea177fd04acacd56c0cbd22")}, + {950000, uint256S("0x4be0afdb9273d232de0bc75b572d8bcfaa146d9efdbe4a4f1ab775334f175b0f")}, + {1050000, uint256S("0x0753b624cc0ab39d8745b436012ce53c087f7b2e077099e746a9557f569a80f3")}, + {1150000, uint256S("0x0264545b51389faea32ac54bf76cd6efb65701d777e7fa1007584114897067f5")}, + {1250000, uint256S("0x452467f2f74580176375f99dd38e9119d564985ba639fa1303718a51351823ab")}, + {1350000, uint256S("0x813725a075bc3cc254742557ce6d3a680cb97ee863f65c5d9a386c1ac9a8e792")}, + {1450000, uint256S("0x5744777ad775063a3e0b9b9c40ac205e8948904e340d11c3c449fb13914c962b")}, + {1550000, uint256S("0xa37ab3260678f6e7f009b2c11fee14bef6add481b411516201cc35b397859bfb")}, + {1700000, uint256S("0x831a655dd58599fda1815f7275194ff69ca53341694ba81f9941eede25c40885")}, + {1800000, uint256S("0x61bb76ed90de21016de81855d3dc01bd192d17d90de4bdf62e8203c2dde675d7")}, + {1900000, uint256S("0x352ca52f9a22fbf1d241082d3bec716ea5bef6b82811f737ae6486bd7771e1c7")}, + {2000000, uint256S("0x2e1252a6ed6d0e7e556d4d0377b10f4b542ae5d6c9822cb08d68490a2a0bb706")}, + } + }; + + } +}; + +/** + * Testnet + */ +class CTestNetParams : public CChainParams { +public: + CTestNetParams() { + strNetworkID = CBaseChainParams::TESTNET; + consensus.ProtocolV2Height = 2060; + consensus.ResearchAgeHeight = 36501; + consensus.BlockV8Height = 311999; + consensus.BlockV9Height = 399000; + consensus.BlockV9TallyHeight = 399120; + consensus.BlockV10Height = 629409; + consensus.BlockV11Height = 1301500; + + pchMessageStart[0] = 0xcd; + pchMessageStart[1] = 0xf2; + pchMessageStart[2] = 0xc0; + pchMessageStart[3] = 0xef; + vAlertPubKey = ParseHex("0471dc165db490094d35cde15b1f5d755fa6ad6f2b5ed0f340e3f17f57389c3c2af113a8cbcc885bde73305a553b5640c83021128008ddf882e856336269080496"); + // TestNet alerts private key + // "308201130201010420b665cff1884e53da26376fd1b433812c9a5a8a4d5221533b15b9629789bb7e42a081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a1440342000471dc165db490094d35cde15b1f5d755fa6ad6f2b5ed0f340e3f17f57389c3c2af113a8cbcc885bde73305a553b5640c83021128008ddf882e856336269080496" + nDefaultPort = 32748; + m_assumed_blockchain_size = 2; + + /* genesis = CreateGenesisBlock(1406674534, 22436, 0x1f00ffff, 1); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x00006e037d7b84104208ecf2a8638d23149d712ea810da604ee2f2cb39bae713")); + assert(genesis.hashMerkleRoot == uint256S("0x5109d5782a26e6a5a5eb76c7867f3e8ddae2bff026632c36afec5dc32ed8ce9f")); */ + + base58Prefix[PUBKEY_ADDRESS] = 111; + base58Prefix[SCRIPT_ADDRESS] = 196; + + m_is_test_chain = true; + m_is_mockable_chain = false; + + checkpointData = { + { + } + }; + } +}; + +static std::unique_ptr globalChainParams; + +const CChainParams &Params() { + assert(globalChainParams); + return *globalChainParams; +} + +std::unique_ptr CreateChainParams(const std::string& chain) +{ + if (chain == CBaseChainParams::MAIN) + return std::unique_ptr(new CMainParams()); + else if (chain == CBaseChainParams::TESTNET) + return std::unique_ptr(new CTestNetParams()); + throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); +} + +void SelectParams(const std::string& network) +{ + SelectBaseParams(network); + globalChainParams = CreateChainParams(network); +} diff --git a/src/chainparams.h b/src/chainparams.h new file mode 100644 index 0000000000..74e5fcd6d4 --- /dev/null +++ b/src/chainparams.h @@ -0,0 +1,131 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "chainparamsbase.h" +#include "consensus/params.h" +#include "protocol.h" + +#include +#include + + +typedef std::map MapCheckpoints; + +struct CCheckpointData { + MapCheckpoints mapCheckpoints; +}; + +/** + * CChainParams defines various tweakable parameters of a given instance of the + * Gridcoin system. There are two: the main network on which people trade goods + * and services and the public test network + */ +class CChainParams +{ +public: + enum Base58Type { + PUBKEY_ADDRESS, + SCRIPT_ADDRESS, + + MAX_BASE58_TYPES + }; + + const Consensus::Params& GetConsensus() const { return consensus; } + const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } + const std::vector& AlertKey() const { return vAlertPubKey; } + int GetDefaultPort() const { return nDefaultPort; } + + // const CBlock& GenesisBlock() const { return genesis; } + /** If this chain is exclusively used for testing */ + bool IsTestChain() const { return m_is_test_chain; } + /** If this chain allows time to be mocked */ + bool IsMockableChain() const { return m_is_mockable_chain; } + /** Minimum free space (in GB) needed for data directory */ + uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; } + /** Return the network string */ + std::string NetworkIDString() const { return strNetworkID; } + const unsigned char& Base58Prefix(Base58Type type) const { return base58Prefix[type]; } + const CCheckpointData& Checkpoints() const { return checkpointData; } +protected: + CChainParams() {} + + Consensus::Params consensus; + CMessageHeader::MessageStartChars pchMessageStart; + std::vector vAlertPubKey; + int nDefaultPort; + uint64_t m_assumed_blockchain_size; + unsigned char base58Prefix[MAX_BASE58_TYPES]; + std::string strNetworkID; + // CBlock genesis; + bool m_is_test_chain; + bool m_is_mockable_chain; + CCheckpointData checkpointData; +}; + +/** + * Creates and returns a std::unique_ptr of the chosen chain. + * @returns a CChainParams* of the chosen chain. + * @throws a std::runtime_error if the chain is not supported. + */ +std::unique_ptr CreateChainParams(const std::string& chain); + +/** + * Return the currently selected parameters. This won't change after app + * startup, except for unit tests. + */ +const CChainParams &Params(); + +/** + * Sets the params returned by Params() to those for the given chain name. + * @throws std::runtime_error when the chain is not supported. + */ +void SelectParams(const std::string& chain); + +inline bool IsProtocolV2(int nHeight) +{ + return nHeight > Params().GetConsensus().ProtocolV2Height; +} + +inline bool IsResearchAgeEnabled(int nHeight) +{ + return nHeight >= Params().GetConsensus().ResearchAgeHeight; +} + +inline bool IsV8Enabled(int nHeight) +{ + // Start creating V8 blocks after these heights. + // In testnet the first V8 block was created on block height 320000. + return nHeight > Params().GetConsensus().BlockV8Height; +} + +inline bool IsV9Enabled(int nHeight) +{ + return nHeight >= Params().GetConsensus().BlockV9Height; +} + +inline bool IsV9Enabled_Tally(int nHeight) +{ + return nHeight >= Params().GetConsensus().BlockV9TallyHeight; +} + +inline bool IsV10Enabled(int nHeight) +{ + // Testnet used a controlled switch by injecting a v10 block + // using a modified client and different miner trigger rules, + // hence the odd height. + return nHeight >= Params().GetConsensus().BlockV10Height; +} + +inline bool IsV11Enabled(int nHeight) +{ + return nHeight >= Params().GetConsensus().BlockV11Height; +} + +inline int GetSuperblockAgeSpacing(int nHeight) +{ + return (fTestNet ? 86400 : (nHeight > 364500) ? 86400 : 43200); +} diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp new file mode 100644 index 0000000000..83ba2ae87e --- /dev/null +++ b/src/chainparamsbase.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparamsbase.h" + +#include "tinyformat.h" +#include + +const std::string CBaseChainParams::MAIN = "main"; +const std::string CBaseChainParams::TESTNET = "test"; + + +static std::unique_ptr globalChainBaseParams; + +const CBaseChainParams& BaseParams() +{ + assert(globalChainBaseParams); + return *globalChainBaseParams; +} + +std::unique_ptr CreateBaseChainParams(const std::string& chain) +{ + if (chain == CBaseChainParams::MAIN) + return MakeUnique("", 32749); + else if (chain == CBaseChainParams::TESTNET) + return MakeUnique("testnet", 32748); + else + throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); +} + +void SelectBaseParams(const std::string& chain) +{ + globalChainBaseParams = CreateBaseChainParams(chain); +} diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h new file mode 100644 index 0000000000..1e9b9df4bb --- /dev/null +++ b/src/chainparamsbase.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "util/memory.h" + +#include +#include + +class ArgsManager; + +/** + * CBaseChainParams defines the base parameters (shared between bitcoin-cli and bitcoind) + * of a given instance of the Bitcoin system. + */ +class CBaseChainParams +{ +public: + ///@{ + /** Chain name strings */ + static const std::string MAIN; + static const std::string TESTNET; + ///@} + + const std::string& DataDir() const { return strDataDir; } + int RPCPort() const { return nRPCPort; } + + CBaseChainParams() = delete; + CBaseChainParams(const std::string& data_dir, int rpc_port) : nRPCPort(rpc_port), strDataDir(data_dir) {} + +private: + int nRPCPort; + std::string strDataDir; +}; + +/** + * Creates and returns a std::unique_ptr of the chosen chain. + * @returns a CBaseChainParams* of the chosen chain. + * @throws a std::runtime_error if the chain is not supported. + */ +std::unique_ptr CreateBaseChainParams(const std::string& chain); + +/** + * Return the currently selected parameters. This won't change after app + * startup, except for unit tests. + */ +const CBaseChainParams& BaseParams(); + +/** Sets the params returned by Params() to those for the given network. */ +void SelectBaseParams(const std::string& chain); diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index a8832144c8..bd8fce761a 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -2,73 +2,17 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include // for 'map_list_of()' #include +#include "chainparams.h" #include "checkpoints.h" #include "uint256.h" - -static const int nCheckpointSpan = 10; - namespace Checkpoints { - typedef std::map MapCheckpoints; - - // - // What makes a good checkpoint block? - // + Is surrounded by blocks with reasonable timestamps - // (no blocks before with a timestamp after, none after with - // timestamp before) - // + Contains no strange transactions - // - static MapCheckpoints mapCheckpoints = - boost::assign::map_list_of - ( 0, hashGenesisBlock ) - ( 40, uint256S("0x0000002c305541bceb763e6f7fce2f111cb752acf9777e64c6f02fab5ef4778c") ) - ( 50, uint256S("0x000000415ff618b8e72eda69e87dc2f2ff8798a5032babbef36b089da0ae2278") ) - ( 6000, uint256S("0x5976ff9d0da7626badf301a9e038ec05d776e5e50839e2505357512945d53b04") ) - ( 17000, uint256S("0x92fe9bafd6c9c1acbe8565ade79460505a70180ac5c3b360489037ef7a4aed42") ) - ( 27000, uint256S("0x1521cd45d0564cb016e816581dd6e2d030f6333a1dac5b79bea71ca8b0186e8d") ) - ( 36500, uint256S("0xcf26a63e66ca95bc7c0189a5239128fd983ef978088f187bd30817aebb2c8424") ) - ( 67000, uint256S("0x429a4ed792c6270a263fa679946ff2c510e55e9a3b7234fa789d66bacd3068a0") ) - ( 70000, uint256S("0x829c215851d7cdf756e7ba9e2c8eeef61e503b15488ffa4becab77c7961d30c5") ) - ( 71000, uint256S("0x708c3319912b19c3547fd9a9a2aa6426c3a4543e84f972b3070a24200bd4fcd3") ) - ( 85000, uint256S("0x928f0669b1f036561a2d53b7588b10c5ea2fcb9e2960a9be593b508a7fcceec1") ) - ( 91000, uint256S("0x8ed361fa50f6c16fbda4f2c7454dd818f2278151987324825bc1ec1eacfa9be2") ) - (101000, uint256S("0x578efd18f7cd5191be3463a2b0db985375f48ee6e8a8940cc6b91d6847fa3614") ) - (118000, uint256S("0x8f8ea6eaeae707ab935b517f1c334e6324df75ad8e5f9fbc4d9fb3cc7aa2e69f") ) - (120000, uint256S("0xe64d19e39d564cc66e931e88c03207c19e4c9a873ca68ccef16ad712830da726") ) - (122000, uint256S("0xb35d4f385bba3c3cb3f9b6914edd6621bde8f78c8c42f58ec47131ed6aac82a9") ) - (124392, uint256S("0x1496cd55d7adad1ada774542165a04102a91f8f80c6e894c05f1d0c2ff7e5a39") ) - (145000, uint256S("0x99f5d7166ad55d6d0e1ac5c7fffaee1d1dd1ff1409738e0d4f13ac1ae38234cc") ) - (278000, uint256S("0x8066e63198c44b9840f664e795b0315d9b752773b267d6212f35593bc0e3b6f4") ) - (361800, uint256S("0x801981d8a8f5809e34a2881ea97600259e1d9d778fa21752a5f6cff4defcd08d") ) - (500000, uint256S("0x3916b53eaa0eb392ce5d7e4eaf7db4f745187743f167539ffa4dc1a30c06acbd") ) - (700000, uint256S("0x2e45c8a834675b505b96792d198c2dc970f560429c635479c347204044acc59b") ) - (770000, uint256S("0xfc13a63162bc0a5a09acc3f284cf959d6812a027bb54b342a0e1ccaaca8627ce") ) - (850000, uint256S("0xc78b15f25ad990d02256907fab92ab37301d129eaea177fd04acacd56c0cbd22") ) - (950000, uint256S("0x4be0afdb9273d232de0bc75b572d8bcfaa146d9efdbe4a4f1ab775334f175b0f") ) - (1050000, uint256S("0x0753b624cc0ab39d8745b436012ce53c087f7b2e077099e746a9557f569a80f3") ) - (1150000, uint256S("0x0264545b51389faea32ac54bf76cd6efb65701d777e7fa1007584114897067f5") ) - (1250000, uint256S("0x452467f2f74580176375f99dd38e9119d564985ba639fa1303718a51351823ab") ) - (1350000, uint256S("0x813725a075bc3cc254742557ce6d3a680cb97ee863f65c5d9a386c1ac9a8e792") ) - (1450000, uint256S("0x5744777ad775063a3e0b9b9c40ac205e8948904e340d11c3c449fb13914c962b") ) - (1550000, uint256S("0xa37ab3260678f6e7f009b2c11fee14bef6add481b411516201cc35b397859bfb") ) - (1700000, uint256S("0x831a655dd58599fda1815f7275194ff69ca53341694ba81f9941eede25c40885") ) - (1800000, uint256S("0x61bb76ed90de21016de81855d3dc01bd192d17d90de4bdf62e8203c2dde675d7") ) - (1900000, uint256S("0x352ca52f9a22fbf1d241082d3bec716ea5bef6b82811f737ae6486bd7771e1c7") ) - (2000000, uint256S("0x2e1252a6ed6d0e7e556d4d0377b10f4b542ae5d6c9822cb08d68490a2a0bb706") ) - ; - - // TestNet has no checkpoints - static MapCheckpoints mapCheckpointsTestnet = - boost::assign::map_list_of - ( 0, hashGenesisBlockTestNet ); - bool CheckHardened(int nHeight, const uint256& hash) { - MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + const MapCheckpoints& checkpoints = Params().Checkpoints().mapCheckpoints; MapCheckpoints::const_iterator i = checkpoints.find(nHeight); if (i == checkpoints.end()) return true; @@ -77,7 +21,7 @@ namespace Checkpoints int GetTotalBlocksEstimate() { - MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + const MapCheckpoints& checkpoints = Params().Checkpoints().mapCheckpoints; if (checkpoints.empty()) return 0; @@ -86,7 +30,7 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const BlockMap& mapBlockIndex) { - MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + const MapCheckpoints& checkpoints = Params().Checkpoints().mapCheckpoints; for (auto const& i : boost::adaptors::reverse(checkpoints)) { @@ -95,7 +39,7 @@ namespace Checkpoints if (t != mapBlockIndex.end()) return t->second; } - return NULL; + return nullptr; } // Check against synchronized checkpoint @@ -103,7 +47,7 @@ namespace Checkpoints { const CBlockIndex* pindexSync = GetLastCheckpoint(mapBlockIndex); - if (pindexSync != NULL && nHeight <= pindexSync->nHeight) + if (pindexSync != nullptr && nHeight <= pindexSync->nHeight) return false; return true; } diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h new file mode 100644 index 0000000000..cc617b689f --- /dev/null +++ b/src/consensus/consensus.h @@ -0,0 +1,25 @@ +#pragma once + +static const int LAST_POW_BLOCK = 2050; +static const int CONSENSUS_LOOKBACK = 5; //Amount of blocks to go back from best block, to avoid counting forked blocks +static const int BLOCK_GRANULARITY = 10; //Consensus block divisor +static const int TALLY_GRANULARITY = BLOCK_GRANULARITY; + +/** The maximum allowed size for a serialized block, in bytes (network rule) */ +static const unsigned int MAX_BLOCK_SIZE = 1000000; +/** Target Blocks Per day */ +static const unsigned int BLOCKS_PER_DAY = 1000; +/** The maximum size for mined blocks */ +static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; +/** The maximum size for transactions we're willing to relay/mine **/ +static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5; +/** The maximum allowed number of signature check operations in a block (network rule) */ +static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; +/** The maximum number of orphan transactions kept in memory */ +static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; +/** The maximum number of entries in an 'inv' protocol message */ +static const unsigned int MAX_INV_SZ = 50000; +/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ +static const int64_t MIN_TX_FEE = 10000; +/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ +static const int64_t MIN_RELAY_TX_FEE = MIN_TX_FEE; diff --git a/src/consensus/params.h b/src/consensus/params.h new file mode 100644 index 0000000000..3846599824 --- /dev/null +++ b/src/consensus/params.h @@ -0,0 +1,33 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "uint256.h" + +namespace Consensus { + +/** + * Parameters that influence chain consensus. + */ +struct Params { + uint256 hashGenesisBlock; + + /** Block height at which protocol v2 becomes active */ + int ProtocolV2Height; + /** Block height at which research age is enabled */ + int ResearchAgeHeight; + /** Block height at which v8 blocks are created after */ + int BlockV8Height; + /** Block height at which v9 blocks are created */ + int BlockV9Height; + /** Block height at which v9 tally becomes active (3 hours after v9) */ + int BlockV9TallyHeight; + /** Block height at which v10 blocks are created */ + int BlockV10Height; + /** Block height at which v11 blocks are created */ + int BlockV11Height; +}; +} // namespace Consensus diff --git a/src/global_objects.hpp b/src/global_objects.hpp deleted file mode 100644 index 8af8718c88..0000000000 --- a/src/global_objects.hpp +++ /dev/null @@ -1,13 +0,0 @@ - - -#ifdef WIN32 -extern QAxObject *globalcom; -extern QAxObject *globalrpccom; -#endif - - -extern QThread *mythread; - - - - diff --git a/src/global_objects_noui.hpp b/src/global_objects_noui.hpp deleted file mode 100755 index 176818ec93..0000000000 --- a/src/global_objects_noui.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GLOBAL_OBJECTS_NOUI_HPP -#define GLOBAL_OBJECTS_NOUI_HPP - -#include "fwd.h" -#include -#include -#include - -extern bool bForceUpdate; -extern bool fQtActive; -extern bool bGridcoinCoreInitComplete; - -// Timers -extern std::map mvTimers; // Contains event timers that reset after max ms duration iterator is exceeded - -#endif /* GLOBAL_OBJECTS_NOUI_HPP */ diff --git a/src/gridcoin/account.h b/src/gridcoin/account.h index 3190c158c7..7c4a3c7e06 100644 --- a/src/gridcoin/account.h +++ b/src/gridcoin/account.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include diff --git a/src/gridcoin/accrual/computer.h b/src/gridcoin/accrual/computer.h index b6b8cb1b86..eb6200d4bf 100644 --- a/src/gridcoin/accrual/computer.h +++ b/src/gridcoin/accrual/computer.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/account.h" diff --git a/src/gridcoin/accrual/newbie.h b/src/gridcoin/accrual/newbie.h index edfb9c9994..0f47b65c21 100644 --- a/src/gridcoin/accrual/newbie.h +++ b/src/gridcoin/accrual/newbie.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/accrual/computer.h" diff --git a/src/gridcoin/accrual/null.h b/src/gridcoin/accrual/null.h index 710ab6b830..8bd6d79152 100644 --- a/src/gridcoin/accrual/null.h +++ b/src/gridcoin/accrual/null.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/accrual/computer.h" diff --git a/src/gridcoin/accrual/research_age.h b/src/gridcoin/accrual/research_age.h index 37cc940b16..cca53f520d 100644 --- a/src/gridcoin/accrual/research_age.h +++ b/src/gridcoin/accrual/research_age.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/accrual/computer.h" diff --git a/src/gridcoin/accrual/snapshot.h b/src/gridcoin/accrual/snapshot.h index b180dc26c9..f818484d39 100644 --- a/src/gridcoin/accrual/snapshot.h +++ b/src/gridcoin/accrual/snapshot.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "arith_uint256.h" @@ -7,10 +11,10 @@ #include "gridcoin/beacon.h" #include "gridcoin/cpid.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/filehash.h" #include "serialize.h" #include "streams.h" #include "tinyformat.h" -#include "filehash.h" #include diff --git a/src/appcache.cpp b/src/gridcoin/appcache.cpp similarity index 90% rename from src/appcache.cpp rename to src/gridcoin/appcache.cpp index 9db0319a93..1c72941a85 100644 --- a/src/appcache.cpp +++ b/src/gridcoin/appcache.cpp @@ -1,4 +1,8 @@ -#include "appcache.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/appcache.h" #include "util.h" #include diff --git a/src/appcache.h b/src/gridcoin/appcache.h similarity index 92% rename from src/appcache.h rename to src/gridcoin/appcache.h index 37867d3952..382a96b049 100644 --- a/src/appcache.h +++ b/src/gridcoin/appcache.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include diff --git a/src/backup.cpp b/src/gridcoin/backup.cpp similarity index 94% rename from src/backup.cpp rename to src/gridcoin/backup.cpp index 0c23b64dcf..5bbc133c85 100644 --- a/src/backup.cpp +++ b/src/gridcoin/backup.cpp @@ -1,8 +1,8 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -// Backup related functions are placed here to keep vital sections of -// code contained while maintaining clean code. - -#include "backup.h" +#include "gridcoin/backup.h" #include "init.h" #include "wallet/walletdb.h" #include "wallet/wallet.h" @@ -14,17 +14,16 @@ #include #include -boost::filesystem::path GetBackupPath(); - +using namespace GRC; using namespace boost; -boost::filesystem::path GetBackupPath() +boost::filesystem::path GRC::GetBackupPath() { filesystem::path defaultDir = GetDataDir() / "walletbackups"; return GetArg("-backupdir", defaultDir.string()); } -std::string GetBackupFilename(const std::string& basename, const std::string& suffix) +std::string GRC::GetBackupFilename(const std::string& basename, const std::string& suffix) { time_t biTime; struct tm * blTime; @@ -41,7 +40,7 @@ std::string GetBackupFilename(const std::string& basename, const std::string& su return rpath.string(); } -bool BackupsEnabled() +bool GRC::BackupsEnabled() { // If either of these configuration options is explicitly set to zero, // disable backups completely: @@ -49,7 +48,7 @@ bool BackupsEnabled() && GetArg("-walletbackupintervalsecs", 1) > 0; } -int64_t GetBackupInterval() +int64_t GRC::GetBackupInterval() { int64_t backup_interval_secs = GetArg("-walletbackupintervalsecs", 86400); @@ -64,7 +63,7 @@ int64_t GetBackupInterval() return backup_interval_secs; } -void RunBackupJob() +void GRC::RunBackupJob() { TRY_LOCK(cs_main, locked_main); @@ -117,7 +116,7 @@ void RunBackupJob() last_backup_time = now; } -bool BackupConfigFile(const std::string& strDest) +bool GRC::BackupConfigFile(const std::string& strDest) { // Check to see if there is a parent_path in strDest to support custom locations by ui - bug fix @@ -144,7 +143,7 @@ bool BackupConfigFile(const std::string& strDest) return false; } -bool BackupWallet(const CWallet& wallet, const std::string& strDest) +bool GRC::BackupWallet(const CWallet& wallet, const std::string& strDest) { if (!wallet.fFileBacked) return false; @@ -187,7 +186,7 @@ bool BackupWallet(const CWallet& wallet, const std::string& strDest) return false; } -bool MaintainBackups(filesystem::path wallet_backup_path, std::vector backup_file_type, +bool GRC::MaintainBackups(filesystem::path wallet_backup_path, std::vector backup_file_type, unsigned int retention_by_num, unsigned int retention_by_days, std::vector& files_removed) { // Backup file retention maintainer. Adapted from the scraper/main log archiver core. @@ -338,7 +337,7 @@ bool MaintainBackups(filesystem::path wallet_backup_path, std::vector #include class CWallet; +namespace GRC { std::string GetBackupFilename(const std::string& basename, const std::string& suffix = ""); boost::filesystem::path GetBackupPath(); @@ -18,7 +21,5 @@ bool BackupConfigFile(const std::string& strDest); bool MaintainBackups(boost::filesystem::path wallet_backup_path, std::vector backup_file_type, unsigned int retention_by_num, unsigned int retention_by_days, std::vector& files_removed); bool BackupWallet(const CWallet& wallet, const std::string& strDest); -extern bool BackupPrivateKeys(const CWallet& wallet, std::string& sTarget, std::string& sErrors); -extern bool BackupWallet(const CWallet& wallet, const std::string& strDest); - -#endif // BACKUP_H +bool BackupPrivateKeys(const CWallet& wallet, std::string& sTarget, std::string& sErrors); +} diff --git a/src/gridcoin/beacon.cpp b/src/gridcoin/beacon.cpp index 2ee85795d7..2e58687dc3 100644 --- a/src/gridcoin/beacon.cpp +++ b/src/gridcoin/beacon.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "base58.h" #include "logging.h" #include "main.h" diff --git a/src/gridcoin/beacon.h b/src/gridcoin/beacon.h index c9b2027e63..96acec209c 100644 --- a/src/gridcoin/beacon.h +++ b/src/gridcoin/beacon.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "key.h" diff --git a/src/gridcoin/boinc.cpp b/src/gridcoin/boinc.cpp new file mode 100644 index 0000000000..0a6db3e401 --- /dev/null +++ b/src/gridcoin/boinc.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/boinc.h" +#include "util.h" + +fs::path GRC::GetBoincDataDir() +{ + std::string path = GetArgument("boincdatadir", ""); + + if (!path.empty()) { + return fs::path(path); + } + + #ifdef WIN32 + HKEY hKey; + if (RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Space Sciences Laboratory, U.C. Berkeley\\BOINC Setup\\", + 0, + KEY_READ|KEY_WOW64_64KEY, + &hKey) == ERROR_SUCCESS) + { + wchar_t szPath[MAX_PATH]; + DWORD dwSize = sizeof(szPath); + + if (RegQueryValueEx( + hKey, + L"DATADIR", + nullptr, + nullptr, + (LPBYTE)&szPath, + &dwSize) == ERROR_SUCCESS) + { + RegCloseKey(hKey); + + fs::path path = std::wstring(szPath); + + if (fs::exists(path)){ + return path; + } else { + LogPrintf("Cannot find BOINC data dir %s.", path.string()); + } + } + + RegCloseKey(hKey); + } + + if (fs::exists("C:\\ProgramData\\BOINC\\")){ + return "C:\\ProgramData\\BOINC\\"; + } else if(fs::exists("C:\\Documents and Settings\\All Users\\Application Data\\BOINC\\")) { + return "C:\\Documents and Settings\\All Users\\Application Data\\BOINC\\"; + } + #endif + + #ifdef __linux__ + if (fs::exists("/var/lib/boinc-client/")) { + return "/var/lib/boinc-client/"; + } else if (fs::exists("/var/lib/boinc/")) { + return "/var/lib/boinc/"; + } + #endif + + #ifdef __APPLE__ + if (fs::exists("/Library/Application Support/BOINC Data/")) { + return "/Library/Application Support/BOINC Data/"; + } + #endif + + LogPrintf("ERROR: Cannot find BOINC data dir"); + return ""; +} diff --git a/src/gridcoin/boinc.h b/src/gridcoin/boinc.h new file mode 100644 index 0000000000..21f315bf13 --- /dev/null +++ b/src/gridcoin/boinc.h @@ -0,0 +1,11 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +namespace GRC { +fs::path GetBoincDataDir(); +} diff --git a/src/gridcoin/claim.cpp b/src/gridcoin/claim.cpp index a2c7e84c0e..ea9c15e15f 100644 --- a/src/gridcoin/claim.cpp +++ b/src/gridcoin/claim.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "key.h" #include "main.h" #include "gridcoin/claim.h" diff --git a/src/gridcoin/claim.h b/src/gridcoin/claim.h index 1a0b1cd0e0..2097153180 100644 --- a/src/gridcoin/claim.h +++ b/src/gridcoin/claim.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/contract/payload.h" diff --git a/src/gridcoin/contract/contract.cpp b/src/gridcoin/contract/contract.cpp index d38a9aa7d3..fd454ad665 100644 --- a/src/gridcoin/contract/contract.cpp +++ b/src/gridcoin/contract/contract.cpp @@ -1,12 +1,17 @@ -#include "appcache.h" -#include "block.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" +#include "gridcoin/appcache.h" #include "gridcoin/claim.h" #include "gridcoin/contract/contract.h" #include "gridcoin/contract/handler.h" #include "gridcoin/beacon.h" #include "gridcoin/project.h" #include "gridcoin/researcher.h" +#include "gridcoin/support/block_finder.h" +#include "gridcoin/support/xml.h" #include "gridcoin/tx_message.h" #include "gridcoin/voting/payloads.h" #include "gridcoin/voting/registry.h" @@ -15,11 +20,7 @@ using namespace GRC; -// Parses the XML-like elements from contract messages: -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end); - -namespace -{ +namespace { //! //! \brief An empty, invalid contract payload. //! diff --git a/src/gridcoin/contract/contract.h b/src/gridcoin/contract/contract.h index 0573d5b029..3868a97ffe 100644 --- a/src/gridcoin/contract/contract.h +++ b/src/gridcoin/contract/contract.h @@ -1,8 +1,12 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once -#include "enumbytes.h" #include "key.h" #include "gridcoin/contract/payload.h" +#include "gridcoin/support/enumbytes.h" #include "serialize.h" #include diff --git a/src/gridcoin/contract/handler.h b/src/gridcoin/contract/handler.h index 1fc0b88746..da3ca26972 100644 --- a/src/gridcoin/contract/handler.h +++ b/src/gridcoin/contract/handler.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once class CBlockIndex; diff --git a/src/gridcoin/contract/message.cpp b/src/gridcoin/contract/message.cpp index b6edf8000c..f8ea26ead4 100644 --- a/src/gridcoin/contract/message.cpp +++ b/src/gridcoin/contract/message.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "gridcoin/contract/message.h" #include "gridcoin/contract/contract.h" #include "script.h" diff --git a/src/gridcoin/contract/message.h b/src/gridcoin/contract/message.h index bee495d58c..2bde8fa3ef 100644 --- a/src/gridcoin/contract/message.h +++ b/src/gridcoin/contract/message.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include diff --git a/src/gridcoin/contract/payload.h b/src/gridcoin/contract/payload.h index e41e4b45ba..6dc2face72 100644 --- a/src/gridcoin/contract/payload.h +++ b/src/gridcoin/contract/payload.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "streams.h" diff --git a/src/gridcoin/cpid.cpp b/src/gridcoin/cpid.cpp index 5c2d6c662e..8671636329 100644 --- a/src/gridcoin/cpid.cpp +++ b/src/gridcoin/cpid.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "gridcoin/cpid.h" #include "util.h" diff --git a/src/gridcoin/cpid.h b/src/gridcoin/cpid.h index 1e704cc153..cb5857bfbe 100644 --- a/src/gridcoin/cpid.h +++ b/src/gridcoin/cpid.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "serialize.h" diff --git a/src/gridcoin/gridcoin.cpp b/src/gridcoin/gridcoin.cpp new file mode 100644 index 0000000000..06accc093f --- /dev/null +++ b/src/gridcoin/gridcoin.cpp @@ -0,0 +1,325 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparams.h" +#include "main.h" +#include "gridcoin/backup.h" +#include "gridcoin/contract/contract.h" +#include "gridcoin/gridcoin.h" +#include "gridcoin/quorum.h" +#include "gridcoin/researcher.h" +#include "gridcoin/support/block_finder.h" +#include "gridcoin/tally.h" +#include "gridcoin/upgrade.h" +#include "init.h" +#include "scheduler.h" +#include "ui_interface.h" + +using namespace GRC; + +extern bool fExplorer; +extern unsigned int nScraperSleep; +extern unsigned int nActiveBeforeSB; +extern bool fScraperActive; + +extern ThreadHandler* netThreads; + +void Scraper(bool bSingleShot = false); +void ScraperSubscriber(); + +namespace { +//! +//! \brief Initialize the service that creates and validate superblocks. +//! +//! \param pindexBest Block index of the tip of the chain. +//! +void InitializeSuperblockQuorum(const CBlockIndex* pindexBest) +{ + LogPrintf("Gridcoin: quorum is %sactive", Quorum::Active() ? "" : "in"); + + if (IsV9Enabled(pindexBest->nHeight)) { + LogPrintf("Gridcoin: Loading superblock cache..."); + uiInterface.InitMessage(_("Loading superblock cache...")); + + Quorum::LoadSuperblockIndex(pindexBest); + } +} + +//! +//! \brief Initialize the service that tracks research rewards. +//! +//! \param pindexBest Block index of the tip of the chain. +//! +//! \return \c false if a problem occurs while loading the stored accrual state. +//! +bool InitializeResearchRewardAccounting(CBlockIndex* pindexBest) +{ + LogPrintf("Gridcoin: initializing research reward accounting..."); + uiInterface.InitMessage(_("Initializing research reward accounting...")); + + const int64_t start_height = Params().GetConsensus().ResearchAgeHeight; + + if (!Tally::Initialize(BlockFinder().FindByHeight(start_height))) { + return error("Failed to initialize tally."); + } + + if (pindexBest->nVersion <= 10) { + LogPrint(BCLog::LogFlags::TALLY, "Gridcoin: loading network averages..."); + uiInterface.InitMessage(_("Loading Network Averages...")); + + Tally::LegacyRecount(Tally::FindLegacyTrigger(pindexBest)); + } + + return true; +} + +//! +//! \brief Reload historical contract state from the blockchain. +//! +//! \param pindexBest Block index of the tip of the chain. +//! +void InitializeContracts(const CBlockIndex* pindexBest) +{ + LogPrintf("Gridcoin: replaying contracts..."); + uiInterface.InitMessage(_("Replaying contracts...")); + + ReplayContracts(pindexBest); +} + +//! +//! \brief Set up the user's CPID for participation in the research reward +//! protocol. +//! +void InitializeResearcherContext() +{ + LogPrintf("Gridcoin: initializing local researcher context..."); + uiInterface.InitMessage(_("Initializing local researcher context...")); + + Researcher::Initialize(); + + if (!pwalletMain->IsLocked()) { + Researcher::Get()->ImportBeaconKeysFromConfig(pwalletMain); + } +} + +//! +//! \brief Run the scraper thread. +//! +//! \param parg Unused. +//! +void ThreadScraper(void* parg) +{ + LogPrint(BCLog::LogFlags::NOISY, "ThreadSraper starting"); + + try { + fScraperActive = true; + Scraper(false); + } catch (std::exception& e) { + fScraperActive = false; + PrintException(&e, "ThreadScraper()"); + } catch(boost::thread_interrupted&) { + fScraperActive = false; + LogPrintf("ThreadScraper exited (interrupt)"); + return; + } catch (...) { + fScraperActive = false; + PrintException(nullptr, "ThreadScraper()"); + } + + fScraperActive = false; + LogPrintf("ThreadScraper exited"); +} + +//! +//! \brief Run the scraper subscriber thread. +//! +//! \param parg Unused. +//! +void ThreadScraperSubscriber(void* parg) +{ + LogPrint(BCLog::LogFlags::NOISY, "ThreadScraperSubscriber starting"); + + try { + ScraperSubscriber(); + } catch (std::exception& e) { + PrintException(&e, "ThreadScraperSubscriber()"); + } catch(boost::thread_interrupted&) { + LogPrintf("ThreadScraperSubscriber exited (interrupt)"); + return; + } catch (...) { + PrintException(nullptr, "ThreadScraperSubscriber()"); + } + + LogPrintf("ThreadScraperSubscriber exited"); +} + +//! +//! \brief Configure and initialize the scraper system. +//! +void InitializeScraper() +{ + // Default to 300 sec (5 min), clamp to 60 minimum, 600 maximum - converted to milliseconds. + nScraperSleep = std::min(std::max(GetArg("-scrapersleep", 300), 60), 600) * 1000; + // Default to 7200 sec (4 hrs), clamp to 300 minimum, 86400 maximum (meaning active all of the time). + nActiveBeforeSB = std::min(std::max(GetArg("-activebeforesb", 14400), 300), 86400); + + // Run the scraper or subscriber housekeeping thread, but not both. The + // subscriber housekeeping thread checks if the flag for the scraper thread + // is true, and basically becomes a no-op, but it is silly to run it if the + // scraper thread is running. The scraper thread does all of the same + // housekeeping functions as the subscriber housekeeping thread. + // + // For example. gridcoinresearch(d) with no args will run the subscriber + // but not the scraper. + // gridcoinresearch(d) -scraper will run the scraper but not the subscriber. + // gridcoinresearch(d) -scraper -usenewnn will run both the scraper and the + // subscriber. + // -disablenn overrides the -usenewnn directive. + if (GetBoolArg("-scraper", false)) { + LogPrintf("Gridcoin: scraper enabled"); + + if (!netThreads->createThread(ThreadScraper, nullptr, "ThreadScraper")) { + LogPrintf("ERROR: createThread(ThreadScraper) failed"); + } + } else { + LogPrintf("Gridcoin: scraper disabled"); + LogPrintf("Gridcoin: scraper subscriber housekeeping thread enabled"); + + if (!netThreads->createThread(ThreadScraperSubscriber, nullptr, "ScraperSubscriber")) { + LogPrintf("ERROR: createThread(ScraperSubscriber) failed"); + } + } +} + +//! +//! \brief Enable explorer functionality for the scraper if requested. +//! +void InitializeExplorerFeatures() +{ + // If -disablenn is NOT specified or set to false... + if (!GetBoolArg("-disablenn", false)) { + // Then if -scraper is specified (set to true)... + if (GetBoolArg("-scraper", false)) { + // Activate explorer extended features if -explorer is set + if (GetBoolArg("-explorer", false)) fExplorer = true; + } + } +} + +//! +//! \brief Set up the background job that creates backup files. +//! +//! \param scheduler Scheduler instance to register jobs with. +//! +void ScheduleBackups(CScheduler& scheduler) +{ + if (!BackupsEnabled()) { + return; + } + + // Run the backup job at a rate of 4x the configured backup interval + // in case the wallet becomes busy when the job runs. This job skips + // a cycle when it encounters lock contention or when a cycle occurs + // sooner than the requested interval: + // + scheduler.scheduleEvery(RunBackupJob, GetBackupInterval() * 1000 / 4); + + // Run the backup job on start-up in case the wallet started after a + // long period of downtime. Some usage patterns may cause the wallet + // to start and shutdown frequently without producing a backup if we + // only create backups from the scheduler cycles. This is a no-op if + // the wallet contains a stored backup timestamp later than the next + // scheduled backup interval: + // + scheduler.scheduleFromNow(RunBackupJob, 60 * 1000); +} + +//! +//! \brief Set up the background job that checks for new Gridcoin versions. +//! +//! \param scheduler Scheduler instance to register jobs with. +//! +void ScheduleUpdateChecks(CScheduler& scheduler) +{ + if (fTestNet) { + LogPrintf("Gridcoin: update checks disabled for testnet"); + return; + } + + if (GetBoolArg("-disableupdatecheck", false)) { + LogPrintf("Gridcoin: update checks disabled by configuration"); + return; + } + + int64_t hours = GetArg("-updatecheckinterval", 5 * 24); + + if (hours < 1) { + LogPrintf("ERROR: invalid -updatecheckinterval: %s. Using default...", + GetArg("-updatecheckinterval", "")); + hours = 24; + } + + LogPrintf("Gridcoin: checking for updates every %" PRId64 " hours", hours); + + scheduler.scheduleEvery([]{ + g_UpdateChecker->CheckForLatestUpdate(); + }, hours * 60 * 60 * 1000); + + // Schedule a start-up check one minute from now: + scheduler.scheduleFromNow([]{ + g_UpdateChecker->CheckForLatestUpdate(); + }, 60 * 1000); +} +} // Anonymous namespace + +// ----------------------------------------------------------------------------- +// Global Variables +// ----------------------------------------------------------------------------- + +std::unique_ptr g_UpdateChecker; +bool fSnapshotRequest = false; + +// ----------------------------------------------------------------------------- +// Functions +// ----------------------------------------------------------------------------- + +bool GRC::Initialize(CBlockIndex* pindexBest) +{ + LogPrintf("Gridcoin: initializing..."); + + InitializeSuperblockQuorum(pindexBest); + + if (!InitializeResearchRewardAccounting(pindexBest)) { + return false; + } + + InitializeContracts(pindexBest); + InitializeResearcherContext(); + + // The scraper is run on the netThreads group, because it shares data structures + // with scraper_net, which is run as part of the network node threads. + InitializeScraper(); + InitializeExplorerFeatures(); + + return true; +} + +void GRC::ScheduleBackgroundJobs(CScheduler& scheduler) +{ + // Primitive, but this is what the scraper does in the scraper housekeeping + // loop. It checks to see if the logs need to be archived by default every + // 5 mins. Note that passing false to the archive function means that if we + // have not crossed over the day boundary, it does nothing, so this is a + // very inexpensive call. Also if -logarchivedaily is set to false, then + // this will be a no-op. + scheduler.scheduleEvery([]{ + fs::path plogfile_out; + LogInstance().archive(false, plogfile_out); + }, 300 * 1000); + + scheduler.scheduleEvery(Researcher::RunRenewBeaconJob, 4 * 60 * 60 * 1000); + + ScheduleBackups(scheduler); + ScheduleUpdateChecks(scheduler); +} diff --git a/src/gridcoin/gridcoin.h b/src/gridcoin/gridcoin.h new file mode 100644 index 0000000000..7f324c9f5e --- /dev/null +++ b/src/gridcoin/gridcoin.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +class CBlockIndex; +class CScheduler; + +namespace GRC { +//! +//! \brief Initialize Gridcoin-specific components and services. +//! +//! \param pindexBest Block index for the tip of the chain. +//! +//! \return \c false if a problem occurs during initialization. +//! +bool Initialize(CBlockIndex* pindexBest); + +//! +//! \brief Set up Gridcoin-specific background jobs. +//! +//! \param scheduler Scheduler instance to register jobs with. +//! +void ScheduleBackgroundJobs(CScheduler& scheduler); +} // namespace GRC diff --git a/src/gridcoin/magnitude.h b/src/gridcoin/magnitude.h index 3d1beff0d9..2d4e03cbd0 100644 --- a/src/gridcoin/magnitude.h +++ b/src/gridcoin/magnitude.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include diff --git a/src/gridcoin/project.cpp b/src/gridcoin/project.cpp index 845ff6dc2e..d315b098ee 100644 --- a/src/gridcoin/project.cpp +++ b/src/gridcoin/project.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" diff --git a/src/gridcoin/project.h b/src/gridcoin/project.h index 97226e67d0..eade659c5e 100644 --- a/src/gridcoin/project.h +++ b/src/gridcoin/project.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/contract/handler.h" diff --git a/src/gridcoin/quorum.cpp b/src/gridcoin/quorum.cpp index 6c95d7e5f3..fc5796e5e1 100644 --- a/src/gridcoin/quorum.cpp +++ b/src/gridcoin/quorum.cpp @@ -1,10 +1,14 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "base58.h" #include "main.h" #include "gridcoin/claim.h" #include "gridcoin/magnitude.h" #include "gridcoin/quorum.h" +#include "gridcoin/scraper/scraper_net.h" #include "gridcoin/superblock.h" -#include "scraper_net.h" #include "util/reverse_iterator.h" #include @@ -631,7 +635,7 @@ class SuperblockValidator LogPrintf("ValidateSuperblock(): No match by project."); - if (g_fOutOfSyncByAge) { + if (OutOfSyncByAge()) { LogPrintf("ValidateSuperblock(): No validation achieved, but node is" "not in sync - skipping validation."); diff --git a/src/gridcoin/quorum.h b/src/gridcoin/quorum.h index 0706bc5bf8..51f6a02204 100644 --- a/src/gridcoin/quorum.h +++ b/src/gridcoin/quorum.h @@ -1,14 +1,20 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include -#include "scraper_net.h" +#include class CBlockIndex; namespace GRC { class Claim; +class Cpid; class Magnitude; +class MiningId; class QuorumHash; class Superblock; class SuperblockPtr; diff --git a/src/gridcoin/researcher.cpp b/src/gridcoin/researcher.cpp index f09ecc173c..4c5d39301e 100644 --- a/src/gridcoin/researcher.cpp +++ b/src/gridcoin/researcher.cpp @@ -1,14 +1,18 @@ -#include "appcache.h" -#include "backup.h" -#include "boinc.h" -#include "contract/message.h" -#include "global_objects_noui.hpp" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "init.h" +#include "gridcoin/appcache.h" +#include "gridcoin/backup.h" #include "gridcoin/beacon.h" +#include "gridcoin/boinc.h" +#include "gridcoin/contract/message.h" #include "gridcoin/magnitude.h" #include "gridcoin/project.h" #include "gridcoin/quorum.h" #include "gridcoin/researcher.h" +#include "gridcoin/support/xml.h" #include "gridcoin/tally.h" #include "span.h" #include "ui_interface.h" @@ -24,9 +28,6 @@ using namespace GRC; -// Parses the XML elements from the BOINC client_state.xml: -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end); - extern CCriticalSection cs_main; extern std::string msMiningErrors; extern int64_t g_v11_timestamp; @@ -810,15 +811,16 @@ AdvertiseBeaconResult RenewBeacon(const Cpid& cpid, const Beacon& beacon) // Class: MiningProject // ----------------------------------------------------------------------------- -MiningProject::MiningProject( - std::string name, +MiningProject::MiningProject(std::string name, Cpid cpid, std::string team, - std::string url) + std::string url, + double rac) : m_name(LowerUnderscore(std::move(name))) , m_cpid(std::move(cpid)) , m_team(std::move(team)) , m_url(std::move(url)) + , m_rac(std::move(rac)) , m_error(Error::NONE) { boost::to_lower(m_team); @@ -830,7 +832,9 @@ MiningProject MiningProject::Parse(const std::string& xml) ExtractXML(xml, "", ""), Cpid::Parse(ExtractXML(xml, "", "")), ExtractXML(xml, "", ""), - ExtractXML(xml, "", "")); + ExtractXML(xml, "", ""), + std::strtold(ExtractXML(xml, "", + "").c_str(), nullptr)); if (IsPoolCpid(project.m_cpid) && !GetBoolArg("-pooloperator", false)) { project.m_error = MiningProject::Error::POOL; @@ -1069,7 +1073,7 @@ void Researcher::Initialize() void Researcher::RunRenewBeaconJob() { - if (g_fOutOfSyncByAge) { + if (OutOfSyncByAge()) { return; } @@ -1085,6 +1089,16 @@ void Researcher::RunRenewBeaconJob() return; } + // Do not send a new beacon without manual action during the grace period + // for beacon readvertisement after block version 11. This prevents users + // from missing the steps needed to verify the new beacon: + // + if (const auto beacon_option = researcher->TryBeacon()) { + if (beacon_option->m_timestamp < g_v11_timestamp) { + return; + } + } + // Do not perform an automated renewal for participants with existing // beacons before a superblock is due. This avoids overwriting beacon // timestamps in the beacon registry in a way that causes the renewed @@ -1237,6 +1251,21 @@ GRC::Magnitude Researcher::Magnitude() const return GRC::Magnitude::Zero(); } +bool Researcher::HasRAC() const +{ + for (const auto& iter : m_projects) + { + // Only one whitelisted project with positive RAC + // is required to return true. + if (iter.second.Eligible() && iter.second.m_rac > 0.0) + { + return true; + } + } + + return false; +} + int64_t Researcher::Accrual() const { const CpidOption cpid = m_mining_id.TryCpid(); @@ -1245,7 +1274,7 @@ int64_t Researcher::Accrual() const return 0; } - const int64_t now = g_fOutOfSyncByAge ? pindexBest->nTime : GetAdjustedTime(); + const int64_t now = OutOfSyncByAge() ? pindexBest->nTime : GetAdjustedTime(); LOCK(cs_main); diff --git a/src/gridcoin/researcher.h b/src/gridcoin/researcher.h index c034dd31be..130a2433b6 100644 --- a/src/gridcoin/researcher.h +++ b/src/gridcoin/researcher.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "key.h" @@ -74,7 +78,7 @@ struct MiningProject //! \param team Associated team parsed from the \c element. //! \param url Project website URL parsed from the \c element. //! - MiningProject(std::string name, Cpid cpid, std::string team, std::string url); + MiningProject(std::string name, Cpid cpid, std::string team, std::string url, double rac); //! //! \brief Initialize a MiningProject instance by parsing the project XML @@ -89,6 +93,7 @@ struct MiningProject Cpid m_cpid; //!< CPID of the BOINC account for the project. std::string m_team; //!< Name of the team joined for the project. std::string m_url; //!< URL of the project website. + double m_rac; //!< RAC of the project. Error m_error; //!< May describe why a project is ineligible. //! @@ -478,6 +483,15 @@ class Researcher //! GRC::Magnitude Magnitude() const; + //! + //! \brief Determine whether the CPID has positive RAC for whitelisted + //! projects. + //! + //! \return true if the client_state.xml file shows positive RAC for the + //! whitelisted projects associated with the CPID. + //! + bool HasRAC() const; + //! //! \brief Get the current research reward accrued for the CPID loaded by //! the wallet. diff --git a/src/scraper/fwd.h b/src/gridcoin/scraper/fwd.h similarity index 97% rename from src/scraper/fwd.h rename to src/gridcoin/scraper/fwd.h index 4aed128a2d..74ba78dd10 100644 --- a/src/scraper/fwd.h +++ b/src/gridcoin/scraper/fwd.h @@ -1,15 +1,17 @@ -#ifndef FWD_H -#define FWD_H +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once #include #include #include -#include "support/allocators/zeroafterfree.h" +#include "gridcoin/scraper/scraper_net.h" #include "util.h" #include "streams.h" -#include "scraper_net.h" /********************* * Scraper ENUMS * @@ -340,5 +342,3 @@ struct AppCacheEntryExt }; typedef std::unordered_map AppCacheSectionExt; - -#endif // FWD_H diff --git a/src/scraper/http.cpp b/src/gridcoin/scraper/http.cpp similarity index 98% rename from src/scraper/http.cpp rename to src/gridcoin/scraper/http.cpp index 43b17a98dd..174003f44f 100644 --- a/src/scraper/http.cpp +++ b/src/gridcoin/scraper/http.cpp @@ -1,4 +1,8 @@ -#include "http.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/scraper/http.h" #include "tinyformat.h" #include "util.h" diff --git a/src/scraper/http.h b/src/gridcoin/scraper/http.h similarity index 94% rename from src/scraper/http.h rename to src/gridcoin/scraper/http.h index 9d7028c3f1..de61fa0ea7 100644 --- a/src/scraper/http.h +++ b/src/gridcoin/scraper/http.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include diff --git a/src/scraper/scraper.cpp b/src/gridcoin/scraper/scraper.cpp similarity index 99% rename from src/scraper/scraper.cpp rename to src/gridcoin/scraper/scraper.cpp index 26b1c75062..685ca68313 100755 --- a/src/scraper/scraper.cpp +++ b/src/gridcoin/scraper/scraper.cpp @@ -1,14 +1,20 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" -#include "block.h" -#include "scraper.h" -#include "scraper_net.h" -#include "http.h" #include "ui_interface.h" +#include "gridcoin/appcache.h" #include "gridcoin/beacon.h" #include "gridcoin/project.h" #include "gridcoin/quorum.h" +#include "gridcoin/scraper/http.h" +#include "gridcoin/scraper/scraper.h" +#include "gridcoin/scraper/scraper_net.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/block_finder.h" +#include "gridcoin/support/xml.h" #include #include @@ -88,9 +94,17 @@ std::vector GetTeamWhiteList(); std::string urlsanity(const std::string& s, const std::string& type); std::string lowercase(std::string s); -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end); ScraperFileManifest StructScraperFileManifest = {}; +// Although scraper_net.h declares these maps, we define them here instead of +// in scraper_net.cpp to ensure that the executable destroys these objects in +// order. They need to be destroyed after ConvergedScraperStatsCache: +// +CCriticalSection CSplitBlob::cs_mapParts; +CCriticalSection CScraperManifest::cs_mapManifest; +std::map CSplitBlob::mapParts; +std::map> CScraperManifest::mapManifest; + // Global cache for converged scraper stats. Access must be with the lock cs_ConvergedScraperStatsCache taken. ConvergedScraperStats ConvergedScraperStatsCache = {}; @@ -975,7 +989,7 @@ void Scraper(bool bSingleShot) // We do NOT want to filter statistics with an out-of-date beacon list or project whitelist. // If called in singleshot mode, wallet will most likely be in sync, because the calling functions check // beforehand. - while (g_fOutOfSyncByAge) + while (OutOfSyncByAge()) { // Signal stats event to UI. uiInterface.NotifyScraperEvent(scrapereventtypes::OutOfSync, CT_UPDATING, {}); @@ -1217,7 +1231,7 @@ void ScraperSubscriber() { // Only proceed if wallet is in sync. Check every 8 seconds since no callback is available. // We do NOT want to filter statistics with an out-of-date beacon list or project whitelist. - while (g_fOutOfSyncByAge) + while (OutOfSyncByAge()) { // Signal stats event to UI. uiInterface.NotifyScraperEvent(scrapereventtypes::OutOfSync, CT_NEW, {}); @@ -4792,7 +4806,7 @@ mmCSManifestsBinnedByScraper ScraperCullAndBinCScraperManifests() // First check for unauthorized manifests just in case a scraper has been deauthorized. // This is only done if in sync. - if (!g_fOutOfSyncByAge) + if (!OutOfSyncByAge()) { unsigned int nDeleted = ScraperDeleteUnauthorizedCScraperManifests(); if (nDeleted) _log(logattribute::WARNING, "ScraperDeleteCScraperManifests", "Deleted " + std::to_string(nDeleted) + " unauthorized manifests."); @@ -5047,7 +5061,7 @@ Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats, bool bContrac // NOTE - OutOfSyncByAge calls PreviousBlockAge(), which takes a lock on cs_main. This is likely a deadlock culprit if called from here // and the scraper or subscriber loop nearly simultaneously. So we use an atomic flag updated by the scraper or subscriber loop. // If not in sync then immediately bail with an empty superblock. - if (g_fOutOfSyncByAge) return empty_superblock; + if (OutOfSyncByAge()) return empty_superblock; // Check the age of the ConvergedScraperStats cache. If less than nScraperSleep / 1000 old (for seconds) or clean, then simply report back the cache contents. // This prevents the relatively heavyweight stats computations from running too often. The time here may not exactly align with diff --git a/src/scraper/scraper.h b/src/gridcoin/scraper/scraper.h similarity index 96% rename from src/scraper/scraper.h rename to src/gridcoin/scraper/scraper.h index 30fbcae945..8111bd86b2 100644 --- a/src/scraper/scraper.h +++ b/src/gridcoin/scraper/scraper.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include @@ -17,16 +21,14 @@ #include #include "sync.h" -#include "appcache.h" #include "wallet/wallet.h" -#include "global_objects_noui.hpp" #include #include "net.h" #include "rpcprotocol.h" // See fwd.h for certain forward declarations that need to be included in other areas. -#include "fwd.h" +#include "gridcoin/scraper/fwd.h" #include "gridcoin/superblock.h" /********************* @@ -100,8 +102,6 @@ int64_t SCRAPER_DEAUTHORIZED_BANSCORE_GRACE_PERIOD = 300; AppCacheSectionExt mScrapersExt = {}; -extern std::atomic_bool g_fOutOfSyncByAge; - CCriticalSection cs_mScrapersExt; diff --git a/src/scraper_net.cpp b/src/gridcoin/scraper/scraper_net.cpp similarity index 98% rename from src/scraper_net.cpp rename to src/gridcoin/scraper/scraper_net.cpp index 13de052cae..c56ed9c572 100644 --- a/src/scraper_net.cpp +++ b/src/gridcoin/scraper/scraper_net.cpp @@ -1,4 +1,6 @@ -/* scraper_net.cpp */ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. /* Define this if you want to show pubkey as address, otherwise hex id */ #define SCRAPER_NET_PK_AS_ADDRESS @@ -12,25 +14,21 @@ #ifdef SCRAPER_NET_PK_AS_ADDRESS #include "base58.h" #endif -#include "scraper_net.h" -#include "appcache.h" -#include "scraper/fwd.h" +#include "gridcoin/appcache.h" #include "gridcoin/project.h" +#include "gridcoin/scraper/fwd.h" +#include "gridcoin/scraper/scraper_net.h" #include "gridcoin/superblock.h" //Globals -std::map CSplitBlob::mapParts; -CCriticalSection CSplitBlob::cs_mapParts; -std::map> CScraperManifest::mapManifest; std::map>> CScraperManifest::mapPendingDeletedManifest; -CCriticalSection CScraperManifest::cs_mapManifest; extern unsigned int SCRAPER_MISBEHAVING_NODE_BANSCORE; extern int64_t SCRAPER_DEAUTHORIZED_BANSCORE_GRACE_PERIOD; extern int64_t SCRAPER_CMANIFEST_RETENTION_TIME; extern double CONVERGENCE_BY_PROJECT_RATIO; extern unsigned int nScraperSleep; extern AppCacheSectionExt mScrapersExt; -extern std::atomic g_nSyncTime; +extern std::atomic g_nTimeBestReceived; extern ConvergedScraperStats ConvergedScraperStatsCache; extern CCriticalSection cs_mScrapersExt; extern CCriticalSection cs_ConvergedScraperStatsCache; @@ -401,7 +399,7 @@ bool CScraperManifest::IsManifestAuthorized(int64_t& nTime, CPubKey& PubKey, uns } else { - nGracePeriodEnd = std::max((int64_t)g_nSyncTime, nLastFalseEntryTime) + SCRAPER_DEAUTHORIZED_BANSCORE_GRACE_PERIOD; + nGracePeriodEnd = std::max(g_nTimeBestReceived, nLastFalseEntryTime) + SCRAPER_DEAUTHORIZED_BANSCORE_GRACE_PERIOD; // If the current time is past the grace period end then set SCRAPER_MISBEHAVING_NODE_BANSCORE, otherwise 0. if (nGracePeriodEnd < GetAdjustedTime()) @@ -435,7 +433,7 @@ void CScraperManifest::UnserializeCheck(CDataStream& ss, unsigned int& banscore_ // the manifest is authorized, then set the checked flag to true, // otherwise terminate the unserializecheck and throw an error, // which will also result in an increase in banscore, if past the grace period. - if (g_fOutOfSyncByAge) + if (OutOfSyncByAge()) { bCheckedAuthorized = false; } @@ -501,7 +499,7 @@ void CScraperManifest::UnserializeCheck(CDataStream& ss, unsigned int& banscore_ unsigned int nMaxProjects = static_cast(std::ceil(static_cast(GRC::GetWhitelist().Snapshot().size()) / std::max(0.5, CONVERGENCE_BY_PROJECT_RATIO)) + 2); - if (!g_fOutOfSyncByAge && projects.size() > nMaxProjects) + if (!OutOfSyncByAge() && projects.size() > nMaxProjects) { // Immediately ban the node from which the manifest was received. banscore_out = GetArg("-banscore", 100); diff --git a/src/scraper_net.h b/src/gridcoin/scraper/scraper_net.h similarity index 96% rename from src/scraper_net.h rename to src/gridcoin/scraper/scraper_net.h index ec105d59c3..e5a652508b 100755 --- a/src/scraper_net.h +++ b/src/gridcoin/scraper/scraper_net.h @@ -1,6 +1,8 @@ -#pragma once +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. -/* scraper_net.h */ +#pragma once /* Maybe the parts system will be useful for other things so let's abstract * that to parent class. Since it will be all in one file there will not be any diff --git a/src/gridcoin/staking/difficulty.cpp b/src/gridcoin/staking/difficulty.cpp new file mode 100644 index 0000000000..88c1b36e2c --- /dev/null +++ b/src/gridcoin/staking/difficulty.cpp @@ -0,0 +1,448 @@ +// Copyright (c) 2011-2012 The PPCoin developers +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" +#include "init.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/staking/kernel.h" +#include "gridcoin/staking/status.h" +#include "main.h" +#include "txdb.h" +#include "wallet/wallet.h" + +#include + +using namespace GRC; + +namespace { +constexpr int64_t TARGET_TIMESPAN = 16 * 60; // 16 mins in seconds +const CBigNum PROOF_OF_STAKE_LIMIT(ArithToUint256(~arith_uint256() >> 20)); + +// ppcoin: find last block index up to pindex +const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake) +{ + while (pindex && pindex->pprev && (pindex->IsProofOfStake() != fProofOfStake)) + pindex = pindex->pprev; + return pindex; +} +} // Anonymous namespace + +// ----------------------------------------------------------------------------- +// Functions +// ----------------------------------------------------------------------------- + +unsigned int GRC::GetNextTargetRequired(const CBlockIndex* pindexLast) +{ + if (pindexLast == nullptr) { + return PROOF_OF_STAKE_LIMIT.GetCompact(); // genesis block + } + + const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, true); + if (pindexPrev->pprev == nullptr) { + return PROOF_OF_STAKE_LIMIT.GetCompact(); // first block + } + + const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, true); + if (pindexPrevPrev->pprev == nullptr) { + return PROOF_OF_STAKE_LIMIT.GetCompact(); // second block + } + + const int64_t nTargetSpacing = GetTargetSpacing(pindexLast->nHeight); + int64_t nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime(); + + if (nActualSpacing < 0) { + nActualSpacing = nTargetSpacing; + } + + // ppcoin: target change every block + // ppcoin: retarget with exponential moving toward target spacing + CBigNum bnNew; + bnNew.SetCompact(pindexPrev->nBits); + + // Gridcoin - Reset Diff to 1 on 12-19-2014 (R Halford) - Diff sticking at + // 2065 due to many incompatible features: + if (pindexLast->nHeight >= 91387 && pindexLast->nHeight <= 91500) { + return PROOF_OF_STAKE_LIMIT.GetCompact(); + } + + // 1-14-2015 R Halford - Make diff reset to zero after periods of exploding + // diff: + if (GetCurrentDifficulty() > 900000) { + return PROOF_OF_STAKE_LIMIT.GetCompact(); + } + + // Since TARGET_TIMESPAN is (16 * 60) or 16 mins and our TargetSpacing = 64, + // the nInterval = 15 min + + const int64_t nInterval = TARGET_TIMESPAN / nTargetSpacing; + bnNew *= (nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing; + bnNew /= (nInterval + 1) * nTargetSpacing; + + if (bnNew <= 0 || bnNew > PROOF_OF_STAKE_LIMIT) { + bnNew = PROOF_OF_STAKE_LIMIT; + } + + return bnNew.GetCompact(); +} + +double GRC::GetDifficulty(const CBlockIndex* blockindex) +{ + // Floating point number that is a multiple of the minimum difficulty, + // minimum difficulty = 1.0. + if (blockindex == nullptr) { + if (pindexBest == nullptr) { + return 1.0; + } else { + blockindex = GetLastBlockIndex(pindexBest, false); + } + } + + return GetBlockDifficulty(blockindex->nBits); +} + +double GRC::GetBlockDifficulty(unsigned int nBits) +{ + // Floating point number that is a multiple of the minimum difficulty, + // minimum difficulty = 1.0. + int nShift = (nBits >> 24) & 0xff; + double dDiff = (double)0x0000ffff / (double)(nBits & 0x00ffffff); + + while (nShift < 29) { + dDiff *= 256.0; + nShift++; + } + + while (nShift > 29) { + dDiff /= 256.0; + nShift--; + } + + return dDiff; +} + +double GRC::GetCurrentDifficulty() +{ + return GetDifficulty(GetLastBlockIndex(pindexBest, true)); +} + +double GRC::GetTargetDifficulty() +{ + return GetBlockDifficulty(GetNextTargetRequired(pindexBest)); +} + +double GRC::GetAverageDifficulty(unsigned int nPoSInterval) +{ + /* + * Diff is inversely related to Target (without the coinweight multiplier), but proportional to the + * effective number of coins on the network. This is tricky, if you want to get the average target value + * used over an interval you should use a harmonic average, since target is inversely related to diff. If + * on the other hand, you want to average diff in a way to also determine the average coins active in + * the network, you should simply use an arithmetic average. See the relation between diff and estimated + * network weight above. We do not need to take into account the actual spacing of the blocks, because this + * already handled by the retargeting in GetNextTargetRequired, and in fact, given the random distribution + * of block spacing, it would be harmful to use a spacing correction for small nPoSInterval sizes. + * + * Also... The number of stakes to include in the average has been reduced to 40 (default) from 72. + * 72 stakes represented 1.8 hours at standard spacing. This is too long. 40 blocks is nominally 1 hour. + */ + + double dDiff = 1.0; + double dDiffSum = 0.0; + unsigned int nStakesHandled = 0; + double result; + + CBlockIndex* pindex = pindexBest; + + while (pindex && nStakesHandled < nPoSInterval) + { + if (pindex->IsProofOfStake()) + { + dDiff = GetDifficulty(pindex); + // dDiff should never be zero, but just in case, skip the block and move to the next one. + if (dDiff) + { + dDiffSum += dDiff; + nStakesHandled++; + LogPrint(BCLog::LogFlags::NOISY, "GetAverageDifficulty debug: dDiff = %f", dDiff); + LogPrint(BCLog::LogFlags::NOISY, "GetAverageDifficulty debug: nStakesHandled = %u", nStakesHandled); + } + } + + pindex = pindex->pprev; + } + + result = nStakesHandled ? dDiffSum / nStakesHandled : 0; + LogPrint(BCLog::LogFlags::NOISY, "GetAverageDifficulty debug: Average dDiff = %f", result); + + return result; +} + +uint64_t GRC::GetStakeWeight(const CWallet& wallet) +{ + if (wallet.GetBalance() <= nReserveBalance) { + return 0; + } + + const int64_t now = GetAdjustedTime(); + + std::vector> coins; + GRC::MinerStatus::ReasonNotStakingCategory unused; + + if (!wallet.SelectCoinsForStaking(now, coins, unused)) { + return 0; + } + + CTxDB txdb("r"); + uint64_t weight = 0; + + LOCK2(cs_main, wallet.cs_wallet); + + for (const auto& pcoin : coins) { + CTxIndex txindex; + + if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex)) { + continue; + } + + if (now - pcoin.first->nTime > nStakeMinAge) { + weight += (pcoin.first->vout[pcoin.second].nValue); + } + } + + return weight; +} + +double GRC::GetEstimatedNetworkWeight(unsigned int nPoSInterval) +{ + // The number of stakes to include in the average has been reduced to 40 (default) from 72. 72 stakes represented 1.8 hours at + // standard spacing. This is too long. 40 blocks is nominally 1 hour. + double result; + + // The constant below comes from (MaxHash / StandardDifficultyTarget) * 16 sec / 90 sec. If you divide it by 80 to convert to GRC you + // get the familiar 9544517.40667 + result = 763561392.533 * GetAverageDifficulty(nPoSInterval); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedNetworkWeight debug: Network Weight = %f", result); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedNetworkWeight debug: Network Weight in GRC = %f", result / 80.0); + + return result; +} + +double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double dConfidence) +{ + /* + * The algorithm below is an attempt to come up with a more accurate way of estimating Time to Stake (ETTS) based on + * the actual situation of the miner and UTXO's. A simple equation will not provide good results, because in mainnet, + * the cooldown period is 16 hours, and depending on how many UTXO's and where they are with respect to getting out of + * cooldown has a lot to do with the expected time to stake. + * + * The way to conceptualize the approach below is to think of the UTXO's as bars on a Gantt Chart. It is a negative Gantt + * chart, meaning that each UTXO bar is cooldown period long, and while the current time is in that bar, the staking probability + * for the UTXO is zero, and UnitStakingProbability elsewhere. A timestamp mask of 16x the normal mask is used to reduce + * the work in the nested loop, so that a 16 hour interval will have a maximum of 225 events, and most likely far less. + * This is important, because the inner loop will be the number of UTXO's. A future improvement to this algorithm would + * also be to quantize (group) the UTXO's themselves (the Gantt bars) so that the work would be further reduced. + * You will see that once the UTXO's are sorted in ascending order based on the time of the end of each of their cooldowns, this + * becomes a manageable algorithm to piece the probabilities together. + * + * You will note that the compound Poisson (geometric) recursive probability relation is used, since you cannot simply add + * the probabilities due to consideration of high confidence (CDF) values of 80% or more. + * + * Thin local data structures are used to hold the UTXO information. This minimizes the amount of time + * that locks on the wallet need to be held at the expense of a little memory consumption. + */ + + double result = 0.0; + + // dDiff must be >= 0 and dConfidence must lie on the interval [0,1) otherwise this is an error. + assert(dDiff >= 0 && dConfidence >= 0 && dConfidence < 1); + + // if dConfidence = 0, then the result must be 0. + if (!dConfidence) + { + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: Confidence of 0 specified: ETTS = %f", result); + return result; + } + + bool staking; + bool able_to_stake; + + { + LOCK(g_miner_status.lock); + + staking = g_miner_status.nLastCoinStakeSearchInterval && g_miner_status.WeightSum; + + able_to_stake = g_miner_status.able_to_stake; + } + + // Get out early if not staking, ignore_staking_status is false, and not able_to_stake and set return value of 0. + if (!ignore_staking_status && !staking && !able_to_stake) + { + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: Not staking: ETTS = %f", result); + return result; + } + + int64_t nValue = 0; + int64_t nCurrentTime = GetAdjustedTime(); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nCurrentTime = %i", nCurrentTime); + + CTxDB txdb("r"); + + // Here I am defining a time mask 16 times as long as the normal stake time mask. This is to quantize the UTXO's into a maximum of + // 16 hours * 3600 / 256 = 225 time bins for evaluation. Otherwise for a large number of UTXO's, this algorithm could become + // really expensive. + const int ETTS_TIMESTAMP_MASK = (16 * (GRC::STAKE_TIMESTAMP_MASK + 1)) - 1; + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: ETTS_TIMESTAMP_MASK = %x", ETTS_TIMESTAMP_MASK); + + int64_t BalanceAvailForStaking = 0; + std::vector vCoins; + + { + LOCK2(cs_main, pwalletMain->cs_wallet); + + BalanceAvailForStaking = pwalletMain->GetBalance() - nReserveBalance; + + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: BalanceAvailForStaking = %u", BalanceAvailForStaking); + + // Get out early if no balance available and set return value of 0. This should already have happened above, because with no + // balance left after reserve, staking should be disabled; however, just to be safe... + if (BalanceAvailForStaking <= 0) + { + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: No balance available: ETTS = %f", result); + return result; + } + + //reminder... void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl=nullptr, bool fIncludeStakingCoins=false) const; + pwalletMain->AvailableCoins(vCoins, true, nullptr, true); + } + + + // An efficient local structure to store the UTXO's with the bare minimum info we need. + typedef std::vector< std::pair > vCoinsExt; + vCoinsExt vUTXO; + // A local ordered set to store the unique "bins" corresponding to the UTXO transaction times. We are going to use this + // for the outer loop. + std::set UniqueUTXOTimes; + // We want the first "event" to be the CurrentTime. This does not have to be quantized. + UniqueUTXOTimes.insert(nCurrentTime); + + // Debug output cooldown... + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nStakeMinAge = %i", nStakeMinAge); + + // If dDiff = 0 from supplied argument (which is also the default), then derive a smoothed difficulty over the default PoSInterval of 40 blocks by calling + // GetAverageDifficulty(40), otherwise let supplied argument dDiff stand. + if (!dDiff) dDiff = GetAverageDifficulty(40); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dDiff = %f", dDiff); + + // The stake probability per "throw" of 1 weight unit = target value at diff of 1.0 / (maxhash * diff). This happens effectively every STAKE_TIMESTAMP_MASK+1 sec. + double dUnitStakeProbability = 1 / (4295032833.0 * dDiff); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dUnitStakeProbability = %e", dUnitStakeProbability); + + + int64_t nTime = 0; + for (const auto& out : vCoins) + { + CTxIndex txindex; + CBlock CoinBlock; //Block which contains CoinTx + if (!txdb.ReadTxIndex(out.tx->GetHash(), txindex)) continue; //Ignore transactions that can't be read. + + if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) continue; + + // We are going to store as an event the time that the UTXO matures (is available for staking again.) + nTime = (CoinBlock.GetBlockTime() & ~ETTS_TIMESTAMP_MASK) + nStakeMinAge; + + nValue = out.tx->vout[out.i].nValue; + + // Only consider UTXO's that are actually stakeable - which means that each one must be less than the available balance + // subtracting the reserve. Each UTXO also has to be greater than 1/80 GRC to result in a weight greater than zero in the CreateCoinStake loop, + // so eliminate UTXO's with less than 0.0125 GRC balances right here. The test with Satoshi units for that is + // nValue >= 1250000. + if (BalanceAvailForStaking >= nValue && nValue >= 1250000) + { + vUTXO.push_back(std::pair( nTime, nValue)); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: pair (relative to current time: <%i, %i>", nTime - nCurrentTime, nValue); + + // Only record a time below if it is after nCurrentTime, because UTXO's that have matured already are already stakeable and can be grouped (will be found) + // by the nCurrentTime record that was already injected above. + if (nTime > nCurrentTime) UniqueUTXOTimes.insert(nTime); + } + } + + + int64_t nTimePrev = nCurrentTime; + int64_t nDeltaTime = 0; + int64_t nThrows = 0; + int64_t nCoinWeight = 0; + double dProbAccumulator = 0; + double dCumulativeProbability = 0; + // Note: Even though this is a compound Poisson process leading to a compound geometric distribution, and the individual probabilities are + // small, we are mounting to high CDFs. This means to be reasonably accurate, we cannot just add the probabilities, because the intersections + // become significant. The CDF of a compound geometric distribution as you do tosses with different probabilities follows the + // recursion relation... CDF.i = 1 - (1 - CDF.i-1)(1 - p.i). If all probabilities are the same, this reduces to the familiar + // CDF.k = 1 - (1 - p)^k where ^ is exponentiation. + for (const auto& itertime : UniqueUTXOTimes) + { + + nTime = itertime; + dProbAccumulator = 0; + + for (auto& iterUTXO : vUTXO) + { + + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: Unique UTXO Time: %u, vector pair <%u, %u>", nTime, iterUTXO.first, iterUTXO.second); + + // If the "negative Gantt chart bar" is ending or has ended for a UTXO, it now accumulates probability. (I.e. the event time being checked + // is greater than or equal to the cooldown expiration of the UTXO.) + // accumulation for that UTXO. + if(nTime >= iterUTXO.first) + { + // The below weight calculation is just like the CalculateStakeWeightV8 in kernel.cpp. + nCoinWeight = iterUTXO.second / 1250000; + + dProbAccumulator = 1 - ((1 - dProbAccumulator) * (1 - (dUnitStakeProbability * nCoinWeight))); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dProbAccumulator = %e", dProbAccumulator); + } + + } + nDeltaTime = nTime - nTimePrev; + nThrows = nDeltaTime / (GRC::STAKE_TIMESTAMP_MASK + 1); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nThrows = %i", nThrows); + dCumulativeProbability = 1 - ((1 - dCumulativeProbability) * pow((1 - dProbAccumulator), nThrows)); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dCumulativeProbability = %e", dCumulativeProbability); + + if (dCumulativeProbability >= dConfidence) break; + + nTimePrev = nTime; + } + + // If (dConfidence - dCumulativeProbability) > 0, it means we exited the negative Gantt chart area and the desired confidence level + // has not been reached. All of the eligible UTXO's are contributing probability, and this is the final dProbAccumulator value. + // If the loop above is degenerate (i.e. only the current time pass through), then dCumulativeProbability will be zero. + // If it was not degenerate and the positive reqions in the Gantt chart area contributed some probability, then dCumulativeProbability will + // be greater than zero. We must compute the amount of time beyond nTime that is required to bridge the gap between + // dCumulativeProbability and dConfidence. If (dConfidence - dCumulativeProbability) <= 0 then we overshot during the Gantt chart area, + // and we will back off by nThrows amount, which will now be negative. + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dProbAccumulator = %e", dProbAccumulator); + + // Shouldn't happen because if we are down here, we are staking, and there have to be eligible UTXO's, but just in case... + if (dProbAccumulator == 0.0) + { + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: ERROR in dProbAccumulator calculations"); + return result; + } + + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dConfidence = %f", dConfidence); + // If nThrows is negative, this just means we overshot in the Gantt chart loop and have to backtrack by nThrows. + nThrows = (int64_t)((log(1 - dConfidence) - log(1 - dCumulativeProbability)) / log(1 - dProbAccumulator)); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nThrows = %i", nThrows); + + nDeltaTime = nThrows * (GRC::STAKE_TIMESTAMP_MASK + 1); + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nDeltaTime = %i", nDeltaTime); + + // Because we are looking at the delta time required past nTime, which is where we exited the Gantt chart loop. + result = nDeltaTime + nTime - nCurrentTime; + LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: ETTS at %d confidence = %i", dConfidence, result); + + return result; +} diff --git a/src/gridcoin/staking/difficulty.h b/src/gridcoin/staking/difficulty.h new file mode 100644 index 0000000000..8e27b6e252 --- /dev/null +++ b/src/gridcoin/staking/difficulty.h @@ -0,0 +1,27 @@ +// Copyright (c) 2011-2012 The PPCoin developers +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +class CBlockIndex; +class CWallet; + +namespace GRC { +// Note that dDiff cannot be = 0 normally. This is set as default because you can't specify the output of +// GetAverageDifficulty(nPosInterval) = to dDiff here. +// The defeult confidence is 1-1/e which is the mean for the geometric distribution for small probabilities. +const double DEFAULT_ETTS_CONFIDENCE = 1.0 - 1.0 / exp(1.0); + +unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast); +double GetDifficulty(const CBlockIndex* blockindex = nullptr); +double GetBlockDifficulty(unsigned int nBits); +double GetCurrentDifficulty(); +double GetTargetDifficulty(); +double GetAverageDifficulty(unsigned int nPoSInterval = 40); + +uint64_t GetStakeWeight(const CWallet& wallet); +double GetEstimatedNetworkWeight(unsigned int nPoSInterval = 40); +double GetEstimatedTimetoStake(bool ignore_staking_status = false, double dDiff = 0.0, double dConfidence = DEFAULT_ETTS_CONFIDENCE); +} // namespace GRC diff --git a/src/gridcoin.cpp b/src/gridcoin/staking/exceptions.cpp similarity index 98% rename from src/gridcoin.cpp rename to src/gridcoin/staking/exceptions.cpp index 6d677c4141..48464810ac 100644 --- a/src/gridcoin.cpp +++ b/src/gridcoin/staking/exceptions.cpp @@ -1,4 +1,8 @@ -#include "gridcoin.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/staking/exceptions.h" extern bool fTestNet; @@ -246,7 +250,7 @@ namespace }; } -const std::set& GetBadBlocks() +const std::set& GRC::GetBadBlocks() { return fTestNet ? bad_blocks_testnet diff --git a/src/gridcoin.h b/src/gridcoin/staking/exceptions.h similarity index 64% rename from src/gridcoin.h rename to src/gridcoin/staking/exceptions.h index 8ec2bdb95c..7ef4a58073 100644 --- a/src/gridcoin.h +++ b/src/gridcoin/staking/exceptions.h @@ -1,8 +1,13 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include #include "uint256.h" +namespace GRC { //! //! \brief Get bad block list. //! @@ -13,3 +18,4 @@ //! \return A list of currently known bad blocks. //! const std::set& GetBadBlocks(); +} diff --git a/src/kernel.cpp b/src/gridcoin/staking/kernel.cpp similarity index 96% rename from src/kernel.cpp rename to src/gridcoin/staking/kernel.cpp index cb56cdbb53..8600ce50ec 100644 --- a/src/kernel.cpp +++ b/src/gridcoin/staking/kernel.cpp @@ -1,16 +1,17 @@ // Copyright (c) 2012-2013 The PPCoin developers -// Copyright (c) 2014 The Gridcoin developers +// Copyright (c) 2014-2020 The Gridcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "arith_uint256.h" -#include "kernel.h" +#include "gridcoin/staking/kernel.h" #include "txdb.h" #include "main.h" #include "streams.h" #include "util.h" using namespace std; +using namespace GRC; namespace { //! @@ -167,8 +168,10 @@ int64_t GetRSAWeightByBlock(const std::string& bb) } } // anonymous namespace +unsigned int GRC::nModifierInterval = 10 * 60; // time to elapse before new modifier is computed + // Get time weight -int64_t GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd) +int64_t GRC::GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd) { // Kernel hash weight starts from 0 at the min age // this change increases active coins participating the hash and helps @@ -266,7 +269,7 @@ static bool SelectBlockFromCandidates( // block. This is to make it difficult for an attacker to gain control of // additional bits in the stake modifier, even after generating a chain of // blocks. -bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier) +bool GRC::ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier) { nStakeModifier = 0; fGeneratedStakeModifier = false; @@ -371,7 +374,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod } // Get stake modifier checksum -unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) +unsigned int GRC::GetStakeModifierChecksum(const CBlockIndex* pindex) { if (pindex->pprev == nullptr && pindexGenesisBlock && pindex != pindexGenesisBlock) { @@ -394,12 +397,12 @@ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) } // Check stake modifier hard checkpoints -bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum) +bool GRC::CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum) { return true; } -bool ReadStakedInput( +bool GRC::ReadStakedInput( CTxDB& txdb, const uint256 prevout_hash, CBlockHeader& out_header, @@ -435,7 +438,7 @@ bool ReadStakedInput( return true; } -bool CalculateLegacyV3HashProof( +bool GRC::CalculateLegacyV3HashProof( CTxDB& txdb, const CBlock& block, const double por_nonce, @@ -506,7 +509,7 @@ bool CalculateLegacyV3HashProof( // good tx hash is not possible as it is not known what stake modifier will be // after the coins mature! -uint256 CalculateStakeHashV8( +uint256 GRC::CalculateStakeHashV8( const CBlockHeader& CoinBlock, const CTransaction& CoinTx, unsigned CoinTxN, @@ -524,7 +527,7 @@ uint256 CalculateStakeHashV8( return ss.GetHash(); } -int64_t CalculateStakeWeightV8(const CTransaction &CoinTx, unsigned CoinTxN) +int64_t GRC::CalculateStakeWeightV8(const CTransaction &CoinTx, unsigned CoinTxN) { int64_t nValueIn = CoinTx.vout[CoinTxN].nValue; nValueIn /= 1250000; @@ -533,7 +536,7 @@ int64_t CalculateStakeWeightV8(const CTransaction &CoinTx, unsigned CoinTxN) // Another version of GetKernelStakeModifier (TomasBrod) // Todo: security considerations -bool FindStakeModifierRev(uint64_t& nStakeModifier,CBlockIndex* pindexPrev) +bool GRC::FindStakeModifierRev(uint64_t& nStakeModifier,CBlockIndex* pindexPrev) { nStakeModifier = 0; const CBlockIndex* pindex = pindexPrev; @@ -554,7 +557,7 @@ bool FindStakeModifierRev(uint64_t& nStakeModifier,CBlockIndex* pindexPrev) // Block Version 8+ check procedure -bool CheckProofOfStakeV8( +bool GRC::CheckProofOfStakeV8( CTxDB& txdb, CBlockIndex* pindexPrev, //previous block in chain index CBlock& Block, //block to check diff --git a/src/kernel.h b/src/gridcoin/staking/kernel.h similarity index 97% rename from src/kernel.h rename to src/gridcoin/staking/kernel.h index 2331d8d0a9..4964a80423 100644 --- a/src/kernel.h +++ b/src/gridcoin/staking/kernel.h @@ -1,11 +1,13 @@ // Copyright (c) 2012-2013 The PPCoin developers +// Copyright (c) 2014-2020 The Gridcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef PPCOIN_KERNEL_H -#define PPCOIN_KERNEL_H + +#pragma once #include "main.h" +namespace GRC { // To decrease granularity of timestamp // Supposed to be 2^n-1 static const int STAKE_TIMESTAMP_MASK = 15; @@ -102,5 +104,4 @@ uint256 CalculateStakeHashV8( uint64_t StakeModifier); int64_t CalculateStakeWeightV8(const CTransaction &CoinTx, unsigned CoinTxN); - -#endif // PPCOIN_KERNEL_H +} // namespace GRC diff --git a/src/gridcoin/staking/reward.cpp b/src/gridcoin/staking/reward.cpp new file mode 100644 index 0000000000..6682d674fe --- /dev/null +++ b/src/gridcoin/staking/reward.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/appcache.h" +#include "gridcoin/staking/reward.h" +#include "main.h" + +namespace { +int64_t GetCoinYearReward(int64_t nTime) +{ + // Gridcoin Global Interest Rate Schedule + int64_t INTEREST = 9; + + if (nTime >= 1410393600 && nTime <= 1417305600) INTEREST = 9 * CENT; // 09% between inception and 11-30-2014 + if (nTime >= 1417305600 && nTime <= 1419897600) INTEREST = 8 * CENT; // 08% between 11-30-2014 and 12-30-2014 + if (nTime >= 1419897600 && nTime <= 1422576000) INTEREST = 8 * CENT; // 08% between 12-30-2014 and 01-30-2015 + if (nTime >= 1422576000 && nTime <= 1425254400) INTEREST = 7 * CENT; // 07% between 01-30-2015 and 02-30-2015 + if (nTime >= 1425254400 && nTime <= 1427673600) INTEREST = 6 * CENT; // 06% between 02-30-2015 and 03-30-2015 + if (nTime >= 1427673600 && nTime <= 1430352000) INTEREST = 5 * CENT; // 05% between 03-30-2015 and 04-30-2015 + if (nTime >= 1430352000 && nTime <= 1438310876) INTEREST = 4 * CENT; // 04% between 05-01-2015 and 07-31-2015 + if (nTime >= 1438310876 && nTime <= 1447977700) INTEREST = 3 * CENT; // 03% between 08-01-2015 and 11-20-2015 + if (nTime > 1447977700) INTEREST = 1.5 * CENT; //1.5% from 11-21-2015 forever + + return INTEREST; +} +} // Anonymous namespace + +// ----------------------------------------------------------------------------- +// Functions +// ----------------------------------------------------------------------------- + +int64_t GRC::GetConstantBlockReward(const CBlockIndex* index) +{ + // The constant block reward is set to a default, voted on value, but this can + // be overridden using an admin message. This allows us to change the reward + // amount without having to release a mandatory with updated rules. In the case + // there is a breach or leaked admin keys the rewards are clamped to twice that + // of the default value. + const int64_t MIN_CBR = 0; + const int64_t MAX_CBR = DEFAULT_CBR * 2; + + int64_t reward = DEFAULT_CBR; + AppCacheEntry oCBReward = ReadCache(Section::PROTOCOL, "blockreward1"); + + //TODO: refactor the expire checking to subroutine + //Note: time constant is same as GetBeaconPublicKey + if ((index->nTime - oCBReward.timestamp) <= (60 * 24 * 30 * 6 * 60)) { + reward = atoi64(oCBReward.value); + } + + reward = std::max(reward, MIN_CBR); + reward = std::min(reward, MAX_CBR); + + return reward; +} + +int64_t GRC::GetProofOfStakeReward( + const uint64_t nCoinAge, + const int64_t nTime, + const CBlockIndex* const pindexLast) +{ + if (pindexLast->nVersion >= 10) { + return GetConstantBlockReward(pindexLast); + } + + return nCoinAge * GetCoinYearReward(nTime) * 33 / (365 * 33 + 8); +} diff --git a/src/gridcoin/staking/reward.h b/src/gridcoin/staking/reward.h new file mode 100644 index 0000000000..26abfecc35 --- /dev/null +++ b/src/gridcoin/staking/reward.h @@ -0,0 +1,16 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +class CBlockIndex; + +namespace GRC { +int64_t GetProofOfStakeReward( + uint64_t nCoinAge, + int64_t nTime, + const CBlockIndex* const pindexLast); + +int64_t GetConstantBlockReward(const CBlockIndex* index); +} // namespace GRC diff --git a/src/gridcoin/staking/status.cpp b/src/gridcoin/staking/status.cpp new file mode 100644 index 0000000000..1e38746c8e --- /dev/null +++ b/src/gridcoin/staking/status.cpp @@ -0,0 +1,82 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/staking/status.h" + +#include + +using namespace GRC; + +namespace { +//! +//! \brief Text descriptions to display when a wallet cannot stake. +//! +//! The sequence of this array matches the items enumerated on +//! MinerStatus::ReasonNotStakingCategory. Update this list as +//! well when those change. +//! +constexpr const char* STAKING_ERROR_STRINGS[] { + "None", + "No Mature Coins", + "No coins", + "Entire balance reserved", + "No UTXOs available due to reserve balance", + "Wallet locked", + "Testnet-only version", + "Offline", +}; +} // Anonymous namespace + +// ----------------------------------------------------------------------------- +// Global Variables +// ----------------------------------------------------------------------------- + +MinerStatus g_miner_status; + +// ----------------------------------------------------------------------------- +// Class: MinerStatus +// ----------------------------------------------------------------------------- + +MinerStatus::MinerStatus(void) +{ + Clear(); + ClearReasonsNotStaking(); + CreatedCnt = AcceptedCnt = KernelsFound = 0; +} + +void MinerStatus::Clear() +{ + WeightSum = ValueSum = WeightMin = WeightMax = 0; + Version = 0; + nLastCoinStakeSearchInterval = 0; +} + +bool MinerStatus::SetReasonNotStaking(ReasonNotStakingCategory not_staking_error) +{ + bool inserted = false; + + if (std::find(vReasonNotStaking.begin(), vReasonNotStaking.end(), not_staking_error) == vReasonNotStaking.end()) + { + vReasonNotStaking.insert(vReasonNotStaking.end(), not_staking_error); + + if (not_staking_error != NONE) + { + if (!ReasonNotStaking.empty()) ReasonNotStaking += "; "; + ReasonNotStaking += STAKING_ERROR_STRINGS[static_cast(not_staking_error)]; + } + + if (not_staking_error > NO_MATURE_COINS) able_to_stake = false; + + inserted = true; + } + + return inserted; +} + +void MinerStatus::ClearReasonsNotStaking() +{ + vReasonNotStaking.clear(); + ReasonNotStaking.clear(); + able_to_stake = true; +} diff --git a/src/gridcoin/staking/status.h b/src/gridcoin/staking/status.h new file mode 100644 index 0000000000..dd87b680c2 --- /dev/null +++ b/src/gridcoin/staking/status.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "sync.h" +#include "uint256.h" + +#include +#include + +namespace GRC { +class MinerStatus +{ +public: + CCriticalSection lock; + + // Update STAKING_ERROR_STRINGS when adding or removing items. + enum ReasonNotStakingCategory + { + NONE, + NO_MATURE_COINS, + NO_COINS, + ENTIRE_BALANCE_RESERVED, + NO_UTXOS_AVAILABLE_DUE_TO_RESERVE, + WALLET_LOCKED, + TESTNET_ONLY, + OFFLINE + }; + + std::vector vReasonNotStaking; + bool able_to_stake = true; + std::string ReasonNotStaking; + + uint64_t WeightSum, WeightMin, WeightMax; + double ValueSum; + int Version; + uint64_t CreatedCnt; + uint64_t AcceptedCnt; + uint64_t KernelsFound; + int64_t nLastCoinStakeSearchInterval; + uint256 m_last_pos_tx_hash; + + void Clear(); + MinerStatus(); + + bool SetReasonNotStaking(ReasonNotStakingCategory not_staking_error); + void ClearReasonsNotStaking(); +}; // MinerStatus +} // namespace GRC + +extern GRC::MinerStatus g_miner_status; diff --git a/src/gridcoin/superblock.cpp b/src/gridcoin/superblock.cpp index eb6687abab..95528f2736 100644 --- a/src/gridcoin/superblock.cpp +++ b/src/gridcoin/superblock.cpp @@ -1,7 +1,12 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "compat/endian.h" #include "hash.h" #include "main.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/xml.h" #include "sync.h" #include "util.h" #include "util/reverse_iterator.h" @@ -13,8 +18,6 @@ using namespace GRC; extern ScraperStatsAndVerifiedBeacons GetScraperStatsAndVerifiedBeacons(const ConvergedScraperStats& stats); -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end); - namespace { //! //! \brief Loads a provided set of scraper statistics into a superblock. diff --git a/src/gridcoin/superblock.h b/src/gridcoin/superblock.h index 0b736273d6..13e9d39632 100644 --- a/src/gridcoin/superblock.h +++ b/src/gridcoin/superblock.h @@ -1,9 +1,13 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/cpid.h" #include "gridcoin/magnitude.h" +#include "gridcoin/scraper/fwd.h" #include "serialize.h" -#include "scraper/fwd.h" #include "uint256.h" #include @@ -441,6 +445,27 @@ class Superblock magnitude = ReadCompactSize(stream); } + //! + //! \brief Record the serialized size of the magnitude map. + //! + //! This overload optimizes the size calculation for the small and + //! medium magnitude maps in the superblock. These maps only store + //! magnitude values fixed to one byte in size so we avoid looping + //! over the collections to compute the total. The large magnitude + //! map serializes values as either one or two bytes so we need to + //! iterate over each item, but a superblock contains far fewer of + //! these records. + //! + //! \param s The size computer instance to record the size with. + //! + template + typename std::enable_if::value>::type + Serialize(CSizeComputer& s) const + { + WriteCompactSize(s, m_magnitudes.size()); + s.seek((sizeof(Cpid) + sizeof(MagnitudeSize)) * m_magnitudes.size()); + } + //! //! \brief Serialize the object to the provided stream. //! diff --git a/src/block.cpp b/src/gridcoin/support/block_finder.cpp similarity index 87% rename from src/block.cpp rename to src/gridcoin/support/block_finder.cpp index 320d2f441b..2e27a8c963 100644 --- a/src/block.cpp +++ b/src/gridcoin/support/block_finder.cpp @@ -1,8 +1,14 @@ -#include "block.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" +#include "gridcoin/support/block_finder.h" #include +using namespace GRC; + BlockFinder::BlockFinder() : cache(nullptr) {} @@ -30,9 +36,9 @@ CBlockIndex* BlockFinder::FindByHeight(int height) while (index && index->pnext && index->nHeight < height) index = index->pnext; } - + cache = index; - return index; + return index; } CBlockIndex* BlockFinder::FindByMinTime(int64_t time) diff --git a/src/block.h b/src/gridcoin/support/block_finder.h similarity index 81% rename from src/block.h rename to src/gridcoin/support/block_finder.h index f53bdb0310..607f391922 100644 --- a/src/block.h +++ b/src/gridcoin/support/block_finder.h @@ -1,7 +1,12 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once -#include "fwd.h" +class CBlockIndex; +namespace GRC { //! //! \brief Chain traversing block finder. //! @@ -12,13 +17,13 @@ class BlockFinder //! \brief Constructor. //! BlockFinder(); - + //! //! \brief Find a block with a specific height. - //! + //! //! Traverses the chain from head or tail, depending on what's closest to //! find the block that matches \p height. This is a caching operation - //! + //! //! \param nHeight Block height to find. //! \return The block with the height closest to \p nHeight if found, otherwise //! \a nullptr is returned. @@ -27,25 +32,26 @@ class BlockFinder //! //! \brief Find block by time. - //! + //! //! Traverses the chain in the same way as FindByHeight() and stops at the //! block which is not older than \p time, or the youngest block if it is //! older than \p time. - //! + //! //! \param time Block time to search for. //! \return The youngest block which is not older than \p time, or the //! head of the chain if it is older than \p time. //! CBlockIndex* FindByMinTime(int64_t time); - + //! //! \brief Reset finder cache. //! //! Clears the block finder cache. This should be used when blocks are removed //! from the chain to avoid accessing deleted memory. - //! + //! void Reset(); - + private: CBlockIndex* cache; }; +} // namespace GRC diff --git a/src/enumbytes.h b/src/gridcoin/support/enumbytes.h similarity index 95% rename from src/enumbytes.h rename to src/gridcoin/support/enumbytes.h index 87fa6708c9..0a59a2a6b9 100644 --- a/src/enumbytes.h +++ b/src/gridcoin/support/enumbytes.h @@ -1,7 +1,12 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "serialize.h" +namespace GRC { //! //! \brief A wrapper around an enum type that provides for serialization of the //! enum values as unsigned integers. @@ -153,3 +158,4 @@ class EnumByte : public EnumBytes { } }; +} // namespace GRC diff --git a/src/filehash.h b/src/gridcoin/support/filehash.h similarity index 80% rename from src/filehash.h rename to src/gridcoin/support/filehash.h index e515df6e64..67d6e61a13 100644 --- a/src/filehash.h +++ b/src/gridcoin/support/filehash.h @@ -1,10 +1,14 @@ -#ifndef FILEHASH_H -#define FILEHASH_H +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once #include "serialize.h" #include "streams.h" #include "hash.h" +namespace GRC { class CAutoHasherFile : public CAutoFile, public CHashWriter { public: @@ -42,5 +46,4 @@ class CAutoHasherFile : public CAutoFile, public CHashWriter return *this; } }; - -#endif // FILEHASH_H +} // namespace GRC diff --git a/src/gridcoin/support/xml.h b/src/gridcoin/support/xml.h new file mode 100644 index 0000000000..24ce3d1cb2 --- /dev/null +++ b/src/gridcoin/support/xml.h @@ -0,0 +1,24 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + +inline std::string ExtractXML(const std::string& xml, const std::string& key, const std::string& key_end) +{ + std::string::size_type loc = xml.find(key, 0); + + if (loc == std::string::npos) { + return ""; + } + + std::string::size_type loc_end = xml.find(key_end, loc + 3); + + if (loc_end == std::string::npos) { + return ""; + } + + return xml.substr(loc + (key.length()), loc_end - loc - (key.length())); +} diff --git a/src/gridcoin/tally.cpp b/src/gridcoin/tally.cpp index 7c0facb754..78bdb47845 100644 --- a/src/gridcoin/tally.cpp +++ b/src/gridcoin/tally.cpp @@ -1,3 +1,8 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparams.h" #include "main.h" #include "gridcoin/accrual/newbie.h" #include "gridcoin/accrual/null.h" @@ -174,7 +179,7 @@ class ResearcherTally m_start_pindex = pindex; for (; pindex; pindex = pindex->pnext) { - if (pindex->nHeight + 1 == GetV11Threshold()) { + if (pindex->nHeight + 1 == Params().GetConsensus().BlockV11Height) { // Set the timestamp for the block version 11 threshold. This // is temporary. Remove this variable in a release that comes // after the hard fork. For now, this is the least cumbersome @@ -490,7 +495,7 @@ class ResearcherTally // starting height yet, so the tally will initialize without it. // if (m_start_pindex == nullptr && pindexGenesisBlock != nullptr) { - const int32_t threshold = GetResearchAgeThreshold(); + const int32_t threshold = Params().GetConsensus().ResearchAgeHeight; const CBlockIndex* pindex = pindexGenesisBlock; for (; pindex && pindex->nHeight < threshold; pindex = pindex->pnext); diff --git a/src/gridcoin/tally.h b/src/gridcoin/tally.h index 7c5eab1916..ed550237d5 100644 --- a/src/gridcoin/tally.h +++ b/src/gridcoin/tally.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/account.h" diff --git a/src/gridcoin/tx_message.h b/src/gridcoin/tx_message.h index 9bec6cbc9f..08b47f08d7 100644 --- a/src/gridcoin/tx_message.h +++ b/src/gridcoin/tx_message.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/contract/payload.h" diff --git a/src/upgrade.cpp b/src/gridcoin/upgrade.cpp similarity index 97% rename from src/upgrade.cpp rename to src/gridcoin/upgrade.cpp index ef4e5044f3..1d2780214f 100644 --- a/src/upgrade.cpp +++ b/src/gridcoin/upgrade.cpp @@ -1,4 +1,8 @@ -#include "upgrade.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/upgrade.h" #include "util.h" #include "init.h" @@ -16,9 +20,11 @@ #include #include -struct_SnapshotExtractStatus ExtractStatus; +using namespace GRC; + +struct_SnapshotExtractStatus GRC::ExtractStatus; -bool fCancelOperation = false; +bool GRC::fCancelOperation = false; Upgrade::Upgrade() { diff --git a/src/upgrade.h b/src/gridcoin/upgrade.h similarity index 94% rename from src/upgrade.h rename to src/gridcoin/upgrade.h index cd448713f6..13c18f262e 100644 --- a/src/upgrade.h +++ b/src/gridcoin/upgrade.h @@ -1,5 +1,8 @@ -#ifndef UPGRADE_H -#define UPGRADE_H +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once #include #include @@ -7,9 +10,11 @@ #include #include -#include "scraper/http.h" +#include "gridcoin/scraper/http.h" #include "ui_interface.h" +namespace GRC { + /** Snapshot Extraction Status struct **/ struct struct_SnapshotExtractStatus{ bool SnapshotZipInvalid = false; @@ -217,9 +222,7 @@ class Progress ProgressString << StartStrings[Type] << StartBar; } }; +} // namespace GRC /** Unique Pointer for CScheduler for update checks **/ -extern std::unique_ptr g_UpdateChecker; - -#endif // UPGRADE_H - +extern std::unique_ptr g_UpdateChecker; diff --git a/src/gridcoin/voting/builders.cpp b/src/gridcoin/voting/builders.cpp index 1f2fa1a5fb..c86343f321 100644 --- a/src/gridcoin/voting/builders.cpp +++ b/src/gridcoin/voting/builders.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "init.h" #include "main.h" #include "gridcoin/beacon.h" diff --git a/src/gridcoin/voting/builders.h b/src/gridcoin/voting/builders.h index 31e767c941..41541aaf33 100644 --- a/src/gridcoin/voting/builders.h +++ b/src/gridcoin/voting/builders.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/voting/fwd.h" diff --git a/src/gridcoin/voting/claims.cpp b/src/gridcoin/voting/claims.cpp index 56ce44b062..d0ff565232 100644 --- a/src/gridcoin/voting/claims.cpp +++ b/src/gridcoin/voting/claims.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "hash.h" #include "main.h" #include "gridcoin/voting/claims.h" diff --git a/src/gridcoin/voting/claims.h b/src/gridcoin/voting/claims.h index bcb3372981..8bfa230522 100644 --- a/src/gridcoin/voting/claims.h +++ b/src/gridcoin/voting/claims.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "key.h" diff --git a/src/gridcoin/voting/fwd.h b/src/gridcoin/voting/fwd.h index f8cb67a33d..7c63391dd2 100644 --- a/src/gridcoin/voting/fwd.h +++ b/src/gridcoin/voting/fwd.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include diff --git a/src/gridcoin/voting/payloads.h b/src/gridcoin/voting/payloads.h index c52ed23d30..4c79c74928 100644 --- a/src/gridcoin/voting/payloads.h +++ b/src/gridcoin/voting/payloads.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/contract/payload.h" diff --git a/src/gridcoin/voting/poll.cpp b/src/gridcoin/voting/poll.cpp index 1f3a3e99f8..026f7482f4 100644 --- a/src/gridcoin/voting/poll.cpp +++ b/src/gridcoin/voting/poll.cpp @@ -1,4 +1,9 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" +#include "gridcoin/support/xml.h" #include "gridcoin/voting/poll.h" #include "span.h" #include "ui_interface.h" diff --git a/src/gridcoin/voting/poll.h b/src/gridcoin/voting/poll.h index d7a7b999c8..6e271f0973 100644 --- a/src/gridcoin/voting/poll.h +++ b/src/gridcoin/voting/poll.h @@ -1,6 +1,10 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once -#include "enumbytes.h" +#include "gridcoin/support/enumbytes.h" #include "gridcoin/voting/fwd.h" #include "serialize.h" #include "uint256.h" diff --git a/src/gridcoin/voting/registry.cpp b/src/gridcoin/voting/registry.cpp index a8078de7e5..00a5d13dce 100644 --- a/src/gridcoin/voting/registry.cpp +++ b/src/gridcoin/voting/registry.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" #include "gridcoin/contract/contract.h" #include "gridcoin/voting/payloads.h" diff --git a/src/gridcoin/voting/registry.h b/src/gridcoin/voting/registry.h index fc28816671..a1dbd56fbf 100644 --- a/src/gridcoin/voting/registry.h +++ b/src/gridcoin/voting/registry.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/contract/handler.h" diff --git a/src/gridcoin/voting/result.cpp b/src/gridcoin/voting/result.cpp index 0b4cae5a96..82cc444e22 100644 --- a/src/gridcoin/voting/result.cpp +++ b/src/gridcoin/voting/result.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" #include "gridcoin/beacon.h" #include "gridcoin/quorum.h" diff --git a/src/gridcoin/voting/result.h b/src/gridcoin/voting/result.h index 618c1e8d33..710b1cd292 100644 --- a/src/gridcoin/voting/result.h +++ b/src/gridcoin/voting/result.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/cpid.h" diff --git a/src/gridcoin/voting/vote.cpp b/src/gridcoin/voting/vote.cpp index f20695b24c..2b2bfe3c9b 100644 --- a/src/gridcoin/voting/vote.cpp +++ b/src/gridcoin/voting/vote.cpp @@ -1,4 +1,9 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" +#include "gridcoin/support/xml.h" #include "gridcoin/voting/vote.h" using namespace GRC; diff --git a/src/gridcoin/voting/vote.h b/src/gridcoin/voting/vote.h index 12dd434980..71c8349d35 100644 --- a/src/gridcoin/voting/vote.h +++ b/src/gridcoin/voting/vote.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "gridcoin/contract/payload.h" diff --git a/src/gridcoinresearchd.cpp b/src/gridcoinresearchd.cpp index ea25bb1517..d65f6d2370 100644 --- a/src/gridcoinresearchd.cpp +++ b/src/gridcoinresearchd.cpp @@ -7,6 +7,8 @@ #include "config/gridcoin-config.h" #endif +#include "chainparams.h" +#include "chainparamsbase.h" #include "util.h" #include "net.h" #include "txdb.h" @@ -15,13 +17,13 @@ #include "rpcserver.h" #include "rpcclient.h" #include "ui_interface.h" -#include "upgrade.h" +#include "gridcoin/upgrade.h" #include #include -#include "global_objects_noui.hpp" #include +extern bool fQtActive; /* Introduction text for doxygen: */ @@ -70,10 +72,10 @@ bool AppInit(int argc, char* argv[]) // First part of help message is specific to bitcoind / RPC client std::string strUsage = _("Gridcoin version") + " " + FormatFullVersion() + "\n\n" + _("Usage:") + "\n" + - " gridcoind [options] " + "\n" + - " gridcoind [options] [params] " + _("Send command to -server or gridcoind") + "\n" + - " gridcoind [options] help " + _("List commands") + "\n" + - " gridcoind [options] help " + _("Get help for a command") + "\n"; + " gridcoinresearchd [options] " + "\n" + + " gridcoinresearchd [options] [params] " + _("Send command to -server or gridcoinresearchd") + "\n" + + " gridcoinresearchd [options] help " + _("List commands") + "\n" + + " gridcoinresearchd [options] help " + _("Get help for a command") + "\n"; strUsage += "\n" + HelpMessage(); @@ -95,7 +97,9 @@ bool AppInit(int argc, char* argv[]) } /** Check here config file in case TestNet is set there and not in mapArgs **/ + SelectParams(CBaseChainParams::MAIN); ReadConfigFile(mapArgs, mapMultiArgs); + SelectParams(mapArgs.count("-testnet") ? CBaseChainParams::TESTNET : CBaseChainParams::MAIN); // Command-line RPC - Test this - ensure single commands execute and exit please. for (int i = 1; i < argc; i++) @@ -114,7 +118,7 @@ bool AppInit(int argc, char* argv[]) // Check to see if the user requested a snapshot and we are not running TestNet! if (mapArgs.count("-snapshotdownload") && !mapArgs.count("-testnet")) { - Upgrade Snapshot; + GRC::Upgrade snapshot; // Let's check make sure gridcoin is not already running in the data directory. // Use new probe feature @@ -129,21 +133,21 @@ bool AppInit(int argc, char* argv[]) { try { - Snapshot.SnapshotMain(); + snapshot.SnapshotMain(); } catch (std::runtime_error& e) { LogPrintf("Snapshot Downloader: Runtime exception occurred in SnapshotMain() (%s)", e.what()); - Snapshot.DeleteSnapshot(); + snapshot.DeleteSnapshot(); exit(1); } } // Delete snapshot file - Snapshot.DeleteSnapshot(); + snapshot.DeleteSnapshot(); } LogPrintf("AppInit"); diff --git a/src/init.cpp b/src/init.cpp index 73f88868cd..4828613e02 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -4,8 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "backup.h" -#include "block.h" +#include "chainparams.h" #include "util.h" #include "net.h" #include "txdb.h" @@ -15,10 +14,7 @@ #include "init.h" #include "ui_interface.h" #include "scheduler.h" -#include "gridcoin/quorum.h" -#include "gridcoin/researcher.h" -#include "gridcoin/tally.h" -#include "upgrade.h" +#include "gridcoin/gridcoin.h" #include #include @@ -29,18 +25,12 @@ #include // for to_lower() #include // for startswith() and endswith() -#include "global_objects_noui.hpp" - static boost::thread_group threadGroup; static CScheduler scheduler; extern void ThreadAppInit2(void* parg); bool IsConfigFileEmpty(); -namespace GRC { void ReplayContracts(const CBlockIndex* pindex); } - -extern void UpdateOutOfSyncByAge(); - #ifndef WIN32 #include #include @@ -50,23 +40,18 @@ using namespace std; using namespace boost; CWallet* pwalletMain; CClientUIInterface uiInterface; +extern bool fQtActive; +extern bool bGridcoinCoreInitComplete; extern bool fConfChange; extern bool fEnforceCanonical; extern unsigned int nNodeLifespan; extern unsigned int nDerivationMethodIndex; extern unsigned int nMinerSleep; -extern unsigned int nScraperSleep; -extern unsigned int nActiveBeforeSB; -extern bool fExplorer; extern bool fUseFastIndex; -extern boost::filesystem::path pathScraper; -bool fSnapshotRequest = false; // Dump addresses to banlist.dat every 5 minutes (300 s) static constexpr int DUMP_BANS_INTERVAL = 300; std::unique_ptr g_banman; -/** Update checker pointer for CScheduler; **/ -std::unique_ptr g_UpdateChecker; ////////////////////////////////////////////////////////////////////////////// // @@ -122,7 +107,9 @@ void Shutdown(void* parg) bitdb.Flush(false); StopNode(); bitdb.Flush(true); + StopRPCThreads(); + boost::filesystem::remove(GetPidFile()); UnregisterWallet(pwalletMain); delete pwalletMain; @@ -314,7 +301,7 @@ std::string HelpMessage() " -snapshoturl= " + _("Optional: Specify url of snapshot.zip file (ex: https://sub.domain.com/location/snapshot.zip)") + "\n" " -snapshotsha256url= " + _("Optional: Specify url of snapshot.sha256 file (ex: https://sub.domain.com/location/snapshot.sha256)") + "\n" " -disableupdatecheck " + _("Optional: Disable update checks by wallet") + "\n" - " -updatecheckinterval= " + _("Optional: Specify custom update interval checks in hours (Default: 24 hours (minimum 1 hour))") + "\n" + " -updatecheckinterval= " + _("Optional: Specify custom update interval checks in hours (Default: 120 hours (minimum 1 hour))") + "\n" " -updatecheckurl= " + _("Optional: Specify url of update version checks (ex: https://sub.domain.com/location/latest") + "\n"; return strUsage; @@ -543,45 +530,10 @@ bool AppInit2(ThreadHandlerPtr threads) LogPrintf("Boost Version: %s", s.str()); - - // The purpose of the complicated defaulting below is that if not running - // the scraper the new nn should run by default. If running the scraper, - // then the new NN should not run unless explicitly specified to do so. - - // For example. gridcoinresearch(d) with no args will run the NN but not the scraper. - // gridcoinresearch(d) -scraper will run the scraper but not the NN components. - // gridcoinresearch(d) -scraper -usenewnn will run both the scraper and the NN. - // -disablenn overrides the -usenewnn directive. - - // If -disablenn is NOT specified or set to false... - if (!GetBoolArg("-disablenn", false)) - { - // Then if -scraper is specified (set to true)... - if (GetBoolArg("-scraper", false)) - { - // Activate explorer extended features if -explorer is set - if (GetBoolArg("-explorer", false)) fExplorer = true; - } - } - - if (GRC::Quorum::Active()) - { - LogPrintf("INFO: Native C++ quorum is active."); - } - else - { - LogPrintf("INFO: Native C++ quorum is inactive."); - } - - nNodeLifespan = GetArg("-addrlifespan", 7); fUseFastIndex = GetBoolArg("-fastindex", false); nMinerSleep = GetArg("-minersleep", 8000); - // Default to 300 sec (5 min), clamp to 60 minimum, 600 maximum - converted to milliseconds. - nScraperSleep = std::min(std::max(GetArg("-scrapersleep", 300), (int64_t) 60), (int64_t) 600) * 1000; - // Default to 7200 sec (4 hrs), clamp to 300 minimum, 86400 maximum (meaning active all of the time). - nActiveBeforeSB = std::min(std::max(GetArg("-activebeforesb", 14400), (int64_t) 300), (int64_t) 86400); nDerivationMethodIndex = 0; fTestNet = GetBoolArg("-testnet"); @@ -705,7 +657,7 @@ bool AppInit2(ThreadHandlerPtr threads) std::string sha256_algo = SHA256AutoDetect(); LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); - LogPrintf("Block version 11 hard fork configured for block %d", GetV11Threshold()); + LogPrintf("Block version 11 hard fork configured for block %d", Params().GetConsensus().BlockV11Height); fs::path datadir = GetDataDir(); fs::path walletFileName = GetArg("-wallet", "wallet.dat"); @@ -945,23 +897,6 @@ bool AppInit2(ThreadHandlerPtr threads) } LogPrintf(" block index %15" PRId64 "ms", GetTimeMillis() - nStart); - UpdateOutOfSyncByAge(); - - if (IsV9Enabled(pindexBest->nHeight)) { - uiInterface.InitMessage(_("Loading superblock cache...")); - LogPrintf("Loading superblock cache..."); - GRC::Quorum::LoadSuperblockIndex(pindexBest); - } - - // Initialize the Gridcoin research reward tally system from the first - // research age block (as defined in main.h): - // - uiInterface.InitMessage(_("Initializing research reward tally...")); - if (!GRC::Tally::Initialize(BlockFinder().FindByHeight(GetResearchAgeThreshold()))) - { - return InitError(_("Failed to initialize tally.")); - } - if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) { PrintBlockTree(); @@ -1140,15 +1075,6 @@ bool AppInit2(ThreadHandlerPtr threads) // ********************************************************* Step 11: start node - uiInterface.InitMessage(_("Loading Persisted Data Cache...")); - - GRC::ReplayContracts(pindexBest); - - GRC::Researcher::Initialize(); - - if (!pwalletMain->IsLocked()) - GRC::Researcher::Get()->ImportBeaconKeysFromConfig(pwalletMain); - if (!CheckDiskSpace()) return false; @@ -1164,13 +1090,6 @@ bool AppInit2(ThreadHandlerPtr threads) LogPrintf("mapAddressBook.size() = %" PRIszu, pwalletMain->mapAddressBook.size()); } - if (pindexBest->nVersion <= 10) { - uiInterface.InitMessage(_("Loading Network Averages...")); - LogPrint(BCLog::LogFlags::TALLY, "Loading network averages"); - - GRC::Tally::LegacyRecount(GRC::Tally::FindLegacyTrigger(pindexBest)); - } - if (!threads->createThread(StartNode, NULL, "Start Thread")) InitError(_("Error: could not start node")); @@ -1203,81 +1122,7 @@ bool AppInit2(ThreadHandlerPtr threads) g_banman->DumpBanlist(); }, DUMP_BANS_INTERVAL * 1000); - // Primitive, but this is what the scraper does in the scraper housekeeping loop. It checks to see if the logs need to be archived - // by default every 5 mins. Note that passing false to the archive function means that if we have not crossed over the day boundary, - // it does nothing, so this is a very inexpensive call. Also if -logarchivedaily is set to false, then this will be a no-op. - scheduler.scheduleEvery([]{ - fs::path plogfile_out; - LogInstance().archive(false, plogfile_out); - }, 300 * 1000); - - if (BackupsEnabled()) { - // Run the backup job at a rate of 4x the configured backup interval - // in case the wallet becomes busy when the job runs. This job skips - // a cycle when it encounters lock contention or when a cycle occurs - // sooner than the requested interval: - // - scheduler.scheduleEvery(RunBackupJob, GetBackupInterval() * 1000 / 4); - - // Run the backup job immediately in case the wallet started after a - // long period of downtime. Some usage patterns may cause the wallet - // to start and shutdown frequently without producing a backup if we - // only create backups from the scheduler thread. This is a no-op if - // the wallet contains a stored backup timestamp later than the next - // scheduled backup interval: - // - RunBackupJob(); - } - - scheduler.scheduleEvery(GRC::Researcher::RunRenewBeaconJob, 4 * 60 * 60 * 1000); - - /** If this is not TestNet we check for updates on startup and daily **/ - /** We still add to the scheduler regardless of the users choice however the choice is respected when they opt out**/ - if (!fTestNet) - { - int64_t UpdateCheckInterval = 24; - - // Save some cycles and only so this area if the argument exists - if (mapArgs.count("-updatecheckinterval")) - { - try - { - UpdateCheckInterval = GetArg("-updatecheckinterval", 24); - // trivial: Don't allow checks less then 1 hour apart of update checks to prevent server DDoS (what is a good value) - if (UpdateCheckInterval < 1) - { - LogPrintf("UpdateChecker: Update check interval too small of %" PRId64 "; Defaulting to 24 hour intervals", UpdateCheckInterval); - - UpdateCheckInterval = 24; - } - } - - catch (const std::exception& ex) - { - // Tell them the exception and what they had put in place - LogPrintf("UpdateChecker: Exception occurred while obtaining interval for update checks (ex: %s -updatecheckinterval=%s); Defaulting to 24 hour intervals", ex.what(), GetArgument("-updatecheckinterval", "")); - - UpdateCheckInterval = 24; - } - } - - scheduler.scheduleEvery([]{g_UpdateChecker->CheckForLatestUpdate();}, UpdateCheckInterval * 60 * 60 * 1000); - - if (!GetBoolArg("-disableupdatecheck", false)) - { - LogPrintf("UpdateChecker: Update checks scheduled every %" PRId64 " hours.", UpdateCheckInterval); - - LogPrintf("Updatechecker: Performing startup update check."); - - g_UpdateChecker->CheckForLatestUpdate(); - } - - else - LogPrintf("UpdateChecker: Update checks are disabled by user."); - } - - else - LogPrintf("UpdateChecker: Update checks are disable for TestNet."); + GRC::ScheduleBackgroundJobs(scheduler); return true; } diff --git a/src/main.cpp b/src/main.cpp index 2a3398aa16..d8478a572e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,21 +11,22 @@ #include "txdb.h" #include "init.h" #include "ui_interface.h" -#include "kernel.h" -#include "block.h" -#include "miner.h" #include "gridcoin/beacon.h" #include "gridcoin/claim.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" #include "gridcoin/quorum.h" #include "gridcoin/researcher.h" +#include "gridcoin/scraper/scraper_net.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/staking/exceptions.h" +#include "gridcoin/staking/kernel.h" +#include "gridcoin/staking/reward.h" +#include "gridcoin/staking/status.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/xml.h" #include "gridcoin/tally.h" #include "gridcoin/tx_message.h" -#include "appcache.h" -#include "scraper_net.h" -#include "gridcoin.h" #include #include @@ -62,14 +63,11 @@ BlockMap mapBlockIndex; set > setStakeSeen; CBigNum bnProofOfWorkLimit(ArithToUint256(~arith_uint256() >> 20)); // "standard" scrypt target limit for proof of work, results with 0,000244140625 proof-of-work difficulty -CBigNum bnProofOfStakeLimit(ArithToUint256(~arith_uint256() >> 20)); -CBigNum bnProofOfStakeLimitV2(ArithToUint256(~arith_uint256() >> 20)); CBigNum bnProofOfWorkLimitTestNet(ArithToUint256(~arith_uint256() >> 16)); //Gridcoin Minimum Stake Age (16 Hours) unsigned int nStakeMinAge = 16 * 60 * 60; // 16 hours unsigned int nStakeMaxAge = -1; // unlimited -unsigned int nModifierInterval = 10 * 60; // time to elapse before new modifier is computed // Gridcoin: int nCoinbaseMaturity = 100; @@ -80,10 +78,8 @@ arith_uint256 nBestChainTrust = 0; arith_uint256 nBestInvalidTrust = 0; uint256 hashBestChain; CBlockIndex* pindexBest = NULL; -// Lets try to start using some lockless synchronization. -std::atomic g_nSyncTime {0}; -std::atomic_bool g_fOutOfSyncByAge {true}; -int64_t nTimeBestReceived = 0; +std::atomic g_previous_block_time; +std::atomic g_nTimeBestReceived; CMedianFilter cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have @@ -109,11 +105,8 @@ int64_t nTransactionFee = MIN_TX_FEE * 10; int64_t nReserveBalance = 0; int64_t nMinimumInputValue = 0; -BlockFinder blockFinder; - // Gridcoin - Rob Halford -bool bForceUpdate = false; bool fQtActive = false; bool bGridcoinCoreInitComplete = false; @@ -139,374 +132,21 @@ bool fColdBoot = true; bool fEnforceCanonical = true; bool fUseFastIndex = false; -std::map mvTimers; // Contains event timers that reset after max ms duration iterator is exceeded - // Temporary block version 11 transition helpers: int64_t g_v11_timestamp = 0; int64_t g_v11_legacy_beacon_days = 14; // End of Gridcoin Global vars -////////////////////////////////////////////////////////////////////////////// -// -// dispatching functions -// -bool TimerMain(std::string timer_name, int max_ms) -{ - mvTimers[timer_name] = mvTimers[timer_name] + 1; - if (mvTimers[timer_name] > max_ms) - { - mvTimers[timer_name]=0; - return true; - } - return false; -} - -double GetEstimatedNetworkWeight(unsigned int nPoSInterval) -{ - // The number of stakes to include in the average has been reduced to 40 (default) from 72. 72 stakes represented 1.8 hours at - // standard spacing. This is too long. 40 blocks is nominally 1 hour. - double result; - - // The constant below comes from (MaxHash / StandardDifficultyTarget) * 16 sec / 90 sec. If you divide it by 80 to convert to GRC you - // get the familiar 9544517.40667 - result = 763561392.533 * GetAverageDifficulty(nPoSInterval); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedNetworkWeight debug: Network Weight = %f", result); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedNetworkWeight debug: Network Weight in GRC = %f", result / 80.0); - - return result; -} - -double GetDifficulty(const CBlockIndex* blockindex) -{ - // Floating point number that is a multiple of the minimum difficulty, - // minimum difficulty = 1.0. - if (blockindex == NULL) - { - if (pindexBest == NULL) - return 1.0; - else - blockindex = GetLastBlockIndex(pindexBest, false); - } - - int nShift = (blockindex->nBits >> 24) & 0xff; - - double dDiff = - (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff); - - while (nShift < 29) - { - dDiff *= 256.0; - nShift++; - } - while (nShift > 29) - { - dDiff /= 256.0; - nShift--; - } - - return dDiff; -} - -double GetBlockDifficulty(unsigned int nBits) -{ - // Floating point number that is a multiple of the minimum difficulty, - // minimum difficulty = 1.0. - int nShift = (nBits >> 24) & 0xff; - - double dDiff = - (double)0x0000ffff / (double)(nBits & 0x00ffffff); - - while (nShift < 29) - { - dDiff *= 256.0; - nShift++; - } - while (nShift > 29) - { - dDiff /= 256.0; - nShift--; - } - - return dDiff; -} - -double GetAverageDifficulty(unsigned int nPoSInterval) -{ - /* - * Diff is inversely related to Target (without the coinweight multiplier), but proportional to the - * effective number of coins on the network. This is tricky, if you want to get the average target value - * used over an interval you should use a harmonic average, since target is inversely related to diff. If - * on the other hand, you want to average diff in a way to also determine the average coins active in - * the network, you should simply use an arithmetic average. See the relation between diff and estimated - * network weight above. We do not need to take into account the actual spacing of the blocks, because this - * already handled by the retargeting in GetNextTargetRequiredV2, and in fact, given the random distribution - * of block spacing, it would be harmful to use a spacing correction for small nPoSInterval sizes. - * - * Also... The number of stakes to include in the average has been reduced to 40 (default) from 72. - * 72 stakes represented 1.8 hours at standard spacing. This is too long. 40 blocks is nominally 1 hour. - */ - - double dDiff = 1.0; - double dDiffSum = 0.0; - unsigned int nStakesHandled = 0; - double result; - - CBlockIndex* pindex = pindexBest; - - while (pindex && nStakesHandled < nPoSInterval) - { - if (pindex->IsProofOfStake()) - { - dDiff = GetDifficulty(pindex); - // dDiff should never be zero, but just in case, skip the block and move to the next one. - if (dDiff) - { - dDiffSum += dDiff; - nStakesHandled++; - LogPrint(BCLog::LogFlags::NOISY, "GetAverageDifficulty debug: dDiff = %f", dDiff); - LogPrint(BCLog::LogFlags::NOISY, "GetAverageDifficulty debug: nStakesHandled = %u", nStakesHandled); - } - } - - pindex = pindex->pprev; - } - - result = nStakesHandled ? dDiffSum / nStakesHandled : 0; - LogPrint(BCLog::LogFlags::NOISY, "GetAverageDifficulty debug: Average dDiff = %f", result); - - return result; -} - -double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double dConfidence) -{ - /* - * The algorithm below is an attempt to come up with a more accurate way of estimating Time to Stake (ETTS) based on - * the actual situation of the miner and UTXO's. A simple equation will not provide good results, because in mainnet, - * the cooldown period is 16 hours, and depending on how many UTXO's and where they are with respect to getting out of - * cooldown has a lot to do with the expected time to stake. - * - * The way to conceptualize the approach below is to think of the UTXO's as bars on a Gantt Chart. It is a negative Gantt - * chart, meaning that each UTXO bar is cooldown period long, and while the current time is in that bar, the staking probability - * for the UTXO is zero, and UnitStakingProbability elsewhere. A timestamp mask of 16x the normal mask is used to reduce - * the work in the nested loop, so that a 16 hour interval will have a maximum of 225 events, and most likely far less. - * This is important, because the inner loop will be the number of UTXO's. A future improvement to this algorithm would - * also be to quantize (group) the UTXO's themselves (the Gantt bars) so that the work would be further reduced. - * You will see that once the UTXO's are sorted in ascending order based on the time of the end of each of their cooldowns, this - * becomes a manageable algorithm to piece the probabilities together. - * - * You will note that the compound Poisson (geometric) recursive probability relation is used, since you cannot simply add - * the probabilities due to consideration of high confidence (CDF) values of 80% or more. - * - * Thin local data structures are used to hold the UTXO information. This minimizes the amount of time - * that locks on the wallet need to be held at the expense of a little memory consumption. - */ - - double result = 0.0; - - // dDiff must be >= 0 and dConfidence must lie on the interval [0,1) otherwise this is an error. - assert(dDiff >= 0 && dConfidence >= 0 && dConfidence < 1); - - // if dConfidence = 0, then the result must be 0. - if (!dConfidence) - { - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: Confidence of 0 specified: ETTS = %f", result); - return result; - } - - bool staking; - bool able_to_stake; - - { - LOCK(MinerStatus.lock); - - staking = MinerStatus.nLastCoinStakeSearchInterval && MinerStatus.WeightSum; - - able_to_stake = MinerStatus.able_to_stake; - } - - // Get out early if not staking, ignore_staking_status is false, and not able_to_stake and set return value of 0. - if (!ignore_staking_status && !staking && !able_to_stake) - { - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: Not staking: ETTS = %f", result); - return result; - } - - int64_t nValue = 0; - int64_t nCurrentTime = GetAdjustedTime(); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nCurrentTime = %i", nCurrentTime); - - CTxDB txdb("r"); - - // Here I am defining a time mask 16 times as long as the normal stake time mask. This is to quantize the UTXO's into a maximum of - // 16 hours * 3600 / 256 = 225 time bins for evaluation. Otherwise for a large number of UTXO's, this algorithm could become - // really expensive. - const int ETTS_TIMESTAMP_MASK = (16 * (STAKE_TIMESTAMP_MASK + 1)) - 1; - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: ETTS_TIMESTAMP_MASK = %x", ETTS_TIMESTAMP_MASK); - - int64_t BalanceAvailForStaking = 0; - vector vCoins; - - { - LOCK2(cs_main, pwalletMain->cs_wallet); - - BalanceAvailForStaking = pwalletMain->GetBalance() - nReserveBalance; - - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: BalanceAvailForStaking = %u", BalanceAvailForStaking); - - // Get out early if no balance available and set return value of 0. This should already have happened above, because with no - // balance left after reserve, staking should be disabled; however, just to be safe... - if (BalanceAvailForStaking <= 0) - { - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: No balance available: ETTS = %f", result); - return result; - } - - //reminder... void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl=NULL, bool fIncludeStakingCoins=false) const; - pwalletMain->AvailableCoins(vCoins, true, NULL, true); - } - - - // An efficient local structure to store the UTXO's with the bare minimum info we need. - typedef vector< std::pair > vCoinsExt; - vCoinsExt vUTXO; - // A local ordered set to store the unique "bins" corresponding to the UTXO transaction times. We are going to use this - // for the outer loop. - std::set UniqueUTXOTimes; - // We want the first "event" to be the CurrentTime. This does not have to be quantized. - UniqueUTXOTimes.insert(nCurrentTime); - - // Debug output cooldown... - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nStakeMinAge = %i", nStakeMinAge); - - // If dDiff = 0 from supplied argument (which is also the default), then derive a smoothed difficulty over the default PoSInterval of 40 blocks by calling - // GetAverageDifficulty(40), otherwise let supplied argument dDiff stand. - if (!dDiff) dDiff = GetAverageDifficulty(40); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dDiff = %f", dDiff); - - // The stake probability per "throw" of 1 weight unit = target value at diff of 1.0 / (maxhash * diff). This happens effectively every STAKE_TIMESTAMP_MASK+1 sec. - double dUnitStakeProbability = 1 / (4295032833.0 * dDiff); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dUnitStakeProbability = %e", dUnitStakeProbability); - - - int64_t nTime = 0; - for (const auto& out : vCoins) - { - CTxIndex txindex; - CBlock CoinBlock; //Block which contains CoinTx - if (!txdb.ReadTxIndex(out.tx->GetHash(), txindex)) continue; //Ignore transactions that can't be read. - - if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) continue; - - // We are going to store as an event the time that the UTXO matures (is available for staking again.) - nTime = (CoinBlock.GetBlockTime() & ~ETTS_TIMESTAMP_MASK) + nStakeMinAge; - - nValue = out.tx->vout[out.i].nValue; - - // Only consider UTXO's that are actually stakeable - which means that each one must be less than the available balance - // subtracting the reserve. Each UTXO also has to be greater than 1/80 GRC to result in a weight greater than zero in the CreateCoinStake loop, - // so eliminate UTXO's with less than 0.0125 GRC balances right here. The test with Satoshi units for that is - // nValue >= 1250000. - if (BalanceAvailForStaking >= nValue && nValue >= 1250000) - { - vUTXO.push_back(std::pair( nTime, nValue)); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: pair (relative to current time: <%i, %i>", nTime - nCurrentTime, nValue); - - // Only record a time below if it is after nCurrentTime, because UTXO's that have matured already are already stakeable and can be grouped (will be found) - // by the nCurrentTime record that was already injected above. - if (nTime > nCurrentTime) UniqueUTXOTimes.insert(nTime); - } - } - - - int64_t nTimePrev = nCurrentTime; - int64_t nDeltaTime = 0; - int64_t nThrows = 0; - int64_t nCoinWeight = 0; - double dProbAccumulator = 0; - double dCumulativeProbability = 0; - // Note: Even though this is a compound Poisson process leading to a compound geometric distribution, and the individual probabilities are - // small, we are mounting to high CDFs. This means to be reasonably accurate, we cannot just add the probabilities, because the intersections - // become significant. The CDF of a compound geometric distribution as you do tosses with different probabilities follows the - // recursion relation... CDF.i = 1 - (1 - CDF.i-1)(1 - p.i). If all probabilities are the same, this reduces to the familiar - // CDF.k = 1 - (1 - p)^k where ^ is exponentiation. - for (const auto& itertime : UniqueUTXOTimes) - { - - nTime = itertime; - dProbAccumulator = 0; - - for (auto& iterUTXO : vUTXO) - { - - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: Unique UTXO Time: %u, vector pair <%u, %u>", nTime, iterUTXO.first, iterUTXO.second); - - // If the "negative Gantt chart bar" is ending or has ended for a UTXO, it now accumulates probability. (I.e. the event time being checked - // is greater than or equal to the cooldown expiration of the UTXO.) - // accumulation for that UTXO. - if(nTime >= iterUTXO.first) - { - // The below weight calculation is just like the CalculateStakeWeightV8 in kernel.cpp. - nCoinWeight = iterUTXO.second / 1250000; - - dProbAccumulator = 1 - ((1 - dProbAccumulator) * (1 - (dUnitStakeProbability * nCoinWeight))); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dProbAccumulator = %e", dProbAccumulator); - } - - } - nDeltaTime = nTime - nTimePrev; - nThrows = nDeltaTime / (STAKE_TIMESTAMP_MASK + 1); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nThrows = %i", nThrows); - dCumulativeProbability = 1 - ((1 - dCumulativeProbability) * pow((1 - dProbAccumulator), nThrows)); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dCumulativeProbability = %e", dCumulativeProbability); - - if (dCumulativeProbability >= dConfidence) break; - - nTimePrev = nTime; - } - - // If (dConfidence - dCumulativeProbability) > 0, it means we exited the negative Gantt chart area and the desired confidence level - // has not been reached. All of the eligible UTXO's are contributing probability, and this is the final dProbAccumulator value. - // If the loop above is degenerate (i.e. only the current time pass through), then dCumulativeProbability will be zero. - // If it was not degenerate and the positive reqions in the Gantt chart area contributed some probability, then dCumulativeProbability will - // be greater than zero. We must compute the amount of time beyond nTime that is required to bridge the gap between - // dCumulativeProbability and dConfidence. If (dConfidence - dCumulativeProbability) <= 0 then we overshot during the Gantt chart area, - // and we will back off by nThrows amount, which will now be negative. - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dProbAccumulator = %e", dProbAccumulator); - - // Shouldn't happen because if we are down here, we are staking, and there have to be eligible UTXO's, but just in case... - if (dProbAccumulator == 0.0) - { - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: ERROR in dProbAccumulator calculations"); - return result; - } - - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dConfidence = %f", dConfidence); - // If nThrows is negative, this just means we overshot in the Gantt chart loop and have to backtrack by nThrows. - nThrows = (int64_t)((log(1 - dConfidence) - log(1 - dCumulativeProbability)) / log(1 - dProbAccumulator)); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nThrows = %i", nThrows); - - nDeltaTime = nThrows * (STAKE_TIMESTAMP_MASK + 1); - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nDeltaTime = %i", nDeltaTime); - - // Because we are looking at the delta time required past nTime, which is where we exited the Gantt chart loop. - result = nDeltaTime + nTime - nCurrentTime; - LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: ETTS at %d confidence = %i", dConfidence, result); - - return result; -} - - void GetGlobalStatus() { //Populate overview try { - uint64_t nWeight = 0; - pwalletMain->GetStakeWeight(nWeight); + uint64_t nWeight = GRC::GetStakeWeight(*pwalletMain); double weight = nWeight/COIN; - double PORDiff = GetDifficulty(GetLastBlockIndex(pindexBest, true)); + double PORDiff = GRC::GetCurrentDifficulty(); std::string sWeight = RoundToString((double)weight,0); //9-6-2015 Add RSA fields to overview @@ -519,17 +159,17 @@ void GetGlobalStatus() GlobalStatusStruct.blocks = ToString(nBestHeight); GlobalStatusStruct.difficulty = RoundToString(PORDiff,3); - GlobalStatusStruct.netWeight = RoundToString(GetEstimatedNetworkWeight() / 80.0,2); + GlobalStatusStruct.netWeight = RoundToString(GRC::GetEstimatedNetworkWeight() / 80.0,2); //todo: use the real weight from miner status (requires scaling) GlobalStatusStruct.coinWeight = sWeight; unsigned long stk_dropped; { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); - if(MinerStatus.WeightSum) - GlobalStatusStruct.coinWeight = RoundToString(MinerStatus.WeightSum / 80.0,2); + if(g_miner_status.WeightSum) + GlobalStatusStruct.coinWeight = RoundToString(g_miner_status.WeightSum / 80.0,2); GlobalStatusStruct.errors.clear(); std::string Alerts = GetWarnings("statusbar"); @@ -539,10 +179,10 @@ void GetGlobalStatus() if (PORDiff < 0.1) GlobalStatusStruct.errors += _("Low difficulty!; "); - if(!MinerStatus.ReasonNotStaking.empty()) - GlobalStatusStruct.errors += _("Miner: ") + MinerStatus.ReasonNotStaking; + if(!g_miner_status.ReasonNotStaking.empty()) + GlobalStatusStruct.errors += _("Miner: ") + g_miner_status.ReasonNotStaking; - stk_dropped = MinerStatus.KernelsFound - MinerStatus.AcceptedCnt; + stk_dropped = g_miner_status.KernelsFound - g_miner_status.AcceptedCnt; } if (stk_dropped) @@ -559,17 +199,6 @@ void GetGlobalStatus() } } -bool Timer_Main(std::string timer_name, int max_ms) -{ - mvTimers[timer_name] = mvTimers[timer_name] + 1; - if (mvTimers[timer_name] > max_ms) - { - mvTimers[timer_name]=0; - return true; - } - return false; -} - void RegisterWallet(CWallet* pwalletIn) { { @@ -620,8 +249,15 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, if (tx.IsCoinStake()) { for (auto const& pwallet : setpwalletRegistered) + { if (pwallet->IsFromMe(tx)) + { pwallet->DisableTransaction(tx); + + LOCK(g_miner_status.lock); + g_miner_status.m_last_pos_tx_hash.SetNull(); + } + } } return; } @@ -1652,132 +1288,6 @@ static const CBlock* GetOrphanRoot(const CBlock* pblock) return pblock; } -static CBigNum GetProofOfStakeLimit(int nHeight) -{ - if (IsProtocolV2(nHeight)) - return bnProofOfStakeLimitV2; - else - return bnProofOfStakeLimit; -} - -int64_t GetCoinYearReward(int64_t nTime) -{ - // Gridcoin Global Interest Rate Schedule - int64_t INTEREST = 9; - if (nTime >= 1410393600 && nTime <= 1417305600) INTEREST = 9 * CENT; // 09% between inception and 11-30-2014 - if (nTime >= 1417305600 && nTime <= 1419897600) INTEREST = 8 * CENT; // 08% between 11-30-2014 and 12-30-2014 - if (nTime >= 1419897600 && nTime <= 1422576000) INTEREST = 8 * CENT; // 08% between 12-30-2014 and 01-30-2015 - if (nTime >= 1422576000 && nTime <= 1425254400) INTEREST = 7 * CENT; // 07% between 01-30-2015 and 02-30-2015 - if (nTime >= 1425254400 && nTime <= 1427673600) INTEREST = 6 * CENT; // 06% between 02-30-2015 and 03-30-2015 - if (nTime >= 1427673600 && nTime <= 1430352000) INTEREST = 5 * CENT; // 05% between 03-30-2015 and 04-30-2015 - if (nTime >= 1430352000 && nTime <= 1438310876) INTEREST = 4 * CENT; // 04% between 05-01-2015 and 07-31-2015 - if (nTime >= 1438310876 && nTime <= 1447977700) INTEREST = 3 * CENT; // 03% between 08-01-2015 and 11-20-2015 - if (nTime > 1447977700) INTEREST = 1.5 * CENT; //1.5% from 11-21-2015 forever - return INTEREST; -} - -// miner's coin stake reward based on coin age spent (coin-days) -int64_t GetConstantBlockReward(const CBlockIndex* index) -{ - // The constant block reward is set to a default, voted on value, but this can - // be overridden using an admin message. This allows us to change the reward - // amount without having to release a mandatory with updated rules. In the case - // there is a breach or leaked admin keys the rewards are clamped to twice that - // of the default value. - const int64_t MIN_CBR = 0; - const int64_t MAX_CBR = DEFAULT_CBR * 2; - - int64_t reward = DEFAULT_CBR; - AppCacheEntry oCBReward = ReadCache(Section::PROTOCOL, "blockreward1"); - - //TODO: refactor the expire checking to subroutine - //Note: time constant is same as GetBeaconPublicKey - if( (index->nTime - oCBReward.timestamp) <= (60 * 24 * 30 * 6 * 60) ) - { - reward = atoi64(oCBReward.value); - } - - reward = std::max(reward, MIN_CBR); - reward = std::min(reward, MAX_CBR); - return reward; -} - -int64_t GetProofOfStakeReward( - const uint64_t nCoinAge, - const int64_t nTime, - const CBlockIndex* const pindexLast) -{ - if (pindexLast->nVersion >= 10) { - return GetConstantBlockReward(pindexLast); - } - - return nCoinAge * GetCoinYearReward(nTime) * 33 / (365 * 33 + 8); -} - - - -static const int64_t nTargetTimespan = 16 * 60; // 16 mins - -// ppcoin: find last block index up to pindex -const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake) -{ - while (pindex && pindex->pprev && (pindex->IsProofOfStake() != fProofOfStake)) - pindex = pindex->pprev; - return pindex; -} - -unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast) -{ - CBigNum bnTargetLimit = GetProofOfStakeLimit(pindexLast->nHeight); - - if (pindexLast == NULL) - return bnTargetLimit.GetCompact(); // genesis block - - const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, true); - if (pindexPrev->pprev == NULL) - return bnTargetLimit.GetCompact(); // first block - const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, true); - if (pindexPrevPrev->pprev == NULL) - return bnTargetLimit.GetCompact(); // second block - - int64_t nTargetSpacing = GetTargetSpacing(pindexLast->nHeight); - int64_t nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime(); - if (nActualSpacing < 0) - nActualSpacing = nTargetSpacing; - - // ppcoin: target change every block - // ppcoin: retarget with exponential moving toward target spacing - CBigNum bnNew; - bnNew.SetCompact(pindexPrev->nBits); - - //Gridcoin - Reset Diff to 1 on 12-19-2014 (R Halford) - Diff sticking at 2065 due to many incompatible features - if (pindexLast->nHeight >= 91387 && pindexLast->nHeight <= 91500) - { - return bnTargetLimit.GetCompact(); - } - - //1-14-2015 R Halford - Make diff reset to zero after periods of exploding diff: - double PORDiff = GetDifficulty(GetLastBlockIndex(pindexBest, true)); - if (PORDiff > 900000) - { - return bnTargetLimit.GetCompact(); - } - - - //Since our nTargetTimespan is (16 * 60) or 16 mins and our TargetSpacing = 64, the nInterval = 15 min - - int64_t nInterval = nTargetTimespan / nTargetSpacing; - bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); - bnNew /= ((nInterval + 1) * nTargetSpacing); - - if (bnNew <= 0 || bnNew > bnTargetLimit) - { - bnNew = bnTargetLimit; - } - - return bnNew.GetCompact(); -} - bool CheckProofOfWork(uint256 hash, unsigned int nBits) { CBigNum bnTarget; @@ -1981,33 +1491,29 @@ int64_t CTransaction::GetValueIn(const MapPrevTx& inputs) const } -// A lock must be taken on cs_main before calling this function. -int64_t PreviousBlockAge() +static void UpdateSyncTime(const CBlockIndex* const pindexBest) { - int64_t blockTime = pindexBest && pindexBest->pprev - ? pindexBest->pprev->GetBlockTime() - : 0; + if (pindexBest && pindexBest->pprev) { + g_previous_block_time.store(pindexBest->pprev->GetBlockTime()); + } else { + g_previous_block_time.store(0); + } - return GetAdjustedTime() - blockTime; + if (!OutOfSyncByAge()) { + g_nTimeBestReceived.store(GetAdjustedTime()); + } } -// A lock must be taken on cs_main before calling this function. -void UpdateOutOfSyncByAge() +bool OutOfSyncByAge() { // Assume we are out of sync if the current block age is 10 // times older than the target spacing. This is the same // rules that Bitcoin uses. - const int64_t maxAge = GetTargetSpacing(nBestHeight) * 10; - - g_fOutOfSyncByAge.store(PreviousBlockAge() >= maxAge); + constexpr int64_t maxAge = 90 * 10; - if (!g_fOutOfSyncByAge) - { - g_nSyncTime.store(GetAdjustedTime()); - } + return GetAdjustedTime() - g_previous_block_time >= maxAge; } - bool LessVerbose(int iMax1000) { //Returns True when RND() level is lower than the number presented @@ -2333,7 +1839,7 @@ class ClaimValidator bool CheckReward(const int64_t research_owed, int64_t& out_stake_owed) const { - out_stake_owed = GetProofOfStakeReward(m_coin_age, m_block.nTime, m_pindex); + out_stake_owed = GRC::GetProofOfStakeReward(m_coin_age, m_block.nTime, m_pindex); if (m_block.nVersion >= 11) { return m_total_claimed <= research_owed + out_stake_owed + m_fees; @@ -2363,7 +1869,7 @@ class ClaimValidator return true; } - if (GetBadBlocks().count(m_pindex->GetBlockHash())) { + if (GRC::GetBadBlocks().count(m_pindex->GetBlockHash())) { LogPrintf( "WARNING: ConnectBlock[%s]: ignored bad investor claim on block %s", __func__, @@ -2493,7 +1999,7 @@ class ClaimValidator } } - if (GetBadBlocks().count(m_pindex->GetBlockHash())) { + if (GRC::GetBadBlocks().count(m_pindex->GetBlockHash())) { LogPrintf( "WARNING: ConnectBlock[%s]: ignored invalid signature in %s", __func__, @@ -2553,7 +2059,7 @@ class ClaimValidator return true; } - if (GetBadBlocks().count(m_pindex->GetBlockHash())) { + if (GRC::GetBadBlocks().count(m_pindex->GetBlockHash())) { LogPrintf( "WARNING: ConnectBlock[%s]: ignored bad research claim in %s", __func__, @@ -2700,7 +2206,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) if (nVersion >= 8 && pindex->nStakeModifier == 0 && pindex->nStakeModifierChecksum == 0) { uint256 tmp_hashProof; - if (!CheckProofOfStakeV8(txdb, pindex->pprev, *this, /*generated_by_me*/ false, tmp_hashProof)) + if (!GRC::CheckProofOfStakeV8(txdb, pindex->pprev, *this, /*generated_by_me*/ false, tmp_hashProof)) return error("ConnectBlock(): check proof-of-stake failed"); } @@ -2819,7 +2325,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) if (!txdb.WriteBlockIndex(CDiskBlockIndex(pindex))) return error("Connect() : WriteBlockIndex for pindex failed"); - if (!g_fOutOfSyncByAge) + if (!OutOfSyncByAge()) { fColdBoot = false; } @@ -2944,11 +2450,10 @@ bool DisconnectBlocksBatch(CTxDB& txdb, list& vResurrect, unsigned cnt_dis++; pindexBest = pindexBest->pprev; hashBestChain = pindexBest->GetBlockHash(); - blockFinder.Reset(); nBestHeight = pindexBest->nHeight; nBestChainTrust = pindexBest->nChainTrust; - UpdateOutOfSyncByAge(); + UpdateSyncTime(pindexBest); if (!txdb.WriteHashBestChain(pindexBest->GetBlockHash())) return error("DisconnectBlocksBatch: WriteHashBestChain failed"); /*fatal*/ @@ -3133,15 +2638,12 @@ bool ReorganizeChain(CTxDB& txdb, unsigned &cnt_dis, unsigned &cnt_con, CBlock & // update best block hashBestChain = hash; pindexBest = pindex; - blockFinder.Reset(); nBestHeight = pindexBest->nHeight; nBestChainTrust = pindexBest->nChainTrust; - nTimeBestReceived = GetAdjustedTime(); - - UpdateOutOfSyncByAge(); - cnt_con++; + UpdateSyncTime(pindexBest); + if (IsV9Enabled_Tally(nBestHeight) && !IsV11Enabled(nBestHeight) && GRC::Tally::IsLegacyTrigger(nBestHeight)) @@ -3228,7 +2730,7 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const CBlockHeader header; CTransaction txPrev; - if (!ReadStakedInput(txdb, txin.prevout.hash, header, txPrev)) + if (!GRC::ReadStakedInput(txdb, txin.prevout.hash, header, txPrev)) { return false; } @@ -3289,12 +2791,12 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const u // ppcoin: compute stake modifier uint64_t nStakeModifier = 0; bool fGeneratedStakeModifier = false; - if (!ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier)) + if (!GRC::ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier)) { LogPrintf("AddToBlockIndex() : ComputeNextStakeModifier() failed"); } pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); - pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); + pindexNew->nStakeModifierChecksum = GRC::GetStakeModifierChecksum(pindexNew); // Add to mapBlockIndex BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; @@ -3353,7 +2855,7 @@ bool CBlock::CheckBlock(int height1, bool fCheckPOW, bool fCheckMerkleRoot, bool return DoS(50, error("CheckBlock[] : proof of work failed")); //Reject blocks with diff that has grown to an extraordinary level (should never happen) - double blockdiff = GetBlockDifficulty(nBits); + double blockdiff = GRC::GetBlockDifficulty(nBits); if (height1 > nGrandfather && blockdiff > 10000000000000000) { return DoS(1, error("CheckBlock[] : Block Bits larger than 10000000000000000.")); @@ -3509,7 +3011,7 @@ bool CBlock::AcceptBlock(bool generated_by_me) if (GetBlockTime() <= pindexPrev->GetPastTimeLimit() || FutureDrift(GetBlockTime(), nHeight) < pindexPrev->GetBlockTime()) return DoS(60, error("AcceptBlock() : block's timestamp is too early")); // Check proof-of-work or proof-of-stake - if (nBits != GetNextTargetRequired(pindexPrev)) + if (nBits != GRC::GetNextTargetRequired(pindexPrev)) return DoS(100, error("AcceptBlock() : incorrect %s", IsProofOfWork() ? "proof-of-work" : "proof-of-stake")); } @@ -3559,7 +3061,7 @@ bool CBlock::AcceptBlock(bool generated_by_me) //no grandfather exceptions //if (IsProofOfStake()) CTxDB txdb("r"); - if(!CheckProofOfStakeV8(txdb, pindexPrev, *this, generated_by_me, hashProof)) + if(!GRC::CheckProofOfStakeV8(txdb, pindexPrev, *this, generated_by_me, hashProof)) { error("WARNING: AcceptBlock(): check proof-of-stake failed for block %s, nonce %f ", hash.ToString().c_str(),(double)nNonce); LogPrintf(" prev %s",pindexPrev->GetBlockHash().ToString()); @@ -3575,7 +3077,7 @@ bool CBlock::AcceptBlock(bool generated_by_me) // testnet: nGrandfather (196551) to version 8 (311999) // CTxDB txdb("r"); - if (!CalculateLegacyV3HashProof(txdb, *this, nNonce, hashProof)) { + if (!GRC::CalculateLegacyV3HashProof(txdb, *this, nNonce, hashProof)) { return error("AcceptBlock(): Failed to carry v7 proof hash."); } } @@ -3636,7 +3138,6 @@ bool GridcoinServices() if (fQtActive && (nBestHeight % 125) == 0 && nBestHeight > 0) { GetGlobalStatus(); - bForceUpdate=true; uiInterface.NotifyBlocksChanged(); } @@ -3662,7 +3163,7 @@ bool GridcoinServices() // system by creating a baseline of the research rewards owed in historical // superblocks so that we can validate the reward for the next block. // - if (nBestHeight + 1 == GetV11Threshold()) { + if (nBestHeight + 1 == Params().GetConsensus().BlockV11Height) { LogPrint(BCLog::LogFlags::TALLY, "GridcoinServices: Priming tally system for v11 threshold."); @@ -4062,24 +3563,9 @@ bool LoadBlockIndex(bool fAllowNew) return error("LoadBlockIndex() : genesis block not accepted"); } - return true; -} - -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end) -{ - string::size_type loc = XMLdata.find(key, 0); - - if (loc == string::npos) { - return ""; - } - - string::size_type loc_end = XMLdata.find(key_end, loc + 3); + UpdateSyncTime(pindexBest); - if (loc_end == string::npos) { - return ""; - } - - return XMLdata.substr(loc + (key.length()), loc_end - loc - (key.length())); + return true; } void PrintBlockTree() @@ -4703,7 +4189,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(CScraperManifest::cs_mapManifest); // Do not send manifests while out of sync. - if (!g_fOutOfSyncByAge) + if (!OutOfSyncByAge()) { // Do not send unauthorized manifests. This check needs to be done here, because in the // case of a scraper deauthorization, a request from another node to forward the manifest diff --git a/src/main.h b/src/main.h index 190f3da5c9..d1837efc0d 100644 --- a/src/main.h +++ b/src/main.h @@ -6,6 +6,8 @@ #define BITCOIN_MAIN_H #include "arith_uint256.h" +#include "chainparams.h" +#include "consensus/consensus.h" #include "util.h" #include "net.h" #include "gridcoin/contract/contract.h" @@ -13,7 +15,6 @@ #include "sync.h" #include "script.h" #include "scrypt.h" -#include "wallet/ismine.h" #include #include @@ -40,30 +41,7 @@ class SuperblockPtr; typedef boost::optional ClaimOption; } -static const int LAST_POW_BLOCK = 2050; -static const int CONSENSUS_LOOKBACK = 5; //Amount of blocks to go back from best block, to avoid counting forked blocks -static const int BLOCK_GRANULARITY = 10; //Consensus block divisor -static const int TALLY_GRANULARITY = BLOCK_GRANULARITY; static const int64_t DEFAULT_CBR = 10 * COIN; - -/** The maximum allowed size for a serialized block, in bytes (network rule) */ -static const unsigned int MAX_BLOCK_SIZE = 1000000; -/** Target Blocks Per day */ -static const unsigned int BLOCKS_PER_DAY = 1000; -/** The maximum size for mined blocks */ -static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; -/** The maximum size for transactions we're willing to relay/mine **/ -static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5; -/** The maximum allowed number of signature check operations in a block (network rule) */ -static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; -/** The maximum number of orphan transactions kept in memory */ -static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100; -/** The maximum number of entries in an 'inv' protocol message */ -static const unsigned int MAX_INV_SZ = 50000; -/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */ -static const int64_t MIN_TX_FEE = 10000; -/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ -static const int64_t MIN_RELAY_TX_FEE = MIN_TX_FEE; /** No amount larger than this (in satoshi) is valid */ static const int64_t MAX_MONEY = 2000000000 * COIN; inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } @@ -78,71 +56,7 @@ static const uint256 hashGenesisBlock = uint256S("0x000005a247b397eadfefa58e872b //TestNet Genesis: static const uint256 hashGenesisBlockTestNet = uint256S("0x00006e037d7b84104208ecf2a8638d23149d712ea810da604ee2f2cb39bae713"); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -inline bool IsProtocolV2(int nHeight) -{ - return (fTestNet ? nHeight > 2060 : nHeight > 85400); -} - -inline int32_t GetResearchAgeThreshold() -{ - return fTestNet ? 36501 : 364501; -} - -inline bool IsResearchAgeEnabled(int nHeight) -{ - return nHeight >= GetResearchAgeThreshold(); -} - -// TODO: Move this and the other height thresholds to their own files. -// Do not put the code in the headers! -inline uint32_t IsV8Enabled(int nHeight) -{ - // Start creating V8 blocks after these heights. - // In testnet the first V8 block was created on block height 320000. - return fTestNet - ? nHeight > 311999 - : nHeight > 1010000; -} - -inline uint32_t IsV9Enabled(int nHeight) -{ - return fTestNet - ? nHeight >= 399000 - : nHeight >= 1144000; -} - -inline bool IsV10Enabled(int nHeight) -{ - // Testnet used a controlled switch by injecting a v10 block - // using a modified client and different miner trigger rules, - // hence the odd height. - return fTestNet - ? nHeight >= 629409 - : nHeight >= 1420000; -} -inline int32_t GetV11Threshold() -{ - return fTestNet - ? 1301500 - : 2053000; -} - -inline bool IsV11Enabled(int nHeight) -{ - return nHeight >= GetV11Threshold(); -} - -inline int GetSuperblockAgeSpacing(int nHeight) -{ - return (fTestNet ? 86400 : (nHeight > 364500) ? 86400 : 43200); -} - -inline bool IsV9Enabled_Tally(int nHeight) -{ - // 3 hours after v9 - return IsV9Enabled(nHeight-120); -} inline int64_t FutureDrift(int64_t nTime, int nHeight) { return nTime + 20 * 60; } inline unsigned int GetTargetSpacing(int nHeight) { return IsProtocolV2(nHeight) ? 90 : 60; } @@ -168,9 +82,7 @@ extern arith_uint256 nBestChainTrust; extern arith_uint256 nBestInvalidTrust; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; -extern std::atomic_bool g_fOutOfSyncByAge; extern const std::string strMessageMagic; -extern int64_t nTimeBestReceived; extern CCriticalSection cs_setpwalletRegistered; extern std::set setpwalletRegistered; extern unsigned char pchMessageStart[4]; @@ -227,42 +139,19 @@ void PrintBlockTree(); bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); bool LoadExternalBlockFile(FILE* fileIn); -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end); bool CheckProofOfWork(uint256 hash, unsigned int nBits); -unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast); -int64_t GetConstantBlockReward(const CBlockIndex* index); - -int64_t GetProofOfStakeReward( - uint64_t nCoinAge, - int64_t nTime, - const CBlockIndex* const pindexLast); - -double GetEstimatedNetworkWeight(unsigned int nPoSInterval = 40); -double GetDifficulty(const CBlockIndex* blockindex = NULL); -double GetBlockDifficulty(unsigned int nBits); -double GetAverageDifficulty(unsigned int nPoSInterval = 40); - -// Note that dDiff cannot be = 0 normally. This is set as default because you can't specify the output of -// GetAverageDifficulty(nPosInterval) = to dDiff here. -// The defeult confidence is 1-1/e which is the mean for the geometric distribution for small probabilities. -const double DEFAULT_ETTS_CONFIDENCE = 1.0 - 1.0 / exp(1.0); -double GetEstimatedTimetoStake(bool ignore_staking_status = false, double dDiff = 0.0, double dConfidence = DEFAULT_ETTS_CONFIDENCE); - GRC::ClaimOption GetClaimByIndex(const CBlockIndex* const pblockindex); int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); - -const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); -void StakeMiner(CWallet *pwallet); void ResendWalletTransactions(bool fForce = false); std::string DefaultWalletAddress(); -int64_t PreviousBlockAge(); +bool OutOfSyncByAge(); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CTransaction &tx, diff --git a/src/miner.cpp b/src/miner.cpp index 11f2d8fd0d..b70ef68e89 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -6,15 +6,19 @@ #include "txdb.h" #include "miner.h" -#include "kernel.h" #include "main.h" #include "gridcoin/beacon.h" #include "gridcoin/claim.h" #include "gridcoin/contract/contract.h" #include "gridcoin/quorum.h" #include "gridcoin/researcher.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/staking/kernel.h" +#include "gridcoin/staking/reward.h" +#include "gridcoin/staking/status.h" #include "gridcoin/tally.h" #include "util.h" +#include "wallet/wallet.h" #include #include @@ -66,7 +70,7 @@ class COrphan //! //! \return Always \false - suitable for returning from the call directly. //! -bool ReturnMinerError(CMinerStatus& status, CMinerStatus::ReasonNotStakingCategory& not_staking_error) +bool ReturnMinerError(GRC::MinerStatus& status, GRC::MinerStatus::ReasonNotStakingCategory& not_staking_error) { LOCK(status.lock); @@ -74,7 +78,7 @@ bool ReturnMinerError(CMinerStatus& status, CMinerStatus::ReasonNotStakingCatego status.SetReasonNotStaking(not_staking_error); - LogPrint(BCLog::LogFlags::VERBOSE, "CreateCoinStake: %s", MinerStatus.ReasonNotStaking); + LogPrint(BCLog::LogFlags::VERBOSE, "CreateCoinStake: %s", g_miner_status.ReasonNotStaking); return false; } @@ -162,51 +166,6 @@ bool TrySignClaim( } } // anonymous namespace -CMinerStatus::CMinerStatus(void) -{ - Clear(); - ClearReasonsNotStaking(); - CreatedCnt= AcceptedCnt= KernelsFound= 0; -} - -void CMinerStatus::Clear() -{ - WeightSum= ValueSum= WeightMin= WeightMax= 0; - Version= 0; - nLastCoinStakeSearchInterval = 0; -} - -bool CMinerStatus::SetReasonNotStaking(ReasonNotStakingCategory not_staking_error) -{ - bool inserted = false; - - if (std::find(vReasonNotStaking.begin(), vReasonNotStaking.end(), not_staking_error) == vReasonNotStaking.end()) - { - vReasonNotStaking.insert(vReasonNotStaking.end(), not_staking_error); - - if (not_staking_error != NONE) - { - if (!ReasonNotStaking.empty()) ReasonNotStaking += "; "; - ReasonNotStaking += vReasonNotStakingStrings[static_cast(not_staking_error)]; - } - - if (not_staking_error > NO_MATURE_COINS) able_to_stake = false; - - inserted = true; - } - - return inserted; -} - -void CMinerStatus::ClearReasonsNotStaking() -{ - vReasonNotStaking.clear(); - ReasonNotStaking.clear(); - able_to_stake = true; -} - -CMinerStatus MinerStatus; - // We want to sort transactions by priority and fee, so: typedef std::tuple TxPriority; class TxPriorityCompare @@ -231,6 +190,61 @@ class TxPriorityCompare } }; +boost::optional GetLastStake(CWallet& wallet) +{ + CWalletTx stake_tx; + uint256 cached_stake_tx_hash; + + { + LOCK(g_miner_status.lock); + cached_stake_tx_hash = g_miner_status.m_last_pos_tx_hash; + } + + if (!cached_stake_tx_hash.IsNull()) { + if (wallet.GetTransaction(cached_stake_tx_hash, stake_tx)) { + return stake_tx; + } + } + + const auto is_my_confirmed_stake = [](const CWalletTx& tx) { + return tx.IsCoinStake() && tx.IsFromMe() && tx.GetDepthInMainChain() > 0; + }; + + { + LOCK2(cs_main, wallet.cs_wallet); + + if (wallet.mapWallet.empty()) { + return boost::none; + } + + auto latest_iter = wallet.mapWallet.cbegin(); + + for (auto iter = ++latest_iter; iter != wallet.mapWallet.cend(); ++iter) { + if (iter->second.nTime > latest_iter->second.nTime + && is_my_confirmed_stake(iter->second)) + { + latest_iter = iter; + } + } + + if (latest_iter == wallet.mapWallet.cbegin() + && !is_my_confirmed_stake(latest_iter->second)) + { + return boost::none; + } + + cached_stake_tx_hash = latest_iter->first; + stake_tx = latest_iter->second; + } + + { + LOCK(g_miner_status.lock); + g_miner_status.m_last_pos_tx_hash = cached_stake_tx_hash; + } + + return stake_tx; +} + // CreateRestOfTheBlock: collect transactions into block and fill in header bool CreateRestOfTheBlock(CBlock &block, CBlockIndex* pindexPrev) { @@ -551,17 +565,17 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key, } //initialize the transaction - txnew.nTime = blocknew.nTime & (~STAKE_TIMESTAMP_MASK); + txnew.nTime = blocknew.nTime & (~GRC::STAKE_TIMESTAMP_MASK); txnew.vin.clear(); txnew.vout.clear(); // Choose coins to use vector> CoinsToStake; - CMinerStatus::ReasonNotStakingCategory not_staking_error; + GRC::MinerStatus::ReasonNotStakingCategory not_staking_error; if (!wallet.SelectCoinsForStaking(txnew.nTime, CoinsToStake, not_staking_error, true)) { - ReturnMinerError(MinerStatus, not_staking_error); + ReturnMinerError(g_miner_status, not_staking_error); return false; } @@ -591,10 +605,10 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key, StakeValueSum += CoinTx.vout[CoinTxN].nValue / (double)COIN; uint64_t StakeModifier = 0; - if(!FindStakeModifierRev(StakeModifier,pindexPrev)) + if(!GRC::FindStakeModifierRev(StakeModifier,pindexPrev)) continue; - CoinWeight = CalculateStakeWeightV8(CoinTx,CoinTxN); - StakeKernelHash.setuint256(CalculateStakeHashV8(CoinBlock,CoinTx,CoinTxN,txnew.nTime,StakeModifier)); + CoinWeight = GRC::CalculateStakeWeightV8(CoinTx,CoinTxN); + StakeKernelHash.setuint256(GRC::CalculateStakeHashV8(CoinBlock,CoinTx,CoinTxN,txnew.nTime,StakeModifier)); CBigNum StakeTarget; StakeTarget.SetCompact(blocknew.nBits); @@ -602,7 +616,7 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key, StakeWeightSum += CoinWeight; StakeWeightMin=std::min(StakeWeightMin,CoinWeight); StakeWeightMax=std::max(StakeWeightMax,CoinWeight); - double StakeKernelDiff = GetBlockDifficulty(StakeKernelHash.GetCompact())*CoinWeight; + double StakeKernelDiff = GRC::GetBlockDifficulty(StakeKernelHash.GetCompact())*CoinWeight; LogPrint(BCLog::LogFlags::MINER, "CreateCoinStake: V%d Time %d, Bits %u, Weight %" PRId64 "\n" @@ -616,7 +630,7 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key, StakeKernelHash.GetHex(), StakeTarget.GetHex(), StakeKernelDiff, - GetBlockDifficulty(blocknew.nBits)); + GRC::GetBlockDifficulty(blocknew.nBits)); if( StakeKernelHash <= StakeTarget ) { @@ -670,18 +684,18 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key, LogPrintf("CreateCoinStake: added kernel type=%d credit=%f", whichType,CoinToDouble(nCredit)); - LOCK(MinerStatus.lock); - MinerStatus.KernelsFound++; + LOCK(g_miner_status.lock); + g_miner_status.KernelsFound++; return true; } } - LOCK(MinerStatus.lock); - MinerStatus.WeightSum = StakeWeightSum; - MinerStatus.ValueSum = StakeValueSum; - MinerStatus.WeightMin=StakeWeightMin; - MinerStatus.WeightMax=StakeWeightMax; - MinerStatus.nLastCoinStakeSearchInterval= txnew.nTime; + LOCK(g_miner_status.lock); + g_miner_status.WeightSum = StakeWeightSum; + g_miner_status.ValueSum = StakeValueSum; + g_miner_status.WeightMin=StakeWeightMin; + g_miner_status.WeightMax=StakeWeightMax; + g_miner_status.nLastCoinStakeSearchInterval= txnew.nTime; return false; } @@ -904,7 +918,7 @@ unsigned int GetNumberOfStakeOutputs(int64_t &nValue, int64_t &nMinStakeSplitVal // passed in MinStakeSplitValue. Note that we use GetAverageDifficulty over a 4 hour (160 block period) rather than // StakeKernelDiff, because the block to block difficulty has too much scatter. Please refer to the above link, // equation (27) on page 10 as a reference for the below formula. - nDesiredStakeOutputValue = G * GetAverageDifficulty(160) * (3.0 / 2.0) * (1 / dEfficiency - 1) * COIN; + nDesiredStakeOutputValue = G * GRC::GetAverageDifficulty(160) * (3.0 / 2.0) * (1 / dEfficiency - 1) * COIN; nDesiredStakeOutputValue = max(nMinStakeSplitValue, nDesiredStakeOutputValue); LogPrint(BCLog::LogFlags::MINER, "GetNumberOfStakeOutputs: nDesiredStakeOutputValue = %f", CoinToDouble(nDesiredStakeOutputValue)); @@ -957,7 +971,7 @@ bool SignStakeBlock(CBlock &block, CKey &key, vector &StakeInp void AddSuperblockContractOrVote(CBlock& blocknew) { - if (g_fOutOfSyncByAge) { + if (OutOfSyncByAge()) { LogPrintf("AddSuperblockContractOrVote: Out of sync."); return; } @@ -1073,7 +1087,7 @@ bool CreateGridcoinReward( } // First argument is coin age - unused since CBR (block version 10) - nReward = GetProofOfStakeReward(0, blocknew.nTime, pindexPrev); + nReward = GRC::GetProofOfStakeReward(0, blocknew.nTime, pindexPrev); claim.m_block_subsidy = nReward; nReward += nFees; @@ -1151,15 +1165,15 @@ bool IsMiningAllowed(CWallet *pwallet) bool status = true; if(pwallet->IsLocked()) { - LOCK(MinerStatus.lock); - MinerStatus.SetReasonNotStaking(CMinerStatus::WALLET_LOCKED); + LOCK(g_miner_status.lock); + g_miner_status.SetReasonNotStaking(GRC::MinerStatus::WALLET_LOCKED); status=false; } if(fDevbuildCripple) { - LOCK(MinerStatus.lock); - MinerStatus.SetReasonNotStaking(CMinerStatus::TESTNET_ONLY); + LOCK(g_miner_status.lock); + g_miner_status.SetReasonNotStaking(GRC::MinerStatus::TESTNET_ONLY); status=false; } @@ -1167,8 +1181,8 @@ bool IsMiningAllowed(CWallet *pwallet) (!fTestNet&& vNodes.size() < 3) ) { - LOCK(MinerStatus.lock); - MinerStatus.SetReasonNotStaking(CMinerStatus::OFFLINE); + LOCK(g_miner_status.lock); + g_miner_status.SetReasonNotStaking(GRC::MinerStatus::OFFLINE); status=false; } @@ -1293,7 +1307,7 @@ bool GetStakeSplitStatusAndParams(int64_t& nMinStakeSplitValue, double& dEfficie // passed in MinStakeSplitValue. Note that we use GetAverageDifficulty over a 4 hour (160 block period) rather than // StakeKernelDiff, because the block to block difficulty has too much scatter. Please refer to the above link, // equation (27) on page 10 as a reference for the below formula. - nDesiredStakeOutputValue = G * GetAverageDifficulty(160) * (3.0 / 2.0) * (1 / dEfficiency - 1) * COIN; + nDesiredStakeOutputValue = G * GRC::GetAverageDifficulty(160) * (3.0 / 2.0) * (1 / dEfficiency - 1) * COIN; nDesiredStakeOutputValue = max(nMinStakeSplitValue, nDesiredStakeOutputValue); } @@ -1327,10 +1341,10 @@ void StakeMiner(CWallet *pwallet) CBlock StakeBlock; { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); //clear miner messages - MinerStatus.ClearReasonsNotStaking(); + g_miner_status.ClearReasonsNotStaking(); //New versions if (IsV11Enabled(pindexPrev->nHeight + 1)) { @@ -1339,7 +1353,7 @@ void StakeMiner(CWallet *pwallet) StakeBlock.nVersion = 10; } - MinerStatus.Version= StakeBlock.nVersion; + g_miner_status.Version = StakeBlock.nVersion; // This is needed due to early initialization of bitcoingui miner_first_pass_complete = true; @@ -1347,9 +1361,9 @@ void StakeMiner(CWallet *pwallet) if(!IsMiningAllowed(pwallet)) { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); - MinerStatus.Clear(); + g_miner_status.Clear(); continue; } @@ -1358,7 +1372,7 @@ void StakeMiner(CWallet *pwallet) // * Create a bare block StakeBlock.nTime= GetAdjustedTime(); StakeBlock.nNonce= 0; - StakeBlock.nBits = GetNextTargetRequired(pindexPrev); + StakeBlock.nBits = GRC::GetNextTargetRequired(pindexPrev); StakeBlock.vtx.resize(2); //tx 0 is coin_base CTransaction &StakeTX= StakeBlock.vtx[1]; //tx 1 is coin_stake @@ -1399,9 +1413,9 @@ void StakeMiner(CWallet *pwallet) LogPrintf("StakeMiner: signed boinchash, coinstake, wholeblock"); { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); - MinerStatus.CreatedCnt++; + g_miner_status.CreatedCnt++; } // * delegate to ProcessBlock @@ -1414,9 +1428,10 @@ void StakeMiner(CWallet *pwallet) LogPrintf("StakeMiner: block processed"); { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); - MinerStatus.AcceptedCnt++; + g_miner_status.AcceptedCnt++; + g_miner_status.m_last_pos_tx_hash = StakeBlock.vtx[1].GetHash(); } } //end while(!fShutdown) diff --git a/src/miner.h b/src/miner.h index d278c400ab..d851291d4d 100644 --- a/src/miner.h +++ b/src/miner.h @@ -7,13 +7,14 @@ #define NOVACOIN_MINER_H #include "main.h" -#include "wallet/wallet.h" -// struct CMinerStatus is in wallet.h to prevent a circular header reference issue +#include + +class CWallet; +class CWalletTx; typedef std::vector< std::pair > SideStakeAlloc; -extern CMinerStatus MinerStatus; extern unsigned int nMinerSleep; // Note the below constant controls the minimum value allowed for post @@ -21,6 +22,8 @@ extern unsigned int nMinerSleep; // It will be converted to Halfords in GetNumberOfStakeOutputs by multiplying by COIN. static const int64_t MIN_STAKE_SPLIT_VALUE_GRC = 800; +boost::optional GetLastStake(CWallet& wallet); + void SplitCoinStakeOutput(CBlock &blocknew, int64_t &nReward, bool &fEnableStakeSplit, bool &fEnableSideStaking, SideStakeAlloc &vSideStakeAlloc, double &dEfficiency); unsigned int GetNumberOfStakeOutputs(int64_t &nValue, int64_t &nMinStakeSplitValue, double &dEfficiency); bool GetSideStakingStatusAndAlloc(SideStakeAlloc& vSideStakeAlloc); diff --git a/src/net.cpp b/src/net.cpp index 83f2ec1389..4bf65e8e32 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -13,6 +13,7 @@ #include "init.h" #include "ui_interface.h" #include "util.h" +#include "gridcoin/gridcoin.h" #include // for to_lower() #include @@ -48,11 +49,7 @@ void ThreadMapPort2(void* parg); #endif void ThreadDNSAddressSeed2(void* parg); bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); - -extern void Scraper(bool bSingleShot = false); -extern void ScraperSubscriber(); - -extern bool fScraperActive; +void StakeMiner(CWallet *pwallet); // // Global state variables @@ -1734,57 +1731,6 @@ void static ThreadStakeMiner(void* parg) LogPrintf("ThreadStakeMiner exited"); } -void static ThreadScraper(void* parg) -{ - LogPrint(BCLog::LogFlags::NOISY, "ThreadSraper starting"); - try - { - fScraperActive = true; - Scraper(false); - } - catch (std::exception& e) - { - fScraperActive = false; - PrintException(&e, "ThreadScraper()"); - } - catch(boost::thread_interrupted&) - { - fScraperActive = false; - LogPrintf("ThreadScraper exited (interrupt)"); - return; - } - catch (...) - { - fScraperActive = false; - PrintException(NULL, "ThreadScraper()"); - } - fScraperActive = false; - LogPrintf("ThreadScraper exited"); -} - -void static ThreadScraperSubscriber(void* parg) -{ - LogPrint(BCLog::LogFlags::NOISY, "ThreadScraperSubscriber starting"); - try - { - ScraperSubscriber(); - } - catch (std::exception& e) - { - PrintException(&e, "ThreadScraperSubscriber()"); - } - catch(boost::thread_interrupted&) - { - LogPrintf("ThreadScraperSubscriber exited (interrupt)"); - return; - } - catch (...) - { - PrintException(NULL, "ThreadScraperSubscriber()"); - } - LogPrintf("ThreadScraperSubscriber exited"); -} - void CNode::RecordBytesRecv(uint64_t bytes) { nTotalBytesRecv += bytes; @@ -2374,25 +2320,8 @@ void StartNode(void* parg) if (!netThreads->createThread(ThreadStakeMiner,pwalletMain,"ThreadStakeMiner")) LogPrintf("Error: createThread(ThreadStakeMiner) failed"); - // Run the scraper or NN housekeeping thread, but not both. The NN housekeeping thread - // checks if the flag for the scraper thread is true, and basically becomes a no-op, but - // it is silly to run it if the scraper thread is running. The scraper thread does all - // of the same housekeeping functions as the NN housekeeping thread. - if (GetBoolArg("-scraper", false)) - { - LogPrintf("Scraper enabled."); - if (!netThreads->createThread(ThreadScraper,NULL,"ThreadScraper")) - LogPrintf("Error: createThread(ThreadScraper) failed"); - } - else - { - LogPrintf("Scraper disabled."); - - LogPrintf("NN housekeeping thread enabled."); - - if (!netThreads->createThread(ThreadScraperSubscriber, NULL, "ScraperSubscriber")) - LogPrintf("Error: createThread(ScraperSubscriber) failed"); - } + // Initialize GRC services. + GRC::Initialize(pindexBest); } bool StopNode() diff --git a/src/protocol.h b/src/protocol.h index 0b8a34f219..5b7c6c9357 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -42,6 +42,7 @@ class CMessageHeader static constexpr size_t MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE; static constexpr size_t CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE; static constexpr size_t HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE; + typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; CMessageHeader(); CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index c82481e23d..3b4b7926ca 100755 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -7,11 +7,12 @@ #include #include "bitcoingui.h" +#include "chainparams.h" +#include "chainparamsbase.h" #include "clientmodel.h" #include "walletmodel.h" #include "researcher/researchermodel.h" #include "optionsmodel.h" -#include "global_objects_noui.hpp" #include "guiutil.h" #include "guiconstants.h" #include "init.h" @@ -20,7 +21,7 @@ #include "txdb.h" #include "util.h" #include "winshutdownmonitor.h" -#include "upgrade.h" +#include "gridcoin/upgrade.h" #include "upgradeqt.h" #include @@ -59,6 +60,9 @@ Q_IMPORT_PLUGIN(QSvgPlugin); Q_IMPORT_PLUGIN(QSvgIconPlugin); #endif +extern bool fQtActive; +extern bool bGridcoinCoreInitComplete; + // Need a global reference for the notifications to find the GUI static BitcoinGUI *guiref; static QSplashScreen *splashref; @@ -201,12 +205,6 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons } #endif - -void timerfire() -{ - -} - /* Handle runaway exceptions. Shows a message box with the problem and quits the program. */ static void handleRunawayException(std::exception *e) @@ -233,7 +231,9 @@ int main(int argc, char *argv[]) // We will load config file here as well. ParseParameters(argc, argv); + SelectParams(CBaseChainParams::MAIN); ReadConfigFile(mapArgs, mapMultiArgs); + SelectParams(mapArgs.count("-testnet") ? CBaseChainParams::TESTNET : CBaseChainParams::MAIN); // Initialize logging as early as possible. InitLogging(); @@ -244,7 +244,7 @@ int main(int argc, char *argv[]) // Here we do it if it was started with the snapshot argument and we not TestNet if (mapArgs.count("-snapshotdownload") && !mapArgs.count("-testnet")) { - Upgrade Snapshot; + GRC::Upgrade snapshot; // Let's check make sure gridcoin is not already running in the data directory. if (!LockDirectory(GetDataDir(), ".lock", false)) @@ -253,19 +253,18 @@ int main(int argc, char *argv[]) exit(1); } - else { try { - Snapshot.SnapshotMain(); + snapshot.SnapshotMain(); } catch (std::runtime_error& e) { LogPrintf("Snapshot Downloader: Runtime exception occurred in SnapshotMain() (%s)", e.what()); - Snapshot.DeleteSnapshot(); + snapshot.DeleteSnapshot(); exit(1); } @@ -273,7 +272,7 @@ int main(int argc, char *argv[]) } // Delete snapshot regardless of result. - Snapshot.DeleteSnapshot(); + snapshot.DeleteSnapshot(); } /** Start Qt as normal before it was moved into this function **/ @@ -310,7 +309,7 @@ int main(int argc, char *argv[]) else { - if (fCancelOperation) + if (GRC::fCancelOperation) LogPrintf("Snapshot: Failed!; Canceled by user."); else @@ -442,12 +441,9 @@ int StartGridcoinQt(int argc, char *argv[]) BitcoinGUI window; guiref = &window; - QTimer *timer = new QTimer(guiref); LogPrintf("Starting Gridcoin"); - QObject::connect(timer, SIGNAL(timeout()), guiref, SLOT(timerfire())); - - if (!threads->createThread(ThreadAppInit2,threads,"AppInit2 Thread")) + if (!threads->createThread(ThreadAppInit2,threads,"AppInit2 Thread")) { LogPrintf("Error; NewThread(ThreadAppInit2) failed"); return 1; @@ -489,7 +485,6 @@ int StartGridcoinQt(int argc, char *argv[]) { window.show(); } - timer->start(5000); // Place this here as guiref has to be defined if we don't want to lose URIs ipcInit(argc, argv); diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 48e3ee4571..0fc9146106 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -98,6 +98,11 @@ res/images/ic_solo_active.svg res/images/ic_solo_inactive.svg + + res/fonts/Inconsolata-Regular.ttf + res/fonts/Inter-Bold.ttf + res/fonts/Inter-Regular.ttf + res/stylesheets/light_stylesheet.qss diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 42b3bee96a..8f40fd2012 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -15,7 +15,6 @@ #include "transactiontablemodel.h" #include "addressbookpage.h" -#include "global_objects_noui.hpp" #include "diagnosticsdialog.h" #include "sendcoinsdialog.h" #include "signverifymessagedialog.h" @@ -39,10 +38,7 @@ #include "rpcconsole.h" #include "wallet/wallet.h" #include "init.h" -#include "block.h" -#include "miner.h" #include "main.h" -#include "backup.h" #include "clicklabel.h" #include "univalue.h" #include "upgradeqt.h" @@ -75,7 +71,6 @@ #include // for opening URLs #include #include -#include #include #include @@ -83,24 +78,22 @@ #include "rpcserver.h" #include "rpcclient.h" #include "rpcprotocol.h" +#include "gridcoin/backup.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/staking/status.h" #include "gridcoin/superblock.h" #include #include // for to_lower() #include -#include "boinc.h" #include "util.h" extern CWallet* pwalletMain; -extern std::string getMacAddress(); - extern std::string FromQString(QString qs); -extern std::string qtExecuteDotNetStringFunction(std::string function, std::string data); +extern CCriticalSection cs_ConvergedScraperStatsCache; void GetGlobalStatus(); -bool IsConfigFileEmpty(); - BitcoinGUI::BitcoinGUI(QWidget *parent): QMainWindow(parent), clientModel(0), @@ -117,6 +110,9 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): setGeometry(QStyle::alignedRect(Qt::LeftToRight,Qt::AlignCenter,QDesktopWidget().availableGeometry(this).size() * 0.6,QDesktopWidget().availableGeometry(this))); + QFontDatabase::addApplicationFont(":/fonts/inter-bold"); + QFontDatabase::addApplicationFont(":/fonts/inter-regular"); + QFontDatabase::addApplicationFont(":/fonts/inconsolata-regular"); setWindowTitle(tr("Gridcoin") + " " + tr("Wallet")); #ifndef Q_OS_MAC @@ -187,12 +183,18 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): diagnosticsDialog = new DiagnosticsDialog(this); - // Clicking on "Verify Message" in the address book sends you to the verify message tab connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString))); // Clicking on "Sign Message" in the receive coins page sends you to the sign message tab connect(receiveCoinsPage, SIGNAL(signMessage(QString)), this, SLOT(gotoSignMessageTab(QString))); + QTimer *overview_update_timer = new QTimer(this); + + // Update every 5 seconds. + overview_update_timer->start(5 * 1000); + + QObject::connect(overview_update_timer, SIGNAL(timeout()), this, SLOT(updateGlobalStatus())); + gotoOverviewPage(); } @@ -455,7 +457,7 @@ void BitcoinGUI::createToolBars() toolbar->setMovable(false); toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); toolbar->setContextMenuPolicy(Qt::PreventContextMenu); - toolbar->setIconSize(QSize(50, 25)); + toolbar->setIconSize(QSize(50 * logicalDpiX() / 96, 25 * logicalDpiX() / 96)); toolbar->addAction(overviewAction); toolbar->addAction(sendCoinsAction); toolbar->addAction(receiveCoinsAction); @@ -653,6 +655,7 @@ void BitcoinGUI::setResearcherModel(ResearcherModel *researcherModel) } overviewPage->setResearcherModel(researcherModel); + diagnosticsDialog->SetResearcherModel(researcherModel); updateBeaconIcon(); connect(researcherModel, SIGNAL(beaconChanged()), this, SLOT(updateBeaconIcon())); @@ -848,19 +851,20 @@ void BitcoinGUI::error(const QString &title, const QString &message, bool modal) void BitcoinGUI::update(const QString &title, const QString& version, const QString &message) { // Create our own message box; A dialog can go here in future for qt if we choose - QMessageBox* updatemsg = new QMessageBox; - - updatemsg->setAttribute(Qt::WA_DeleteOnClose); - updatemsg->setWindowTitle(title); - updatemsg->setText(version); - updatemsg->setDetailedText(message); - updatemsg->setIcon(QMessageBox::Information); - updatemsg->setStandardButtons(QMessageBox::Ok); - updatemsg->setModal(false); + + updateMessageDialog.reset(new QMessageBox); + + updateMessageDialog->setWindowTitle(title); + updateMessageDialog->setText(version); + updateMessageDialog->setDetailedText(message); + updateMessageDialog->setIcon(QMessageBox::Information); + updateMessageDialog->setStandardButtons(QMessageBox::Ok); + updateMessageDialog->setModal(false); + connect(updateMessageDialog.get(), &QMessageBox::finished, [this](int) { updateMessageDialog.reset(); }); // Due to slight delay in gui load this could appear behind the gui ui // The only other option available would make the message box stay on top of all applications - QTimer::singleShot(5000, updatemsg, SLOT(show())); + QTimer::singleShot(5000, updateMessageDialog.get(), SLOT(show())); } void BitcoinGUI::changeEvent(QEvent *e) @@ -1207,13 +1211,13 @@ void BitcoinGUI::backupWallet() QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QString walletfilename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)")); if(!walletfilename.isEmpty()) { - if(!BackupWallet(*pwalletMain, FromQString(walletfilename))) { + if(!GRC::BackupWallet(*pwalletMain, FromQString(walletfilename))) { QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location.")); } } QString configfilename = QFileDialog::getSaveFileName(this, tr("Backup Config"), saveDir, tr("Wallet Config (*.conf)")); if(!configfilename.isEmpty()) { - if(!BackupConfigFile(FromQString(configfilename))) { + if(!GRC::BackupConfigFile(FromQString(configfilename))) { QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location.")); } } @@ -1274,20 +1278,24 @@ void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) hide(); } - - -bool Timer(std::string timer_name, int max_ms) +void BitcoinGUI::updateGlobalStatus() { - mvTimers[timer_name] = mvTimers[timer_name] + 1; - if (mvTimers[timer_name] > max_ms) + // This is needed to prevent segfaulting due to early GUI initialization compared to core. + if (miner_first_pass_complete) { - mvTimers[timer_name]=0; - return true; + try + { + GetGlobalStatus(); + overviewPage->updateglobalstatus(); + setNumConnections(clientModel->getNumConnections()); + } + catch(std::runtime_error &e) + { + LogPrintf("GENERAL RUNTIME ERROR!"); + } } - return false; } - void BitcoinGUI::toggleHidden() { showNormalIfMinimized(true); @@ -1306,48 +1314,7 @@ void BitcoinGUI::updateWeight() if (!lockWallet) return; - pwalletMain->GetStakeWeight(nWeight); -} - - -std::string getMacAddress() -{ - std::string myMac = "?:?:?:?"; - foreach(QNetworkInterface netInterface, QNetworkInterface::allInterfaces()) - { - // Return only the first non-loopback MAC Address - if (!(netInterface.flags() & QNetworkInterface::IsLoopBack)) - { - myMac = netInterface.hardwareAddress().toUtf8().constData(); - } - } - return myMac; -} - -void BitcoinGUI::timerfire() -{ - try - { - if (Timer("status_update",5)) - { - GetGlobalStatus(); - bForceUpdate=true; - } - - if (bForceUpdate) - { - bForceUpdate=false; - overviewPage->updateglobalstatus(); - setNumConnections(clientModel->getNumConnections()); - } - - } - catch(std::runtime_error &e) - { - LogPrintf("GENERAL RUNTIME ERROR!"); - } - - + nWeight = GRC::GetStakeWeight(*pwalletMain); } QString BitcoinGUI::GetEstimatedStakingFrequency(unsigned int nEstimateTime) @@ -1402,22 +1369,22 @@ void BitcoinGUI::updateStakingIcon() bool able_to_stake; { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); // nWeight is in GRC units rather than miner weight units because this is more familiar to users. - nWeight = MinerStatus.WeightSum / 80.0; - nLastInterval = MinerStatus.nLastCoinStakeSearchInterval; - ReasonNotStaking = MinerStatus.ReasonNotStaking; + nWeight = g_miner_status.WeightSum / 80.0; + nLastInterval = g_miner_status.nLastCoinStakeSearchInterval; + ReasonNotStaking = g_miner_status.ReasonNotStaking; - able_to_stake = MinerStatus.able_to_stake; + able_to_stake = g_miner_status.able_to_stake; } staking = nLastInterval && nWeight; - nNetworkWeight = GetEstimatedNetworkWeight() / 80.0; + nNetworkWeight = GRC::GetEstimatedNetworkWeight() / 80.0; // It is ok to run this regardless of staking status, because it bails early in // the not able to stake situation. - estimated_staking_freq = GetEstimatedStakingFrequency(GetEstimatedTimetoStake()); + estimated_staking_freq = GetEstimatedStakingFrequency(GRC::GetEstimatedTimetoStake()); if (staking) { @@ -1446,6 +1413,8 @@ void BitcoinGUI::updateStakingIcon() void BitcoinGUI::updateScraperIcon(int scraperEventtype, int status) { + LOCK(cs_ConvergedScraperStatsCache); + const ConvergedScraperStats& ConvergedScraperStatsCache = clientModel->getConvergedScraperStatsCache(); int64_t nConvergenceTime = ConvergedScraperStatsCache.nTime; diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index e4e7bd638c..d65965e816 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "guiconstants.h" class TransactionTableModel; @@ -29,6 +30,7 @@ class QAbstractItemModel; class QModelIndex; class QStackedWidget; class QUrl; +class QMessageBox; QT_END_NAMESPACE /** @@ -78,6 +80,7 @@ class BitcoinGUI : public QMainWindow SendCoinsDialog *sendCoinsPage; VotingDialog *votingPage; SignVerifyMessageDialog *signVerifyMessageDialog; + std::unique_ptr updateMessageDialog; QLabel *labelEncryptionIcon; QLabel *labelStakingIcon; @@ -244,9 +247,7 @@ private slots: QString GetEstimatedStakingFrequency(unsigned int nEstimateTime); - void timerfire(); - - + void updateGlobalStatus(); }; #endif diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index cbe0dc9d2b..4d0824d829 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -8,6 +8,8 @@ #include "alert.h" #include "main.h" +#include "gridcoin/scraper/fwd.h" +#include "gridcoin/staking/difficulty.h" #include "gridcoin/superblock.h" #include "ui_interface.h" #include "util.h" @@ -18,7 +20,6 @@ static const int64_t nClientStartupTime = GetTime(); extern ConvergedScraperStats ConvergedScraperStatsCache; -extern CCriticalSection cs_ConvergedScraperStatsCache; ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : QObject(parent), optionsModel(optionsModel), peerTableModel(nullptr), @@ -137,11 +138,9 @@ void ClientModel::updateScraper(int scraperEventtype, int status, const QString emit updateScraperStatus(scraperEventtype, status); } -ConvergedScraperStats ClientModel::getConvergedScraperStatsCache() const +// Requires a lock on cs_ConvergedScraperStatsCache +const ConvergedScraperStats& ClientModel::getConvergedScraperStatsCache() const { - // May not be necessary to take lock, since this is read only. Consider removing. - LOCK(cs_ConvergedScraperStatsCache); - return ConvergedScraperStatsCache; } @@ -214,7 +213,7 @@ QString ClientModel::formatBoostVersion() const QString ClientModel::getDifficulty() const { //12-2-2014;R Halford; Display POR Diff on RPC Console - double PORDiff = GetDifficulty(GetLastBlockIndex(pindexBest, true)); + double PORDiff = GRC::GetCurrentDifficulty(); std::string diff = RoundToString(PORDiff,4); return QString::fromStdString(diff); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 88f810f963..d088e83efd 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -2,7 +2,6 @@ #define CLIENTMODEL_H #include -#include "scraper/fwd.h" class OptionsModel; class AddressTableModel; @@ -55,7 +54,7 @@ class ClientModel : public QObject QString formatBoostVersion() const; QString getDifficulty() const; - ConvergedScraperStats getConvergedScraperStatsCache() const; + const ConvergedScraperStats& getConvergedScraperStatsCache() const; private: OptionsModel *optionsModel; PeerTableModel *peerTableModel; diff --git a/src/qt/diagnosticsdialog.cpp b/src/qt/diagnosticsdialog.cpp index ce46002391..7b7b7ad0fd 100644 --- a/src/qt/diagnosticsdialog.cpp +++ b/src/qt/diagnosticsdialog.cpp @@ -1,5 +1,8 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" -#include "boinc.h" #include "util.h" #include @@ -8,15 +11,19 @@ #include "diagnosticsdialog.h" #include "ui_diagnosticsdialog.h" +#include "gridcoin/boinc.h" #include "gridcoin/researcher.h" -#include "upgrade.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/upgrade.h" +#include "qt/researcher/researchermodel.h" #include #include -DiagnosticsDialog::DiagnosticsDialog(QWidget *parent) : +DiagnosticsDialog::DiagnosticsDialog(QWidget *parent, ResearcherModel* researcher_model) : QDialog(parent), - ui(new Ui::DiagnosticsDialog) + ui(new Ui::DiagnosticsDialog), + m_researcher_model(researcher_model) { ui->setupUi(this); } @@ -26,6 +33,48 @@ DiagnosticsDialog::~DiagnosticsDialog() delete ui; } +void DiagnosticsDialog::SetResearcherModel(ResearcherModel *researcherModel) +{ + m_researcher_model = researcherModel; +} + +void DiagnosticsDialog::SetResultLabel(QLabel *label, DiagnosticTestStatus test_status, + DiagnosticResult test_result, QString override_text) +{ + switch (test_status) + { + case DiagnosticTestStatus::unknown: + label->setText(tr("")); + label->setStyleSheet(""); + break; + case DiagnosticTestStatus::pending: + label->setText(tr("Testing...")); + label->setStyleSheet(""); + break; + case DiagnosticTestStatus::completed: + switch (test_result) + { + case DiagnosticResult::NA: + label->setText(tr("N/A")); + label->setStyleSheet("color:black;background-color:grey"); + break; + case DiagnosticResult::passed: + label->setText(tr("Passed")); + label->setStyleSheet("color:white;background-color:green"); + break; + case DiagnosticResult::warning: + label->setText(tr("Warning")); + label->setStyleSheet("color:black;background-color:yellow"); + break; + case DiagnosticResult::failed: + label->setText(tr("Failed")); + label->setStyleSheet("color:white;background-color:red"); + } + } + + if (override_text.size()) label->setText(override_text); +} + unsigned int DiagnosticsDialog::GetNumberOfTestsPending() { LOCK(cs_diagnostictests); @@ -56,12 +105,18 @@ DiagnosticsDialog::DiagnosticTestStatus DiagnosticsDialog::GetTestStatus(std::st } } -unsigned int DiagnosticsDialog::UpdateTestStatus(std::string test_name, DiagnosticTestStatus test_status) +unsigned int DiagnosticsDialog::UpdateTestStatus(std::string test_name, QLabel *label, + DiagnosticTestStatus test_status, DiagnosticResult test_result, + QString override_text) { LOCK(cs_diagnostictests); test_status_map[test_name] = test_status; + SetResultLabel(label, test_status, test_result, override_text); + + UpdateOverallDiagnosticResult(test_result); + return test_status_map.size(); } @@ -128,149 +183,41 @@ void DiagnosticsDialog::DisplayOverallDiagnosticResult() { LOCK(cs_diagnostictests); - if (GetOverallDiagnosticStatus() == pending) - { - ui->overallResultResultLabel->setText(tr("Testing...")); - ui->overallResultResultLabel->setStyleSheet(""); - } - else - { - // Overall status must be completed, so display overall result - switch (GetOverallDiagnosticResult()) - { - case NA: - ui->overallResultResultLabel->clear(); - ui->overallResultResultLabel->setStyleSheet(""); - break; - - case passed: - ui->overallResultResultLabel->setText(tr("Passed")); - ui->overallResultResultLabel->setStyleSheet("color:white;background-color:green"); - break; - - case warning: - ui->overallResultResultLabel->setText(tr("Warning")); - ui->overallResultResultLabel->setStyleSheet("color:black;background-color:yellow"); - break; - - case failed: - ui->overallResultResultLabel->setText(tr("Failed")); - ui->overallResultResultLabel->setStyleSheet("color:white;background-color:red"); - } - } + SetResultLabel(ui->overallResultResultLabel, GetOverallDiagnosticStatus(), GetOverallDiagnosticResult()); this->repaint(); } bool DiagnosticsDialog::VerifyBoincPath() { - boost::filesystem::path boincPath = (boost::filesystem::path) GetBoincDataDir(); + boost::filesystem::path boincPath = (boost::filesystem::path) GRC::GetBoincDataDir(); if (boincPath.empty()) boincPath = (boost::filesystem::path) GetArgument("boincdatadir", ""); boincPath = boincPath / "client_state.xml"; - return boost::filesystem::exists(boincPath) ? true : false; + return boost::filesystem::exists(boincPath); } bool DiagnosticsDialog::VerifyIsCPIDValid() { - boost::filesystem::path clientStatePath = GetBoincDataDir(); - - if (!clientStatePath.empty()) - clientStatePath = clientStatePath / "client_state.xml"; - - else - clientStatePath = (boost::filesystem::path) GetArgument("boincdatadir", "") / "client_state.xml"; - - if (clientStatePath.empty()) - return false; - - fsbridge::ifstream clientStateStream; - std::string clientState; - - clientStateStream.open(clientStatePath); - clientState.assign((std::istreambuf_iterator(clientStateStream)), std::istreambuf_iterator()); - clientStateStream.close(); - - size_t pos = 0; - std::string cpid; - - if ((pos = clientState.find("")) != std::string::npos) - { - cpid = clientState.substr(pos + 15, clientState.length()); - pos = cpid.find(""); - cpid.erase(pos, cpid.length()); - } - - return (GRC::Researcher::Get()->Id().ToString() == cpid) ? true : false; + return m_researcher_model->hasEligibleProjects(); } bool DiagnosticsDialog::VerifyCPIDIsEligible() { - return GRC::Researcher::Get()->Eligible(); + return m_researcher_model->hasActiveBeacon(); } bool DiagnosticsDialog::VerifyWalletIsSynced() { - int64_t nwalletAge = PreviousBlockAge(); - - return (nwalletAge < (60 * 60)) ? true : false; + return !OutOfSyncByAge(); } bool DiagnosticsDialog::VerifyCPIDHasRAC() { - double racValue = 0; - - boost::filesystem::path clientStatePath = (boost::filesystem::path) GetBoincDataDir(); - - if (!clientStatePath.empty()) - clientStatePath = clientStatePath / "client_state.xml"; - - else - clientStatePath = (boost::filesystem::path) GetArgument("boincdatadir", "") / "client_state.xml"; - - if (clientStatePath.empty()) - return false; - - fsbridge::ifstream clientStateStream; - std::string clientState; - std::vector racStrings; - - clientStateStream.open(clientStatePath.string()); - clientState.assign((std::istreambuf_iterator(clientStateStream)), std::istreambuf_iterator()); - clientStateStream.close(); - - if (clientState.length() > 0) - { - size_t pos = 0; - std::string delim = ""; - std::string line; - - while ((pos = clientState.find(delim)) != std::string::npos) - { - line = clientState.substr(0, pos); - clientState.erase(0, pos + delim.length()); - pos = line.find(""); - racStrings.push_back(line.substr(pos + 20, line.length())); - } - - for (auto const& racString : racStrings) - { - try - { - racValue += std::stod(racString); - } - - catch (std::exception& ex) - { - continue; - } - } - } - - return (racValue >= 1) ? true : false; + return m_researcher_model->hasRAC(); } double DiagnosticsDialog::VerifyETTSReasonable() @@ -279,9 +226,9 @@ double DiagnosticsDialog::VerifyETTSReasonable() // and also use a 960 block diff as the input, which smooths out short // term fluctuations. The standard 1-1/e confidence (mean) is used. - double diff = GetAverageDifficulty(960); + double diff = GRC::GetAverageDifficulty(960); - double result = GetEstimatedTimetoStake(true, diff); + double result = GRC::GetEstimatedTimetoStake(true, diff); return result; } @@ -324,125 +271,75 @@ void DiagnosticsDialog::on_testButton_clicked() ResetOverallDiagnosticResult(number_of_tests); DisplayOverallDiagnosticResult(); - // Tests that are N/A if in investor mode. - if (GRC::Researcher::ConfiguredForInvestorMode()) + // Tests that are N/A if in investor or pool mode. + if (m_researcher_model->configuredForInvestorMode() || m_researcher_model->detectedPoolMode()) { - // N/A tests for investor mode - ui->boincPathResultLabel->setText(tr("N/A")); - ui->boincPathResultLabel->setStyleSheet("color:black;background-color:grey"); - UpdateTestStatus("boincPath", completed); - - ui->verifyCPIDValidResultLabel->setText(tr("N/A")); - ui->verifyCPIDValidResultLabel->setStyleSheet("color:black;background-color:grey"); - UpdateTestStatus("verifyCPIDValid", completed); - - ui->verifyCPIDHasRACResultLabel->setText(tr("N/A")); - ui->verifyCPIDHasRACResultLabel->setStyleSheet("color:black;background-color:grey"); - UpdateTestStatus("verifyCPIDHasRAC", completed); - - ui->verifyCPIDIsInNNResultLabel->setText(tr("N/A")); - ui->verifyCPIDIsInNNResultLabel->setStyleSheet("color:black;background-color:grey"); - UpdateTestStatus("verifyCPIDIsInNN", completed); - - ui->checkETTSResultLabel->setText(tr("N/A")); - ui->checkETTSResultLabel->setStyleSheet("color:black;background-color:grey"); - UpdateTestStatus("checkETTS", completed); - + // N/A tests for investor/pool mode + UpdateTestStatus("boincPath", ui->boincPathResultLabel, completed, NA); + UpdateTestStatus("verifyCPIDValid", ui->verifyCPIDValidResultLabel, completed, NA); + UpdateTestStatus("verifyCPIDHasRAC", ui->verifyCPIDHasRACResultLabel, completed, NA); + UpdateTestStatus("verifyCPIDIsActive", ui->verifyCPIDIsActiveResultLabel, completed, NA); + UpdateTestStatus("checkETTS", ui->checkETTSResultLabel, completed, NA); } else { //BOINC path - ui->boincPathResultLabel->setStyleSheet(""); - ui->boincPathResultLabel->setText(tr("Testing...")); - UpdateTestStatus("boincPath", pending); + UpdateTestStatus("boincPath", ui->boincPathResultLabel, pending, NA); this->repaint(); if (VerifyBoincPath()) { - ui->boincPathResultLabel->setText(tr("Passed")); - ui->boincPathResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("boincPath", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("boincPath", ui->boincPathResultLabel, completed, passed); } else { - ui->boincPathResultLabel->setText(tr("Failed")); - ui->boincPathResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("boincPath", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("boincPath", ui->boincPathResultLabel, completed, failed); } //CPID valid - ui->verifyCPIDValidResultLabel->setStyleSheet(""); - ui->verifyCPIDValidResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyCPIDValid", pending); + UpdateTestStatus("verifyCPIDValid", ui->verifyCPIDValidResultLabel, pending, NA); this->repaint(); if (VerifyIsCPIDValid()) { - ui->verifyCPIDValidResultLabel->setText(tr("Passed")); - ui->verifyCPIDValidResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifyCPIDValid", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifyCPIDValid", ui->verifyCPIDValidResultLabel, completed, passed); } else { - ui->verifyCPIDValidResultLabel->setText(tr("Failed: BOINC CPID does not match CPID")); - ui->verifyCPIDValidResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifyCPIDValid", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyCPIDValid", ui->verifyCPIDValidResultLabel, completed, failed); } //CPID has rac - ui->verifyCPIDHasRACResultLabel->setStyleSheet(""); - ui->verifyCPIDHasRACResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyCPIDHasRAC", pending); + UpdateTestStatus("verifyCPIDHasRAC", ui->verifyCPIDHasRACResultLabel, pending, NA); this->repaint(); if (VerifyCPIDHasRAC()) { - ui->verifyCPIDHasRACResultLabel->setText(tr("Passed")); - ui->verifyCPIDHasRACResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifyCPIDHasRAC", completed); - UpdateOverallDiagnosticResult(passed); - + UpdateTestStatus("verifyCPIDHasRAC", ui->verifyCPIDHasRACResultLabel, completed, passed); } else { - ui->verifyCPIDHasRACResultLabel->setText(tr("Failed")); - ui->verifyCPIDHasRACResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifyCPIDHasRAC", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyCPIDHasRAC", ui->verifyCPIDHasRACResultLabel, completed, failed); } - //cpid is in nn - ui->verifyCPIDIsInNNResultLabel->setStyleSheet(""); - ui->verifyCPIDIsInNNResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyCPIDIsInNN", pending); + //cpid is active + UpdateTestStatus("verifyCPIDIsActive", ui->verifyCPIDIsActiveResultLabel, pending, NA); this->repaint(); if (VerifyCPIDIsEligible()) { - ui->verifyCPIDIsInNNResultLabel->setText(tr("Passed")); - ui->verifyCPIDIsInNNResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifyCPIDIsInNN", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifyCPIDIsActive", ui->verifyCPIDIsActiveResultLabel, completed, passed); } else { - ui->verifyCPIDIsInNNResultLabel->setText(tr("Failed")); - ui->verifyCPIDIsInNNResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifyCPIDIsInNN", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyCPIDIsActive", ui->verifyCPIDIsActiveResultLabel, completed, failed); } // verify reasonable ETTS // This is only checked if wallet is a researcher wallet because the purpose is to // alert the owner that his stake time is too long and therefore there is a chance // of research rewards loss between stakes due to the 180 day limit. - ui->checkETTSResultLabel->setStyleSheet(""); - ui->checkETTSResultLabel->setText(tr("Testing...")); - UpdateTestStatus("checkETTS", pending); + UpdateTestStatus("checkETTS", ui->checkETTSResultLabel, pending, NA); double ETTS = VerifyETTSReasonable() / (24.0 * 60.0 * 60.0); @@ -465,156 +362,110 @@ void DiagnosticsDialog::on_testButton_clicked() // ETTS of zero actually means no coins, i.e. infinite. if (ETTS == 0.0) { - ui->checkETTSResultLabel->setText(tr("Failed: ETTS is infinite. No coins to stake.")); - ui->checkETTSResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("checkETTS", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("checkETTS", ui->checkETTSResultLabel, completed, failed, + tr("Failed: ETTS is infinite. No coins to stake.")); } else if (ETTS > 90.0) { - ui->checkETTSResultLabel->setText(tr("Failed: ETTS = %1 > 90 days") - .arg(QString(rounded_ETTS.c_str()))); - ui->checkETTSResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("checkETTS", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("checkETTS", ui->checkETTSResultLabel, completed, failed, + tr("Failed: ETTS is infinite. No coins to stake.")); } else if (ETTS > 45.0 && ETTS <= 90.0) { - ui->checkETTSResultLabel->setText(tr("Warning: 45 days < ETTS = %1 <= 90 days") - .arg(QString(rounded_ETTS.c_str()))); - ui->checkETTSResultLabel->setStyleSheet("color:black;background-color:yellow"); - UpdateTestStatus("checkETTS", completed); - UpdateOverallDiagnosticResult(warning); + UpdateTestStatus("checkETTS", ui->checkETTSResultLabel, completed, warning, + tr("Warning: 45 days < ETTS = %1 <= 90 days").arg(QString(rounded_ETTS.c_str()))); } else { - ui->checkETTSResultLabel->setText(tr("Passed: ETTS = %1 <= 45 days") - .arg(QString(rounded_ETTS.c_str()))); - ui->checkETTSResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("checkETTS", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("checkETTS", ui->checkETTSResultLabel, completed, passed, + tr("Passed: ETTS = %1 <= 45 days").arg(QString(rounded_ETTS.c_str()))); } } // Tests that are common to both investor and researcher mode. // wallet synced - ui->verifyWalletIsSyncedResultLabel->setStyleSheet(""); - ui->verifyWalletIsSyncedResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyWalletIsSynced", pending); + UpdateTestStatus("verifyWalletIsSynced", ui->verifyWalletIsSyncedResultLabel, pending, NA); this->repaint(); if (VerifyWalletIsSynced()) { - ui->verifyWalletIsSyncedResultLabel->setText(tr("Passed")); - ui->verifyWalletIsSyncedResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifyWalletIsSynced", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifyWalletIsSynced", ui->verifyWalletIsSyncedResultLabel, completed, passed); } else { - ui->verifyWalletIsSyncedResultLabel->setText(tr("Failed")); - ui->verifyWalletIsSyncedResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifyWalletIsSynced", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyWalletIsSynced", ui->verifyWalletIsSyncedResultLabel, completed, failed); } // clock - ui->verifyClockResultLabel->setStyleSheet(""); - ui->verifyClockResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyClockResult", pending); + UpdateTestStatus("verifyClockResult", ui->verifyClockResultLabel, pending, NA); this->repaint(); VerifyClock(); // seed nodes - ui->verifySeedNodesResultLabel->setStyleSheet(""); - ui->verifySeedNodesResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifySeedNodes", pending); + UpdateTestStatus("verifySeedNodes", ui->verifySeedNodesResultLabel, pending, NA); this->repaint(); unsigned int seed_node_connections = VerifyCountSeedNodes(); if (seed_node_connections >= 1 && seed_node_connections < 3) { - ui->verifySeedNodesResultLabel->setText(tr("Warning: Count = %1 (Pass = 3+)").arg(QString::number(seed_node_connections))); - ui->verifySeedNodesResultLabel->setStyleSheet("color:black;background-color:yellow"); - UpdateTestStatus("verifySeedNodes", completed); - UpdateOverallDiagnosticResult(warning); + UpdateTestStatus("verifySeedNodes", ui->verifySeedNodesResultLabel, completed, warning, + tr("Warning: Count = %1 (Pass = 3+)").arg(QString::number(seed_node_connections))); } else if(seed_node_connections >= 3) { - ui->verifySeedNodesResultLabel->setText(tr("Passed: Count = %1").arg(QString::number(seed_node_connections))); - ui->verifySeedNodesResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifySeedNodes", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifySeedNodes", ui->verifySeedNodesResultLabel, completed, passed, + tr("Passed: Count = %1").arg(QString::number(seed_node_connections))); } else { - ui->verifySeedNodesResultLabel->setText(tr("Failed: Count = %1").arg(QString::number(seed_node_connections))); - ui->verifySeedNodesResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifySeedNodes", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifySeedNodes", ui->verifySeedNodesResultLabel, completed, failed, + tr("Failed: Count = %1").arg(QString::number(seed_node_connections))); } // connection count - ui->verifyConnectionsResultLabel->setStyleSheet(""); - ui->verifyConnectionsResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyConnections", pending); + UpdateTestStatus("verifyConnections", ui->verifyConnectionsResultLabel, pending, NA); this->repaint(); unsigned int connections = VerifyCountConnections(); if (connections <= 7 && connections >= 1) { - ui->verifyConnectionsResultLabel->setText(tr("Warning: Count = %1 (Pass = 8+)").arg(QString::number(connections))); - ui->verifyConnectionsResultLabel->setStyleSheet("color:black;background-color:yellow"); - UpdateTestStatus("verifyConnections", completed); - UpdateOverallDiagnosticResult(warning); + UpdateTestStatus("verifyConnections", ui->verifyConnectionsResultLabel, completed, warning, + tr("Warning: Count = %1 (Pass = 8+)").arg(QString::number(connections))); } else if (connections >= 8) { - ui->verifyConnectionsResultLabel->setText(tr("Passed: Count = %1").arg(QString::number(connections))); - ui->verifyConnectionsResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifyConnections", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifyConnections", ui->verifyConnectionsResultLabel, completed, passed, + tr("Passed: Count = %1").arg(QString::number(connections))); } else { - ui->verifyConnectionsResultLabel->setText(tr("Failed: Count = %1").arg(QString::number(connections))); - ui->verifyConnectionsResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifyConnections", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyConnections", ui->verifyConnectionsResultLabel, completed, failed, + tr("Failed: Count = %1").arg(QString::number(connections))); } // tcp port - ui->verifyTCPPortResultLabel->setStyleSheet(""); - ui->verifyTCPPortResultLabel->setText(tr("Testing...")); - UpdateTestStatus("verifyTCPPort", pending); + UpdateTestStatus("verifyTCPPort", ui->verifyTCPPortResultLabel, pending, NA); this->repaint(); VerifyTCPPort(); // client version - ui->checkClientVersionResultLabel->setStyleSheet(""); - ui->checkClientVersionResultLabel->setText(tr("Testing...")); - UpdateTestStatus("checkClientVersion", pending); + UpdateTestStatus("checkClientVersion", ui->checkClientVersionResultLabel, pending, NA); std::string client_message; if (g_UpdateChecker->CheckForLatestUpdate(false, client_message)) { - ui->checkClientVersionResultLabel->setText(tr("Warning: New Client version available:\n %1").arg(QString(client_message.c_str()))); - ui->checkClientVersionResultLabel->setStyleSheet("color:black;background-color:yellow;height:2em"); - UpdateTestStatus("checkClientVersion", completed); - UpdateOverallDiagnosticResult(warning); + UpdateTestStatus("checkClientVersion", ui->checkClientVersionResultLabel, completed, warning, + tr("Warning: New Client version available:\n %1").arg(QString(client_message.c_str()))); } else { - ui->checkClientVersionResultLabel->setText(tr("Passed")); - ui->checkClientVersionResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("checkClientVersion", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("checkClientVersion", ui->checkClientVersionResultLabel, completed, passed); } DisplayOverallDiagnosticResult(); @@ -675,7 +526,10 @@ void DiagnosticsDialog::clkFinished() if (BufferSocket.size() == 48) { int nNTPCount = 40; - unsigned long DateTimeIn = uchar(BufferSocket.at(nNTPCount)) + (uchar(BufferSocket.at(nNTPCount + 1)) << 8) + (uchar(BufferSocket.at(nNTPCount + 2)) << 16) + (uchar(BufferSocket.at(nNTPCount + 3)) << 24); + unsigned long DateTimeIn = uchar(BufferSocket.at(nNTPCount)) + + (uchar(BufferSocket.at(nNTPCount + 1)) << 8) + + (uchar(BufferSocket.at(nNTPCount + 2)) << 16) + + (uchar(BufferSocket.at(nNTPCount + 3)) << 24); long tmit = ntohl((time_t)DateTimeIn); tmit -= 2208988800U; @@ -687,24 +541,13 @@ void DiagnosticsDialog::clkFinished() if (timeDiff.minutes() < 3) { - ui->verifyClockResultLabel->setText(tr("Passed")); - ui->verifyClockResultLabel->setStyleSheet("color:white;background-color:green"); - UpdateTestStatus("verifyClockResult", completed); - - // We need this here because there is no return call (callback) to the on_testButton_clicked function - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifyClockResult", ui->verifyClockResultLabel, completed, passed); } else { - ui->verifyClockResultLabel->setText(tr("Failed: Sync local time with network")); - ui->verifyClockResultLabel->setStyleSheet("color:white;background-color:red"); - UpdateTestStatus("verifyClockResult", completed); - - // We need this here because there is no return call (callback) to the on_testButton_clicked function - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyClockResult", ui->verifyClockResultLabel, completed, failed); } - // We need this here because there is no return call (callback) to the on_testButton_clicked function DisplayOverallDiagnosticResult(); return; @@ -717,12 +560,8 @@ void DiagnosticsDialog::clkFinished() // above, then when the timer calls clkFinished again, it will hit this conditional and be a no-op. if (GetTestStatus("verifyClockResult") != completed) { - ui->verifyClockResultLabel->setText(tr("Warning: Cannot connect to NTP server")); - ui->verifyClockResultLabel->setStyleSheet("color:black;background-color:yellow"); - UpdateTestStatus("verifyClockResult", completed); - - // We need this here because there is no return call (callback) to the on_testButton_clicked function - UpdateOverallDiagnosticResult(warning); + UpdateTestStatus("verifyClockResult", ui->verifyClockResultLabel,completed, warning, + tr("Warning: Cannot connect to NTP server")); DisplayOverallDiagnosticResult(); } @@ -744,12 +583,7 @@ void DiagnosticsDialog::VerifyTCPPort() void DiagnosticsDialog::TCPFinished() { tcpSocket->close(); - ui->verifyTCPPortResultLabel->setText(tr("Passed")); - ui->verifyTCPPortResultLabel->setStyleSheet("color:white;background-color:green"); - - // We need this here because there is no return call (callback) to the on_testButton_clicked function - UpdateTestStatus("verifyTCPPort", completed); - UpdateOverallDiagnosticResult(passed); + UpdateTestStatus("verifyTCPPort", ui->verifyTCPPortResultLabel, completed, passed); DisplayOverallDiagnosticResult(); @@ -758,12 +592,8 @@ void DiagnosticsDialog::TCPFinished() void DiagnosticsDialog::TCPFailed(QAbstractSocket::SocketError socket) { - ui->verifyTCPPortResultLabel->setText(tr("Warning: Port 32749 may be blocked by your firewall")); - ui->verifyTCPPortResultLabel->setStyleSheet("color:black;background-color:yellow"); - - // We need this here because there is no return call (callback) to the on_testButton_clicked function - UpdateTestStatus("verifyTCPPort", completed); - UpdateOverallDiagnosticResult(failed); + UpdateTestStatus("verifyTCPPort", ui->verifyTCPPortResultLabel, completed, warning, + tr("Warning: Port 32749 may be blocked by your firewall")); DisplayOverallDiagnosticResult(); diff --git a/src/qt/diagnosticsdialog.h b/src/qt/diagnosticsdialog.h index 28831188f2..04c262a016 100644 --- a/src/qt/diagnosticsdialog.h +++ b/src/qt/diagnosticsdialog.h @@ -1,14 +1,21 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef DIAGNOSTICSDIALOG_H #define DIAGNOSTICSDIALOG_H #include #include +#include #include #include #include "sync.h" +class ResearcherModel; + namespace Ui { class DiagnosticsDialog; } @@ -18,7 +25,7 @@ class DiagnosticsDialog : public QDialog Q_OBJECT public: - explicit DiagnosticsDialog(QWidget *parent = 0); + explicit DiagnosticsDialog(QWidget *parent = 0, ResearcherModel* researcher_model = nullptr); ~DiagnosticsDialog(); enum DiagnosticResult @@ -71,12 +78,17 @@ class DiagnosticsDialog : public QDialog typedef std::unordered_map mDiagnosticTestStatus; mDiagnosticTestStatus test_status_map; + ResearcherModel *m_researcher_model; + QUdpSocket *udpSocket; QTcpSocket *tcpSocket; public: + void SetResearcherModel(ResearcherModel *researcherModel); unsigned int GetNumberOfTestsPending(); - unsigned int UpdateTestStatus(std::string test_name, DiagnosticTestStatus test_status); + unsigned int UpdateTestStatus(std::string test_name, QLabel *label, + DiagnosticTestStatus test_status, DiagnosticResult test_result, + QString override_text = QString()); DiagnosticTestStatus GetTestStatus(std::string test_name); void ResetOverallDiagnosticResult(unsigned int& number_of_tests); void UpdateOverallDiagnosticResult(DiagnosticResult diagnostic_result_in); @@ -84,6 +96,10 @@ class DiagnosticsDialog : public QDialog DiagnosticTestStatus GetOverallDiagnosticStatus(); void DisplayOverallDiagnosticResult(); +private: + void SetResultLabel(QLabel *label, DiagnosticTestStatus test_status, + DiagnosticResult test_result, QString override_text = QString()); + private slots: void on_testButton_clicked(); void clkFinished(); diff --git a/src/qt/forms/diagnosticsdialog.ui b/src/qt/forms/diagnosticsdialog.ui index c8f941c0ba..7d57d42ccd 100644 --- a/src/qt/forms/diagnosticsdialog.ui +++ b/src/qt/forms/diagnosticsdialog.ui @@ -50,7 +50,7 @@ 8 - + 0 @@ -75,7 +75,7 @@ - + 0 diff --git a/src/qt/forms/researcherwizardsummarypage.ui b/src/qt/forms/researcherwizardsummarypage.ui index be6a083764..0a95056716 100644 --- a/src/qt/forms/researcherwizardsummarypage.ui +++ b/src/qt/forms/researcherwizardsummarypage.ui @@ -196,6 +196,19 @@ + + + + + 0 + 0 + + + + Review Beacon Verification + + + @@ -204,6 +217,12 @@ QSizePolicy::Expanding + + + 0 + 0 + + diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index fb6af3196e..51798b0d00 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -20,12 +20,6 @@ #include #include -#ifdef WIN32 -#include -#include "../global_objects.hpp" -#include "../global_objects_noui.hpp" -#endif - #define DECORATION_SIZE 64 class TxViewDelegate : public QAbstractItemDelegate diff --git a/src/qt/res/fonts/Inconsolata-Regular.ttf b/src/qt/res/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000000..457d262cf5 Binary files /dev/null and b/src/qt/res/fonts/Inconsolata-Regular.ttf differ diff --git a/src/qt/res/fonts/Inter-Bold.ttf b/src/qt/res/fonts/Inter-Bold.ttf new file mode 100644 index 0000000000..847ffd191b Binary files /dev/null and b/src/qt/res/fonts/Inter-Bold.ttf differ diff --git a/src/qt/res/fonts/Inter-Regular.ttf b/src/qt/res/fonts/Inter-Regular.ttf new file mode 100644 index 0000000000..3b7e686e54 Binary files /dev/null and b/src/qt/res/fonts/Inter-Regular.ttf differ diff --git a/src/qt/res/stylesheets/dark_stylesheet.qss b/src/qt/res/stylesheets/dark_stylesheet.qss index f550b71ce2..c06f8a209a 100644 --- a/src/qt/res/stylesheets/dark_stylesheet.qss +++ b/src/qt/res/stylesheets/dark_stylesheet.qss @@ -1,9 +1,15 @@ /* general */ +* { + font-family: "Inter"; + font-size: 10pt; +} + + QMainWindow { background-color:rgb(49,54,59); border:none; - font-family:'Open Sans'; + font-family: "Inter"; } BitcoinAmountField{ @@ -22,24 +28,20 @@ QFrame[frameShape="5"] { QToolButton { color: white; - background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(49,54,59), stop: 1 rgb(49,54,59)); - border:none; + background-color: rgb(49,54,59); } QToolButton:hover { - background-color:qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(65,0,127), stop: 1 rgb(65,0,127)); color:white; - border:none; + background-color: rgb(65,0,127); } QToolButton:checked { - background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(64,68,82), stop: 1 rgb(64,68,82)); - border:none; + background-color: rgb(64,68,82); } QToolButton:checked:hover { - background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(65,0,127), stop: 1 rgb(65,0,127)); - border:none; + background-color: rgb(65,0,127); } QMenuBar { @@ -347,6 +349,7 @@ QTabBar::tab:!first { margin-left: -0.065em; } + QTabBar::tab:selected { background-color: rgb(58, 64, 69); border-bottom-color: rgb(58, 64, 69); @@ -362,10 +365,16 @@ QTabBar::tab:!selected:hover { background-color: rgb(58, 64, 69); } -QTextEdit{ +QTextEdit { background-color: rgb(35,38,41); } +/* RPC Console */ +#messagesWidget, #lineEdit { + font-family: "Inconsolata"; + font-size: 10pt; +} + QPlainTextEdit{ background-color: rgb(35,38,41); } @@ -394,7 +403,7 @@ QCheckBox{ #toolbar { border:none; padding-top:1.25em; - min-width:8em; + min-width:8.5em; height:100%; color: white; } @@ -413,8 +422,8 @@ QCheckBox{ } QToolBar#toolbar QToolButton { - padding-left:1em; - padding-right:1em; + padding-left:1.25em; + padding-right:1.25em; padding-top:0.5em; padding-bottom:0.5em; margin:0.25em; diff --git a/src/qt/res/stylesheets/light_stylesheet.qss b/src/qt/res/stylesheets/light_stylesheet.qss index 55e70b1d5e..cf5d05db58 100644 --- a/src/qt/res/stylesheets/light_stylesheet.qss +++ b/src/qt/res/stylesheets/light_stylesheet.qss @@ -1,9 +1,14 @@ /* general */ +* { + font-family: "Inter"; + font-size: 10pt; +} + QMainWindow { background-color:rgb(240,240,240); border:none; - font-family:'Open Sans'; + font-family: "Inter"; } BitcoinAmountField{ @@ -12,24 +17,20 @@ BitcoinAmountField{ QToolButton { color: black; - background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(240,240,240), stop: 1 rgb(240,240,240)); - border:none; + background-color: rgb(240,240,240); } QToolButton:hover { - background-color:qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(65,0,127), stop: 1 rgb(65,0,127)); color:white; - border:none; + background-color: rgb(65,0,127); } QToolButton:checked { - background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(200,200,200), stop: 1 rgb(200,200,200)); - border:none; + background-color: rgb(200,200,200); } QToolButton:checked:hover { - background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 rgb(65,0,127), stop: 1 rgb(65,0,127)); - border:none; + background-color: rgb(65,0,127); } QMenuBar { @@ -347,10 +348,16 @@ QTabBar::tab:!selected:hover { background: rgb(255, 255, 255); } -QTextEdit{ +QTextEdit { background-color: white; } +/* RPC Console */ +#messagesWidget, #lineEdit { + font-family: "Inconsolata"; + font-size: 10pt; +} + QPlainTextEdit{ background-color: white; } @@ -369,7 +376,7 @@ QListWidget{ #toolbar { border:none; padding-top:1.25em; - min-width:8em; + min-width:8.5em; height:100%; color: black; } @@ -388,8 +395,8 @@ QListWidget{ } QToolBar#toolbar QToolButton { - padding-left:1em; - padding-right:1em; + padding-left:1.25em; + padding-right:1.25em; padding-top:0.5em; padding-bottom:0.5em; margin:0.25em; diff --git a/src/qt/res/stylesheets/native_stylesheet.qss b/src/qt/res/stylesheets/native_stylesheet.qss index 4043fc857a..ffabefce47 100644 --- a/src/qt/res/stylesheets/native_stylesheet.qss +++ b/src/qt/res/stylesheets/native_stylesheet.qss @@ -1,7 +1,36 @@ /* general */ +* { + font-family: "Inter"; + font-size: 10pt; +} + QMainWindow { - font-family:'Open Sans'; + font-family: "Inter"; +} + +QMenuBar { + background: rgb(240,240,240); + color: black; +} + +QMenuBar::item { + padding-bottom:0.5em; + padding-top:0.5em; + padding-left:1em; + padding-right:1em; + color: black; + background-color: rgb(240,240,240); +} + +QTextEdit { + background-color: white; +} + +/* RPC Console */ +#messagesWidget, #lineEdit { + font-family: "Inconsolata"; + font-size: 10pt; } /* Main Window*/ @@ -9,7 +38,7 @@ QMainWindow { #toolbar { border:none; padding-top:1.25em; - min-width:8em; + min-width:8.5em; height:100%; } @@ -26,8 +55,8 @@ QMainWindow { } QToolBar#toolbar QToolButton { - padding-left:1em; - padding-right:1em; + padding-left:1.25em; + padding-right:1.25em; padding-top:0.5em; padding-bottom:0.5em; margin:0.25em; diff --git a/src/qt/researcher/projecttablemodel.cpp b/src/qt/researcher/projecttablemodel.cpp index 83418b1c33..79769260ad 100644 --- a/src/qt/researcher/projecttablemodel.cpp +++ b/src/qt/researcher/projecttablemodel.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "gridcoin/researcher.h" #include "qt/researcher/projecttablemodel.h" diff --git a/src/qt/researcher/projecttablemodel.h b/src/qt/researcher/projecttablemodel.h index 6760b71076..b13a68d433 100644 --- a/src/qt/researcher/projecttablemodel.h +++ b/src/qt/researcher/projecttablemodel.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef PROJECTTABLEMODEL_H #define PROJECTTABLEMODEL_H diff --git a/src/qt/researcher/researchermodel.cpp b/src/qt/researcher/researchermodel.cpp index 09fd2cd1db..7187f6adb2 100644 --- a/src/qt/researcher/researchermodel.cpp +++ b/src/qt/researcher/researchermodel.cpp @@ -1,7 +1,11 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "base58.h" -#include "boinc.h" #include "main.h" #include "gridcoin/beacon.h" +#include "gridcoin/boinc.h" #include "gridcoin/magnitude.h" #include "gridcoin/project.h" #include "gridcoin/quorum.h" @@ -239,6 +243,11 @@ bool ResearcherModel::hasMagnitude() const return m_researcher->Magnitude() != 0; } +bool ResearcherModel::hasRAC() const +{ + return m_researcher->HasRAC(); +} + bool ResearcherModel::needsBeaconAuth() const { if (!hasPendingBeacon() || !IsV11Enabled(nBestHeight + 1)) { diff --git a/src/qt/researcher/researchermodel.h b/src/qt/researcher/researchermodel.h index 636f5090e5..4321fdd820 100644 --- a/src/qt/researcher/researchermodel.h +++ b/src/qt/researcher/researchermodel.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERMODEL_H #define RESEARCHERMODEL_H @@ -86,6 +90,7 @@ class ResearcherModel : public QObject bool hasPendingBeacon() const; bool hasRenewableBeacon() const; bool hasMagnitude() const; + bool hasRAC() const; bool needsBeaconAuth() const; bool needsV2BeaconUpgrade() const; diff --git a/src/qt/researcher/researcherwizard.cpp b/src/qt/researcher/researcherwizard.cpp index c69f0d6005..f920e9c0de 100644 --- a/src/qt/researcher/researcherwizard.cpp +++ b/src/qt/researcher/researcherwizard.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizard.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizard.h" @@ -48,6 +52,14 @@ ResearcherWizard::ResearcherWizard( connect(ui->modePage, SIGNAL(detailLinkButtonClicked()), this, SLOT(onDetailLinkButtonClicked())); + // This enables the "review beacon verification" button on the summary page + // to switch the current page back to beacon authentication page. Since the + // summary page cannot navigate back to specific pages directly, it emits a + // signal that we wire up here to change the page when requested: + // + connect(ui->summaryPage, SIGNAL(reviewBeaconAuthButtonClicked()), + this, SLOT(onReviewBeaconAuthButtonClicked())); + // This enables the beacon "renew" button on the summary page to switch the // current page back to beacon page. Since the summary page cannot navigate // back to a specific page directly, it emits a signal that we wire up here @@ -108,6 +120,16 @@ void ResearcherWizard::onDetailLinkButtonClicked() restart(); } +void ResearcherWizard::onReviewBeaconAuthButtonClicked() +{ + // This handles the beacon "renew" button on the summary page. Qt doesn't + // give us a good way to switch directly to the beacon page, so we rewind + // and start from it instead: + // + setStartId(PageAuth); + restart(); +} + void ResearcherWizard::onRenewBeaconButtonClicked() { // This handles the beacon "renew" button on the summary page. Qt doesn't diff --git a/src/qt/researcher/researcherwizard.h b/src/qt/researcher/researcherwizard.h index b6897e35e6..f9eba3c91e 100644 --- a/src/qt/researcher/researcherwizard.h +++ b/src/qt/researcher/researcherwizard.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARD_H #define RESEARCHERWIZARD_H @@ -59,6 +63,7 @@ private slots: void setStartOverButtonVisibility(int page_id); void onCustomButtonClicked(int which); void onDetailLinkButtonClicked(); + void onReviewBeaconAuthButtonClicked(); void onRenewBeaconButtonClicked(); }; diff --git a/src/qt/researcher/researcherwizardauthpage.cpp b/src/qt/researcher/researcherwizardauthpage.cpp index 636ad5b20b..2a4b0c2ebc 100644 --- a/src/qt/researcher/researcherwizardauthpage.cpp +++ b/src/qt/researcher/researcherwizardauthpage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardauthpage.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizardauthpage.h" diff --git a/src/qt/researcher/researcherwizardauthpage.h b/src/qt/researcher/researcherwizardauthpage.h index 0e1dfdb763..55b648b6a4 100644 --- a/src/qt/researcher/researcherwizardauthpage.h +++ b/src/qt/researcher/researcherwizardauthpage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDAUTHPAGE_H #define RESEARCHERWIZARDAUTHPAGE_H diff --git a/src/qt/researcher/researcherwizardbeaconpage.cpp b/src/qt/researcher/researcherwizardbeaconpage.cpp index 50b3422287..d1364d650e 100644 --- a/src/qt/researcher/researcherwizardbeaconpage.cpp +++ b/src/qt/researcher/researcherwizardbeaconpage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardbeaconpage.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizard.h" diff --git a/src/qt/researcher/researcherwizardbeaconpage.h b/src/qt/researcher/researcherwizardbeaconpage.h index 461da6ee71..ff23a0c80a 100644 --- a/src/qt/researcher/researcherwizardbeaconpage.h +++ b/src/qt/researcher/researcherwizardbeaconpage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDBEACONPAGE_H #define RESEARCHERWIZARDBEACONPAGE_H diff --git a/src/qt/researcher/researcherwizardemailpage.cpp b/src/qt/researcher/researcherwizardemailpage.cpp index 3c4e879b98..d50d1582a0 100644 --- a/src/qt/researcher/researcherwizardemailpage.cpp +++ b/src/qt/researcher/researcherwizardemailpage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardemailpage.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizardemailpage.h" diff --git a/src/qt/researcher/researcherwizardemailpage.h b/src/qt/researcher/researcherwizardemailpage.h index 6f5bff0e38..893632077e 100644 --- a/src/qt/researcher/researcherwizardemailpage.h +++ b/src/qt/researcher/researcherwizardemailpage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDEMAILPAGE_H #define RESEARCHERWIZARDEMAILPAGE_H diff --git a/src/qt/researcher/researcherwizardinvestorpage.cpp b/src/qt/researcher/researcherwizardinvestorpage.cpp index a5de49b016..7649594b52 100644 --- a/src/qt/researcher/researcherwizardinvestorpage.cpp +++ b/src/qt/researcher/researcherwizardinvestorpage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardinvestorpage.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizard.h" diff --git a/src/qt/researcher/researcherwizardinvestorpage.h b/src/qt/researcher/researcherwizardinvestorpage.h index 12f338f51d..b39666bce6 100644 --- a/src/qt/researcher/researcherwizardinvestorpage.h +++ b/src/qt/researcher/researcherwizardinvestorpage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDINVESTORPAGE_H #define RESEARCHERWIZARDINVESTORPAGE_H diff --git a/src/qt/researcher/researcherwizardmodedetailpage.cpp b/src/qt/researcher/researcherwizardmodedetailpage.cpp index bd60a35202..06ef3fdba4 100644 --- a/src/qt/researcher/researcherwizardmodedetailpage.cpp +++ b/src/qt/researcher/researcherwizardmodedetailpage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardmodedetailpage.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizard.h" diff --git a/src/qt/researcher/researcherwizardmodedetailpage.h b/src/qt/researcher/researcherwizardmodedetailpage.h index 4587698576..9d052a92d5 100644 --- a/src/qt/researcher/researcherwizardmodedetailpage.h +++ b/src/qt/researcher/researcherwizardmodedetailpage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDMODEDETAILPAGE_H #define RESEARCHERWIZARDMODEDETAILPAGE_H diff --git a/src/qt/researcher/researcherwizardmodepage.cpp b/src/qt/researcher/researcherwizardmodepage.cpp index 1e742df4fd..15d6980915 100644 --- a/src/qt/researcher/researcherwizardmodepage.cpp +++ b/src/qt/researcher/researcherwizardmodepage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardmodepage.h" #include "qt/researcher/researchermodel.h" #include "qt/researcher/researcherwizard.h" diff --git a/src/qt/researcher/researcherwizardmodepage.h b/src/qt/researcher/researcherwizardmodepage.h index 224c8d0237..c416889dab 100644 --- a/src/qt/researcher/researcherwizardmodepage.h +++ b/src/qt/researcher/researcherwizardmodepage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDMODEPAGE_H #define RESEARCHERWIZARDMODEPAGE_H diff --git a/src/qt/researcher/researcherwizardpoolpage.cpp b/src/qt/researcher/researcherwizardpoolpage.cpp index a9259cf571..7f06eba8dd 100644 --- a/src/qt/researcher/researcherwizardpoolpage.cpp +++ b/src/qt/researcher/researcherwizardpoolpage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "base58.h" #include "key.h" #include "qt/forms/ui_researcherwizardpoolpage.h" diff --git a/src/qt/researcher/researcherwizardpoolpage.h b/src/qt/researcher/researcherwizardpoolpage.h index 58d4587e4d..b839fbaf5a 100644 --- a/src/qt/researcher/researcherwizardpoolpage.h +++ b/src/qt/researcher/researcherwizardpoolpage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDPOOLPAGE_H #define RESEARCHERWIZARDPOOLPAGE_H diff --git a/src/qt/researcher/researcherwizardpoolsummarypage.cpp b/src/qt/researcher/researcherwizardpoolsummarypage.cpp index 7e2b283fec..6f4a13cacd 100644 --- a/src/qt/researcher/researcherwizardpoolsummarypage.cpp +++ b/src/qt/researcher/researcherwizardpoolsummarypage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardpoolsummarypage.h" #include "qt/researcher/projecttablemodel.h" #include "qt/researcher/researchermodel.h" diff --git a/src/qt/researcher/researcherwizardpoolsummarypage.h b/src/qt/researcher/researcherwizardpoolsummarypage.h index bf4f36785e..76e799f8d3 100644 --- a/src/qt/researcher/researcherwizardpoolsummarypage.h +++ b/src/qt/researcher/researcherwizardpoolsummarypage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDPOOLSUMMARYPAGE_H #define RESEARCHERWIZARDPOOLSUMMARYPAGE_H diff --git a/src/qt/researcher/researcherwizardprojectspage.cpp b/src/qt/researcher/researcherwizardprojectspage.cpp index af1f4914c7..4a0a8221d9 100644 --- a/src/qt/researcher/researcherwizardprojectspage.cpp +++ b/src/qt/researcher/researcherwizardprojectspage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/forms/ui_researcherwizardprojectspage.h" #include "qt/researcher/projecttablemodel.h" #include "qt/researcher/researchermodel.h" diff --git a/src/qt/researcher/researcherwizardprojectspage.h b/src/qt/researcher/researcherwizardprojectspage.h index c0f1677bd5..8aa8b9d1b1 100644 --- a/src/qt/researcher/researcherwizardprojectspage.h +++ b/src/qt/researcher/researcherwizardprojectspage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDPROJECTSPAGE_H #define RESEARCHERWIZARDPROJECTSPAGE_H diff --git a/src/qt/researcher/researcherwizardsummarypage.cpp b/src/qt/researcher/researcherwizardsummarypage.cpp index 08ba3d3153..3208fd134d 100644 --- a/src/qt/researcher/researcherwizardsummarypage.cpp +++ b/src/qt/researcher/researcherwizardsummarypage.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "qt/bitcoinunits.h" #include "qt/forms/ui_researcherwizardsummarypage.h" #include "qt/researcher/projecttablemodel.h" @@ -87,6 +91,7 @@ void ResearcherWizardSummaryPage::refreshSummary() ui->statusLabel->setText(m_researcher_model->formatStatus()); ui->magnitudeLabel->setText(m_researcher_model->formatMagnitude()); ui->accrualLabel->setText(m_researcher_model->formatAccrual(unit)); + ui->reviewBeaconAuthButton->setVisible(m_researcher_model->needsBeaconAuth()); ui->beaconDetailsIconLabel->setPixmap( m_researcher_model->getBeaconStatusIcon().pixmap(icon_size, icon_size)); @@ -153,6 +158,16 @@ void ResearcherWizardSummaryPage::reloadProjects() refreshProjects(); } +void ResearcherWizardSummaryPage::on_reviewBeaconAuthButton_clicked() +{ + // This enables the "review beacon auth" button to switch the current page + // back to verify beacon page. Since a wizard page cannot set the wizard's + // current index directly, this emits a signal that the wizard connects to + // the slot that changes the page for us: + // + emit reviewBeaconAuthButtonClicked(); +} + void ResearcherWizardSummaryPage::on_renewBeaconButton_clicked() { // This enables the page's beacon "renew" button to switch the current page diff --git a/src/qt/researcher/researcherwizardsummarypage.h b/src/qt/researcher/researcherwizardsummarypage.h index 799edcdf88..78db415d82 100644 --- a/src/qt/researcher/researcherwizardsummarypage.h +++ b/src/qt/researcher/researcherwizardsummarypage.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef RESEARCHERWIZARDSUMMARYPAGE_H #define RESEARCHERWIZARDSUMMARYPAGE_H @@ -35,6 +39,7 @@ class ResearcherWizardSummaryPage : public QWizardPage ProjectTableModel *m_table_model; signals: + void reviewBeaconAuthButtonClicked(); void renewBeaconButtonClicked(); private slots: @@ -43,6 +48,7 @@ private slots: void refreshOverallStatus(); void refreshProjects(); void reloadProjects(); + void on_reviewBeaconAuthButton_clicked(); void on_renewBeaconButton_clicked(); }; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index e292fe05fa..39f4973bdb 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -438,8 +438,8 @@ void RPCConsole::clear() // Set default style sheet ui->messagesWidget->document()->setDefaultStyleSheet( "table { }" - "td.time { color: #808080; padding-top: 3px; } " - "td.message { font-family: Monospace; font-size: 12px; } " + "td.time { color: #808080; valign: bottom;} " + "td.message { valign: bottom; } " "td.cmd-request { color: #006060; } " "td.cmd-error { color: red; } " "b { color: #006060; } " diff --git a/src/qt/upgradeqt.cpp b/src/qt/upgradeqt.cpp index 3a30291635..6181ea9afa 100644 --- a/src/qt/upgradeqt.cpp +++ b/src/qt/upgradeqt.cpp @@ -1,5 +1,10 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "upgradeqt.h" -#include "upgrade.h" +#include "gridcoin/upgrade.h" + #include #include #include @@ -9,6 +14,8 @@ #include #include +using namespace GRC; + UpgradeQt::UpgradeQt() {} QString UpgradeQt::ToQString(const std::string& string) diff --git a/src/qt/upgradeqt.h b/src/qt/upgradeqt.h index 70dad08e6a..1561c5de39 100644 --- a/src/qt/upgradeqt.h +++ b/src/qt/upgradeqt.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef UPGRADEQT_H #define UPGRADEQT_H diff --git a/src/qt/votingdialog.cpp b/src/qt/votingdialog.cpp index f2431730c6..c6bb11a064 100644 --- a/src/qt/votingdialog.cpp +++ b/src/qt/votingdialog.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include #include #include diff --git a/src/qt/votingdialog.h b/src/qt/votingdialog.h index 380cc06641..6dd8226be9 100644 --- a/src/qt/votingdialog.h +++ b/src/qt/votingdialog.h @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef VOTINGDIALOG_H #define VOTINGDIALOG_H diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index a64cb0cf4d..72efc5148b 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -7,9 +7,10 @@ #include "rpcserver.h" #include "rpcprotocol.h" #include "init.h" // for pwalletMain -#include "block.h" #include "checkpoints.h" #include "txdb.h" +#include "gridcoin/appcache.h" +#include "gridcoin/backup.h" #include "gridcoin/beacon.h" #include "gridcoin/claim.h" #include "gridcoin/contract/contract.h" @@ -17,11 +18,11 @@ #include "gridcoin/project.h" #include "gridcoin/quorum.h" #include "gridcoin/researcher.h" +#include "gridcoin/staking/difficulty.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/block_finder.h" #include "gridcoin/tally.h" #include "gridcoin/tx_message.h" -#include "backup.h" -#include "appcache.h" #include "util.h" #include @@ -46,7 +47,7 @@ double CoinToDouble(double surrogate); extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); UniValue ContractToJson(const GRC::Contract& contract); -BlockFinder RPCBlockFinder; +GRC::BlockFinder RPCBlockFinder; UniValue ClaimToJson(const GRC::Claim& claim, const CBlockIndex* const pindex) { @@ -138,7 +139,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fP result.pushKV("time", block.GetBlockTime()); result.pushKV("nonce", (uint64_t)block.nNonce); result.pushKV("bits", strprintf("%08x", block.nBits)); - result.pushKV("difficulty", GetDifficulty(blockindex)); + result.pushKV("difficulty", GRC::GetDifficulty(blockindex)); result.pushKV("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')); result.pushKV("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')); @@ -263,8 +264,8 @@ UniValue getdifficulty(const UniValue& params, bool fHelp) LOCK(cs_main); UniValue obj(UniValue::VOBJ); - obj.pushKV("current", GetDifficulty(GetLastBlockIndex(pindexBest, true))); - obj.pushKV("target", GetBlockDifficulty(GetNextTargetRequired(pindexBest))); + obj.pushKV("current", GRC::GetCurrentDifficulty()); + obj.pushKV("target", GRC::GetTargetDifficulty()); return obj; } @@ -404,7 +405,7 @@ UniValue backupprivatekeys(const UniValue& params, bool fHelp) string sTarget; UniValue res(UniValue::VOBJ); - bool bBackupPrivateKeys = BackupPrivateKeys(*pwalletMain, sTarget, sErrors); + bool bBackupPrivateKeys = GRC::BackupPrivateKeys(*pwalletMain, sTarget, sErrors); if (!bBackupPrivateKeys) res.pushKV("error", sErrors); @@ -623,7 +624,7 @@ UniValue advertisebeacon(const UniValue& params, bool fHelp) if (force && !IsV11Enabled(nBestHeight + 1)) { throw JSONRPCError(RPC_INVALID_REQUEST, - "force not available until block " + std::to_string(GetV11Threshold())); + "force not available until block " + std::to_string(Params().GetConsensus().BlockV11Height)); } GRC::AdvertiseBeaconResult result = GRC::Researcher::Get()->AdvertiseBeacon(force); @@ -699,7 +700,7 @@ UniValue revokebeacon(const UniValue& params, bool fHelp) if (!IsV11Enabled(nBestHeight + 1)) { throw JSONRPCError(RPC_INVALID_REQUEST, - "revokebeacon not available until block " + std::to_string(GetV11Threshold())); + "revokebeacon not available until block " + std::to_string(Params().GetConsensus().BlockV11Height)); } const GRC::AdvertiseBeaconResult result = GRC::Researcher::Get()->RevokeBeacon(*cpid); @@ -784,9 +785,28 @@ UniValue beaconconvergence(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( - "verifiedbeaconreport\n" + "beaconconvergence\n" "\n" - "Displays verified and pending beacons from the scraper viewpoint.\n"); + "Displays verified and pending beacons from the scraper or subscriber viewpoint.\n" + "\n" + "There are three output sections:\n" + "\n" + "verified_beacons_from_scraper_global:\n" + "\n" + "Comes directly from the scraper global map for verified beacons. This is\n" + "for scraper monitoring of an individual scraper and will be empty if not\n" + "run on an actual scraper node." + "\n" + "verified_beacons_from_latest_convergence:\n" + "\n" + "From the latest convergence formed from all of the scrapers. This list\n" + "is what will be activated in the next superblock.\n" + "\n" + "pending_beacons_from_GetConsensusBeaconList:\n" + "\n" + "This is a list of pending beacons. Note that it is subject to a one\n" + "hour ladder, so it will lag the information from the\n" + "pendingbeaconreport rpc call.\n"); UniValue results(UniValue::VOBJ); @@ -804,7 +824,7 @@ UniValue beaconconvergence(const UniValue& params, bool fHelp) verified_from_global.push_back(entry); } - results.pushKV("verified beacons from scraper global", verified_from_global); + results.pushKV("verified_beacons_from_scraper_global", verified_from_global); UniValue verified_from_convergence(UniValue::VARR); ScraperPendingBeaconMap verified_beacons_from_convergence = GetVerifiedBeaconsForReport(false); @@ -820,7 +840,7 @@ UniValue beaconconvergence(const UniValue& params, bool fHelp) verified_from_convergence.push_back(entry); } - results.pushKV("verified beacons from latest convergence", verified_from_convergence); + results.pushKV("verified_beacons_from_latest_convergence", verified_from_convergence); UniValue pending(UniValue::VARR); ScraperPendingBeaconMap pending_beacons = GetPendingBeaconsForReport(); @@ -836,7 +856,7 @@ UniValue beaconconvergence(const UniValue& params, bool fHelp) pending.push_back(entry); } - results.pushKV("pending beacons from GetConsensusBeaconList", pending); + results.pushKV("pending_beacons_from_GetConsensusBeaconList", pending); return results; } @@ -1796,8 +1816,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) res.pushKV("blocks", nBestHeight); res.pushKV("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)); - diff.pushKV("current", GetDifficulty(GetLastBlockIndex(pindexBest, true))); - diff.pushKV("target", GetBlockDifficulty(GetNextTargetRequired(pindexBest))); + diff.pushKV("current", GRC::GetCurrentDifficulty()); + diff.pushKV("target", GRC::GetTargetDifficulty()); res.pushKV("difficulty", diff); res.pushKV("testnet", fTestNet); res.pushKV("errors", GetWarnings("statusbar")); @@ -1924,7 +1944,7 @@ UniValue MagnitudeReport(const GRC::Cpid cpid) { UniValue json(UniValue::VOBJ); - const int64_t now = g_fOutOfSyncByAge ? pindexBest->nTime : GetAdjustedTime(); + const int64_t now = OutOfSyncByAge() ? pindexBest->nTime : GetAdjustedTime(); const GRC::ResearchAccount& account = GRC::Tally::GetAccount(cpid); const GRC::AccrualComputer calc = GRC::Tally::GetComputer(cpid, now, pindexBest); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index adbc83bf8e..1293294fe2 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -134,6 +134,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listreceivedbyaddress" , 2 }, { "listsinceblock" , 1 }, { "listsinceblock" , 2 }, + { "liststakes" , 0 }, { "listtransactions" , 1 }, { "listtransactions" , 2 }, { "listtransactions" , 3 }, diff --git a/src/rpcdataacq.cpp b/src/rpcdataacq.cpp index 623df293c7..78e9981597 100644 --- a/src/rpcdataacq.cpp +++ b/src/rpcdataacq.cpp @@ -6,12 +6,12 @@ #include "main.h" #include "rpcserver.h" -#include "kernel.h" -#include "block.h" #include "txdb.h" #include "gridcoin/claim.h" #include "gridcoin/quorum.h" +#include "gridcoin/staking/difficulty.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/block_finder.h" #include "util.h" #include @@ -26,7 +26,7 @@ using namespace GRC; using namespace std; -extern BlockFinder RPCBlockFinder; +extern GRC::BlockFinder RPCBlockFinder; // Brod static bool compare_second(const pair &p1, const pair &p2) @@ -128,7 +128,7 @@ UniValue rpc_getblockstats(const UniValue& params, bool fHelp) { poscount++; //stakeinputtotal+=block.vtx[1].vin[0].nValue; - double diff = GetDifficulty(cur); + double diff = GRC::GetDifficulty(cur); diff_sum += diff; diff_max=std::max(diff_max,diff); diff_min=std::min(diff_min,diff); @@ -364,7 +364,7 @@ UniValue rpc_getsupervotes(const UniValue& params, bool fHelp) ) { - double diff = GetDifficulty(cur); + double diff = GRC::GetDifficulty(cur); signed int delta = 0; if(cur->pprev) delta = (cur->nTime - cur->pprev->nTime); @@ -504,7 +504,7 @@ UniValue rpc_exportstats(const UniValue& params, bool fHelp) if(cur->nHeight>endblock) continue; - double i_diff = GetDifficulty(cur); + double i_diff = GRC::GetDifficulty(cur); sum_diff= sum_diff + i_diff; min_diff=std::min(min_diff,i_diff); max_diff=std::max(max_diff,i_diff); @@ -658,7 +658,7 @@ UniValue rpc_getrecentblocks(const UniValue& params, bool fHelp) 100 json */ - double diff = GetDifficulty(cur); + double diff = GRC::GetDifficulty(cur); signed int delta = 0; if(cur->pprev) delta = (cur->nTime - cur->pprev->nTime); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index efd8f2dc66..d8a20c80ac 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -9,6 +9,8 @@ #include "gridcoin/accrual/snapshot.h" #include "gridcoin/quorum.h" #include "gridcoin/researcher.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/staking/status.h" #include "gridcoin/superblock.h" #include "gridcoin/tally.h" #include "gridcoin/voting/fwd.h" @@ -42,38 +44,37 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) uint64_t nExpectedTime = 0; { LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->GetStakeWeight(nWeight); - - nNetworkWeight = GetEstimatedNetworkWeight(); - nCurrentDiff = GetDifficulty(GetLastBlockIndex(pindexBest, true)); - nTargetDiff = GetBlockDifficulty(GetNextTargetRequired(pindexBest)); - nExpectedTime = GetEstimatedTimetoStake(); + nWeight = GRC::GetStakeWeight(*pwalletMain); + nNetworkWeight = GRC::GetEstimatedNetworkWeight(); + nCurrentDiff = GRC::GetCurrentDifficulty(); + nTargetDiff = GRC::GetTargetDifficulty(); + nExpectedTime = GRC::GetEstimatedTimetoStake(); } obj.pushKV("blocks", nBestHeight); diff.pushKV("current", nCurrentDiff); diff.pushKV("target", nTargetDiff); - { LOCK(MinerStatus.lock); + { LOCK(g_miner_status.lock); // not using real weight to not break calculation - bool staking = MinerStatus.nLastCoinStakeSearchInterval && MinerStatus.WeightSum; - diff.pushKV("last-search-interval", MinerStatus.nLastCoinStakeSearchInterval); - weight.pushKV("minimum", MinerStatus.WeightMin); - weight.pushKV("maximum", MinerStatus.WeightMax); - weight.pushKV("combined", MinerStatus.WeightSum); - weight.pushKV("valuesum", MinerStatus.ValueSum); + bool staking = g_miner_status.nLastCoinStakeSearchInterval && g_miner_status.WeightSum; + diff.pushKV("last-search-interval", g_miner_status.nLastCoinStakeSearchInterval); + weight.pushKV("minimum", g_miner_status.WeightMin); + weight.pushKV("maximum", g_miner_status.WeightMax); + weight.pushKV("combined", g_miner_status.WeightSum); + weight.pushKV("valuesum", g_miner_status.ValueSum); weight.pushKV("legacy", nWeight/(double)COIN); obj.pushKV("stakeweight", weight); obj.pushKV("netstakeweight", nNetworkWeight); obj.pushKV("netstakingGRCvalue", nNetworkWeight / 80.0); obj.pushKV("staking", staking); - obj.pushKV("mining-error", MinerStatus.ReasonNotStaking); + obj.pushKV("mining-error", g_miner_status.ReasonNotStaking); obj.pushKV("time-to-stake_days", nExpectedTime/86400.0); obj.pushKV("expectedtime", nExpectedTime); - obj.pushKV("mining-version", MinerStatus.Version); - obj.pushKV("mining-created", MinerStatus.CreatedCnt); - obj.pushKV("mining-accepted", MinerStatus.AcceptedCnt); - obj.pushKV("mining-kernels-found", MinerStatus.KernelsFound); + obj.pushKV("mining-version", g_miner_status.Version); + obj.pushKV("mining-created", g_miner_status.CreatedCnt); + obj.pushKV("mining-accepted", g_miner_status.AcceptedCnt); + obj.pushKV("mining-kernels-found", g_miner_status.KernelsFound); } int64_t nMinStakeSplitValue = 0; @@ -138,6 +139,75 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) return obj; } +UniValue getlaststake(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getlaststake\n" + "\n" + "Fetch information about this wallet's last staked block.\n"); + + const boost::optional stake_tx = GetLastStake(*pwalletMain); + + if (!stake_tx) { + throw JSONRPCError(RPC_WALLET_ERROR, "No prior staked blocks found."); + } + + int64_t height; + int64_t timestamp; + int64_t confirmations; + + int64_t mint_amount = 0; + int64_t side_stake_amount = 0; + int64_t research_reward_amount; + + { + LOCK(cs_main); + + const CBlockIndex* const pindex = mapBlockIndex[stake_tx->hashBlock]; + + height = pindex->nHeight; + timestamp = pindex->nTime; + research_reward_amount = pindex->nResearchSubsidy; + confirmations = stake_tx->GetDepthInMainChain(); + } + + for (const auto txo : stake_tx->vout) { + if (pwalletMain->IsMine(txo)) { + mint_amount += txo.nValue; + } else { + side_stake_amount += txo.nValue; + } + } + + const int64_t elapsed_seconds = GetAdjustedTime() - timestamp; + UniValue json(UniValue::VOBJ); + + json.pushKV("block", stake_tx->hashBlock.ToString()); + json.pushKV("height", height); + json.pushKV("confirmations", confirmations); + json.pushKV("immature", confirmations < nCoinbaseMaturity); + json.pushKV("txid", stake_tx->GetHash().ToString()); + json.pushKV("time", timestamp); + json.pushKV("elapsed_seconds", elapsed_seconds); + json.pushKV("elapsed_days", elapsed_seconds / 86400.0); + json.pushKV("mint", ValueFromAmount(mint_amount - stake_tx->GetDebit())); + json.pushKV("research_reward", ValueFromAmount(research_reward_amount)); + json.pushKV("side_stake", ValueFromAmount(side_stake_amount)); + + CTxDestination dest; + + if (ExtractDestination(stake_tx->vout[1].scriptPubKey, dest)) { + json.pushKV("address", CBitcoinAddress(dest).ToString()); + } else { + json.pushKV("address", ""); + } + + json.pushKV("label", stake_tx->strFromAccount); + + return json; +} + UniValue auditsnapshotaccrual(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -177,7 +247,7 @@ UniValue auditsnapshotaccrual(const UniValue& params, bool fHelp) const int64_t computed = GRC::Tally::GetAccrual(*cpid, now, pindexBest); const CBlockIndex* pindex = pindexBest; const CBlockIndex* pindex_low = pindex; - const int64_t threshold = GetV11Threshold(); + const int64_t threshold = Params().GetConsensus().BlockV11Height; const int64_t max_depth = IsV11Enabled(pindex->nHeight) ? threshold - BLOCKS_PER_DAY * 30 * 6 : pindex->nHeight + 1 - BLOCKS_PER_DAY * 30 * 6; diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 79e627c399..ab5d3055d8 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -3,14 +3,15 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "block.h" #include "init.h" #include "main.h" #include "gridcoin/beacon.h" #include "gridcoin/claim.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" +#include "gridcoin/staking/difficulty.h" #include "gridcoin/superblock.h" +#include "gridcoin/support/block_finder.h" #include "gridcoin/tx_message.h" #include "gridcoin/voting/payloads.h" #include "rpcprotocol.h" @@ -52,7 +53,7 @@ std::vector> GetTxStakeBoincHashInfo(const C res.push_back(std::make_pair(_("Height"), ToString(pindex->nHeight))); res.push_back(std::make_pair(_("Block Version"), ToString(block.nVersion))); - res.push_back(std::make_pair(_("Difficulty"), RoundToString(GetBlockDifficulty(block.nBits),8))); + res.push_back(std::make_pair(_("Difficulty"), RoundToString(GRC::GetBlockDifficulty(block.nBits),8))); res.push_back(std::make_pair(_("CPID"), claim.m_mining_id.ToString())); res.push_back(std::make_pair(_("Interest"), FormatMoney(claim.m_block_subsidy))); @@ -758,7 +759,7 @@ UniValue consolidatemsunspent(const UniValue& params, bool fHelp) LOCK(cs_main); - BlockFinder blockfinder; + GRC::BlockFinder blockfinder; CBlockIndex* pblkindex = blockfinder.FindByHeight((nBlockStart - 1)); @@ -1028,7 +1029,7 @@ UniValue scanforunspent(const UniValue& params, bool fHelp) { LOCK(cs_main); - BlockFinder blockfinder; + GRC::BlockFinder blockfinder; CBlockIndex* pblkindex = blockfinder.FindByHeight((nBlockStart - 1)); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 299f396e1d..2a5ef942b1 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -318,6 +318,7 @@ static const CRPCCommand vRPCCommands[] = { "listreceivedbyaccount", &listreceivedbyaccount, cat_wallet }, { "listreceivedbyaddress", &listreceivedbyaddress, cat_wallet }, { "listsinceblock", &listsinceblock, cat_wallet }, + { "liststakes", &liststakes, cat_wallet }, { "listtransactions", &listtransactions, cat_wallet }, { "listunspent", &listunspent, cat_wallet }, { "consolidateunspent", &consolidateunspent, cat_wallet }, @@ -350,6 +351,7 @@ static const CRPCCommand vRPCCommands[] = { "beaconreport", &beaconreport, cat_mining }, { "beaconstatus", &beaconstatus, cat_mining }, { "explainmagnitude", &explainmagnitude, cat_mining }, + { "getlaststake", &getlaststake, cat_mining }, { "getmininginfo", &getmininginfo, cat_mining }, { "lifetime", &lifetime, cat_mining }, { "magnitude", &magnitude, cat_mining }, diff --git a/src/rpcserver.h b/src/rpcserver.h index e20bc96664..ce2741a1d2 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -133,6 +133,7 @@ extern UniValue listaddressgroupings(const UniValue& params, bool fHelp); extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp); extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp); extern UniValue listsinceblock(const UniValue& params, bool fHelp); +extern UniValue liststakes(const UniValue& params, bool fHelp); extern UniValue listtransactions(const UniValue& params, bool fHelp); extern UniValue listunspent(const UniValue& params, bool fHelp); extern UniValue consolidateunspent(const UniValue& params, bool fHelp); @@ -165,6 +166,7 @@ extern UniValue beaconreport(const UniValue& params, bool fHelp); extern UniValue beaconconvergence(const UniValue& params, bool fHelp); extern UniValue beaconstatus(const UniValue& params, bool fHelp); extern UniValue explainmagnitude(const UniValue& params, bool fHelp); +extern UniValue getlaststake(const UniValue& params, bool fHelp); extern UniValue getmininginfo(const UniValue& params, bool fHelp); extern UniValue lifetime(const UniValue& params, bool fHelp); extern UniValue magnitude(const UniValue& params, bool fHelp); diff --git a/src/scraper/.gitignore b/src/scraper/.gitignore deleted file mode 100644 index e10eea0bc6..0000000000 --- a/src/scraper/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -userpass.dat -scraper.time -scraper.log -GridcoinScraper2.pro* -main.cpp -test -*.gz diff --git a/src/test/checkpoints_tests.cpp b/src/test/checkpoints_tests.cpp index 64fc10c7de..73cf8dc816 100644 --- a/src/test/checkpoints_tests.cpp +++ b/src/test/checkpoints_tests.cpp @@ -5,6 +5,7 @@ #include #include +#include "../chainparams.h" #include "../checkpoints.h" #include "../util.h" @@ -14,6 +15,7 @@ BOOST_AUTO_TEST_SUITE(Checkpoints_tests) BOOST_AUTO_TEST_CASE(sanity) { + SelectParams(CBaseChainParams::MAIN); uint256 p40 = uint256S("0x0000002c305541bceb763e6f7fce2f111cb752acf9777e64c6f02fab5ef4778c"); uint256 p500000 = uint256S("0x3916b53eaa0eb392ce5d7e4eaf7db4f745187743f167539ffa4dc1a30c06acbd"); BOOST_CHECK(Checkpoints::CheckHardened(40, p40)); diff --git a/src/test/data/client_state.xml b/src/test/data/client_state.xml index fa5993e757..4fe0602ebe 100644 --- a/src/test/data/client_state.xml +++ b/src/test/data/client_state.xml @@ -129,7 +129,7 @@ The file also contains invalid project sections for negative test cases. 1806 12345 0.000000 - 0.000000 + 1.100000 1540012345.000000 0 0 @@ -187,7 +187,7 @@ The file also contains invalid project sections for negative test cases. 8edc235ddcecf9c416a5f9417d56f4fd 1541012345.000000 0.000000 - 0.000000 + 2.200000 1540012345.000000 3 12345 @@ -252,7 +252,7 @@ The file also contains invalid project sections for negative test cases. 8edc235ddcecf9c416a5f9417d56f4fd 1541012345.000000 0.000000 - 0.000000 + 3.300000 1540012345.000000 3 12345 @@ -323,7 +323,7 @@ The file also contains invalid project sections for negative test cases. 1806 12345 0.000000 - 0.000000 + 4.400000 1540012345.000000 0 0 diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index 556de8002b..5a289455d5 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -53,6 +53,8 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); } + + fs::remove(tmpfile1); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/appcache_tests.cpp b/src/test/gridcoin/appcache_tests.cpp similarity index 87% rename from src/test/appcache_tests.cpp rename to src/test/gridcoin/appcache_tests.cpp index e5a4397168..bfcdf2b303 100644 --- a/src/test/appcache_tests.cpp +++ b/src/test/gridcoin/appcache_tests.cpp @@ -1,4 +1,8 @@ -#include "appcache.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/appcache.h" #include diff --git a/src/test/gridcoin/beacon_tests.cpp b/src/test/gridcoin/beacon_tests.cpp index 2c55adc8e1..8c8355f20e 100644 --- a/src/test/gridcoin/beacon_tests.cpp +++ b/src/test/gridcoin/beacon_tests.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "base58.h" #include "gridcoin/beacon.h" diff --git a/src/test/block_tests.cpp b/src/test/gridcoin/block_finder_tests.cpp similarity index 85% rename from src/test/block_tests.cpp rename to src/test/gridcoin/block_finder_tests.cpp index 3acd830b6d..40feac136e 100755 --- a/src/test/block_tests.cpp +++ b/src/test/gridcoin/block_finder_tests.cpp @@ -1,5 +1,9 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" -#include "block.h" +#include "gridcoin/support/block_finder.h" #include #include @@ -37,12 +41,12 @@ namespace }; } -BOOST_AUTO_TEST_SUITE(block_tests); +BOOST_AUTO_TEST_SUITE(block_finder_tests); BOOST_AUTO_TEST_CASE(FindBlockInNormalChainShouldWork) { BlockChain<100> chain; - BlockFinder finder; + GRC::BlockFinder finder; for(auto& block : chain.blocks) BOOST_CHECK_EQUAL(&block, finder.FindByHeight(block.nHeight)); } @@ -50,7 +54,7 @@ BOOST_AUTO_TEST_CASE(FindBlockInNormalChainShouldWork) BOOST_AUTO_TEST_CASE(FindBlockAboveHighestHeightShouldReturnHighestBlock) { BlockChain<100> chain; - BlockFinder finder; + GRC::BlockFinder finder; CBlockIndex& last = chain.blocks.back(); BOOST_CHECK_EQUAL(&last, finder.FindByHeight(101)); } @@ -58,7 +62,7 @@ BOOST_AUTO_TEST_CASE(FindBlockAboveHighestHeightShouldReturnHighestBlock) BOOST_AUTO_TEST_CASE(FindBlockByHeightShouldWorkOnChainsWithJustOneBlock) { BlockChain<1> chain; - BlockFinder finder; + GRC::BlockFinder finder; BOOST_CHECK_EQUAL(&chain.blocks.front(), finder.FindByHeight(0)); BOOST_CHECK_EQUAL(&chain.blocks.front(), finder.FindByHeight(1)); BOOST_CHECK_EQUAL(&chain.blocks.front(), finder.FindByHeight(-1)); @@ -68,8 +72,8 @@ BOOST_AUTO_TEST_CASE(FindBlockByTimeShouldReturnNextYoungestBlock) { // Chain with block times 0, 10, 20, 30, 40 etc. BlockChain<10> chain; - BlockFinder finder; - + GRC::BlockFinder finder; + // Finding the block older than time 10 should return block #2 // which has time 20. BOOST_CHECK_EQUAL(&chain.blocks[2], finder.FindByMinTime(11)); @@ -80,7 +84,7 @@ BOOST_AUTO_TEST_CASE(FindBlockByTimeShouldReturnNextYoungestBlock) BOOST_AUTO_TEST_CASE(FindBlockByTimeShouldReturnLastBlockIfOlderThanTime) { BlockChain<10> chain; - BlockFinder finder; + GRC::BlockFinder finder; BOOST_CHECK_EQUAL(&chain.blocks.back(), finder.FindByMinTime(999999)); } diff --git a/src/test/gridcoin/claim_tests.cpp b/src/test/gridcoin/claim_tests.cpp index 5ff40ed055..0c9ad39aef 100644 --- a/src/test/gridcoin/claim_tests.cpp +++ b/src/test/gridcoin/claim_tests.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "gridcoin/claim.h" #include "key.h" diff --git a/src/test/gridcoin/contract_tests.cpp b/src/test/gridcoin/contract_tests.cpp index 0ab255836a..88431b65c3 100644 --- a/src/test/gridcoin/contract_tests.cpp +++ b/src/test/gridcoin/contract_tests.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "hash.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" diff --git a/src/test/gridcoin/cpid_tests.cpp b/src/test/gridcoin/cpid_tests.cpp index 0868cb5543..34a692499c 100644 --- a/src/test/gridcoin/cpid_tests.cpp +++ b/src/test/gridcoin/cpid_tests.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "gridcoin/cpid.h" #include "streams.h" diff --git a/src/test/enumbytes.cpp b/src/test/gridcoin/enumbytes_tests.cpp similarity index 77% rename from src/test/enumbytes.cpp rename to src/test/gridcoin/enumbytes_tests.cpp index 3b3d17544a..f48a2c0686 100644 --- a/src/test/enumbytes.cpp +++ b/src/test/gridcoin/enumbytes_tests.cpp @@ -1,4 +1,8 @@ -#include "enumbytes.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "gridcoin/support/enumbytes.h" #include "streams.h" #include @@ -19,27 +23,27 @@ enum class TestEnum { // EnumByte // ----------------------------------------------------------------------------- -BOOST_AUTO_TEST_SUITE(EnumByte_) +BOOST_AUTO_TEST_SUITE(EnumByte) BOOST_AUTO_TEST_CASE(it_initalizes_to_zero) { - const EnumByte a; + const GRC::EnumByte a; BOOST_CHECK(a.Value() == TestEnum::A); } BOOST_AUTO_TEST_CASE(it_initializes_to_an_enum_value) { - const EnumByte b(TestEnum::B); + const GRC::EnumByte b(TestEnum::B); BOOST_CHECK(b.Value() == TestEnum::B); } BOOST_AUTO_TEST_CASE(it_compares_another_enum_wrapper) { - const EnumByte a1; - const EnumByte a2; - const EnumByte b(TestEnum::B); + const GRC::EnumByte a1; + const GRC::EnumByte a2; + const GRC::EnumByte b(TestEnum::B); BOOST_CHECK(a1 == a2); BOOST_CHECK(a1 != b); @@ -61,8 +65,8 @@ BOOST_AUTO_TEST_CASE(it_compares_another_enum_wrapper) BOOST_AUTO_TEST_CASE(it_compares_an_enum_of_the_wrapped_type) { - const EnumByte a; - const EnumByte b(TestEnum::B); + const GRC::EnumByte a; + const GRC::EnumByte b(TestEnum::B); BOOST_CHECK(a == TestEnum::A); BOOST_CHECK(a != TestEnum::B); @@ -84,14 +88,14 @@ BOOST_AUTO_TEST_CASE(it_compares_an_enum_of_the_wrapped_type) BOOST_AUTO_TEST_CASE(it_produces_an_unsigned_integer_for_the_enum_value) { - const EnumByte b(TestEnum::B); + const GRC::EnumByte b(TestEnum::B); BOOST_CHECK(b.Raw() == static_cast(TestEnum::B)); } BOOST_AUTO_TEST_CASE(it_serializes_to_a_stream) { - const EnumByte b(TestEnum::B); + const GRC::EnumByte b(TestEnum::B); const CDataStream expected = CDataStream(SER_NETWORK, 1) << static_cast(TestEnum::B); @@ -111,7 +115,7 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream) CDataStream stream = CDataStream(SER_NETWORK, 1) << static_cast(TestEnum::B); - EnumByte b; + GRC::EnumByte b; stream >> b; BOOST_CHECK(b == TestEnum::B); @@ -122,7 +126,7 @@ BOOST_AUTO_TEST_CASE(it_refuses_to_deserialize_out_of_range_values) CDataStream stream = CDataStream(SER_NETWORK, 1) << static_cast(TestEnum::OUT_OF_BOUND); - EnumByte out; + GRC::EnumByte out; BOOST_CHECK_THROW(stream >> out, std::ios_base::failure); } diff --git a/src/test/gridcoin/magnitude_tests.cpp b/src/test/gridcoin/magnitude_tests.cpp index 7e3f366049..303007e06f 100644 --- a/src/test/gridcoin/magnitude_tests.cpp +++ b/src/test/gridcoin/magnitude_tests.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "gridcoin/magnitude.h" #include "streams.h" diff --git a/src/test/gridcoin/project_tests.cpp b/src/test/gridcoin/project_tests.cpp index d3520eaa5c..860918b328 100644 --- a/src/test/gridcoin/project_tests.cpp +++ b/src/test/gridcoin/project_tests.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" diff --git a/src/test/gridcoin/researcher_tests.cpp b/src/test/gridcoin/researcher_tests.cpp index da11d2de80..2597aeda82 100644 --- a/src/test/gridcoin/researcher_tests.cpp +++ b/src/test/gridcoin/researcher_tests.cpp @@ -1,5 +1,9 @@ -#include "appcache.h" +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "main.h" +#include "gridcoin/appcache.h" #include "gridcoin/beacon.h" #include "gridcoin/contract/contract.h" #include "gridcoin/project.h" @@ -142,12 +146,14 @@ BOOST_AUTO_TEST_CASE(it_initializes_with_project_data) 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, }); - GRC::MiningProject project("project name", expected, "team name", "url"); + GRC::MiningProject project("project name", expected, "team name", "url", + 0.0); BOOST_CHECK(project.m_name == "project name"); BOOST_CHECK(project.m_cpid == expected); BOOST_CHECK(project.m_team == "team name"); BOOST_CHECK(project.m_url == "url"); + BOOST_CHECK(project.m_rac == 0.0); BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE); } @@ -166,6 +172,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_project_xml_string) Team Name XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX f5d8234352e5a5ae3915debba7258294 + 123.45 )XML"); @@ -175,6 +182,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_project_xml_string) BOOST_CHECK(project.m_cpid == cpid); BOOST_CHECK(project.m_team == "team name"); BOOST_CHECK(project.m_url == "https://example.com/"); + BOOST_CHECK(project.m_rac == 123.45); BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE); // Clean up: @@ -199,6 +207,7 @@ BOOST_AUTO_TEST_CASE(it_falls_back_to_compute_a_missing_external_cpid) b8b58cce3c90c7dc9f3601674202b21c XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 123.45 )XML"); @@ -208,6 +217,7 @@ BOOST_AUTO_TEST_CASE(it_falls_back_to_compute_a_missing_external_cpid) BOOST_CHECK(project.m_cpid == cpid); BOOST_CHECK(project.m_team == "team name"); BOOST_CHECK(project.m_url == "https://example.com/"); + BOOST_CHECK(project.m_rac == 123.45); BOOST_CHECK(project.m_error == GRC::MiningProject::Error::NONE); // Clean up: @@ -216,14 +226,16 @@ BOOST_AUTO_TEST_CASE(it_falls_back_to_compute_a_missing_external_cpid) BOOST_AUTO_TEST_CASE(it_normalizes_project_names) { - GRC::MiningProject project("Project_NAME", GRC::Cpid(), "team name", "url"); + GRC::MiningProject project("Project_NAME", GRC::Cpid(), "team name", "url", + 0.0); BOOST_CHECK(project.m_name == "project name"); } BOOST_AUTO_TEST_CASE(it_converts_team_names_to_lowercase) { - GRC::MiningProject project("project name", GRC::Cpid(), "TEAM NAME", "url"); + GRC::MiningProject project("project name", GRC::Cpid(), "TEAM NAME", "url", + 0.0); BOOST_CHECK(project.m_team == "team name"); } @@ -233,7 +245,8 @@ BOOST_AUTO_TEST_CASE(it_determines_whether_a_project_is_eligible) // Eligibility is determined by the absence of an error set while loading // the project from BOINC's client_state.xml file. - GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url"); + GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url", + 0.0); BOOST_CHECK(project.Eligible() == true); @@ -263,7 +276,8 @@ BOOST_AUTO_TEST_CASE(it_detects_projects_with_pool_cpids) BOOST_AUTO_TEST_CASE(it_determines_whether_a_project_is_whitelisted) { - GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url"); + GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url", + 0.0); GRC::WhitelistSnapshot s(std::make_shared(GRC::ProjectList { GRC::Project("Enigma", "http://enigma.test/@", 1234567), @@ -317,7 +331,8 @@ BOOST_AUTO_TEST_CASE(it_determines_whether_a_project_is_whitelisted) BOOST_AUTO_TEST_CASE(it_formats_error_messages_for_display) { - GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url"); + GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url", + 0.0); BOOST_CHECK(project.ErrorMessage().empty() == true); @@ -345,8 +360,10 @@ BOOST_AUTO_TEST_CASE(it_is_iterable) { GRC::MiningProjectMap projects; - projects.Set(GRC::MiningProject("project name 1", GRC::Cpid(), "team name", "url")); - projects.Set(GRC::MiningProject("project name 2", GRC::Cpid(), "team name", "url")); + projects.Set(GRC::MiningProject("project name 1", GRC::Cpid(), "team name", + "url", 0.0)); + projects.Set(GRC::MiningProject("project name 2", GRC::Cpid(), "team name", + "url", 0.0)); auto counter = 0; @@ -370,6 +387,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections) Project Name 1 Gridcoin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 123.45 f5d8234352e5a5ae3915debba7258294 )XML", @@ -379,6 +397,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections) Project Name 2 Gridcoin YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY + 567.89 8edc235ddcecf9c416a5f9417d56f4fd )XML", @@ -394,6 +413,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections) BOOST_CHECK(project1->m_cpid == cpid_1); BOOST_CHECK(project1->m_team == "gridcoin"); BOOST_CHECK(project1->m_url == "https://example.com/1"); + BOOST_CHECK(project1->m_rac == 123.45); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); } else { @@ -405,6 +425,7 @@ BOOST_AUTO_TEST_CASE(it_parses_a_set_of_project_xml_sections) BOOST_CHECK(project2->m_cpid == cpid_2); BOOST_CHECK(project2->m_team == "gridcoin"); BOOST_CHECK(project2->m_url == "https://example.com/2"); + BOOST_CHECK(project2->m_rac == 567.89); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); } else { @@ -426,6 +447,7 @@ BOOST_AUTO_TEST_CASE(it_skips_loading_project_xml_with_empty_project_names) Gridcoin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 123.45 f5d8234352e5a5ae3915debba7258294 )XML", @@ -435,6 +457,7 @@ BOOST_AUTO_TEST_CASE(it_skips_loading_project_xml_with_empty_project_names) https://example.com/ Gridcoin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 123.45 f5d8234352e5a5ae3915debba7258294 )XML", @@ -450,8 +473,10 @@ BOOST_AUTO_TEST_CASE(it_counts_the_number_of_projects) BOOST_CHECK(projects.size() == 0); - projects.Set(GRC::MiningProject("project name 1", GRC::Cpid(), "team name", "url")); - projects.Set(GRC::MiningProject("project name 2", GRC::Cpid(), "team name", "url")); + projects.Set(GRC::MiningProject("project name 1", GRC::Cpid(), "team name", + "url", 0.0)); + projects.Set(GRC::MiningProject("project name 2", GRC::Cpid(), "team name", + "url", 0.0)); BOOST_CHECK(projects.size() == 2); } @@ -462,7 +487,8 @@ BOOST_AUTO_TEST_CASE(it_indicates_whether_it_contains_any_projects) BOOST_CHECK(projects.empty() == true); - projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name", "url")); + projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name", + "url", 0.0)); BOOST_CHECK(projects.empty() == false); } @@ -470,7 +496,8 @@ BOOST_AUTO_TEST_CASE(it_indicates_whether_it_contains_any_projects) BOOST_AUTO_TEST_CASE(it_indicates_whether_it_contains_any_pool_projects) { GRC::MiningProjectMap projects; - GRC::MiningProject project("project name", GRC::Cpid(), "team name", "url"); + GRC::MiningProject project("project name", GRC::Cpid(), "team name", + "url", 0.0); project.m_error = GRC::MiningProject::Error::POOL; projects.Set(std::move(project)); @@ -482,7 +509,8 @@ BOOST_AUTO_TEST_CASE(it_fetches_a_project_by_name) { GRC::MiningProjectMap projects; - projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name", "url")); + projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name", + "url", 0.0)); BOOST_CHECK(projects.Try("project name")->m_name == "project name"); BOOST_CHECK(projects.Try("nonexistent") == nullptr); @@ -492,8 +520,10 @@ BOOST_AUTO_TEST_CASE(it_does_not_overwrite_projects_with_the_same_name) { GRC::MiningProjectMap projects; - projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name 1", "url")); - projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name 2", "url")); + projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name 1", + "url", 0.0)); + projects.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name 2", + "url", 0.0)); BOOST_CHECK(projects.Try("project name")->m_team == "team name 1"); } @@ -502,9 +532,12 @@ BOOST_AUTO_TEST_CASE(it_applies_a_provided_team_whitelist) { GRC::MiningProjectMap projects; - projects.Set(GRC::MiningProject("project 1", GRC::Cpid(), "gridcoin", "url")); - projects.Set(GRC::MiningProject("project 2", GRC::Cpid(), "team 1", "url")); - projects.Set(GRC::MiningProject("project 3", GRC::Cpid(), "team 2", "url")); + projects.Set(GRC::MiningProject("project 1", GRC::Cpid(), "gridcoin", + "url", 1.0)); + projects.Set(GRC::MiningProject("project 2", GRC::Cpid(), "team 1", + "url", 0.0)); + projects.Set(GRC::MiningProject("project 3", GRC::Cpid(), "team 2", + "url", 0.0)); // Before applying a whitelist, all projects are eligible: @@ -609,7 +642,8 @@ BOOST_AUTO_TEST_CASE(it_initializes_with_researcher_context_data) { GRC::MiningProjectMap expected; - expected.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name", "url")); + expected.Set(GRC::MiningProject("project name", GRC::Cpid(), "team name", + "url", 0.0)); GRC::Researcher researcher(GRC::Cpid(), expected); @@ -672,14 +706,15 @@ BOOST_AUTO_TEST_CASE(it_reports_ineligible_when_beacon_missing_or_expired) RemoveTestBeacon(GRC::Cpid()); } -BOOST_AUTO_TEST_CASE(it_provides_an_overall_status_of_the_reseracher_context) +BOOST_AUTO_TEST_CASE(it_provides_an_overall_status_of_the_researcher_context) { GRC::Researcher researcher; BOOST_CHECK(researcher.Status() == GRC::ResearcherStatus::INVESTOR); GRC::MiningProjectMap projects; - projects.Set(GRC::MiningProject("ineligible", GRC::Cpid(), "team name", "url")); + projects.Set(GRC::MiningProject("ineligible", GRC::Cpid(), "team name", + "url", 0.0)); researcher = GRC::Researcher(GRC::MiningId::ForInvestor(), projects); @@ -711,6 +746,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton) Project Name 1 Gridcoin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 1.1 f5d8234352e5a5ae3915debba7258294 )XML", @@ -720,6 +756,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton) Project Name 2 Gridcoin YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY + 2.2 8edc235ddcecf9c416a5f9417d56f4fd )XML", @@ -739,6 +776,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton) BOOST_CHECK(project1->m_cpid == cpid_1); BOOST_CHECK(project1->m_team == "gridcoin"); BOOST_CHECK(project1->m_url == "https://example.com/1"); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); } else { @@ -750,6 +788,7 @@ BOOST_AUTO_TEST_CASE(it_parses_project_xml_to_a_global_researcher_singleton) BOOST_CHECK(project2->m_cpid == cpid_2); BOOST_CHECK(project2->m_team == "gridcoin"); BOOST_CHECK(project2->m_url == "https://example.com/2"); + BOOST_CHECK(project2->m_rac == 2.2); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); } else { @@ -773,6 +812,7 @@ BOOST_AUTO_TEST_CASE(it_looks_up_loaded_boinc_projects_by_name) Name Gridcoin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 1.1 f5d8234352e5a5ae3915debba7258294 )XML", @@ -787,6 +827,7 @@ BOOST_AUTO_TEST_CASE(it_looks_up_loaded_boinc_projects_by_name) BOOST_CHECK(project->m_cpid == cpid); BOOST_CHECK(project->m_team == "gridcoin"); BOOST_CHECK(project->m_url == "https://example.com/"); + BOOST_CHECK(project->m_rac == 1.1); BOOST_CHECK(project->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project->Eligible() == true); } else { @@ -819,6 +860,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) Project Name 1 Not Gridcoin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 1.1 f5d8234352e5a5ae3915debba7258294 )XML", @@ -828,6 +870,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) https://example.com/ Project Name 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 2.2 f5d8234352e5a5ae3915debba7258294 )XML", @@ -837,6 +880,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) https://example.com/ Project Name 3 Gridcoin + 3.3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX invalid @@ -847,6 +891,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) https://example.com/ Project Name 4 Gridcoin + 4.4 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX )XML", @@ -856,6 +901,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) https://example.com/ Project Name 5 Gridcoin + 5.5 invalid f5d8234352e5a5ae3915debba7258294 @@ -866,6 +912,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) https://example.com/ Project Name 6 Gridcoin + 6.6 f5d8234352e5a5ae3915debba7258294 )XML", @@ -875,9 +922,21 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) https://example.com/ Project Name 7 Gridcoin + 7.7 7d0d73fe026d66fd4ab8d5d8da32a611 )XML", + // Malformed RAC: + R"XML( + + https://example.com/ + Project Name 8 + Not Gridcoin + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + FOO + f5d8234352e5a5ae3915debba7258294 + + )XML", })); GRC::Cpid cpid = GRC::Cpid::Parse("f5d8234352e5a5ae3915debba7258294"); @@ -886,12 +945,13 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(GRC::Researcher::Get()->Id() == GRC::MiningId::ForInvestor()); const GRC::MiningProjectMap& projects = GRC::Researcher::Get()->Projects(); - BOOST_CHECK(projects.size() == 7); + BOOST_CHECK(projects.size() == 8); if (const GRC::ProjectOption project1 = projects.Try("project name 1")) { BOOST_CHECK(project1->m_name == "project name 1"); BOOST_CHECK(project1->m_cpid == cpid); BOOST_CHECK(project1->m_team == "not gridcoin"); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project1->Eligible() == false); } else { @@ -902,6 +962,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project2->m_name == "project name 2"); BOOST_CHECK(project2->m_cpid == cpid); BOOST_CHECK(project2->m_team.empty() == true); + BOOST_CHECK(project2->m_rac == 2.2); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project2->Eligible() == false); } else { @@ -912,6 +973,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project3->m_name == "project name 3"); BOOST_CHECK(project3->m_cpid == GRC::Cpid()); BOOST_CHECK(project3->m_team == "gridcoin"); + BOOST_CHECK(project3->m_rac == 3.3); BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::MALFORMED_CPID); BOOST_CHECK(project3->Eligible() == false); } else { @@ -922,6 +984,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project4->m_name == "project name 4"); BOOST_CHECK(project4->m_cpid == GRC::Cpid()); BOOST_CHECK(project4->m_team == "gridcoin"); + BOOST_CHECK(project4->m_rac == 4.4); BOOST_CHECK(project4->m_error == GRC::MiningProject::Error::MALFORMED_CPID); BOOST_CHECK(project4->Eligible() == false); } else { @@ -932,6 +995,7 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project5->m_name == "project name 5"); BOOST_CHECK(project5->m_cpid == cpid); BOOST_CHECK(project5->m_team == "gridcoin"); + BOOST_CHECK(project5->m_rac == 5.5); BOOST_CHECK(project5->m_error == GRC::MiningProject::Error::MISMATCHED_CPID); BOOST_CHECK(project5->Eligible() == false); } else { @@ -942,20 +1006,36 @@ BOOST_AUTO_TEST_CASE(it_tags_invalid_projects_with_errors_when_parsing_xml) BOOST_CHECK(project6->m_name == "project name 6"); BOOST_CHECK(project6->m_cpid == cpid); BOOST_CHECK(project6->m_team == "gridcoin"); + BOOST_CHECK(project6->m_rac == 6.6); BOOST_CHECK(project6->m_error == GRC::MiningProject::Error::MISMATCHED_CPID); BOOST_CHECK(project6->Eligible() == false); } else { BOOST_FAIL("Project 6 does not exist in the mining project map."); } - if (const GRC::ProjectOption project6 = projects.Try("project name 7")) { - BOOST_CHECK(project6->m_name == "project name 7"); - BOOST_CHECK(project6->m_error == GRC::MiningProject::Error::POOL); - BOOST_CHECK(project6->Eligible() == false); + if (const GRC::ProjectOption project7 = projects.Try("project name 7")) { + BOOST_CHECK(project7->m_name == "project name 7"); + BOOST_CHECK(project7->m_rac == 7.7); + BOOST_CHECK(project7->m_error == GRC::MiningProject::Error::POOL); + BOOST_CHECK(project7->Eligible() == false); } else { BOOST_FAIL("Project 7 does not exist in the mining project map."); } + if (const GRC::ProjectOption project8 = projects.Try("project name 8")) { + BOOST_CHECK(project8->m_name == "project name 8"); + BOOST_CHECK(project8->m_cpid == cpid); + BOOST_CHECK(project8->m_team == "not gridcoin"); + BOOST_CHECK(project8->m_rac == 0.0); + BOOST_CHECK(project8->m_error == GRC::MiningProject::Error::INVALID_TEAM); + BOOST_CHECK(project8->Eligible() == false); + } else { + BOOST_FAIL("Project 8 does not exist in the mining project map."); + } + + // HasRAC should be false. + BOOST_CHECK(!GRC::Researcher::Get()->HasRAC()); + // Clean up: SetArgument("email", ""); GRC::Researcher::Reload(GRC::MiningProjectMap()); @@ -1008,6 +1088,7 @@ BOOST_AUTO_TEST_CASE(it_skips_the_team_requirement_when_set_by_protocol) Project Name 1 ! Not Gridcoin ! XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 1.1 f5d8234352e5a5ae3915debba7258294 )XML", @@ -1025,12 +1106,16 @@ BOOST_AUTO_TEST_CASE(it_skips_the_team_requirement_when_set_by_protocol) BOOST_CHECK(project1->m_name == "project name 1"); BOOST_CHECK(project1->m_cpid == cpid); BOOST_CHECK(project1->m_team == "! not gridcoin !"); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); } else { BOOST_FAIL("Project 1 does not exist in the mining project map."); } + // HasRAC should be true. + BOOST_CHECK(GRC::Researcher::Get()->HasRAC()); + // Clean up: SetArgument("email", ""); DeleteCache(Section::PROTOCOL, "REQUIRE_TEAM_WHITELIST_MEMBERSHIP"); @@ -1051,6 +1136,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) https://example.com/ Project Name 1 ! Not Gridcoin ! + 1.1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX f5d8234352e5a5ae3915debba7258294 @@ -1060,6 +1146,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) https://example.com/ Project Name 2 Team 1 + 0 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX f5d8234352e5a5ae3915debba7258294 @@ -1069,6 +1156,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) https://example.com/ Project Name 3 Team 2 + 0 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX f5d8234352e5a5ae3915debba7258294 @@ -1087,6 +1175,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) BOOST_CHECK(project1->m_name == "project name 1"); BOOST_CHECK(project1->m_cpid == cpid); BOOST_CHECK(project1->m_team == "! not gridcoin !"); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::INVALID_TEAM); BOOST_CHECK(project1->Eligible() == false); } else { @@ -1097,6 +1186,7 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) BOOST_CHECK(project2->m_name == "project name 2"); BOOST_CHECK(project2->m_cpid == cpid); BOOST_CHECK(project2->m_team == "team 1"); + BOOST_CHECK(project2->m_rac == 0); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); } else { @@ -1107,12 +1197,16 @@ BOOST_AUTO_TEST_CASE(it_applies_the_team_whitelist_when_set_by_the_protocol) BOOST_CHECK(project3->m_name == "project name 3"); BOOST_CHECK(project3->m_cpid == cpid); BOOST_CHECK(project3->m_team == "team 2"); + BOOST_CHECK(project3->m_rac == 0); BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project3->Eligible() == true); } else { BOOST_FAIL("Project 3 does not exist in the mining project map."); } + // HasRAC should be false, because the only eligible projects have zero RAC. + BOOST_CHECK(!GRC::Researcher::Get()->HasRAC()); + // Clean up: SetArgument("email", ""); DeleteCache(Section::PROTOCOL, "TEAM_WHITELIST"); @@ -1421,6 +1515,7 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_CHECK(project1->m_name == "valid project 1"); BOOST_CHECK(project1->m_cpid == cpid_1); BOOST_CHECK(project1->m_team == "gridcoin"); + BOOST_CHECK(project1->m_rac == 1.1); BOOST_CHECK(project1->m_url == "https://project1.example.com/boinc/"); BOOST_CHECK(project1->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project1->Eligible() == true); @@ -1432,6 +1527,7 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_CHECK(project2->m_name == "valid project 2"); BOOST_CHECK(project2->m_cpid == cpid_2); BOOST_CHECK(project2->m_team == "gridcoin"); + BOOST_CHECK(project2->m_rac == 2.2); BOOST_CHECK(project2->m_url == "https://project2.example.com/boinc/"); BOOST_CHECK(project2->m_error == GRC::MiningProject::Error::NONE); BOOST_CHECK(project2->Eligible() == true); @@ -1444,6 +1540,7 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_CHECK(project3->m_name == "invalid project 3"); BOOST_CHECK(project3->m_cpid == cpid_2); BOOST_CHECK(project3->m_team == "gridcoin"); + BOOST_CHECK(project3->m_rac == 3.3); BOOST_CHECK(project3->m_url == "https://project3.example.com/boinc/"); BOOST_CHECK(project3->m_error == GRC::MiningProject::Error::MISMATCHED_CPID); BOOST_CHECK(project3->Eligible() == false); @@ -1451,6 +1548,9 @@ void it_parses_project_xml_from_a_client_state_xml_file() BOOST_FAIL("Project 3 does not exist in the mining project map."); } + // HasRAC should be true. + BOOST_CHECK(GRC::Researcher::Get()->HasRAC()); + // Clean up: SetArgument("email", ""); SetArgument("boincdatadir", ""); diff --git a/src/test/gridcoin/superblock_tests.cpp b/src/test/gridcoin/superblock_tests.cpp index 8a0c5b291a..513697c5fe 100644 --- a/src/test/gridcoin/superblock_tests.cpp +++ b/src/test/gridcoin/superblock_tests.cpp @@ -1,7 +1,12 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #include "base58.h" #include "compat/endian.h" +#include "gridcoin/scraper/scraper_net.h" #include "gridcoin/superblock.h" -#include "scraper_net.h" +#include "gridcoin/support/xml.h" #include "streams.h" #include @@ -15,8 +20,6 @@ #include "test/data/superblock_packed.bin.h" #include "test/data/superblock_unpacked.txt.h" -std::string ExtractXML(const std::string& XMLdata, const std::string& key, const std::string& key_end); - namespace { //! //! \brief Legacy functions used to test backward compatibility with the old diff --git a/src/test/gridcoin_tests.cpp b/src/test/gridcoin_tests.cpp index afd02645ce..1acfb0c17b 100755 --- a/src/test/gridcoin_tests.cpp +++ b/src/test/gridcoin_tests.cpp @@ -1,8 +1,13 @@ +// Copyright (c) 2014-2020 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparams.h" #include "uint256.h" #include "util.h" #include "main.h" -#include "global_objects_noui.hpp" -#include "appcache.h" +#include "gridcoin/appcache.h" +#include "gridcoin/staking/reward.h" #include #include @@ -10,7 +15,6 @@ #include extern bool fTestNet; -double RoundFromString(std::string s, int place); namespace { @@ -37,6 +41,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_V8ShouldBeEnabledOnBlock1010000InProduction) { bool was_testnet = fTestNet; fTestNet = false; + SelectParams(CBaseChainParams::MAIN); BOOST_CHECK(IsV8Enabled(1009999) == false); BOOST_CHECK(IsV8Enabled(1010000) == false); BOOST_CHECK(IsV8Enabled(1010001) == true); @@ -47,7 +52,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_V8ShouldBeEnabledOnBlock312000InTestnet) { bool was_testnet = fTestNet; fTestNet = true; - + SelectParams(CBaseChainParams::TESTNET); // With testnet block 312000 was created as the first V8 block, // hence the difference in testing setup compared to the production // tests. @@ -77,7 +82,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_DefaultCBRShouldBe10) { CBlockIndex index; index.nTime = 1538066417; - BOOST_CHECK_EQUAL(GetConstantBlockReward(&index), DEFAULT_CBR); + BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), DEFAULT_CBR); } BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldOverrideDefault) @@ -90,7 +95,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldOverrideDefault) index.nTime = time; WriteCache(Section::PROTOCOL, "blockreward1", ToString(cbr), time); - BOOST_CHECK_EQUAL(GetConstantBlockReward(&index), cbr); + BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), cbr); } BOOST_AUTO_TEST_CASE(gridcoin_NegativeCBRShouldClampTo0) @@ -100,7 +105,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_NegativeCBRShouldClampTo0) index.nTime = time; WriteCache(Section::PROTOCOL, "blockreward1", ToString(-1 * COIN), time); - BOOST_CHECK_EQUAL(GetConstantBlockReward(&index), 0); + BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), 0); } BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldClampTo2xDefault) @@ -110,7 +115,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldClampTo2xDefault) index.nTime = time; WriteCache(Section::PROTOCOL, "blockreward1", ToString(DEFAULT_CBR * 2.1), time); - BOOST_CHECK_EQUAL(GetConstantBlockReward(&index), DEFAULT_CBR * 2); + BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), DEFAULT_CBR * 2); } BOOST_AUTO_TEST_CASE(gridcoin_ObsoleteConfigurableCBRShouldResortToDefault) @@ -123,7 +128,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_ObsoleteConfigurableCBRShouldResortToDefault) // relative to the block. WriteCache(Section::PROTOCOL, "blockreward1", ToString(3 * COIN), index.nTime - max_message_age - 1); - BOOST_CHECK_EQUAL(GetConstantBlockReward(&index), DEFAULT_CBR); + BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), DEFAULT_CBR); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_gridcoin.cpp b/src/test/test_gridcoin.cpp index edd6df7ee5..dc50162263 100644 --- a/src/test/test_gridcoin.cpp +++ b/src/test/test_gridcoin.cpp @@ -1,6 +1,7 @@ #define BOOST_TEST_MODULE Gridcoin Test Suite #include +#include "chainparams.h" #include "wallet/db.h" #include "main.h" #include "wallet/wallet.h" @@ -16,6 +17,7 @@ struct TestingSetup { TestingSetup() { fPrintToDebugger = true; // don't want to write to debug.log file fUseFastIndex = true; // Don't verify block hashes when loading + SelectParams(CBaseChainParams::MAIN); noui_connect(); bitdb.MakeMock(); bool fFirstRun; diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp index c2840eda28..cf1bcbc3af 100644 --- a/src/txdb-leveldb.cpp +++ b/src/txdb-leveldb.cpp @@ -13,16 +13,17 @@ #include #include -#include "kernel.h" +#include "gridcoin/staking/kernel.h" #include "txdb.h" #include "main.h" -#include "global_objects_noui.hpp" #include "ui_interface.h" #include "util.h" using namespace std; using namespace boost; +extern bool fQtActive; + leveldb::DB *txdb; // global pointer for LevelDB object instance static leveldb::Options GetOptions() { @@ -384,6 +385,7 @@ bool CTxDB::LoadBlockIndex() // Watch for genesis block if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) pindexGenesisBlock = pindexNew; + if(fQtActive) { if ((pindexNew->nHeight % 10000) == 0) @@ -426,8 +428,8 @@ bool CTxDB::LoadBlockIndex() CBlockIndex* pindex = item.second; pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust(); // NovaCoin: calculate stake modifier checksum - pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); - if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) + pindex->nStakeModifierChecksum = GRC::GetStakeModifierChecksum(pindex); + if (!GRC::CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016" PRIx64, pindex->nHeight, pindex->nStakeModifier); } diff --git a/src/ui_interface.h b/src/ui_interface.h index eccf966108..a1b285af0f 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -14,7 +14,7 @@ #include #include -#include "scraper/fwd.h" +#include "gridcoin/scraper/fwd.h" class CBasicKeyStore; class CWallet; diff --git a/src/util.cpp b/src/util.cpp index 39ff85c33f..095d5fc043 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -8,6 +8,7 @@ #include "version.h" #include "ui_interface.h" #include "util.h" +#include "util/memory.h" #include // for to_lower() #include diff --git a/src/util.h b/src/util.h index 9d2dd0da54..94ece2dd3d 100644 --- a/src/util.h +++ b/src/util.h @@ -89,13 +89,6 @@ static const int64_t CENT = 1000000; void SetupEnvironment(); -//! Substitute for C++14 std::make_unique. -template -std::unique_ptr MakeUnique(Args&&... args) -{ - return std::unique_ptr(new T(std::forward(args)...)); -} - //void MilliSleep(int64_t n); extern int GetDayOfYear(int64_t timestamp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 89288b4281..f6971100eb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -9,10 +9,11 @@ #include "rpcprotocol.h" #include "init.h" #include "base58.h" -#include "backup.h" #include "streams.h" #include "util.h" -#include "miner.h" +#include "gridcoin/backup.h" +#include "gridcoin/staking/difficulty.h" +#include "gridcoin/staking/status.h" #include "gridcoin/tx_message.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" @@ -114,8 +115,8 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.pushKV("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())); obj.pushKV("ip", addrSeenByPeer.ToStringIP()); - diff.pushKV("current", GetDifficulty(GetLastBlockIndex(pindexBest, true))); - diff.pushKV("target", GetBlockDifficulty(GetNextTargetRequired(pindexBest))); + diff.pushKV("current", GRC::GetCurrentDifficulty()); + diff.pushKV("target", GRC::GetTargetDifficulty()); obj.pushKV("difficulty", diff); obj.pushKV("testnet", fTestNet); @@ -154,12 +155,12 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) } { - LOCK(MinerStatus.lock); + LOCK(g_miner_status.lock); - bool staking = MinerStatus.nLastCoinStakeSearchInterval && MinerStatus.WeightSum; + bool staking = g_miner_status.nLastCoinStakeSearchInterval && g_miner_status.WeightSum; res.pushKV("staking", staking); - res.pushKV("mining-error", MinerStatus.ReasonNotStaking); + res.pushKV("mining-error", g_miner_status.ReasonNotStaking); } return res; @@ -1377,7 +1378,9 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) return ListReceived(params, true); } - void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter=ISMINE_SPENDABLE) + void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, + bool fLong, UniValue& ret, const isminefilter& filter = ISMINE_SPENDABLE, + bool stakes_only = false) { int64_t nFee; string strSentAccount; @@ -1390,7 +1393,7 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); // List: Sent - if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) + if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount) && !stakes_only) { for (auto const& s : listSent) { @@ -1488,9 +1491,15 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) case MinedType::POR_SIDE_STAKE_SEND : entry.pushKV("Type", "POR SIDE STAKE SENT"); break; default : entry.pushKV("Type", "UNKNOWN"); break; } + + // Skip posting this entry if stakes only is desired and not an actual stake. + if (stakes_only && gentype != MinedType::POR && gentype != MinedType::POS) continue; } else { + // Skip posting this entry for non-stake receives. + if (stakes_only) continue; + entry.pushKV("category", "receive"); } entry.pushKV("fee", ValueFromAmount(-nFee)); @@ -1521,62 +1530,62 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Un UniValue listtransactions(const UniValue& params, bool fHelp) { - if (fHelp || params.size() > 4) + if (fHelp || params.size() > 4) throw runtime_error( - "listtransactions ( \"account\" count from includeWatchonly)\n" - "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" - "\nArguments:\n" - "1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n" - " If \"\" is set, it will list transactions for the default account.\n" - "2. count (numeric, optional, default=10) The number of transactions to return\n" - "3. from (numeric, optional, default=0) The number of transactions to skip\n" - "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n" - " If \"\" is set true, it will list sent transactions as well\n" - "\nResult:\n" - "[\n" - " {\n" - " \"account\":\"accountname\", (string) The account name associated with the transaction. \n" - " It will be \"\" for the default account.\n" - " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n" - " move transactions (category = move).\n" - " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n" - " transaction between accounts, and not associated with an address,\n" - " transaction id or block. 'send' and 'receive' transactions are \n" - " associated with an address, transaction id and block details\n" - " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n" - " 'move' category for moves outbound. It is positive for the 'receive' category,\n" - " and for the 'move' category for inbound funds.\n" - " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n" - " 'send' category of transactions.\n" - " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" - " 'receive' category of transactions.\n" - " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n" - " category of transactions.\n" - " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n" - " category of transactions.\n" - " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" - " \"walletconflicts\" : [\n" - " \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n" - " ],\n" - " \"respendsobserved\" : [\n" - " \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n" - " ],\n" - " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" - " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" - " for 'send' and 'receive' category of transactions.\n" - " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" - " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n" - " from (for receiving funds, positive amounts), or went to (for sending funds,\n" - " negative amounts).\n" - " }\n" - "]\n" - - "\nExamples:\n" - "\nList the most recent 10 transactions in the systems\n" - "\nList the most recent 10 transactions for the tabby account\n" - "\nList transactions 100 to 120 from the tabby account\n" - "\nAs a json rpc call\n" - ); + "listtransactions ( \"account\" count from includeWatchonly)\n" + "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" + "\nArguments:\n" + "1. \"account\" (string, optional) The account name. If not included, it will list all transactions for all accounts.\n" + " If \"\" is set, it will list transactions for the default account.\n" + "2. count (numeric, optional, default=10) The number of transactions to return\n" + "3. from (numeric, optional, default=0) The number of transactions to skip\n" + "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n" + " If \"\" is set true, it will list sent transactions as well\n" + "\nResult:\n" + "[\n" + " {\n" + " \"account\":\"accountname\", (string) The account name associated with the transaction. \n" + " It will be \"\" for the default account.\n" + " \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for \n" + " move transactions (category = move).\n" + " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n" + " transaction between accounts, and not associated with an address,\n" + " transaction id or block. 'send' and 'receive' transactions are \n" + " associated with an address, transaction id and block details\n" + " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n" + " 'move' category for moves outbound. It is positive for the 'receive' category,\n" + " and for the 'move' category for inbound funds.\n" + " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n" + " 'send' category of transactions.\n" + " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n" + " 'receive' category of transactions.\n" + " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n" + " category of transactions.\n" + " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n" + " category of transactions.\n" + " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n" + " \"walletconflicts\" : [\n" + " \"conflictid\", (string) Ids of transactions, including equivalent clones, that re-spend a txid input.\n" + " ],\n" + " \"respendsobserved\" : [\n" + " \"respendid\", (string) Ids of transactions, NOT equivalent clones, that re-spend a txid input. \"Double-spends.\"\n" + " ],\n" + " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n" + " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n" + " for 'send' and 'receive' category of transactions.\n" + " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n" + " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n" + " from (for receiving funds, positive amounts), or went to (for sending funds,\n" + " negative amounts).\n" + " }\n" + "]\n" + + "\nExamples:\n" + "\nList the most recent 10 transactions in the systems\n" + "\nList the most recent 10 transactions for the tabby account\n" + "\nList transactions 100 to 120 from the tabby account\n" + "\nAs a json rpc call\n" + ); string strAccount = "*"; int nCount = 10; @@ -1648,6 +1657,59 @@ UniValue listtransactions(const UniValue& params, bool fHelp) return ret; } +UniValue liststakes(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "liststakes ( count )\n" + "\n" + "Returns count most recent stakes." + ); + + string strAccount = "*"; + int nCount = 10; + isminefilter filter = ISMINE_SPENDABLE; + if (params.size() > 0) + { + nCount = params[0].get_int(); + } + + if (nCount < 0) + { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); + } + + UniValue ret_superset(UniValue::VARR); + UniValue ret(UniValue::VARR); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + std::list acentries; + CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + + // iterate backwards until we have at least nCount items to return: + for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + { + CWalletTx *const pwtx = it->second.first; + if (pwtx != 0) + ListTransactions(*pwtx, strAccount, 0, true, ret_superset, filter, true); + CAccountingEntry *const pacentry = it->second.second; + if (pacentry != 0) + AcentryToJSON(*pacentry, strAccount, ret_superset); + + if ((int)ret_superset.size() >= nCount) break; + } + // ret is newest to oldest, for the stake listings, we will leave in that order. + std::vector arrTmp = ret_superset.getValues(); + + for (const auto& iter : arrTmp) + { + ret.push_back(iter); + } + + return ret; +} + UniValue listaccounts(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) @@ -1903,8 +1965,8 @@ UniValue backupwallet(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - bool bWalletBackupResults = BackupWallet(*pwalletMain, GetBackupFilename("wallet.dat")); - bool bConfigBackupResults = BackupConfigFile(GetBackupFilename("gridcoinresearch.conf")); + bool bWalletBackupResults = GRC::BackupWallet(*pwalletMain, GRC::GetBackupFilename("wallet.dat")); + bool bConfigBackupResults = GRC::BackupConfigFile(GRC::GetBackupFilename("gridcoinresearch.conf")); std::vector backup_file_type; @@ -1914,7 +1976,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp) std::vector files_removed; UniValue u_files_removed(UniValue::VARR); - bool bMaintainBackupResults = MaintainBackups(GetBackupPath(), backup_file_type, 0, 0, files_removed); + bool bMaintainBackupResults = GRC::MaintainBackups(GRC::GetBackupPath(), backup_file_type, 0, 0, files_removed); for (const auto& iter : files_removed) { @@ -1971,7 +2033,7 @@ UniValue maintainbackups(const UniValue& params, bool fHelp) std::vector files_removed; UniValue u_files_removed(UniValue::VARR); - bool bMaintainBackupResults = MaintainBackups(GetBackupPath(), backup_file_type, + bool bMaintainBackupResults = GRC::MaintainBackups(GRC::GetBackupPath(), backup_file_type, retention_by_num, retention_by_days, files_removed); for (const auto& iter : files_removed) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cf9c5a98ed..9eb2cbed50 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -9,11 +9,9 @@ #include "crypter.h" #include "ui_interface.h" #include "base58.h" -#include "kernel.h" #include "wallet/coincontrol.h" #include #include -#include "block.h" #include "rpcserver.h" #include "rpcclient.h" #include "rpcprotocol.h" @@ -22,13 +20,17 @@ #include "main.h" #include "util.h" #include -#include "global_objects_noui.hpp" #include "gridcoin/researcher.h" +#include "gridcoin/staking/kernel.h" +#include "gridcoin/support/block_finder.h" using namespace std; +extern bool fQtActive; + bool fConfChange; unsigned int nDerivationMethodIndex; +extern std::atomic g_nTimeBestReceived; namespace { struct CompareValueOnly @@ -1199,7 +1201,7 @@ void CWallet::ResendWalletTransactions(bool fForce) // Only do it if there's been a new block since last time static int64_t nLastTime; - if (nTimeBestReceived < nLastTime) + if (g_nTimeBestReceived < nLastTime) return; nLastTime = GetAdjustedTime(); } @@ -1215,7 +1217,7 @@ void CWallet::ResendWalletTransactions(bool fForce) CWalletTx& wtx = item.second; // Don't rebroadcast until it's had plenty of time that // it should have gotten in already by now. - if (fForce || nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) + if (fForce || g_nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); } for (auto const &item : mapSorted) @@ -1622,7 +1624,7 @@ bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set UTXO) */ bool CWallet::SelectCoinsForStaking(unsigned int nSpendTime, std::vector >& vCoinsRet, - CMinerStatus::ReasonNotStakingCategory& not_staking_error, bool fMiner) const + GRC::MinerStatus::ReasonNotStakingCategory& not_staking_error, bool fMiner) const { int64_t BalanceToConsider = GetBalance(); @@ -1630,7 +1632,7 @@ bool CWallet::SelectCoinsForStaking(unsigned int nSpendTime, std::vector vwtxPrev; - - vector > vCoins; - CMinerStatus::ReasonNotStakingCategory not_staking_error; - nWeight = 0; - - if (!SelectCoinsForStaking(GetAdjustedTime(), vCoins, not_staking_error)) - return false; - - int64_t nCurrentTime = GetAdjustedTime(); - CTxDB txdb("r"); - - LOCK2(cs_main, cs_wallet); - for (auto const& pcoin : vCoins) - { - CTxIndex txindex; - if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex)) - continue; - //1-13-2015 - if (IsProtocolV2(nBestHeight+1)) - { - if (nCurrentTime - pcoin.first->nTime > nStakeMinAge) - { - nWeight += (pcoin.first->vout[pcoin.second].nValue); - } - } - else - { - int64_t nTimeWeight = GetWeight((int64_t)pcoin.first->nTime, nCurrentTime); //StakeKernelHashV1 - CBigNum bnWeight = CBigNum(pcoin.first->vout[pcoin.second].nValue) * nTimeWeight / COIN / (24 * 60 * 60); - - // Weight is greater than zero - if (nTimeWeight > 0) - { - nWeight += bnWeight.getuint64(); - } - } - } - - - return true; -} - // Call after CreateTransaction unless you want to abort bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { @@ -2711,7 +2661,7 @@ void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { mapKeyBirth[it->first] = it->second.nCreateTime; // map in which we'll infer heights of other keys - CBlockIndex *pindexMax = BlockFinder().FindByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin + CBlockIndex *pindexMax = GRC::BlockFinder().FindByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin std::map mapKeyFirstBlock; std::set setKeys; GetKeys(setKeys); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a52c32a797..5bd8507a10 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -9,6 +9,7 @@ #include #include #include +#include "gridcoin/staking/status.h" #include "main.h" #include "key.h" #include "keystore.h" @@ -25,7 +26,6 @@ class CWalletTx; class CReserveKey; class COutput; class CCoinControl; -struct CMinerStatus; /** (client) version numbers for particular wallet features */ enum WalletFeature @@ -50,55 +50,6 @@ enum MinedType SUPERBLOCK = 8 }; -// CMinerStatus is here to prevent circular include problems. -struct CMinerStatus -{ - CCriticalSection lock; - - enum ReasonNotStakingCategory - { - NONE, - NO_MATURE_COINS, - NO_COINS, - ENTIRE_BALANCE_RESERVED, - NO_UTXOS_AVAILABLE_DUE_TO_RESERVE, - WALLET_LOCKED, - TESTNET_ONLY, - OFFLINE - }; - - std::vector vReasonNotStaking; - - const std::vector vReasonNotStakingStrings = { "None", - "No Mature Coins", - "No coins", - "Entire balance reserved", - "No UTXOs available due to reserve balance", - "Wallet locked", - "Testnet-only version", - "Offline" }; - - bool able_to_stake = true; - - std::string ReasonNotStaking; - - uint64_t WeightSum, WeightMin, WeightMax; - double ValueSum; - int Version; - uint64_t CreatedCnt; - uint64_t AcceptedCnt; - uint64_t KernelsFound; - int64_t nLastCoinStakeSearchInterval; - - void Clear(); - CMinerStatus(); - - bool SetReasonNotStaking(ReasonNotStakingCategory not_staking_error); - void ClearReasonsNotStaking(); -}; - - - /** A key pool entry */ class CKeyPool { @@ -247,7 +198,7 @@ class CWallet : public CCryptoKeyStore void AvailableCoinsForStaking(std::vector& vCoins, unsigned int nSpendTime) const; bool SelectCoinsForStaking(unsigned int nSpendTime, std::vector >& vCoinsRet, - CMinerStatus::ReasonNotStakingCategory& not_staking_error, bool fMiner = false) const; + GRC::MinerStatus::ReasonNotStakingCategory& not_staking_error, bool fMiner = false) const; void AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl=NULL, bool fIncludeStakingCoins=false) const; bool SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64_t& nValueRet) const; bool SelectSmallestCoins(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64_t& nValueRet) const; @@ -310,8 +261,6 @@ class CWallet : public CCryptoKeyStore bool CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl *coinControl=NULL); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); - bool GetStakeWeight(uint64_t& nWeight); - std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee=false); std::string SendMoneyToDestination(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee=false);