diff --git a/CHANGELOG.md b/CHANGELOG.md index 36a8d9d113..72ba3d7dbd 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,35 @@ 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.1.0.0] 2020-11-01, mandatory, "Gladys" +### Added + - rpc: Add out-of-sync status to "getinfo" and "getblockchaininfo" #1925 (@cyrossignol) + - gui: add autocomplete to rpc console #1927 (@Pythonix) + - consensus: Add checkpoint post block v11 transition #1919 (@cyrossignol) + - researcher: Add -forcecpid configuration option #1935 (@cyrossignol) + - gui: Adds detection if version is below last mandatory #1939 (@jamescowens) + - contract: Reimplement legacy administrative contract validation #1943 (@cyrossignol) + - voting: Add poll choices to "gettransaction" RPC contract output #1948 (@cyrossignol) + +### Changed + - doc: Fix link in build-openbsd.md #1924 (@Pythonix) + - voting: Decrease poll duration to 90 days #1936 (@cyrossignol) + - refactor: Revert init order to fix rejected net messages @1941 (@cyrossignol) + - refactor: port amount.h #1937 (@div72) + - refactor: Normalize boost::filesystem to fs namespace #1942 (@cyrossignol) + - accrual: Apply accrual for new CPIDs from existing snapshots #1944 (@cyrossignol) + - accrual: Reset research account when disconnecting first block #1947 (@cyrossignol) + +### Removed + - refactor: Clean up transitional code for block version 11 #1933 (@cyrossignol) + +### Fixed + - Modify depends packages for openSUSE and other Redhat like distributions and fix mingw bdb53 compile #1932 (@jamescowens) + - contract: Fix ability to reorganize contracts #1934 (@cyrossignol) + - accrual: Fix snapshot accrual for new CPIDs #1931 (@cyrossignol) + - rpc: Clean up getblockstats #1938 (@jamescowens) + - scraper, rpc: Correct missing mScraperStats initialization in ConvergedScraperStats (@jamescowens) + ## [5.0.2.0] 2020-10-08, leisure ### Added - trivial: Add and update copyright headers in Gridcoin files #1897 (@cyrossignol) diff --git a/configure.ac b/configure.ac index abf8bf21f9..98ca28293a 100755 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ 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, 2) +define(_CLIENT_VERSION_MINOR, 1) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2020) diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index afac697e12..05da9acf6a 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -8,6 +8,7 @@ $(package)_build_subdir=build_unix define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-cxx --disable-replication + $(package)_config_opts+=--libdir=$($($(package)_type)_prefix)/lib $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 diff --git a/depends/packages/bdb53.mk b/depends/packages/bdb53.mk old mode 100755 new mode 100644 index d964ddad8d..2a9af2010d --- a/depends/packages/bdb53.mk +++ b/depends/packages/bdb53.mk @@ -8,6 +8,7 @@ $(package)_build_subdir=build_unix define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-cxx --disable-replication + $(package)_config_opts+=--libdir=$($($(package)_type)_prefix)/lib $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 @@ -20,6 +21,7 @@ endef define $(package)_preprocess_cmds sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' src/dbinc/atomic.h && \ sed -i.old 's/atomic_init/atomic_init_db/' src/dbinc/atomic.h src/mp/mp_region.c src/mp/mp_mvcc.c src/mp/mp_fget.c src/mutex/mut_method.c src/mutex/mut_tas.c && \ + sed -i.old "s/WinIoCtl.h/winioctl.h/g" src/dbinc/win_db.h && \ cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub dist endef diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk old mode 100755 new mode 100644 diff --git a/depends/packages/bzip2.mk b/depends/packages/bzip2.mk old mode 100755 new mode 100644 diff --git a/depends/packages/curl.mk b/depends/packages/curl.mk old mode 100755 new mode 100644 index d9ed3ea56e..73944b9fcf --- a/depends/packages/curl.mk +++ b/depends/packages/curl.mk @@ -10,11 +10,12 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared $(package)_config_opts+= --enable-static $(package)_config_opts+= --without-brotli + $(package)_config_opts+= --libdir=$($($(package)_type)_prefix)/lib $(package)_config_opts_release+=--disable-debug-mode $(package)_config_opts_linux+=--with-pic # Disable OpenSSL for Windows and use native SSL stack (SSPI/Schannel): $(package)_config_opts_mingw32+= --with-winssl --without-ssl - # This extra flag for macOS is necesarry as curl will append a -mmacosx-version-min=10.8 otherwise + # This extra flag for macOS is necessary as curl will append a -mmacosx-version-min=10.8 otherwise # which will cause the linker to fail as it cannot optimize away a __builtin_available(MacOS 10.11...) call # which requires a link to compiler runtime library. $(package)_cflags_darwin=-mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/packages/libzip.mk b/depends/packages/libzip.mk old mode 100755 new mode 100644 index f3c59c99f3..a35ace1274 --- a/depends/packages/libzip.mk +++ b/depends/packages/libzip.mk @@ -31,7 +31,9 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds - $($(package)_build_opts) CFLAGS=$(i686_cflag) ./configure --host=$(host) --prefix=$(host_prefix) --with-zlib=$(host_prefix) --with-bzip2=$(host_prefix) --with-pic --enable-static --enable-shared=no + $($(package)_build_opts) CFLAGS=$(i686_cflag) ./configure --host=$(host) \ + --prefix=$(host_prefix) --with-zlib=$(host_prefix) --with-bzip2=$(host_prefix) \ + --with-pic --enable-static --enable-shared=no --libdir=$($($(package)_type)_prefix)/lib endef define $(package)_build_cmds diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk old mode 100755 new mode 100644 diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk old mode 100755 new mode 100644 diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk old mode 100755 new mode 100644 diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk index bd97880d69..8a2e420205 100644 --- a/depends/packages/qrencode.mk +++ b/depends/packages/qrencode.mk @@ -6,7 +6,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5 define $(package)_set_vars - $(package)_config_opts=--disable-shared -without-tools --disable-sdltest + $(package)_config_opts=--disable-shared -without-tools --disable-sdltest --libdir="$($($(package)_type)_prefix)/lib" $(package)_config_opts_linux=--with-pic $(package)_cxxflags_aarch64_linux = $(GCCFLAGS) $(package)_cflags_aarch64_linux = $(GCCFLAGS) diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk old mode 100755 new mode 100644 diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index 2dd80f4d90..93bfb26b5d 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -70,7 +70,7 @@ config_opts="runtime-link=shared threadapi=pthread threading=multi link=static v BerkeleyDB is only necessary for the wallet functionality. To skip this, pass `--disable-wallet` to `./configure`. -See "Berkeley DB" in [build_unix.md](build_unix.md) for instructions on how to build BerkeleyDB 4.8. +See "Berkeley DB" in [build-unix.md](build-unix.md) for instructions on how to build BerkeleyDB 4.8. You cannot use the BerkeleyDB library from ports, for the same reason as boost above (g++/libstd++ incompatibility). ```bash diff --git a/src/Makefile.am b/src/Makefile.am index 5d0757ebe9..9456f856ed 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ GRIDCOIN_CORE_H = \ addrdb.h \ addrman.h \ alert.h \ + amount.h \ arith_uint256.h \ attributes.h \ banman.h \ diff --git a/src/amount.h b/src/amount.h new file mode 100644 index 0000000000..81415f981f --- /dev/null +++ b/src/amount.h @@ -0,0 +1,29 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_AMOUNT_H +#define BITCOIN_AMOUNT_H + +#include + +/** Amount in halfords (Can be negative) */ +typedef int64_t CAmount; + +static const CAmount COIN = 100000000; +static const CAmount CENT = 1000000; + +/** No amount larger than this (in Halford) is valid. + * + * Note that this constant is *not* the total money supply, which in Gridcoin + * currently happens to be less than 2,000,000,000 GRC for various reasons, but + * rather a sanity check. As this sanity check is used by consensus-critical + * validation code, the exact value of the MAX_MONEY constant is consensus + * critical; in unusual circumstances like a overflow bug that allowed + * for the creation of coins out of thin air modification could lead to a fork. + * */ +static const CAmount MAX_MONEY = 2000000000 * COIN; +inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } + +#endif // BITCOIN_AMOUNT_H diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 24e92fce05..a3a02f5b07 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -124,9 +124,9 @@ class CMainParams : public CChainParams { {1800000, uint256S("0x61bb76ed90de21016de81855d3dc01bd192d17d90de4bdf62e8203c2dde675d7")}, {1900000, uint256S("0x352ca52f9a22fbf1d241082d3bec716ea5bef6b82811f737ae6486bd7771e1c7")}, {2000000, uint256S("0x2e1252a6ed6d0e7e556d4d0377b10f4b542ae5d6c9822cb08d68490a2a0bb706")}, + {2054000, uint256S("0xfa1342b4076ca65be64abd7f9cea50cbbdb6247a6937f1f02d6e76494aab20bf")}, } }; - } }; diff --git a/src/chainparams.h b/src/chainparams.h index 74e5fcd6d4..4fde700ebc 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -129,3 +129,8 @@ inline int GetSuperblockAgeSpacing(int nHeight) { return (fTestNet ? 86400 : (nHeight > 364500) ? 86400 : 43200); } + +inline int GetNewbieSnapshotFixHeight() +{ + return fTestNet ? 1393000 : 2104000; +} diff --git a/src/gridcoin/account.h b/src/gridcoin/account.h index 7c4a3c7e06..c47828573f 100644 --- a/src/gridcoin/account.h +++ b/src/gridcoin/account.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include #include @@ -32,8 +33,8 @@ typedef boost::optional BlockPtrOption; class ResearchAccount { public: - int64_t m_accrual; //!< Research accrued last superblock. - int64_t m_total_research_subsidy; //!< Total lifetime research paid. + CAmount m_accrual; //!< Research accrued last superblock. + CAmount m_total_research_subsidy; //!< Total lifetime research paid. uint32_t m_total_magnitude; //!< Total lifetime magnitude sum. uint32_t m_accuracy; //!< Non-zero magnitude payment count. @@ -43,8 +44,12 @@ class ResearchAccount //! //! \brief Initialize an empty research account. //! - ResearchAccount() - : m_accrual(0) + //! \param accrual Research reward accrued as of the last superblock. New + //! accounts may carry pending accrual even though the CPIDs never staked + //! a block before. + //! + ResearchAccount(const CAmount accrual = 0) + : m_accrual(accrual) , m_total_research_subsidy(0) , m_total_magnitude(0) , m_accuracy(0) diff --git a/src/gridcoin/accrual/computer.h b/src/gridcoin/accrual/computer.h index eb6200d4bf..e5ade056d7 100644 --- a/src/gridcoin/accrual/computer.h +++ b/src/gridcoin/accrual/computer.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/account.h" #include @@ -26,7 +27,7 @@ class IAccrualComputer //! //! \return Max reward allowed in units of 1/100000000 GRC. //! - virtual int64_t MaxReward() const = 0; + virtual CAmount MaxReward() const = 0; //! //! \brief Get the magnitude unit factored into the reward calculation. @@ -60,14 +61,14 @@ class IAccrualComputer //! //! \return Average research payment in units of 1/100000000 GRC. //! - virtual int64_t PaymentPerDay() const = 0; + virtual CAmount PaymentPerDay() const = 0; //! //! \brief Get the average daily research payment limit of the account. //! //! \return Payment per day limit in units of 1/100000000 GRC. //! - virtual int64_t PaymentPerDayLimit() const = 0; + virtual CAmount PaymentPerDayLimit() const = 0; //! //! \brief Determine whether the account exceeded the daily payment limit. @@ -83,7 +84,7 @@ class IAccrualComputer //! //! \return Expected daily payment in units of 1/100000000 GRC. //! - virtual int64_t ExpectedDaily() const = 0; + virtual CAmount ExpectedDaily() const = 0; //! //! \brief Get the pending research reward for the account without applying @@ -91,7 +92,7 @@ class IAccrualComputer //! //! \return Pending payment in units of 1/100000000 GRC. //! - virtual int64_t RawAccrual() const = 0; + virtual CAmount RawAccrual() const = 0; //! //! \brief Get the pending research reward for the account as expected by @@ -99,7 +100,7 @@ class IAccrualComputer //! //! \return Pending payment in units of 1/100000000 GRC. //! - virtual int64_t Accrual() const = 0; + virtual CAmount Accrual() const = 0; }; //! diff --git a/src/gridcoin/accrual/newbie.h b/src/gridcoin/accrual/newbie.h index 0f47b65c21..74d5409fdd 100644 --- a/src/gridcoin/accrual/newbie.h +++ b/src/gridcoin/accrual/newbie.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/accrual/computer.h" #include "gridcoin/beacon.h" @@ -43,7 +44,7 @@ class NewbieAccrualComputer : public IAccrualComputer { } - int64_t MaxReward() const override + CAmount MaxReward() const override { return 500 * COIN; } @@ -72,12 +73,12 @@ class NewbieAccrualComputer : public IAccrualComputer return 0; } - int64_t PaymentPerDay() const override + CAmount PaymentPerDay() const override { return 0; } - int64_t PaymentPerDayLimit() const override + CAmount PaymentPerDayLimit() const override { return MaxReward(); } @@ -87,17 +88,17 @@ class NewbieAccrualComputer : public IAccrualComputer return RawAccrual() > PaymentPerDayLimit(); } - int64_t ExpectedDaily() const override + CAmount ExpectedDaily() const override { return m_magnitude * m_magnitude_unit * COIN; } - int64_t RawAccrual() const override + CAmount RawAccrual() const override { return AccrualDays() * ExpectedDaily(); } - int64_t Accrual() const override + CAmount Accrual() const override { if (m_magnitude <= 0) { return 0; diff --git a/src/gridcoin/accrual/null.h b/src/gridcoin/accrual/null.h index 8bd6d79152..b3690270fd 100644 --- a/src/gridcoin/accrual/null.h +++ b/src/gridcoin/accrual/null.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/accrual/computer.h" namespace { @@ -20,7 +21,7 @@ class NullAccrualComputer : public IAccrualComputer // See IAccrualComputer for inherited API documentation. public: - int64_t MaxReward() const override + CAmount MaxReward() const override { return 0; } @@ -45,12 +46,12 @@ class NullAccrualComputer : public IAccrualComputer return 0; } - int64_t PaymentPerDay() const override + CAmount PaymentPerDay() const override { return 0; } - int64_t PaymentPerDayLimit() const override + CAmount PaymentPerDayLimit() const override { return 0; } @@ -60,17 +61,17 @@ class NullAccrualComputer : public IAccrualComputer return false; } - int64_t ExpectedDaily() const override + CAmount ExpectedDaily() const override { return 0; } - int64_t RawAccrual() const override + CAmount RawAccrual() const override { return 0; } - int64_t Accrual() const override + CAmount Accrual() const override { return 0; } diff --git a/src/gridcoin/accrual/research_age.h b/src/gridcoin/accrual/research_age.h index cca53f520d..d8c7349f03 100644 --- a/src/gridcoin/accrual/research_age.h +++ b/src/gridcoin/accrual/research_age.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/accrual/computer.h" namespace { @@ -19,10 +20,10 @@ using namespace GRC; //! \return A value in units of GRC that represents the maximum research reward //! expected per block. //! -int64_t GetMaxResearchSubsidy(const int64_t nTime) +CAmount GetMaxResearchSubsidy(const int64_t nTime) { // Gridcoin Global Daily Maximum Researcher Subsidy Schedule - int MaxSubsidy = 500; + CAmount MaxSubsidy = 500; if (nTime > 1447977700) MaxSubsidy = 50; // from 11-20-2015 forever else if (nTime >= 1445309276 && nTime <= 1447977700) MaxSubsidy = 75; // between 10-20-2015 and 11-20-2015 @@ -78,7 +79,7 @@ class ResearchAgeComputer : public IAccrualComputer //! //! \return Max reward allowed in units of 1/100000000 GRC. //! - int64_t MaxReward() const override + CAmount MaxReward() const override { return GetMaxResearchSubsidy(m_payment_time) * 255 * COIN; } @@ -135,7 +136,7 @@ class ResearchAgeComputer : public IAccrualComputer //! //! \return Average research payment in units of 1/100000000 GRC. //! - int64_t PaymentPerDay() const override + CAmount PaymentPerDay() const override { if (m_account.IsNew()) { return 0; @@ -158,7 +159,7 @@ class ResearchAgeComputer : public IAccrualComputer //! //! \return Payment per day limit in units of 1/100000000 GRC. //! - int64_t PaymentPerDayLimit() const override + CAmount PaymentPerDayLimit() const override { return m_account.AverageLifetimeMagnitude() * m_magnitude_unit * COIN * 5; } @@ -180,7 +181,7 @@ class ResearchAgeComputer : public IAccrualComputer //! //! \return Expected daily payment in units of 1/100000000 GRC. //! - int64_t ExpectedDaily() const override + CAmount ExpectedDaily() const override { return m_magnitude * m_magnitude_unit * COIN; } @@ -191,7 +192,7 @@ class ResearchAgeComputer : public IAccrualComputer //! //! \return Pending payment in units of 1/100000000 GRC. //! - int64_t RawAccrual() const override + CAmount RawAccrual() const override { double current_avg_magnitude = AverageMagnitude(); @@ -209,7 +210,7 @@ class ResearchAgeComputer : public IAccrualComputer //! //! \return Pending payment in units of 1/100000000 GRC. //! - int64_t Accrual() const override + CAmount Accrual() const override { // Note that if the RA block span < 10, we want to return 0 for the // accrual amount so the CPID can still receive an accurate accrual @@ -250,8 +251,8 @@ class ResearchAgeComputer : public IAccrualComputer return 0; } - const int64_t accrual = RawAccrual(); - const int64_t max_reward = MaxReward(); + const CAmount accrual = RawAccrual(); + const CAmount max_reward = MaxReward(); if (accrual > max_reward) { return max_reward; diff --git a/src/gridcoin/accrual/snapshot.h b/src/gridcoin/accrual/snapshot.h index f818484d39..f273babb99 100644 --- a/src/gridcoin/accrual/snapshot.h +++ b/src/gridcoin/accrual/snapshot.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "arith_uint256.h" #include "fs.h" #include "gridcoin/account.h" @@ -102,7 +103,7 @@ class SnapshotCalculator //! //! \return Accrual earned in units of 1/100000000 GRC. //! - int64_t AccrualDelta(const Cpid& cpid, const ResearchAccount& account) const + CAmount AccrualDelta(const Cpid& cpid, const ResearchAccount& account) const { int64_t accrual_timespan; @@ -244,7 +245,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator { } - int64_t MaxReward() const override + CAmount MaxReward() const override { // The maximum accrual that a CPID can claim in one block is limited to // the amount of accrual that a CPID can collect over two days when the @@ -328,7 +329,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator return m_last_height - m_account.LastRewardHeight(); } - int64_t PaymentPerDay() const override + CAmount PaymentPerDay() const override { if (m_account.IsNew()) { return 0; @@ -344,7 +345,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator return m_account.m_total_research_subsidy / lifetime_days; } - int64_t PaymentPerDayLimit() const override + CAmount PaymentPerDayLimit() const override { return MaxReward(); } @@ -354,7 +355,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator return RawAccrual() > PaymentPerDayLimit(); } - int64_t ExpectedDaily() const override + CAmount ExpectedDaily() const override { // Since this informational value is not consensus-critical, we use // floating-point arithmetic for readability: @@ -362,7 +363,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator return CurrentMagnitude(m_cpid).Floating() * MagnitudeUnit() * COIN; } - int64_t RawAccrual() const override + CAmount RawAccrual() const override { if (m_account.LastRewardHeight() >= m_superblock.m_height) { return AccrualDelta(m_cpid, m_account); @@ -371,9 +372,9 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator return m_account.m_accrual + AccrualDelta(m_cpid, m_account); } - int64_t Accrual() const override + CAmount Accrual() const override { - const int64_t accrual = RawAccrual(); + const CAmount accrual = RawAccrual(); if (accrual > MaxReward()) { return MaxReward(); @@ -489,7 +490,7 @@ class AccrualSnapshot //! \return Accrued research rewards at the time of the snapshot in units //! of 1/100000000 GRC or zero if the CPID does not exist in the snapshot. //! - int64_t GetAccrual(const Cpid cpid) const + CAmount GetAccrual(const Cpid cpid) const { auto iter = m_records.find(cpid); @@ -1415,6 +1416,15 @@ class AccrualSnapshotRepository account.m_accrual = snapshot.GetAccrual(cpid); } + // Apply snapshot accrual for any CPIDs with no accounting record as + // of the last superblock: + // + for (const auto& cpid_pair : snapshot.m_records) { + if (accounts.find(cpid_pair.first) == accounts.end()) { + accounts[cpid_pair.first].m_accrual = cpid_pair.second; + } + } + return true; } diff --git a/src/gridcoin/backup.cpp b/src/gridcoin/backup.cpp index 5bbc133c85..5049ebe666 100644 --- a/src/gridcoin/backup.cpp +++ b/src/gridcoin/backup.cpp @@ -9,17 +9,13 @@ #include "util.h" #include "util/time.h" -#include - -#include #include using namespace GRC; -using namespace boost; -boost::filesystem::path GRC::GetBackupPath() +fs::path GRC::GetBackupPath() { - filesystem::path defaultDir = GetDataDir() / "walletbackups"; + fs::path defaultDir = GetDataDir() / "walletbackups"; return GetArg("-backupdir", defaultDir.string()); } @@ -32,7 +28,7 @@ std::string GRC::GetBackupFilename(const std::string& basename, const std::strin char boTime[200]; strftime(boTime, sizeof(boTime), "%Y-%m-%dT%H-%M-%S", blTime); std::string sBackupFilename; - filesystem::path rpath; + fs::path rpath; sBackupFilename = basename + "-" + std::string(boTime); if (!suffix.empty()) sBackupFilename = sBackupFilename + "-" + suffix; @@ -120,22 +116,22 @@ 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 - filesystem::path ConfigSource = GetConfigFile(); - filesystem::path ConfigTarget = strDest; - filesystem::create_directories(ConfigTarget.parent_path()); + fs::path ConfigSource = GetConfigFile(); + fs::path ConfigTarget = strDest; + fs::create_directories(ConfigTarget.parent_path()); try { #if BOOST_VERSION >= 107400 - filesystem::copy_file(ConfigSource, ConfigTarget, filesystem::copy_options::overwrite_existing); + fs::copy_file(ConfigSource, ConfigTarget, fs::copy_options::overwrite_existing); #elif BOOST_VERSION >= 104000 - filesystem::copy_file(ConfigSource, ConfigTarget, filesystem::copy_option::overwrite_if_exists); + fs::copy_file(ConfigSource, ConfigTarget, fs::copy_option::overwrite_if_exists); #else - filesystem::copy_file(ConfigSource, ConfigTarget); + fs::copy_file(ConfigSource, ConfigTarget); #endif LogPrintf("BackupConfigFile: Copied gridcoinresearch.conf to %s", ConfigTarget.string()); return true; } - catch(const filesystem::filesystem_error &e) + catch(const fs::filesystem_error &e) { LogPrintf("BackupConfigFile: Error copying gridcoinresearch.conf to %s - %s", ConfigTarget.string(), e.what()); return false; @@ -159,23 +155,23 @@ bool GRC::BackupWallet(const CWallet& wallet, const std::string& strDest) bitdb.mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat - filesystem::path WalletSource = GetDataDir() / wallet.strWalletFile; - filesystem::path WalletTarget = strDest; - filesystem::create_directories(WalletTarget.parent_path()); - if (filesystem::is_directory(WalletTarget)) + fs::path WalletSource = GetDataDir() / wallet.strWalletFile; + fs::path WalletTarget = strDest; + fs::create_directories(WalletTarget.parent_path()); + if (fs::is_directory(WalletTarget)) WalletTarget /= wallet.strWalletFile; try { #if BOOST_VERSION >= 107400 - filesystem::copy_file(WalletSource, WalletTarget, filesystem::copy_options::overwrite_existing); + fs::copy_file(WalletSource, WalletTarget, fs::copy_options::overwrite_existing); #elif BOOST_VERSION >= 104000 - filesystem::copy_file(WalletSource, WalletTarget, filesystem::copy_option::overwrite_if_exists); + fs::copy_file(WalletSource, WalletTarget, fs::copy_option::overwrite_if_exists); #else - filesystem::copy_file(WalletSource, WalletTarget); + fs::copy_file(WalletSource, WalletTarget); #endif LogPrintf("BackupWallet: Copied wallet.dat to %s", WalletTarget.string()); } - catch(const filesystem::filesystem_error &e) { + catch(const fs::filesystem_error &e) { LogPrintf("BackupWallet: Error copying wallet.dat to %s - %s", WalletTarget.string(), e.what()); return false; } @@ -186,7 +182,7 @@ bool GRC::BackupWallet(const CWallet& wallet, const std::string& strDest) return false; } -bool GRC::MaintainBackups(filesystem::path wallet_backup_path, std::vector backup_file_type, +bool GRC::MaintainBackups(fs::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. @@ -327,7 +323,7 @@ bool GRC::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(); +fs::path GetBackupPath(); bool BackupsEnabled(); int64_t GetBackupInterval(); void RunBackupJob(); bool BackupConfigFile(const std::string& strDest); -bool MaintainBackups(boost::filesystem::path wallet_backup_path, std::vector backup_file_type, +bool MaintainBackups(fs::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); bool BackupPrivateKeys(const CWallet& wallet, std::string& sTarget, std::string& sErrors); diff --git a/src/gridcoin/beacon.cpp b/src/gridcoin/beacon.cpp index 2e58687dc3..d8c47a391a 100644 --- a/src/gridcoin/beacon.cpp +++ b/src/gridcoin/beacon.cpp @@ -16,7 +16,6 @@ using namespace GRC; using LogFlags = BCLog::LogFlags; extern int64_t g_v11_timestamp; -extern int64_t g_v11_legacy_beacon_days; namespace { BeaconRegistry g_beacons; @@ -147,7 +146,7 @@ bool Beacon::Expired(const int64_t now) const // hard-fork: // if (m_timestamp <= g_v11_timestamp) { - return now - g_v11_timestamp > g_v11_legacy_beacon_days * 86400; + return now - g_v11_timestamp > 14 * 86400; } return false; @@ -375,30 +374,7 @@ void BeaconRegistry::Delete(const ContractContext& ctx) bool BeaconRegistry::Validate(const Contract& contract, const CTransaction& tx) const { - // For legacy beacons, check that the unused parts contain non-empty values - // for compatibility with the existing protocol to prevent a fork. - // if (contract.m_version <= 1) { - // Only administrative contracts can delete legacy beacons. This is - // verified by master public key when checking the contract. - // - if (contract.m_action == ContractAction::REMOVE) { - return true; - } - - if (!contract.m_body.WellFormed(contract.m_action.Value())) { - return false; - } - - const ContractPayload payload = contract.m_body.AssumeLegacy(); - const std::string value = DecodeBase64(payload->LegacyValueString()); - const std::vector parts = split(value, ";"); - - if (parts.size() < 4) return false; - if (parts[0].empty()) return false; - if (parts[2].empty()) return false; - if (parts[3].empty()) return false; - return true; } diff --git a/src/gridcoin/beacon.h b/src/gridcoin/beacon.h index 96acec209c..0192740cae 100644 --- a/src/gridcoin/beacon.h +++ b/src/gridcoin/beacon.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "key.h" #include "gridcoin/contract/handler.h" #include "gridcoin/contract/payload.h" @@ -325,7 +326,7 @@ class BeaconPayload : public IContractPayload //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { return 0.5 * COIN; } diff --git a/src/gridcoin/claim.cpp b/src/gridcoin/claim.cpp index ea9c15e15f..68336b98f1 100644 --- a/src/gridcoin/claim.cpp +++ b/src/gridcoin/claim.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "key.h" #include "main.h" #include "gridcoin/claim.h" @@ -185,7 +186,7 @@ bool Claim::ContainsSuperblock() const return m_superblock->WellFormed(); } -int64_t Claim::TotalSubsidy() const +CAmount Claim::TotalSubsidy() const { return m_block_subsidy + m_research_subsidy; } @@ -236,44 +237,3 @@ uint256 Claim::GetHash() const return hasher.GetHash(); } - -std::string Claim::ToString(const int block_version) const -{ - constexpr char delim[] = "<|>"; - - const int subsidy_places = block_version < 8 ? 2 : 8; - - // Note: Commented-out items recorded to document removed fields: - // - return m_mining_id.ToString() - + delim // + mcpid.projectname - + delim // + mcpid.aesskein - + delim // + RoundToString(mcpid.rac, 0) - + delim // + RoundToString(mcpid.pobdifficulty, 5) - + delim // + RoundToString((double)mcpid.diffbytes, 0) - + delim // + mcpid.enccpid - + delim // + mcpid.encaes - + delim // + RoundToString(mcpid.nonce, 0) - + delim // + RoundToString(mcpid.NetworkRAC, 0) - + delim + m_client_version - + delim + RoundToString((double)m_research_subsidy / COIN, subsidy_places) - + delim // + std::to_string(m_last_payment_time) - + delim // + std::to_string(m_rsa_weight) - + delim // + mcpid.cpidv2 - + delim + std::to_string(m_magnitude) - + delim + m_quorum_address - + delim + BlockHashToString(m_last_block_hash) - + delim + RoundToString((double)m_block_subsidy / COIN, subsidy_places) - + delim + m_organization - + delim // + mcpid.OrganizationKey - + delim + m_quorum_hash.ToString() - + delim + (m_superblock->WellFormed() ? m_superblock->PackLegacy() : "") - + delim // + RoundToString(mcpid.ResearchSubsidy2,2) - + delim // + RoundToString(m_research_age, 6) - + delim + RoundToString(m_magnitude_unit, MAG_UNIT_PLACES) - + delim // + RoundToString(m_average_magnitude, 2) - + delim // + BlockHashToString(m_last_por_block_hash) - + delim // + mcpid.CurrentNeuralHash - + delim // + m_public_key.ToString() - + delim + EncodeBase64(m_signature.data(), m_signature.size()); -} diff --git a/src/gridcoin/claim.h b/src/gridcoin/claim.h index 2097153180..acd2e34f93 100644 --- a/src/gridcoin/claim.h +++ b/src/gridcoin/claim.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/contract/payload.h" #include "gridcoin/cpid.h" #include "gridcoin/superblock.h" @@ -73,7 +74,7 @@ class Claim : public IContractPayload //! external CPID of the researcher. For this case, it must match a CPID //! advertised in a verified beacon. //! - MiningId m_mining_id; // MiningCPID::cpid + MiningId m_mining_id; //! //! \brief The version string of the wallet software running on the node @@ -86,7 +87,7 @@ class Claim : public IContractPayload //! Max length: 30 bytes. Blocks that contain a claim structure with a //! version field longer than 30 characters are rejected. //! - std::string m_client_version; // MiningCPID::clientversion + std::string m_client_version; //! //! \brief A user-customizable field that may contain any arbitrary data. @@ -99,7 +100,7 @@ class Claim : public IContractPayload //! Max length: 50 bytes. Blocks that contain a claim structure with an //! organization field longer than 50 characters are rejected. //! - std::string m_organization; // MiningCPID::Organization + std::string m_organization; //! //! \brief The value minted for generating the new block in units of @@ -114,21 +115,7 @@ class Claim : public IContractPayload //! incoming reward claims and can index those calculated values without //! this field. It can be considered informational. //! - int64_t m_block_subsidy; // MiningCPID::InterestSubsidy - - //! - //! \brief Hash of the block below the block containing this claim. - //! - //! Nodes check that this hash matches the hash of block that precedes the - //! block that contains the claim. This hash is signed along with the CPID - //! to prevent replay of the research reward subsidy. - //! - //! The significance of the last block is embedded into the claim signature - //! for researchers so we can consider this field informational. - //! - //! TODO: Remove this field after the switch to block version 11. - //! - uint256 m_last_block_hash; // MiningCPID::lastblockhash + CAmount m_block_subsidy; //! //! \brief The value of the research rewards claimed by the node in units @@ -141,7 +128,7 @@ class Claim : public IContractPayload //! incoming reward claims and can index those calculated values without //! this field. It can be considered informational. //! - int64_t m_research_subsidy; // MiningCPID::ResearchSubsidy + CAmount m_research_subsidy; //! //! \brief The researcher magnitude value from the superblock at the time @@ -154,14 +141,14 @@ class Claim : public IContractPayload //! //! Previous protocol versions used the magnitude in reward calculations. //! - uint16_t m_magnitude; // MiningCPID::Magnitude + uint16_t m_magnitude; //! //! \brief The magnitude ratio of the network at the time of the claim. //! //! Informational. //! - double m_magnitude_unit; // MiningCPID::ResearchMagnitudeUnit + double m_magnitude_unit; //! //! \brief Produced by signing the CPID and last block hash with a beacon @@ -170,7 +157,7 @@ class Claim : public IContractPayload //! Nodes verify this signature with the CPID's stored beacon key to prevent //! unauthorized claim or replay of the research reward subsidy. //! - std::vector m_signature; // MiningCPID::BoincSignature + std::vector m_signature; //! //! \brief Hash of the superblock to vote for. @@ -179,7 +166,7 @@ class Claim : public IContractPayload //! superblock contract by submitting in this field the contract hash of //! the pending superblock that the node caches locally. //! - QuorumHash m_quorum_hash; // MiningCPID::NeuralHash + QuorumHash m_quorum_hash; //! //! \brief The default wallet address of the node submitting the claim. @@ -188,7 +175,7 @@ class Claim : public IContractPayload //! owned by the node. It will determine whether a node may participate in //! the superblock quorum for a particular day. //! - std::string m_quorum_address; // MiningCPID::GRCAddress + std::string m_quorum_address; //! //! \brief The complete superblock data when the node submitting the claim @@ -197,7 +184,7 @@ class Claim : public IContractPayload //! Must be accompanied by a valid superblock hash in the \c m_quorum_hash //! field. //! - SuperblockPtr m_superblock; // MiningCPID::superblock + SuperblockPtr m_superblock; //! //! \brief Initialize an empty, invalid reward claim object. @@ -276,13 +263,8 @@ class Claim : public IContractPayload //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { - // TODO: remove redefinition of this constant when porting amount.h - // from Bitcoin: - // - constexpr int64_t MAX_MONEY = 2000000000 * COIN; - // Prevent users from sending this contract manually: return MAX_MONEY; } @@ -308,7 +290,7 @@ class Claim : public IContractPayload //! \return The sum of the block subsidy and research subsidy declared in //! the claim. //! - int64_t TotalSubsidy() const; + CAmount TotalSubsidy() const; //! //! \brief Sign an instance that claims research rewards. diff --git a/src/gridcoin/contract/contract.cpp b/src/gridcoin/contract/contract.cpp index fd454ad665..7aa080ae56 100644 --- a/src/gridcoin/contract/contract.cpp +++ b/src/gridcoin/contract/contract.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "main.h" #include "gridcoin/appcache.h" #include "gridcoin/claim.h" @@ -50,7 +51,7 @@ class EmptyPayload : public IContractPayload return ""; } - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { return MAX_MONEY; } @@ -120,7 +121,7 @@ class LegacyPayload : public IContractPayload return m_value; } - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { return Contract::STANDARD_BURN_AMOUNT; } @@ -330,6 +331,63 @@ class Dispatcher //! Dispatcher g_dispatcher; +//! +//! \brief Validate a legacy contract message. +//! +//! This function performs a sanity check for historical contract messages. It +//! verifies the contract signature for administrative contracts only. Version +//! 2 contracts undergo much more robust validation. Testnet contains some bad +//! administrative contracts that this routine filters out. +//! +//! \param contract The version 1 contract to validate. +//! \param tx The transaction that contains the contract. +//! +//! \return \c true if the contract passes validation. +//! +bool CheckLegacyContract(const Contract& contract, const CTransaction& tx) +{ + if (!contract.WellFormed()) { + return false; + } + + if (!contract.RequiresMasterKey()) { + return true; + } + + const std::string base64_sig = ExtractXML(tx.hashBoinc, "", ""); + + if (base64_sig.empty()) { + return false; + } + + bool invalid; + const std::vector sig = DecodeBase64(base64_sig.c_str(), &invalid); + + if (invalid) { + return false; + } + + const std::string type_string = contract.m_type.ToString(); + + // We use static_cast here instead of dynamic_cast to avoid the lookup. The + // value of m_payload is guaranteed to be a LegacyPayload for v1 contracts: + // + const ContractPayload payload = contract.m_body.AssumeLegacy(); + const auto& body = static_cast(*payload); + + const uint256 body_hash = Hash( + type_string.begin(), + type_string.end(), + body.m_key.begin(), + body.m_key.end(), + body.m_value.begin(), + body.m_value.end()); + + CKey key; + key.SetPubKey(CWallet::MasterPublicKey()); + + return key.Verify(body_hash, sig); +} } // anonymous namespace // ----------------------------------------------------------------------------- @@ -417,8 +475,8 @@ void GRC::ApplyContracts( bool& out_found_contract) { for (const auto& contract : tx.GetContracts()) { - // V2 contract signatures are checked upon receipt: - if (contract.m_version == 1 && !contract.Validate()) { + // V2 contracts are checked upon receipt: + if (contract.m_version == 1 && !CheckLegacyContract(contract, tx)) { continue; } @@ -427,11 +485,10 @@ void GRC::ApplyContracts( // TODO: move this into the appropriate contract handler. // if (contract.m_type == ContractType::PROTOCOL) { - const ContractPayload payload = contract.m_body.AssumeLegacy(); - const std::string key = payload->LegacyKeyString(); + const auto payload = contract.SharePayloadAs(); - if (key == "REQUIRE_TEAM_WHITELIST_MEMBERSHIP" - || key == "TEAM_WHITELIST") + if (payload->m_key == "REQUIRE_TEAM_WHITELIST_MEMBERSHIP" + || payload->m_key == "TEAM_WHITELIST") { // Rescan in-memory project CPIDs to resolve a primary CPID // that fits the now active team requirement settings: @@ -461,8 +518,8 @@ void GRC::RevertContracts(const CTransaction& tx, const CBlockIndex* const pinde { // Reverse the contracts. Reorganize will load any previous versions: for (const auto& contract : tx.GetContracts()) { - // V2 contract signatures are checked upon receipt: - if (contract.m_version == 1 && !contract.VerifySignature()) { + // V2 contracts are checked upon receipt: + if (contract.m_version == 1 && !CheckLegacyContract(contract, tx)) { continue; } @@ -474,15 +531,13 @@ void GRC::RevertContracts(const CTransaction& tx, const CBlockIndex* const pinde // Class: Contract // ----------------------------------------------------------------------------- -constexpr int64_t Contract::STANDARD_BURN_AMOUNT; // for clang +constexpr CAmount Contract::STANDARD_BURN_AMOUNT; // for clang Contract::Contract() : m_version(Contract::CURRENT_VERSION) , m_type(ContractType::UNKNOWN) , m_action(ContractAction::UNKNOWN) , m_body() - , m_signature() - , m_public_key() { } @@ -494,90 +549,19 @@ Contract::Contract( , m_type(type) , m_action(action) , m_body(std::move(body)) - , m_signature() - , m_public_key() { } Contract::Contract( - int version, + uint32_t version, Contract::Type type, Contract::Action action, - Contract::Body body, - Contract::Signature signature, - Contract::PublicKey public_key) + Contract::Body body) : m_version(version) , m_type(type) , m_action(action) , m_body(std::move(body)) - , m_signature(std::move(signature)) - , m_public_key(std::move(public_key)) -{ -} - -const CPubKey& Contract::MessagePublicKey() -{ - // If the message key changes, add a conditional entry to this method that - // returns the new key for the appropriate height. - - // 044b2938fbc38071f24bede21e838a0758a52a0085f2e034e7f971df445436a25 - // 2467f692ec9c5ba7e5eaa898ab99cbd9949496f7e3cafbf56304b1cc2e5bdf06e - static const CPubKey since_block_0 ({ - 0x04, 0x4b, 0x29, 0x38, 0xfb, 0xc3, 0x80, 0x71, 0xf2, 0x4b, 0xed, - 0xe2, 0x1e, 0x83, 0x8a, 0x07, 0x58, 0xa5, 0x2a, 0x00, 0x85, 0xf2, - 0xe0, 0x34, 0xe7, 0xf9, 0x71, 0xdf, 0x44, 0x54, 0x36, 0xa2, 0x52, - 0x46, 0x7f, 0x69, 0x2e, 0xc9, 0xc5, 0xba, 0x7e, 0x5e, 0xaa, 0x89, - 0x8a, 0xb9, 0x9c, 0xbd, 0x99, 0x49, 0x49, 0x6f, 0x7e, 0x3c, 0xaf, - 0xbf, 0x56, 0x30, 0x4b, 0x1c, 0xc2, 0xe5, 0xbd, 0xf0, 0x6e - }); - - return since_block_0; -} - -const CPrivKey& Contract::MessagePrivateKey() { - // If the message key changes, add a conditional entry to this method that - // returns the new key for the appropriate height. - - // 308201130201010420fbd45ffb02ff05a3322c0d77e1e7aea264866c24e81e5ab - // 6a8e150666b4dc6d8a081a53081a2020101302c06072a8648ce3d0101022100ff - // fffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300 - // 604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28 - // d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a685541 - // 99c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af - // 48a03bbfd25e8cd0364141020101a144034200044b2938fbc38071f24bede21e8 - // 38a0758a52a0085f2e034e7f971df445436a252467f692ec9c5ba7e5eaa898ab9 - // 9cbd9949496f7e3cafbf56304b1cc2e5bdf06e - static const CPrivKey since_block_0 { - 0x30, 0x82, 0x01, 0x13, 0x02, 0x01, 0x01, 0x04, 0x20, 0xfb, 0xd4, - 0x5f, 0xfb, 0x02, 0xff, 0x05, 0xa3, 0x32, 0x2c, 0x0d, 0x77, 0xe1, - 0xe7, 0xae, 0xa2, 0x64, 0x86, 0x6c, 0x24, 0xe8, 0x1e, 0x5a, 0xb6, - 0xa8, 0xe1, 0x50, 0x66, 0x6b, 0x4d, 0xc6, 0xd8, 0xa0, 0x81, 0xa5, - 0x30, 0x81, 0xa2, 0x02, 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x21, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x30, 0x06, 0x04, - 0x01, 0x00, 0x04, 0x01, 0x07, 0x04, 0x41, 0x04, 0x79, 0xbe, 0x66, - 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, - 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, - 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, 0x48, 0x3a, 0xda, 0x77, - 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, - 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, - 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8, 0x02, 0x21, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, - 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, 0x02, 0x01, 0x01, - 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x4b, 0x29, 0x38, 0xfb, 0xc3, - 0x80, 0x71, 0xf2, 0x4b, 0xed, 0xe2, 0x1e, 0x83, 0x8a, 0x07, 0x58, - 0xa5, 0x2a, 0x00, 0x85, 0xf2, 0xe0, 0x34, 0xe7, 0xf9, 0x71, 0xdf, - 0x44, 0x54, 0x36, 0xa2, 0x52, 0x46, 0x7f, 0x69, 0x2e, 0xc9, 0xc5, - 0xba, 0x7e, 0x5e, 0xaa, 0x89, 0x8a, 0xb9, 0x9c, 0xbd, 0x99, 0x49, - 0x49, 0x6f, 0x7e, 0x3c, 0xaf, 0xbf, 0x56, 0x30, 0x4b, 0x1c, 0xc2, - 0xe5, 0xbd, 0xf0, 0x6e - }; - - return since_block_0; } bool Contract::Detect(const std::string& message) @@ -600,13 +584,7 @@ Contract Contract::Parse(const std::string& message) Contract::Action::Parse(ExtractXML(message, "", "")), Contract::Body(ContractPayload::Make( ExtractXML(message, "", ""), - ExtractXML(message, "", ""))), - Contract::Signature::Parse(ExtractXML(message, "", "")), - // None of the currently-valid contract types support signing with a - // user-supplied private key, so we can skip parsing the public keys - // altogether. We verify contracts with the master and message keys: - //Contract::PublicKey::Parse(ExtractXML(message, "", "")), - Contract::PublicKey()); + ExtractXML(message, "", "")))); } bool Contract::RequiresMasterKey() const @@ -626,35 +604,7 @@ bool Contract::RequiresMasterKey() const } } -bool Contract::RequiresMessageKey() const -{ - switch (m_type.Value()) { - case ContractType::BEACON: return m_action == ContractAction::ADD; - case ContractType::POLL: return m_action == ContractAction::ADD; - case ContractType::VOTE: return m_action == ContractAction::ADD; - default: return false; - } -} - -bool Contract::RequiresSpecialKey() const -{ - return RequiresMessageKey() || RequiresMasterKey(); -} - -const CPubKey& Contract::ResolvePublicKey() const -{ - if (RequiresMessageKey()) { - return MessagePublicKey(); - } - - if (RequiresMasterKey()) { - return CWallet::MasterPublicKey(); - } - - return m_public_key.Key(); -} - -int64_t Contract::RequiredBurnAmount() const +CAmount Contract::RequiredBurnAmount() const { return m_body.m_payload->RequiredBurnAmount(); } @@ -664,19 +614,7 @@ bool Contract::WellFormed() const return m_version > 0 && m_version <= Contract::CURRENT_VERSION && m_type != ContractType::UNKNOWN && m_action != ContractAction::UNKNOWN - && m_body.WellFormed(m_action.Value()) - // Version 2+ contracts rely on the signatures in the transactions - // instead of embedding another signature in the contract: - && (m_version > 1 || m_signature.Viable()) - && (m_version > 1 || (RequiresSpecialKey() || m_public_key.Viable())); -} - -bool Contract::Validate() const -{ - return WellFormed() - // Version 2+ contracts rely on the signatures in the transactions - // instead of embedding another signature in the contract: - && (m_version > 1 || VerifySignature()); + && m_body.WellFormed(m_action.Value()); } ContractPayload Contract::SharePayload() const @@ -688,94 +626,17 @@ ContractPayload Contract::SharePayload() const return m_body.ConvertFromLegacy(m_type.Value()); } -bool Contract::Sign(CKey& private_key) -{ - std::vector output; - - if (!private_key.Sign(GetHash(), output)) { - Log("ERROR: Failed to sign contract"); - return false; - } - - m_signature = std::move(output); - - if (!RequiresSpecialKey()) { - m_public_key = private_key.GetPubKey(); - } - - return true; -} - -bool Contract::SignWithMessageKey() -{ - CKey key; - - key.SetPrivKey(MessagePrivateKey()); - - return Sign(key); -} - -bool Contract::VerifySignature() const -{ - CKey key; - - if (!key.SetPubKey(ResolvePublicKey())) { - Log("ERROR: Failed to set contract public key"); - return false; - } - - return key.Verify(GetHash(), m_signature.Raw()); -} - -uint256 Contract::GetHash() const -{ - if (m_version > 1) { - return SerializeHash(*this); - } - - const std::string type_string = m_type.ToString(); - - // We use static_cast here instead of dynamic_cast to avoid the lookup. The - // value of m_payload is guaranteed to be a LegacyPayload for v1 contracts. - // - const auto& payload = static_cast(*m_body.m_payload); - - return Hash( - type_string.begin(), - type_string.end(), - payload.m_key.begin(), - payload.m_key.end(), - payload.m_value.begin(), - payload.m_value.end()); -} - -std::string Contract::ToString() const -{ - if (m_type == ContractType::MESSAGE) { - return "" + m_body.m_payload->LegacyValueString() + ""; - } - - return "" + m_type.ToString() + "" - + "" + m_body.m_payload->LegacyKeyString() + "" - + "" + m_body.m_payload->LegacyValueString() + "" - + "" + m_action.ToString() + "" - + "" + m_public_key.ToString() + "" - + "" + m_signature.ToString() + ""; -} - void Contract::Log(const std::string& prefix) const { // TODO: temporary... needs better logging LogPrint(BCLog::LogFlags::CONTRACT, - ": %s: v%d, %s, %s, %s, %s, %s, %s", + ": %s: v%d, %s, %s, %s, %s", prefix, m_version, m_type.ToString(), m_action.ToString(), m_body.m_payload->LegacyKeyString(), - m_body.m_payload->LegacyValueString(), - m_public_key.ToString(), - m_signature.ToString()); + m_body.m_payload->LegacyValueString()); } // ----------------------------------------------------------------------------- @@ -937,117 +798,6 @@ void Contract::Body::ResetType(const ContractType type) } } -// ----------------------------------------------------------------------------- -// Class: Contract::Signature -// ----------------------------------------------------------------------------- - -Contract::Signature::Signature() : m_bytes() -{ -} - -Contract::Signature::Signature(std::vector bytes) - : m_bytes(std::move(bytes)) -{ -} - -Contract::Signature Contract::Signature::Parse(const std::string& input) -{ - if (input.empty()) { - return Contract::Signature(); - } - - bool invalid; - std::vector decoded = DecodeBase64(input.c_str(), &invalid); - - if (invalid) { - return Contract::Signature(); - } - - return Contract::Signature(std::move(decoded)); -} - -bool Contract::Signature::Viable() const -{ - // The DER-encoded ASN.1 ECDSA signatures typically contain 70 or 71 bytes, - // but may hold up to 73. Sizes as low as 68 bytes seen on mainnet. We only - // check the number of bytes here as an early step: - return m_bytes.size() >= 64 && m_bytes.size() <= 73; -} - -const std::vector& Contract::Signature::Raw() const -{ - return m_bytes; -} - -Contract Contract::ToLegacy() const -{ - return Contract( - 1, - m_type, - m_action, - ContractPayload::Make( - m_body.m_payload->LegacyKeyString(), - m_body.m_payload->LegacyValueString()), - m_signature, - m_public_key); -} - -std::string Contract::Signature::ToString() const -{ - if (m_bytes.empty()) { - return std::string(); - } - - return EncodeBase64(m_bytes.data(), m_bytes.size()); -} - -// ----------------------------------------------------------------------------- -// Class: Contract::PublicKey -// ----------------------------------------------------------------------------- - -Contract::PublicKey::PublicKey() : m_key() -{ -} - -Contract::PublicKey::PublicKey(CPubKey key) - : m_key(std::move(key)) -{ -} - -Contract::PublicKey Contract::PublicKey::Parse(const std::string& input) -{ - if (input.empty()) { - return Contract::PublicKey(); - } - - return Contract::PublicKey(CPubKey(ParseHex(input))); -} - -bool Contract::PublicKey::operator==(const CPubKey& other) const -{ - return m_key == other; -} - -bool Contract::PublicKey::operator!=(const CPubKey& other) const -{ - return m_key != other; -} - -bool Contract::PublicKey::Viable() const -{ - return m_key.IsValid(); -} - -const CPubKey& Contract::PublicKey::Key() const -{ - return m_key; -} - -std::string Contract::PublicKey::ToString() const -{ - return HexStr(m_key.Raw()); -} - // ----------------------------------------------------------------------------- // Abstract Class: IContractHandler // ----------------------------------------------------------------------------- diff --git a/src/gridcoin/contract/contract.h b/src/gridcoin/contract/contract.h index 3868a97ffe..cb880ffb38 100644 --- a/src/gridcoin/contract/contract.h +++ b/src/gridcoin/contract/contract.h @@ -4,7 +4,7 @@ #pragma once -#include "key.h" +#include "amount.h" #include "gridcoin/contract/payload.h" #include "gridcoin/support/enumbytes.h" #include "serialize.h" @@ -50,7 +50,7 @@ class Contract //! \brief The amount of coin set for a burn output in a transaction that //! broadcasts a contract in units of 1/100000000 GRC. //! - static constexpr int64_t STANDARD_BURN_AMOUNT = 0.5 * COIN; + static constexpr CAmount STANDARD_BURN_AMOUNT = 0.5 * COIN; //! //! \brief A contract type from a transaction message. @@ -211,129 +211,6 @@ class Contract void ResetType(const ContractType type); }; // Contract::Body - //! - //! \brief Parses and stores a contract message signature in binary format. - //! - struct Signature - { - //! - //! \brief Initialize an empty, invalid \c Signature object. - //! - Signature(); - - //! - //! \brief Initialize a \c Signature object from a series of bytes. - //! - //! \param bytes As DER-encoded ASN.1 ECDSA. - //! - Signature(std::vector bytes); - - //! - //! \brief Create a \c Signature object from its string representation. - //! - //! \param input Base64 encoding of the binary signature. Typically - //! 96 characters. - //! - static Signature Parse(const std::string& input); - - //! - //! \brief Determine whether the object contains a viable signature. - //! - //! This method does NOT verify the signature against a public key. Use - //! only for early checks to determine whether to continue verification. - //! - //! \return \c true if resembles a DER-encoded ASN.1 ECDSA signature. - //! - bool Viable() const; - - //! - //! \brief Get the bytes in the signature. - //! - //! \return Typically 70 to 72 bytes. - //! - const std::vector& Raw() const; - - //! - //! \brief Get the string representation of the signature. - //! - //! \return Base64 encoding of the binary signature. - //! - std::string ToString() const; - - private: - std::vector m_bytes; //!< As DER-encoded ASN.1 ECDSA. - }; // Contract::Signature - - //! - //! \brief Parses and stores the contract public key in binary format. - //! - struct PublicKey - { - //! - //! \brief Initialize an empty, invalid \c PublicKey object. - //! - PublicKey(); - - //! - //! \brief Wrap a \c PublicKey object around a \c CPubKey instance. - //! - //! \param key The public key to wrap. - //! - PublicKey(CPubKey key); - - //! - //! \brief Create a \c PublicKey object from its string representation. - //! - //! \param input Hex string representation of the bytes in the key. - //! - static PublicKey Parse(const std::string& input); - - //! - //! \brief Compare a supplied \CPubKey object for equality. - //! - //! \param other A public key to check equality for. - //! - //! \return \c true if the supplied public key's bytes match. - //! - bool operator==(const CPubKey& other) const; - - //! - //! \brief Compare a supplied \CPubKey object for inequality. - //! - //! \param other A public key to check inequality for. - //! - //! \return \c true if the supplied public key's bytes do not match. - //! - bool operator!=(const CPubKey& other) const; - - //! - //! \brief Determine whether the object contains a viable public key. - //! - //! This method does NOT verify the key's structure. Use only for early - //! checks to determine whether to continue verification. - //! - //! \return \true if resembles a full or compressed public key. - //! - bool Viable() const; - - //! - //! \brief Get the wrapped \c CPubKey object. - //! - //! \return A reference to the wrapped key object. - //! - const CPubKey& Key() const; - - //! - //! \brief Get the string representation of the public key. - //! - //! \return Hex string representation of the bytes in the key. - //! - std::string ToString() const; - - private: - CPubKey m_key; //!< The wrapped public key. - }; // Contract::PublicKey - //! //! \brief Version number of the serialized contract format. //! @@ -352,8 +229,6 @@ class Contract Type m_type; //!< Determines how to handle the contract. Action m_action; //!< Action to perform with the contract. Body m_body; //!< Payload specific to the contract type. - Signature m_signature; //!< Proves authenticity of the contract. - PublicKey m_public_key; //!< Verifies the contract signature. //! //! \brief Initialize an empty \c Contract object. @@ -380,38 +255,14 @@ class Contract //! \param type Contract type parsed from the transaction message. //! \param action Contract action parsed from the transaction message. //! \param body The body payload of the contract. - //! \param signature Proves authenticity of the contract message. - //! \param public_key Optional for some types. Verifies the signature. - //! - Contract( - int version, - Type type, - Action action, - Body body, - Signature signature, - PublicKey public_key); - - //! - //! \brief Get the message public key used to verify public contracts. //! - //! \return A \c CPubKey object containing the message public key. - //! - static const CPubKey& MessagePublicKey(); - - //! - //! \brief Get the message private key used to sign public contracts. - //! - //! The private key is revealed by design, for public messages only. - //! - //! \return The message private key as a secure vector of bytes. - //! - static const CPrivKey& MessagePrivateKey(); + Contract(uint32_t version, Type type, Action action, Body body); //! //! \brief Determine whether the supplied message might contain a contract. //! - //! Call \c Contract::WellFormed() or \c Contract::VerifySignature() to - //! check whether a contract is actually viable. + //! Call \c Contract::WellFormed() to check whether a contract is actually + //! viable. //! //! \param message A message as it exists in a transaction. //! @@ -436,35 +287,12 @@ class Contract //! bool RequiresMasterKey() const; - //! - //! \brief Determine whether the contract shall sign the message or verify - //! the signature using the embedded, shared message keys. - //! - //! \return \c true for certain public actions (add poll, vote, beacon...). - //! - bool RequiresMessageKey() const; - - //! - //! \brief Determine whether the contract shall sign the message or verify - //! the signature using a special (non-user-supplied) key. - //! - //! \return \c true when a contract requires the master or message keys. - //! - bool RequiresSpecialKey() const; - - //! - //! \brief Get the public key used to verify the contract's signature. - //! - //! \return The appropriate public key for the contract type. - //! - const CPubKey& ResolvePublicKey() const; - //! //! \brief Get the burn fee amount required to send a particular contract. //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const; + CAmount RequiredBurnAmount() const; //! //! \brief Determine whether the instance represents a complete contract. @@ -478,14 +306,6 @@ class Contract //! bool WellFormed() const; - //! - //! \brief Determine whether a received contract is completely valid. - //! - //! \return \c true if the contract is well-formed and contains a valid - //! signature. - //! - bool Validate() const; - //! //! \brief Get the wrapped contract payload object. //! @@ -562,54 +382,6 @@ class Contract return std::move(static_cast(*SharePayload()));; } - //! - //! \brief Sign the contract using the provided private key. - //! - //! \param private_key The key to sign the message with. - //! - //! \return \c true if the signature was successfully created. - //! - bool Sign(CKey& private_key); - - //! - //! \brief Sign the contract using the shared message private key. - //! - //! \return \c true if the signature was successfully created. - //! - bool SignWithMessageKey(); - - //! - //! \brief Validate the integrity and authenticity of the contract message - //! by verifying its digital signature. - //! - //! \return \c true if the signature validates the contract's claims. - //! - bool VerifySignature() const; - - //! - //! \brief Generate a hash of the contract data as the input to create or - //! verify the contract signature. - //! - //! \return Hash of the contract type, key, and value. Versions 2+ also - //! include the action. - //! - uint256 GetHash() const; - - //! - //! \brief Get the string representation of the contract. - //! - //! \return The contract string in an XML-like format as published in a - //! transaction message. - //! - std::string ToString() const; - - //! - //! \brief Convert a contract to legacy format. - //! - //! \return A copy of the contract with a legacy key/value string payload. - //! - Contract ToLegacy() const; - //! //! \brief Write a message to the debug log with the contract data. //! diff --git a/src/gridcoin/contract/message.cpp b/src/gridcoin/contract/message.cpp index f8ea26ead4..e3e7184d8a 100644 --- a/src/gridcoin/contract/message.cpp +++ b/src/gridcoin/contract/message.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "gridcoin/contract/message.h" #include "gridcoin/contract/contract.h" #include "script.h" @@ -60,10 +61,10 @@ bool SelectMasterInputOutput(CCoinControl& coin_control) //! //! \return \c true if coin selection succeeded. //! -bool CreateContractTx(CWalletTx& wtx_out, CReserveKey reserve_key, int64_t burn_fee) +bool CreateContractTx(CWalletTx& wtx_out, CReserveKey reserve_key, CAmount burn_fee) { CCoinControl coin_control_out; - int64_t applied_fee_out; // Unused + CAmount applied_fee_out; // Unused bool admin = false; // If the input transaction already selected some inputs, ensure that we @@ -120,8 +121,8 @@ std::string SendContractTx(CWalletTx& wtx_new) return strError; } - int64_t balance = pwalletMain->GetBalance(); - int64_t burn_fee = 0; + CAmount balance = pwalletMain->GetBalance(); + CAmount burn_fee = 0; for (const auto& contract : wtx_new.vContracts) { burn_fee += contract.RequiredBurnAmount(); @@ -181,23 +182,6 @@ std::pair GRC::SendContract(CWalletTx wtx) return std::make_pair(std::move(wtx), "Transaction contains no contract."); } - // TODO: remove this after the v11 mandatory block. We don't need to sign - // version 2 contracts: - if (!IsV11Enabled(nBestHeight + 1)) { - Contract& contract = wtx.vContracts[0]; - contract = contract.ToLegacy(); - - if (contract.RequiresMessageKey() && !contract.SignWithMessageKey()) { - return std::make_pair( - std::move(wtx), - "Failed to sign contract with shared message key."); - } - - // Convert any binary contracts to the legacy string representation. - // - wtx.hashBoinc = contract.ToString(); - } - std::string error = SendContractTx(wtx); return std::make_pair(std::move(wtx), std::move(error)); diff --git a/src/gridcoin/contract/payload.h b/src/gridcoin/contract/payload.h index 6dc2face72..0179cf211a 100644 --- a/src/gridcoin/contract/payload.h +++ b/src/gridcoin/contract/payload.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "streams.h" #include @@ -125,7 +126,7 @@ class IContractPayload //! //! \return Burn fee in units of 1/100000000 GRC. //! - virtual int64_t RequiredBurnAmount() const = 0; + virtual CAmount RequiredBurnAmount() const = 0; //! //! \brief Serialize the contract to the provided file. diff --git a/src/gridcoin/gridcoin.cpp b/src/gridcoin/gridcoin.cpp index 06accc093f..eeef5090e5 100644 --- a/src/gridcoin/gridcoin.cpp +++ b/src/gridcoin/gridcoin.cpp @@ -23,8 +23,6 @@ extern unsigned int nScraperSleep; extern unsigned int nActiveBeforeSB; extern bool fScraperActive; -extern ThreadHandler* netThreads; - void Scraper(bool bSingleShot = false); void ScraperSubscriber(); @@ -36,8 +34,6 @@ namespace { //! 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...")); @@ -157,7 +153,9 @@ void ThreadScraperSubscriber(void* parg) //! //! \brief Configure and initialize the scraper system. //! -void InitializeScraper() +//! \param threads Used to start the scraper housekeeping threads. +//! +void InitializeScraper(ThreadHandlerPtr threads) { // 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; @@ -173,20 +171,17 @@ void InitializeScraper() // 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")) { + if (!threads->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")) { + if (!threads->createThread(ThreadScraperSubscriber, nullptr, "ScraperSubscriber")) { LogPrintf("ERROR: createThread(ScraperSubscriber) failed"); } } @@ -197,14 +192,7 @@ void InitializeScraper() //! 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; - } - } + fExplorer = GetBoolArg("-scraper", false) && GetBoolArg("-explorer", false); } //! @@ -284,7 +272,7 @@ bool fSnapshotRequest = false; // Functions // ----------------------------------------------------------------------------- -bool GRC::Initialize(CBlockIndex* pindexBest) +bool GRC::Initialize(ThreadHandlerPtr threads, CBlockIndex* pindexBest) { LogPrintf("Gridcoin: initializing..."); @@ -296,10 +284,7 @@ bool GRC::Initialize(CBlockIndex* pindexBest) 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(); + InitializeScraper(threads); InitializeExplorerFeatures(); return true; diff --git a/src/gridcoin/gridcoin.h b/src/gridcoin/gridcoin.h index 7f324c9f5e..3f18141926 100644 --- a/src/gridcoin/gridcoin.h +++ b/src/gridcoin/gridcoin.h @@ -11,11 +11,12 @@ namespace GRC { //! //! \brief Initialize Gridcoin-specific components and services. //! +//! \param threads Used to start Gridcoin threads. //! \param pindexBest Block index for the tip of the chain. //! //! \return \c false if a problem occurs during initialization. //! -bool Initialize(CBlockIndex* pindexBest); +bool Initialize(ThreadHandlerPtr threads, CBlockIndex* pindexBest); //! //! \brief Set up Gridcoin-specific background jobs. diff --git a/src/gridcoin/project.h b/src/gridcoin/project.h index eade659c5e..5301a34f08 100644 --- a/src/gridcoin/project.h +++ b/src/gridcoin/project.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/contract/handler.h" #include "gridcoin/contract/payload.h" #include "serialize.h" @@ -120,9 +121,9 @@ class Project : public IContractPayload //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { - return 0.5 * COIN; // TODO: reduce fee for admin contracts? + return Contract::STANDARD_BURN_AMOUNT; } //! diff --git a/src/gridcoin/quorum.cpp b/src/gridcoin/quorum.cpp index fc5796e5e1..794d5f8168 100644 --- a/src/gridcoin/quorum.cpp +++ b/src/gridcoin/quorum.cpp @@ -1481,12 +1481,6 @@ LegacyConsensus g_legacy_consensus; // Class: Quorum // ----------------------------------------------------------------------------- -bool Quorum::Active() -{ - return !GetBoolArg("-disablenn", false) - && (!GetBoolArg("-scraper", false) || GetBoolArg("-usenewnn", false)); -} - bool Quorum::Participating(const std::string& grc_address, const int64_t time) { return LegacyConsensus::Participating(grc_address, time); @@ -1696,10 +1690,6 @@ void Quorum::LoadSuperblockIndex(const CBlockIndex* pindexLast) Superblock Quorum::CreateSuperblock() { - if (!Active()) { - return Superblock(); - } - return ScraperGetSuperblockContract(); } diff --git a/src/gridcoin/quorum.h b/src/gridcoin/quorum.h index 51f6a02204..4310359cd5 100644 --- a/src/gridcoin/quorum.h +++ b/src/gridcoin/quorum.h @@ -62,14 +62,6 @@ class ExplainMagnitudeProject class Quorum { public: - //! - //! \brief Determine whether the quorum system is active. - //! - //! \return \c true if the scraper is disabled or if the quorum system is - //! explicitly configured as active. - //! - static bool Active(); - //! //! \brief Determine whether the provided address participates in the //! quorum consensus at the specified time. diff --git a/src/gridcoin/researcher.cpp b/src/gridcoin/researcher.cpp index 4c5d39301e..8b3b521d0b 100644 --- a/src/gridcoin/researcher.cpp +++ b/src/gridcoin/researcher.cpp @@ -30,7 +30,6 @@ using namespace GRC; extern CCriticalSection cs_main; extern std::string msMiningErrors; -extern int64_t g_v11_timestamp; namespace { //! @@ -1089,16 +1088,6 @@ 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 @@ -1185,8 +1174,26 @@ void Researcher::Reload(MiningProjectMap projects, GRC::BeaconError beacon_error MiningId mining_id = MiningId::ForInvestor(); - for (const auto& project_pair : projects) { - TryProjectCpid(mining_id, project_pair.second); + // Enable a user to override CPIDs detected from BOINC's client_state.xml + // file. This provides some flexibility for a user that needs to manage a + // split CPID situation or for people that run a wallet on computers that + // do not have BOINC installed: + // + if (mapArgs.count("-forcecpid")) { + mining_id = MiningId::Parse(GetArg("-forcecpid", "")); + + if (mining_id.Which() == MiningId::Kind::CPID) { + LogPrintf("Configuration forces CPID: %s", mining_id.ToString()); + } else { + LogPrintf("ERROR: invalid CPID in -forcecpid"); + mining_id = MiningId::ForInvestor(); + } + } + + if (mining_id.Which() != MiningId::Kind::CPID) { + for (const auto& project_pair : projects) { + TryProjectCpid(mining_id, project_pair.second); + } } if (const CpidOption cpid = mining_id.TryCpid()) { @@ -1266,7 +1273,7 @@ bool Researcher::HasRAC() const return false; } -int64_t Researcher::Accrual() const +CAmount Researcher::Accrual() const { const CpidOption cpid = m_mining_id.TryCpid(); @@ -1381,7 +1388,7 @@ AdvertiseBeaconResult Researcher::AdvertiseBeacon(const bool force) LOCK2(cs_main, pwalletMain->cs_wallet); const BeaconRegistry& beacons = GetBeaconRegistry(); - const BeaconOption current_beacon = beacons.Try(*cpid); + const BeaconOption current_beacon = beacons.TryActive(*cpid, GetAdjustedTime()); AdvertiseBeaconResult result(GRC::BeaconError::NONE); @@ -1393,13 +1400,7 @@ AdvertiseBeaconResult Researcher::AdvertiseBeacon(const bool force) } else if (!current_beacon) { result = SendNewBeacon(*cpid); } else { - // Temporary transition to version 2 beacons after the block version 11 - // threshold. Legacy beacons are not renewable: - if (current_beacon->m_timestamp <= g_v11_timestamp) { - result = SendNewBeacon(*cpid); - } else { - result = RenewBeacon(*cpid, *current_beacon); - } + result = RenewBeacon(*cpid, *current_beacon); } if (result.Error() == GRC::BeaconError::NONE) { diff --git a/src/gridcoin/researcher.h b/src/gridcoin/researcher.h index 130a2433b6..25917089f6 100644 --- a/src/gridcoin/researcher.h +++ b/src/gridcoin/researcher.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "key.h" #include "gridcoin/cpid.h" @@ -498,7 +499,7 @@ class Researcher //! //! \return Research reward accrual in units of 1/100000000 GRC. //! - int64_t Accrual() const; + CAmount Accrual() const; //! //! \brief Get a value that indicates how the wallet participates in the diff --git a/src/gridcoin/scraper/http.cpp b/src/gridcoin/scraper/http.cpp index 174003f44f..fc931fe008 100644 --- a/src/gridcoin/scraper/http.cpp +++ b/src/gridcoin/scraper/http.cpp @@ -303,7 +303,7 @@ void Http::DownloadSnapshot() { std::string url = GetArg("-snapshoturl", "https://download.gridcoin.us/download/downloadstake/signed/snapshot.zip"); - boost::filesystem::path destination = GetDataDir() / "snapshot.zip"; + fs::path destination = GetDataDir() / "snapshot.zip"; ScopedFile fp(fsbridge::fopen(destination, "wb"), &fclose); diff --git a/src/gridcoin/scraper/scraper.cpp b/src/gridcoin/scraper/scraper.cpp index 685ca68313..e73e37fd49 100755 --- a/src/gridcoin/scraper/scraper.cpp +++ b/src/gridcoin/scraper/scraper.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include using namespace GRC; +namespace boostio = boost::iostreams; // These are initialized empty. GetDataDir() cannot be called here. It is too early. fs::path pathDataDir = {}; @@ -2401,7 +2403,7 @@ uint256 GetFileHash(const fs::path& inputfile) return nHash; // use file size to size memory buffer - int dataSize = boost::filesystem::file_size(inputfile); + int dataSize = fs::file_size(inputfile); std::vector vchData; vchData.resize(dataSize); @@ -4030,7 +4032,7 @@ bool ScraperSendFileManifestContents(CBitcoinAddress& Address, CKey& Key) } // use file size to size memory buffer - int dataSize = boost::filesystem::file_size(inputfilewpath); + int dataSize = fs::file_size(inputfilewpath); std::vector vchData; vchData.resize(dataSize); @@ -4121,7 +4123,7 @@ bool ScraperSendFileManifestContents(CBitcoinAddress& Address, CKey& Key) } // use file size to size memory buffer - int dataSize = boost::filesystem::file_size(inputfilewpath); + int dataSize = fs::file_size(inputfilewpath); std::vector vchData; vchData.resize(dataSize); @@ -5126,11 +5128,7 @@ Superblock ScraperGetSuperblockContract(bool bStoreConvergedStats, bool bContrac ConvergedScraperStatsCache.nTime = GetAdjustedTime(); ConvergedScraperStatsCache.Convergence = StructConvergedManifest; - if (IsV11Enabled(nBestHeight + 1)) { - superblock = Superblock::FromConvergence(ConvergedScraperStatsCache); - } else { - superblock = Superblock::FromConvergence(ConvergedScraperStatsCache, 1); - } + superblock = Superblock::FromConvergence(ConvergedScraperStatsCache); ConvergedScraperStatsCache.NewFormatSuperblock = superblock; @@ -5325,8 +5323,6 @@ UniValue ConvergedScraperStatsToJson(ConvergedScraperStats& ConvergedScraperStat const ConvergedManifest& PastConvergence = iter.second.second; - ScraperStats mScraperConvergedStats = GetScraperStatsByConvergedManifest(PastConvergence).mScraperStats; - entry.pushKV("past_convergence_timestamp", PastConvergence.timestamp); entry.pushKV("past_convergence_datetime", DateTimeStrFormat("%x %H:%M:%S UTC", PastConvergence.timestamp)); @@ -5475,24 +5471,8 @@ UniValue testnewsb(const UniValue& params, bool fHelp) // Contract binary pack/unpack check... _log(logattribute::INFO, "testnewsb", "Checking compatibility with binary SB pack/unpack by packing then unpacking, then comparing to the original"); - std::string legacy_packed_contract; - { - LOCK(cs_ConvergedScraperStatsCache); - - legacy_packed_contract = ConvergedScraperStatsCache.NewFormatSuperblock.PackLegacy(); - uint64_t legacy_packed_size = legacy_packed_contract.size(); - - _log(logattribute::INFO, "testnewsb", "legacy packed size = " + std::to_string(legacy_packed_size)); - res.pushKV("legacy packed size", legacy_packed_size); - } - SuperblockPtr NewFormatSuperblock = SuperblockPtr::Empty(); - Superblock NewFormatSuperblock_out; - CDataStream ss(SER_NETWORK, 1); - uint64_t nNewFormatSuperblockSerSize; - uint64_t nNewFormatSuperblock_outSerSize; QuorumHash nNewFormatSuperblockHash; - QuorumHash nNewFormatSuperblock_outHash; uint32_t nNewFormatSuperblockReducedContentHashFromConvergenceHint; uint32_t nNewFormatSuperblockReducedContentHashFromUnderlyingManifestHint; @@ -5513,7 +5493,6 @@ UniValue testnewsb(const UniValue& params, bool fHelp) _log(logattribute::INFO, "testnewsb", "zero-mag count = " + std::to_string(NewFormatSuperblock->m_cpids.Zeros())); res.pushKV("zero-mag count", (uint64_t) NewFormatSuperblock->m_cpids.Zeros()); - nNewFormatSuperblockSerSize = GetSerializeSize(*NewFormatSuperblock, SER_NETWORK, 1); nNewFormatSuperblockHash = NewFormatSuperblock->GetHash(); _log(logattribute::INFO, "testnewsb", "NewFormatSuperblock.m_version = " + std::to_string(NewFormatSuperblock->m_version)); @@ -5522,44 +5501,11 @@ UniValue testnewsb(const UniValue& params, bool fHelp) nNewFormatSuperblockReducedContentHashFromConvergenceHint = NewFormatSuperblock->m_convergence_hint; nNewFormatSuperblockReducedContentHashFromUnderlyingManifestHint = NewFormatSuperblock->m_manifest_content_hint; - _log(logattribute::INFO, "testnewsb", "nNewFormatSuperblockSerSize = " + std::to_string(nNewFormatSuperblockSerSize)); - res.pushKV("nNewFormatSuperblockSerSize", nNewFormatSuperblockSerSize); - - ss << *NewFormatSuperblock; - ss >> NewFormatSuperblock_out; - - nNewFormatSuperblock_outSerSize = GetSerializeSize(NewFormatSuperblock_out, SER_NETWORK, 1); - nNewFormatSuperblock_outHash = NewFormatSuperblock_out.GetHash(); - - _log(logattribute::INFO, "testnewsb", "nNewFormatSuperblock_outSerSize = " + std::to_string(nNewFormatSuperblock_outSerSize)); - res.pushKV("nNewFormatSuperblock_outSerSize", nNewFormatSuperblock_outSerSize); - - if (NewFormatSuperblock->GetHash() == nNewFormatSuperblock_outHash) - { - _log(logattribute::INFO, "testnewsb", "NewFormatSuperblock serialization passed."); - res.pushKV("NewFormatSuperblock serialization", "passed"); - } - else - { - _log(logattribute::ERR, "testnewsb", "NewFormatSuperblock serialization FAILED."); - res.pushKV("NewFormatSuperblock serialization", "FAILED"); - } - - Superblock NewFormatSuperblockFromLegacy = Superblock::UnpackLegacy(legacy_packed_contract); - QuorumHash new_legacy_hash = QuorumHash::Hash(NewFormatSuperblockFromLegacy); - - res.pushKV("NewFormatSuperblockHash", nNewFormatSuperblockHash.ToString()); - _log(logattribute::INFO, "testnewsb", "NewFormatSuperblockHash = " + nNewFormatSuperblockHash.ToString()); - res.pushKV("new_legacy_hash", new_legacy_hash.ToString()); - _log(logattribute::INFO, "testnewsb", "new_legacy_hash = " + new_legacy_hash.ToString()); res.pushKV("nNewFormatSuperblockReducedContentHashFromConvergenceHint", (uint64_t) nNewFormatSuperblockReducedContentHashFromConvergenceHint); _log(logattribute::INFO, "testnewsb", "nNewFormatSuperblockReducedContentHashFromConvergenceHint = " + std::to_string(nNewFormatSuperblockReducedContentHashFromConvergenceHint)); res.pushKV("nNewFormatSuperblockReducedContentHashFromUnderlyingManifestHint", (uint64_t) nNewFormatSuperblockReducedContentHashFromUnderlyingManifestHint); _log(logattribute::INFO, "testnewsb", "nNewFormatSuperblockReducedContentHashFromUnderlyingManifestHint = " + std::to_string(nNewFormatSuperblockReducedContentHashFromUnderlyingManifestHint)); - _log(logattribute::INFO, "testnewsb", "NewFormatSuperblock legacy unpack number of zero mags = " + std::to_string(NewFormatSuperblock->m_cpids.Zeros())); - res.pushKV("NewFormatSuperblock legacy unpack number of zero mags", std::to_string(NewFormatSuperblock->m_cpids.Zeros())); - // Log the number of bits used to force key collisions. _log(logattribute::INFO, "testnewsb", "nReducedCacheBits = " + std::to_string(nReducedCacheBits)); res.pushKV("nReducedCacheBits", std::to_string(nReducedCacheBits)); diff --git a/src/gridcoin/scraper/scraper.h b/src/gridcoin/scraper/scraper.h index 8111bd86b2..7773da05fd 100644 --- a/src/gridcoin/scraper/scraper.h +++ b/src/gridcoin/scraper/scraper.h @@ -5,20 +5,12 @@ #pragma once #include -#include #include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include "sync.h" #include "wallet/wallet.h" @@ -31,14 +23,6 @@ #include "gridcoin/scraper/fwd.h" #include "gridcoin/superblock.h" -/********************* -* Scraper Namespace * -*********************/ - -namespace fs = boost::filesystem; -namespace boostio = boost::iostreams; - - /********************* * Global Defaults * *********************/ diff --git a/src/gridcoin/staking/difficulty.cpp b/src/gridcoin/staking/difficulty.cpp index 88c1b36e2c..14af0390e0 100644 --- a/src/gridcoin/staking/difficulty.cpp +++ b/src/gridcoin/staking/difficulty.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "bignum.h" #include "init.h" #include "gridcoin/staking/difficulty.h" @@ -283,7 +284,7 @@ double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, do return result; } - int64_t nValue = 0; + CAmount nValue = 0; int64_t nCurrentTime = GetAdjustedTime(); LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nCurrentTime = %i", nCurrentTime); @@ -295,7 +296,7 @@ double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, do 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; + CAmount BalanceAvailForStaking = 0; std::vector vCoins; { @@ -319,7 +320,7 @@ double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, do // An efficient local structure to store the UTXO's with the bare minimum info we need. - typedef std::vector< std::pair > vCoinsExt; + 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. @@ -360,7 +361,7 @@ double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, do // nValue >= 1250000. if (BalanceAvailForStaking >= nValue && nValue >= 1250000) { - vUTXO.push_back(std::pair( nTime, nValue)); + 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) diff --git a/src/gridcoin/staking/kernel.cpp b/src/gridcoin/staking/kernel.cpp index 8600ce50ec..479f15bbb0 100644 --- a/src/gridcoin/staking/kernel.cpp +++ b/src/gridcoin/staking/kernel.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "arith_uint256.h" #include "gridcoin/staking/kernel.h" #include "txdb.h" @@ -529,7 +530,7 @@ uint256 GRC::CalculateStakeHashV8( int64_t GRC::CalculateStakeWeightV8(const CTransaction &CoinTx, unsigned CoinTxN) { - int64_t nValueIn = CoinTx.vout[CoinTxN].nValue; + CAmount nValueIn = CoinTx.vout[CoinTxN].nValue; nValueIn /= 1250000; return nValueIn; } diff --git a/src/gridcoin/staking/kernel.h b/src/gridcoin/staking/kernel.h index 4964a80423..9e6575532b 100644 --- a/src/gridcoin/staking/kernel.h +++ b/src/gridcoin/staking/kernel.h @@ -5,6 +5,7 @@ #pragma once +#include "amount.h" #include "main.h" namespace GRC { diff --git a/src/gridcoin/staking/reward.cpp b/src/gridcoin/staking/reward.cpp index 6682d674fe..ff37d8863d 100644 --- a/src/gridcoin/staking/reward.cpp +++ b/src/gridcoin/staking/reward.cpp @@ -2,19 +2,19 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "gridcoin/appcache.h" #include "gridcoin/staking/reward.h" #include "main.h" namespace { -int64_t GetCoinYearReward(int64_t nTime) +CAmount GetCoinYearReward(int64_t nTime) { // Gridcoin Global Interest Rate Schedule - int64_t INTEREST = 9; + CAmount 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 >= 1417305600 && nTime <= 1422576000) INTEREST = 8 * CENT; // 08% between 11-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 @@ -30,17 +30,17 @@ int64_t GetCoinYearReward(int64_t nTime) // Functions // ----------------------------------------------------------------------------- -int64_t GRC::GetConstantBlockReward(const CBlockIndex* index) +CAmount 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; + const CAmount MIN_CBR = 0; + const CAmount MAX_CBR = DEFAULT_CBR * 2; - int64_t reward = DEFAULT_CBR; + CAmount reward = DEFAULT_CBR; AppCacheEntry oCBReward = ReadCache(Section::PROTOCOL, "blockreward1"); //TODO: refactor the expire checking to subroutine @@ -55,7 +55,7 @@ int64_t GRC::GetConstantBlockReward(const CBlockIndex* index) return reward; } -int64_t GRC::GetProofOfStakeReward( +CAmount GRC::GetProofOfStakeReward( const uint64_t nCoinAge, const int64_t nTime, const CBlockIndex* const pindexLast) diff --git a/src/gridcoin/staking/reward.h b/src/gridcoin/staking/reward.h index 26abfecc35..2e9779de45 100644 --- a/src/gridcoin/staking/reward.h +++ b/src/gridcoin/staking/reward.h @@ -4,13 +4,15 @@ #pragma once +#include "amount.h" + class CBlockIndex; namespace GRC { -int64_t GetProofOfStakeReward( +CAmount GetProofOfStakeReward( uint64_t nCoinAge, int64_t nTime, const CBlockIndex* const pindexLast); -int64_t GetConstantBlockReward(const CBlockIndex* index); +CAmount GetConstantBlockReward(const CBlockIndex* index); } // namespace GRC diff --git a/src/gridcoin/superblock.cpp b/src/gridcoin/superblock.cpp index 95528f2736..2cf7f2f6b3 100644 --- a/src/gridcoin/superblock.cpp +++ b/src/gridcoin/superblock.cpp @@ -68,9 +68,9 @@ class ScraperStatsSuperblockBuilder continue; case statsobjecttype::byCPID: - m_superblock.m_cpids.RoundAndAdd( + m_superblock.m_cpids.Add( Cpid::Parse(object_id), - entry.second.statsvalue.dMag); + Magnitude::RoundFrom(entry.second.statsvalue.dMag)); break; @@ -226,18 +226,6 @@ class ScraperStatsQuorumHasher } } - //! - //! \brief Round and hash a CPID/magnitude pair as it would exist - //! in the Superblock::CpidIndex container. - //! - //! \param cpid The CPID value to hash. - //! \param magnitude The magnitude value to hash. - //! - void RoundAndAdd(Cpid cpid, double magnitude) - { - Add(cpid, Magnitude::RoundFrom(magnitude)); - } - //! //! \brief Hash a project statistics entry as it would exist in the //! Superblock::ProjectIndex container. @@ -580,15 +568,6 @@ Superblock Superblock::FromStats(const ScraperStatsAndVerifiedBeacons& stats_and Superblock superblock(version); ScraperStatsSuperblockBuilder builder(superblock); - if (version == 1) { - // Force the CPID index into legacy mode to capture zero-magnitude - // CPIDs that result from rounding. - // - // TODO: encapsulate this - // - superblock.m_cpids = Superblock::CpidIndex(0); - } - builder.BuildFromStats(stats_and_verified_beacons); return superblock; @@ -818,29 +797,6 @@ void Superblock::CpidIndex::Add(const Cpid cpid, const Magnitude magnitude) m_total_magnitude += magnitude.Scaled(); } -void Superblock::CpidIndex::RoundAndAdd(const Cpid cpid, const double magnitude) -{ - // The ScraperGetNeuralContract() function that these classes replace - // rounded magnitude values using a half-away-from-zero rounding mode - // to determine whether floating-point magnitudes round-down to zero, - // but it added the magnitude values to the superblock with half-even - // rounding. This caused legacy superblock contracts to contain CPIDs - // with zero magnitude when the rounding results differed. - // - // To create legacy superblocks from scraper statistics with matching - // hashes, we filter magnitudes using the same rounding rules: - // - if (m_legacy) { - if (std::round(magnitude) > 0) { - AddLegacy(cpid, std::nearbyint(magnitude)); - } else { - m_zero_magnitude_count++; - } - } else { - Add(cpid, Magnitude::RoundFrom(magnitude)); - } -} - void Superblock::CpidIndex::AddLegacy(const Cpid cpid, const uint16_t magnitude) { m_legacy_magnitudes.emplace_back(cpid, magnitude); diff --git a/src/gridcoin/superblock.h b/src/gridcoin/superblock.h index 13e9d39632..a366b68f81 100644 --- a/src/gridcoin/superblock.h +++ b/src/gridcoin/superblock.h @@ -20,6 +20,7 @@ extern int64_t SCRAPER_CMANIFEST_RETENTION_TIME; extern std::vector GetVerifiedBeaconIDs(const ConvergedManifest& StructConvergedManifest); extern std::vector GetVerifiedBeaconIDs(const ScraperPendingBeaconMap& VerifiedBeaconMap); +extern ScraperStatsAndVerifiedBeacons GetScraperStatsByConvergedManifest(const ConvergedManifest& StructConvergedManifest); class CBlockIndex; class ConvergedScraperStats; // Forward for Superblock @@ -827,15 +828,6 @@ class Superblock //! void AddLegacy(const Cpid cpid, const uint16_t magnitude); - //! - //! \brief Add the supplied mining ID to the index if it represents a - //! valid CPID after rounding the magnitude to an integer. - //! - //! \param cpid The CPID to add. - //! \param magnitude Total magnitude to associate with the CPID. - //! - void RoundAndAdd(const Cpid cpid, const double magnitude); - //! //! \brief Get a hash of the magnitude segments. //! @@ -1323,9 +1315,7 @@ class Superblock //! CONSENSUS: Although this method produces a legacy contract compatible //! with older protocols, it does not guarantee that the contract matches //! exactly to legacy input contract versions imported by UnpackLegacy(). - //! Use this method to produce new contracts from a superblock object. Do - //! not reproduce existing superblock contracts with this routine if they - //! will be retransmitted to other nodes. + //! We retain this method for unit tests only. //! //! \return Legacy superblock contract as a string of XML-like text data //! and binary-packed CPID/magnitude data. @@ -1572,6 +1562,8 @@ struct ConvergedScraperStats bClean = false; nTime = nTime_in; + + mScraperConvergedStats = GetScraperStatsByConvergedManifest(Convergence).mScraperStats; } // Flag to indicate cache is clean or dirty (i.e. state change of underlying statistics has occurred. diff --git a/src/gridcoin/tally.cpp b/src/gridcoin/tally.cpp index 78bdb47845..66ae5bfc3f 100644 --- a/src/gridcoin/tally.cpp +++ b/src/gridcoin/tally.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "chainparams.h" #include "main.h" #include "gridcoin/accrual/newbie.h" @@ -23,6 +24,19 @@ using LogFlags = BCLog::LogFlags; extern int64_t g_v11_timestamp; namespace { +//! +//! \brief Determines whether the snapshot accrual system should enable the fix +//! for an issue that prevents new CPIDs from accruing research rewards. +//! +//! The snapshot accrual system released with mandatory v5.0.0 contained a bug +//! that prevented a CPID from accruing research rewards earlier than the last +//! superblock if that CPID never staked a block before. The fix causes a hard +//! fork so this flag controls the activation based on block height. +//! +//! This fix is temporary and can be removed after the next mandatory release. +//! +bool g_newbie_snapshot_fix_enabled; + //! //! \brief Set the correct CPID from the block claim when the block index //! contains a zero CPID. @@ -288,8 +302,11 @@ class ResearcherTally assert(account.m_first_block_ptr != nullptr); assert(pindex == account.m_last_block_ptr); + // When disconnecting a CPID's first block, reset the account, but + // retain the pending snapshot accrual amount: + // if (pindex == account.m_first_block_ptr) { - m_researchers.erase(iter); + account = ResearchAccount(account.m_accrual); return; } @@ -326,7 +343,7 @@ class ResearcherTally // switch to block version 11. // if (superblock->m_version >= 2) { - TallySuperblockAccrual(superblock.m_timestamp); + TallySuperblockAccrual(superblock); if (!m_snapshots.Store(superblock.m_height, m_researchers)) { return false; @@ -513,13 +530,13 @@ class ResearcherTally //! //! \brief Tally research rewards accrued since the current superblock - //! arrived. + //! arrived for the snapshot accrual system. //! - //! \param payment_time Time of payment to calculate rewards at. + //! \param superblock Incoming superblock to calculate rewards at. //! - void TallySuperblockAccrual(const int64_t payment_time) + void TallySuperblockAccrual(const SuperblockPtr& superblock) { - const SnapshotCalculator calc(payment_time, m_current_superblock); + const SnapshotCalculator calc(superblock.m_timestamp, m_current_superblock); for (auto& account_pair : m_researchers) { const Cpid cpid = account_pair.first; @@ -531,6 +548,25 @@ class ResearcherTally account.m_accrual += calc.AccrualDelta(cpid, account); } + + // Versions 5.0.x for the mandatory block version 11 protocol hard-fork + // contain a bug that prevented new CPIDs from accruing rewards earlier + // than the latest superblock because the loop above does not reconcile + // the pending accrual for CPIDs without a research account yet. + // + if (!g_newbie_snapshot_fix_enabled) { + return; + } + + // Record snapshot accrual for any CPIDs with no accounting record as + // of the last superblock: + // + for (const auto& iter : superblock->m_cpids) { + if (m_researchers.find(iter.Cpid()) == m_researchers.end()) { + ResearchAccount& account = m_researchers[iter.Cpid()]; + account.m_accrual = calc.AccrualDelta(iter.Cpid(), account); + } + } } //! @@ -645,6 +681,7 @@ class ResearcherTally return true; } +public: //! //! \brief Wipe out the entire snapshot accrual state and rebuild the //! snapshots and each account's accrual from the initial threshold. @@ -706,6 +743,8 @@ bool Tally::Initialize(CBlockIndex* pindex) return true; } + g_newbie_snapshot_fix_enabled = pindex->nHeight + 1 >= GetNewbieSnapshotFixHeight(); + const int64_t start_time = GetTimeMillis(); g_researcher_tally.Initialize(pindex, Quorum::CurrentSuperblock()); @@ -732,6 +771,13 @@ bool Tally::ActivateSnapshotAccrual(const CBlockIndex* const pindex) Quorum::CurrentSuperblock()); } +bool Tally::FixNewbieSnapshotAccrual() +{ + g_newbie_snapshot_fix_enabled = true; + + return g_researcher_tally.RebuildAccrualSnapshots(); +} + bool Tally::IsLegacyTrigger(const uint64_t height) { return height % TALLY_GRANULARITY == 0; @@ -748,7 +794,7 @@ CBlockIndex* Tally::FindLegacyTrigger(CBlockIndex* pindex) return pindex; } -int64_t Tally::MaxEmission(const int64_t payment_time) +CAmount Tally::MaxEmission(const int64_t payment_time) { return NetworkTally::MaxEmission(payment_time) * COIN; } @@ -772,7 +818,7 @@ const ResearchAccount& Tally::GetAccount(const Cpid cpid) return g_researcher_tally.GetAccount(cpid); } -int64_t Tally::GetAccrual( +CAmount Tally::GetAccrual( const Cpid cpid, const int64_t payment_time, const CBlockIndex* const last_block_ptr) @@ -914,7 +960,7 @@ void Tally::LegacyRecount(const CBlockIndex* pindex) g_network_tally.ApplySuperblock(Quorum::CurrentSuperblock()); } - int64_t total_research_subsidy = 0; + CAmount total_research_subsidy = 0; while (pindex->nHeight > min_depth) { if (!pindex->pprev) { diff --git a/src/gridcoin/tally.h b/src/gridcoin/tally.h index ed550237d5..aed39d71a0 100644 --- a/src/gridcoin/tally.h +++ b/src/gridcoin/tally.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/account.h" #include "gridcoin/accrual/computer.h" @@ -52,6 +53,16 @@ class Tally //! static bool ActivateSnapshotAccrual(const CBlockIndex* const pindex); + //! + //! \brief Activate the fix for an issue that prevents new CPIDs from + //! accruing research rewards earlier than the latest superblock. + //! + //! \param pindex Index of the block to activate the fix for. + //! + //! \return \c false if an error occurs while resetting the snapshot system. + //! + static bool FixNewbieSnapshotAccrual(); + //! //! \brief Check whether the height of the specified block matches the //! tally granularity. @@ -78,7 +89,7 @@ class Tally //! //! \return Maximum daily emission in units of 1/100000000 GRC. //! - static int64_t MaxEmission(const int64_t payment_time); + static CAmount MaxEmission(const int64_t payment_time); //! //! \brief Get the current network magnitude unit. @@ -116,7 +127,7 @@ class Tally //! //! \return Research reward accrual in units of 1/100000000 GRC. //! - static int64_t GetAccrual( + static CAmount GetAccrual( const Cpid cpid, const int64_t payment_time, const CBlockIndex* const last_block_ptr); diff --git a/src/gridcoin/upgrade.cpp b/src/gridcoin/upgrade.cpp index 1d2780214f..f66f813c8c 100644 --- a/src/gridcoin/upgrade.cpp +++ b/src/gridcoin/upgrade.cpp @@ -10,14 +10,11 @@ #include #include #include -#include #include #include -#include #include #include -#include #include using namespace GRC; @@ -125,6 +122,7 @@ bool Upgrade::CheckForLatestUpdate(bool ui_dialog, std::string client_message_ou } bool NewVersion = false; + bool NewMandatory = false; try { // Left to right version numbers. @@ -135,7 +133,14 @@ bool Upgrade::CheckForLatestUpdate(bool ui_dialog, std::string client_message_ou break; if (std::stoi(GithubVersion[x]) > LocalVersion[x]) + { NewVersion = true; + + if (x < 2) + { + NewMandatory = true; + } + } } } catch (std::exception& ex) @@ -152,6 +157,11 @@ bool Upgrade::CheckForLatestUpdate(bool ui_dialog, std::string client_message_ou client_message_out.append(_("Github version: ") + GithubReleaseData + "\r\n"); client_message_out.append(_("This update is ") + GithubReleaseType + "\r\n\r\n"); + if (NewMandatory) + { + client_message_out.append(_("WARNING: A mandatory release is available. Please upgrade as soon as possible.\n")); + } + std::string ChangeLog = GithubReleaseBody; if (ui_dialog) @@ -298,7 +308,7 @@ bool Upgrade::VerifySHA256SUM() SHA256_CTX ctx; SHA256_Init(&ctx); - boost::filesystem::path fileloc = GetDataDir() / "snapshot.zip"; + fs::path fileloc = GetDataDir() / "snapshot.zip"; unsigned char *buffer[32768]; int bytesread = 0; @@ -338,31 +348,31 @@ bool Upgrade::VerifySHA256SUM() bool Upgrade::CleanupBlockchainData() { - boost::filesystem::path CleanupPath = GetDataDir(); + fs::path CleanupPath = GetDataDir(); // We must delete previous blockchain data // txleveldb // blk*.dat - boost::filesystem::directory_iterator IterEnd; + fs::directory_iterator IterEnd; try { // Remove the files. We iterate as we know blk* will exist more and more in future as well - for (boost::filesystem::directory_iterator Iter(CleanupPath); Iter != IterEnd; ++Iter) + for (fs::directory_iterator Iter(CleanupPath); Iter != IterEnd; ++Iter) { - if (boost::filesystem::is_directory(Iter->path())) + if (fs::is_directory(Iter->path())) { size_t DirLoc = Iter->path().string().find("txleveldb"); if (DirLoc != std::string::npos) - if (!boost::filesystem::remove_all(*Iter)) + if (!fs::remove_all(*Iter)) return false; continue; } - else if (boost::filesystem::is_regular_file(*Iter)) + else if (fs::is_regular_file(*Iter)) { size_t FileLoc = Iter->path().filename().string().find("blk"); @@ -371,7 +381,7 @@ bool Upgrade::CleanupBlockchainData() std::string filetocheck = Iter->path().filename().string(); // Check it ends with .dat and starts with blk if (filetocheck.substr(0, 3) == "blk" && filetocheck.substr(filetocheck.length() - 4, 4) == ".dat") - if (!boost::filesystem::remove(*Iter)) + if (!fs::remove(*Iter)) return false; } continue; @@ -379,7 +389,7 @@ bool Upgrade::CleanupBlockchainData() } } - catch (boost::filesystem::filesystem_error &ex) + catch (fs::filesystem_error &ex) { LogPrintf("Snapshot (CleanupBlockchainData): Exception occurred: %s", ex.what()); @@ -393,7 +403,7 @@ bool Upgrade::ExtractSnapshot() { std::string ArchiveFileString = GetDataDir().string() + "/snapshot.zip"; const char* ArchiveFile = ArchiveFileString.c_str(); - boost::filesystem::path ExtractPath = GetDataDir(); + fs::path ExtractPath = GetDataDir(); struct zip* ZipArchive; struct zip_file* ZipFile; struct zip_stat ZipStat; @@ -450,7 +460,7 @@ bool Upgrade::ExtractSnapshot() { // Does this require a directory if (ZipStat.name[strlen(ZipStat.name) - 1] == '/') - boost::filesystem::create_directory(ExtractPath / ZipStat.name); + fs::create_directory(ExtractPath / ZipStat.name); else { @@ -465,7 +475,7 @@ bool Upgrade::ExtractSnapshot() return false; } - boost::filesystem::path ExtractFileString = ExtractPath / ZipStat.name; + fs::path ExtractFileString = ExtractPath / ZipStat.name; FILE* ExtractFile = fsbridge::fopen(ExtractFileString, "wb"); @@ -540,14 +550,14 @@ void Upgrade::DeleteSnapshot() // File is out of scope now check if it exists and if so delete it. try { - boost::filesystem::path snapshotpath = GetDataDir() / "snapshot.zip"; + fs::path snapshotpath = GetDataDir() / "snapshot.zip"; - if (boost::filesystem::exists(snapshotpath)) - if (boost::filesystem::is_regular_file(snapshotpath)) - boost::filesystem::remove(snapshotpath); + if (fs::exists(snapshotpath)) + if (fs::is_regular_file(snapshotpath)) + fs::remove(snapshotpath); } - catch (boost::filesystem::filesystem_error& e) + catch (fs::filesystem_error& e) { LogPrintf("Snapshot Downloader: Exception occurred while attempting to delete snapshot (%s)", e.code().message()); } diff --git a/src/gridcoin/voting/builders.cpp b/src/gridcoin/voting/builders.cpp index c86343f321..21dc59cf06 100644 --- a/src/gridcoin/voting/builders.cpp +++ b/src/gridcoin/voting/builders.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "init.h" #include "main.h" #include "gridcoin/beacon.h" @@ -46,8 +47,8 @@ class AddressOutputs public: CKeyID m_key_id; //!< Address of the outputs. std::vector m_outpoints; //!< Outputs for the address. - std::vector m_amounts; //!< Amounts for each output. - int64_t m_total_amount; //!< Total amount of the outputs. + std::vector m_amounts; //!< Amounts for each output. + CAmount m_total_amount; //!< Total amount of the outputs. //! //! \brief Initialize an output address grouping. @@ -694,7 +695,7 @@ class PollClaimBuilder static bool TryTrimAddress(AddressOutputs& address) { std::vector& outpoints = address.m_outpoints; - std::vector& amounts = address.m_amounts; + std::vector& amounts = address.m_amounts; while (outpoints.size() > PollEligibilityClaim::MAX_OUTPOINTS) { address.m_total_amount -= amounts.back(); @@ -812,9 +813,9 @@ void SelectFinalInputs(CWallet& wallet, CWalletTx& tx) // contract.SharePayload().As().m_claim.ExpandDummySignatures(); - const int64_t burn_fee = contract.RequiredBurnAmount(); + const CAmount burn_fee = contract.RequiredBurnAmount(); CReserveKey reserve_key(&wallet); // unused - int64_t out_applied_fee; + CAmount out_applied_fee; if (!wallet.CreateTransaction( CScript() << OP_RETURN, @@ -833,58 +834,6 @@ void SelectFinalInputs(CWallet& wallet, CWalletTx& tx) tx.vin = std::move(mock_tx.vin); } - -//! -//! \brief Convert poll choice offsets into a string of labels for legacy votes. -//! -//! \param poll Supplies the choice labels for the legacy string. -//! \param vote Contains the responses to convert into the legacy string. -//! -//! \return A semicolon-delimited string of poll choice labels that match the -//! choices selected for the vote. -//! -std::string MakeLegacyResponsesString(const Poll& poll, const Vote& vote) -{ - std::string out; - auto offset_iter = vote.m_responses.begin(); - - if (offset_iter != vote.m_responses.end()) { - out += poll.Choices().At(*offset_iter)->m_label; - ++offset_iter; - } - - for (; offset_iter != vote.m_responses.end(); ++offset_iter) { - out += ";"; - out += poll.Choices().At(*offset_iter)->m_label; - ++offset_iter; - } - - return out; -} - -//! -//! \brief Convert a vote object into a legacy vote contract. -//! -//! \param wallet Supplies the voter's current GRC balance. -//! \param poll Supplies string elements for the legacy contract. -//! \param vote The vote to convert into a legacy vote contract. -//! -//! \return A contract object with a legacy vote payload for submission in a -//! transaction. -//! -Contract MakeLegacyVote(const CWallet& wallet, const Poll& poll, const Vote& vote) -{ - const ResearcherPtr researcher = Researcher::Get(); - const MiningId mining_id = researcher->Id(); - - return MakeContract( - ContractAction::ADD, - poll.m_title + ";" + DefaultWalletAddress() + ";" + mining_id.ToString(), - mining_id, - (wallet.GetBalance() + wallet.GetStake()) / COIN, - researcher->Magnitude().Floating(), - MakeLegacyResponsesString(poll, vote)); -} } // Anonymous namespace // ----------------------------------------------------------------------------- @@ -1000,10 +949,16 @@ PollBuilder PollBuilder::SetDuration(const uint32_t days) std::to_string(Poll::MIN_DURATION_DAYS))); } - if (days > Poll::MAX_DURATION_DAYS) { + // The protocol allows poll durations up to 180 days. To limit unhelpful + // or unintentional poll durations, user-facing pieces discourage a poll + // longer than: + // + constexpr uint32_t max_duration_days = 90; + + if (days > max_duration_days) { throw VotingError(strprintf( _("Poll duration cannot exceed %s days."), - std::to_string(Poll::MAX_DURATION_DAYS))); + std::to_string(max_duration_days))); } m_poll->m_duration_days = days; @@ -1270,14 +1225,6 @@ CWalletTx VoteBuilder::BuildContractTx(CWallet* const pwallet) CWalletTx tx; - // Unlike other contract types, legacy vote contracts cannot be transformed - // into the corresponding binary format in block version 11+: - // - if (!IsV11Enabled(nBestHeight + 1)) { - tx.vContracts.emplace_back(MakeLegacyVote(*pwallet, *m_poll, *m_vote)); - return tx; - } - const VoteClaimBuilder claim_builder(*pwallet, Researcher::Get()); claim_builder.BuildClaim(*m_vote, *m_poll); diff --git a/src/gridcoin/voting/claims.h b/src/gridcoin/voting/claims.h index 8bfa230522..6ca988eb02 100644 --- a/src/gridcoin/voting/claims.h +++ b/src/gridcoin/voting/claims.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "key.h" #include "gridcoin/cpid.h" #include "gridcoin/magnitude.h" @@ -88,7 +89,7 @@ class AddressClaim //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const + CAmount RequiredBurnAmount() const { // 0.001 GRC per claimed UTXO: return m_outpoints.size() * COIN / 1000; @@ -182,9 +183,9 @@ class BalanceClaim //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const + CAmount RequiredBurnAmount() const { - int64_t amount = 0; + CAmount amount = 0; for (const auto& claim : m_address_claims) { // 0.01 per address + a scaled fee based on the number of outputs: @@ -246,7 +247,7 @@ class MagnitudeClaim //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const + CAmount RequiredBurnAmount() const { if (m_mining_id.Which() == MiningId::Kind::CPID) { // Flat 0.01 GRC: @@ -351,7 +352,7 @@ class PollEligibilityClaim //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const + CAmount RequiredBurnAmount() const { // A scaled fee based on the number of claimed outputs: return m_address_claim.RequiredBurnAmount(); @@ -420,7 +421,7 @@ class VoteWeightClaim //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const + CAmount RequiredBurnAmount() const { return m_magnitude_claim.RequiredBurnAmount() + m_balance_claim.RequiredBurnAmount(); diff --git a/src/gridcoin/voting/fwd.h b/src/gridcoin/voting/fwd.h index 7c63391dd2..3b86ba190a 100644 --- a/src/gridcoin/voting/fwd.h +++ b/src/gridcoin/voting/fwd.h @@ -4,6 +4,8 @@ #pragma once +#include "amount.h" + #include namespace GRC { @@ -19,7 +21,7 @@ using PollResultOption = boost::optional; //! //! \brief The unspent amount that a poll creator must hold in an address. //! -constexpr int64_t POLL_REQUIRED_BALANCE = 100000 * COIN; +constexpr CAmount POLL_REQUIRED_BALANCE = 100000 * COIN; //! //! \brief The maximum number of choices that a poll can contain. diff --git a/src/gridcoin/voting/payloads.h b/src/gridcoin/voting/payloads.h index 4c79c74928..3086ace2cb 100644 --- a/src/gridcoin/voting/payloads.h +++ b/src/gridcoin/voting/payloads.h @@ -126,7 +126,7 @@ class PollPayload : public IContractPayload //! std::string LegacyValueString() const override { - return m_poll.ToString(); + return std::string(); // Legacy serialization removed } //! @@ -134,7 +134,7 @@ class PollPayload : public IContractPayload //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { // 50 GRC + a scaled fee based on the number of claimed outputs: return (50 * COIN) + m_claim.RequiredBurnAmount(); diff --git a/src/gridcoin/voting/poll.cpp b/src/gridcoin/voting/poll.cpp index 026f7482f4..364b44dbcc 100644 --- a/src/gridcoin/voting/poll.cpp +++ b/src/gridcoin/voting/poll.cpp @@ -74,19 +74,6 @@ Poll::ChoiceList ParseChoices(const std::string& value) return choices; } -//! -//! \brief Format the poll expiration timestamp for a legacy poll contract. -//! -//! \param poll The poll object to generate the expiration timestamp for. -//! -//! \return The string representation of the timestamp in seconds at which the -//! poll expires suitable for the "" field of a legacy contract. -//! -std::string FormatLegacyExpiration(const Poll& poll) -{ - return std::to_string(poll.m_timestamp + (poll.m_duration_days * 86400)); -} - //! //! \brief Poll choices to return for polls with a yes/no/abstain response type. //! @@ -220,17 +207,6 @@ const Poll::ChoiceList& Poll::Choices() const return m_choices; } -std::string Poll::ToString() const -{ - return "" + m_title + "" - + "" + std::to_string(m_duration_days) + "" - + "" + m_question + "" - + "" + m_choices.ToString() + "" - + "" + std::to_string(m_weight_type.Raw()) + "" - + "" + m_url + "" - + "" + FormatLegacyExpiration(*this) + ""; -} - std::string Poll::WeightTypeToString() const { switch (m_weight_type.Value()) { @@ -329,21 +305,3 @@ void ChoiceList::Add(std::string label) { m_choices.emplace_back(std::move(label)); } - -std::string ChoiceList::ToString() const -{ - std::string out; - auto iter = m_choices.begin(); - - if (iter != m_choices.end()) { - out += iter->m_label; - ++iter; - } - - for (; iter != m_choices.end(); ++iter) { - out += ";"; - out += iter->m_label; - } - - return out; -} diff --git a/src/gridcoin/voting/poll.h b/src/gridcoin/voting/poll.h index 6e271f0973..4ed774f7a8 100644 --- a/src/gridcoin/voting/poll.h +++ b/src/gridcoin/voting/poll.h @@ -186,14 +186,6 @@ class Poll //! void Add(std::string label); - //! - //! \brief Get the legacy string representation of the choices for the - //! poll. - //! - //! \return The poll choice labels as a semicolon-delimited string. - //! - std::string ToString() const; - ADD_SERIALIZE_METHODS; template @@ -320,13 +312,6 @@ class Poll //! const ChoiceList& Choices() const; - //! - //! \brief Get the legacy string representation of a version 1 poll contract. - //! - //! \return Poll data in the legacy, XML-like string format. - //! - std::string ToString() const; - //! //! \brief Get the string representation of the poll's weight type. //! diff --git a/src/gridcoin/voting/registry.cpp b/src/gridcoin/voting/registry.cpp index 00a5d13dce..5345e2e743 100644 --- a/src/gridcoin/voting/registry.cpp +++ b/src/gridcoin/voting/registry.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "main.h" #include "gridcoin/contract/contract.h" #include "gridcoin/voting/payloads.h" @@ -107,7 +108,7 @@ class PollClaimValidator } const CTxDestination address = claim.m_public_key.GetID(); - int64_t amount = 0; + CAmount amount = 0; for (const auto& txo : claim.m_outpoints) { amount += Resolve(txo, address); diff --git a/src/gridcoin/voting/result.cpp b/src/gridcoin/voting/result.cpp index 82cc444e22..bfa05600d2 100644 --- a/src/gridcoin/voting/result.cpp +++ b/src/gridcoin/voting/result.cpp @@ -284,9 +284,9 @@ class VoteResolver //! //! \return Claimed amount in units of 1/100000000 GRC. //! - int64_t Resolve(const BalanceClaim& claim, const ClaimMessage& message) + CAmount Resolve(const BalanceClaim& claim, const ClaimMessage& message) { - int64_t amount = 0; + CAmount amount = 0; for (const auto& address_claim : claim.m_address_claims) { amount += Resolve(address_claim, message); @@ -306,7 +306,7 @@ class VoteResolver //! \throws InvalidVoteError If the vote fails to validate or if an IO //! error occurs. //! - int64_t Resolve(const AddressClaim& claim, const ClaimMessage& message) + CAmount Resolve(const AddressClaim& claim, const ClaimMessage& message) { if (!claim.VerifySignature(message)) { LogPrint(LogFlags::VOTE, "%s: bad address signature", __func__); @@ -314,7 +314,7 @@ class VoteResolver } const CTxDestination address = claim.m_public_key.GetID(); - int64_t amount = 0; + CAmount amount = 0; for (const auto& txo : claim.m_outpoints) { amount += Resolve(txo, address); @@ -334,7 +334,7 @@ class VoteResolver //! \throws InvalidVoteError If the vote fails to validate or if an IO //! error occurs. //! - int64_t Resolve(const COutPoint& txo, const CTxDestination& address) + CAmount Resolve(const COutPoint& txo, const CTxDestination& address) { if (m_seen_txos.find(txo) != m_seen_txos.end()) { LogPrint(LogFlags::VOTE, "%s: duplicate txo", __func__); @@ -447,10 +447,10 @@ class VoteResolver //! \throws InvalidVoteError If the vote fails to validate or if an IO //! error occurs. //! - int64_t ResolveAmount( + CAmount ResolveAmount( const CTxDestination& address, const CDiskTxPos& disk_pos, - int64_t amount) + CAmount amount) { // Although this routine could make a nice recursive algorithm, we need // to ensure that it won't overflow the stack. Instead, we implement an @@ -461,9 +461,9 @@ class VoteResolver struct TxoFrame { CDiskTxPos m_pos; - int64_t m_amount; + CAmount m_amount; - TxoFrame(const CDiskTxPos pos, int64_t amount) + TxoFrame(const CDiskTxPos pos, CAmount amount) : m_pos(pos), m_amount(amount) { } @@ -529,7 +529,7 @@ class VoteResolver const uint256 tx_hash = tx.GetHash(); // Intermediate mapping of output offsets to amounts: - std::vector> next_txos; + std::vector> next_txos; // Find outputs for the same address: for (uint32_t i = 0; i < tx.vout.size(); ++i) { @@ -1024,7 +1024,7 @@ SuperblockPtr ResolveSuperblockForPoll(const Poll& poll) //! \return Money supply as of the last block in the poll window in units of //! 1/100000000 GRC. //! -int64_t ResolveMoneySupplyForPoll(const Poll& poll) +CAmount ResolveMoneySupplyForPoll(const Poll& poll) { if (!poll.Expired(pindexBest->nTime)) { return pindexBest->nMoneySupply; diff --git a/src/gridcoin/voting/vote.cpp b/src/gridcoin/voting/vote.cpp index 2b2bfe3c9b..51797a9b6b 100644 --- a/src/gridcoin/voting/vote.cpp +++ b/src/gridcoin/voting/vote.cpp @@ -83,21 +83,3 @@ LegacyVote::ParseResponses(const std::map& choice_map) con return responses; } - -std::string LegacyVote::ToString() const -{ - const auto round_to_string = [](const double value) { - return std::to_string(std::nearbyint(value)); - }; - - const std::vector parts = split(m_key, ";"); - const std::string title = parts.size() >= 1 ? parts[0] : ""; - const std::string address = parts.size() >= 2 ? parts[1] : ""; - - return "" + title + "" - + "" + m_responses + "" - + "" + m_mining_id.ToString() + "" - + "" + address + "" - + "" + round_to_string(m_amount) + "" - + "" + round_to_string(m_magnitude) + ""; -} diff --git a/src/gridcoin/voting/vote.h b/src/gridcoin/voting/vote.h index 71c8349d35..f71f32c458 100644 --- a/src/gridcoin/voting/vote.h +++ b/src/gridcoin/voting/vote.h @@ -4,6 +4,7 @@ #pragma once +#include "amount.h" #include "gridcoin/contract/payload.h" #include "gridcoin/voting/claims.h" #include "serialize.h" @@ -140,7 +141,7 @@ class Vote : public IContractPayload //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { // 0.01 GRC for the vote contract + the scaled claim fee: return (COIN / 100) + m_claim.RequiredBurnAmount(); @@ -268,28 +269,16 @@ class LegacyVote : public IContractPayload //! std::string LegacyValueString() const override { - return ToString(); + return std::string(); // Legacy serialization removed } - //! - //! \brief Get the string representation of a legacy vote. - //! - //! \return XML-like string of a vote contract for a legacy contract. - //! - std::string ToString() const; - //! //! \brief Get the burn fee amount required to send a particular contract. //! //! \return Burn fee in units of 1/100000000 GRC. //! - int64_t RequiredBurnAmount() const override + CAmount RequiredBurnAmount() const override { - // TODO: remove redefinition of this constant when porting amount.h - // from Bitcoin: - // - constexpr int64_t MAX_MONEY = 2000000000 * COIN; - // Prevent users from sending this contract manually: return MAX_MONEY; } diff --git a/src/gridcoinresearchd.cpp b/src/gridcoinresearchd.cpp index d65f6d2370..89c7c42dc5 100644 --- a/src/gridcoinresearchd.cpp +++ b/src/gridcoinresearchd.cpp @@ -90,7 +90,7 @@ bool AppInit(int argc, char* argv[]) return false; } - if (!boost::filesystem::is_directory(GetDataDir(false))) + if (!fs::is_directory(GetDataDir(false))) { fprintf(stderr, "Error: Specified directory does not exist\n"); Shutdown(NULL); diff --git a/src/init.cpp b/src/init.cpp index 4828613e02..4fd7cbb045 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -16,9 +16,6 @@ #include "scheduler.h" #include "gridcoin/gridcoin.h" -#include -#include -#include #include #include @@ -37,7 +34,6 @@ bool IsConfigFileEmpty(); #endif using namespace std; -using namespace boost; CWallet* pwalletMain; CClientUIInterface uiInterface; extern bool fQtActive; @@ -107,10 +103,8 @@ void Shutdown(void* parg) bitdb.Flush(false); StopNode(); bitdb.Flush(true); - StopRPCThreads(); - - boost::filesystem::remove(GetPidFile()); + fs::remove(GetPidFile()); UnregisterWallet(pwalletMain); delete pwalletMain; // close transaction database to prevent lock issue on restart @@ -290,6 +284,13 @@ std::string HelpMessage() " -blockmaxsize= " + _("Set maximum block size in bytes (default: 250000)") + "\n" + " -blockprioritysize= " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n" + + "\n" + _("Research reward system options:") + "\n" + + " -email= " + _("Email address to use for CPID detection. Must match your BOINC account email") + "\n" + + " -boincdatadir= " + _("Path to the BOINC data directory for CPID detection when the BOINC client uses a non-default directory") + "\n" + + " -forcecpid= " + _("Override automatic CPID detection with the specified CPID") + "\n" + + " -investor " + _("Disable CPID detection and do not participate in the research reward system") + "\n" + + " -pooloperator " + _("Skip pool CPID checks for staking nodes run by pool administrators") + "\n" + + "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" + " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" + " -rpcsslcertificatechainfile= " + _("Server certificate file (default: server.cert)") + "\n" + @@ -739,7 +740,7 @@ bool AppInit2(ThreadHandlerPtr threads) return false; } - if (filesystem::exists(GetDataDir() / walletFileName)) + if (fs::exists(GetDataDir() / walletFileName)) { CDBEnv::VerifyResult r = bitdb.Verify(walletFileName.string(), CWalletDB::Recover); if (r == CDBEnv::RECOVER_OK) @@ -1042,13 +1043,13 @@ bool AppInit2(ThreadHandlerPtr threads) exit(0); } - filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat"; - if (filesystem::exists(pathBootstrap)) { + fs::path pathBootstrap = GetDataDir() / "bootstrap.dat"; + if (fs::exists(pathBootstrap)) { uiInterface.InitMessage(_("Importing bootstrap blockchain data file.")); FILE *file = fsbridge::fopen(pathBootstrap, "rb"); if (file) { - filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; + fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LoadExternalBlockFile(file); RenameOver(pathBootstrap, pathBootstrapOld); } @@ -1080,6 +1081,8 @@ bool AppInit2(ThreadHandlerPtr threads) RandAddSeedPerfmon(); + GRC::Initialize(threads, pindexBest); + //// debug print if (LogInstance().WillLogCategory(BCLog::LogFlags::VERBOSE)) { diff --git a/src/logging.cpp b/src/logging.cpp index d7befa462f..50532a42be 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/src/main.cpp b/src/main.cpp index d8478a572e..0db17aed89 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "util.h" #include "net.h" #include "streams.h" @@ -134,7 +135,6 @@ bool fUseFastIndex = false; // 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 @@ -374,54 +374,6 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) return nEvicted; } - - -std::string DefaultWalletAddress() -{ - static std::string sDefaultWalletAddress; - if (!sDefaultWalletAddress.empty()) - return sDefaultWalletAddress; - - try - { - //Gridcoin - Find the default public GRC address (since a user may have many receiving addresses): - for (auto const& item : pwalletMain->mapAddressBook) - { - const CBitcoinAddress& address = item.first; - const std::string& strName = item.second; - isminetype fMine = IsMine(*pwalletMain, address.Get()); - if ((fMine != ISMINE_NO) && strName == "Default") - { - sDefaultWalletAddress=CBitcoinAddress(address).ToString(); - return sDefaultWalletAddress; - } - } - - //Can't Find - for (auto const& item : pwalletMain->mapAddressBook) - { - const CBitcoinAddress& address = item.first; - //const std::string& strName = item.second; - isminetype fMine = IsMine(*pwalletMain, address.Get()); - if (fMine != ISMINE_NO) - { - sDefaultWalletAddress=CBitcoinAddress(address).ToString(); - return sDefaultWalletAddress; - } - } - } - catch (std::exception& e) - { - return "ERROR"; - } - return "NA"; -} - - - - - - ////////////////////////////////////////////////////////////////////////////// // // CTransaction and CTxIndex @@ -756,7 +708,7 @@ bool CTransaction::CheckContracts(const MapPrevTx& inputs) const return DoS(100, error("%s: legacy contract", __func__)); } - if (!contract.Validate()) { + if (!contract.WellFormed()) { return DoS(100, error("%s: malformed contract", __func__)); } @@ -877,23 +829,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CTransaction &tx, bool* pfMissingInput *pfMissingInputs = false; // Mandatory switch to binary contracts (tx version 2): - if (IsV11Enabled(nBestHeight + 1) && tx.nVersion < 2) { - // Disallow tx version 1 after the mandatory block to prohibit the - // use of legacy string contracts: + if (tx.nVersion < 2) { return tx.DoS(100, error("AcceptToMemoryPool : legacy transaction")); } - // Reject version 2 transactions until mandatory threshold. - // - // CTransaction::CURRENT_VERSION is now 2, but we cannot send version 2 - // transactions with binary contracts until clients can handle them. - // - // TODO: remove this check in the next release after mandatory block. - // - if (!IsV11Enabled(nBestHeight + 1) && tx.nVersion > 1) { - return error("AcceptToMemoryPool : v2 transaction too early"); - } - if (!tx.CheckTransaction()) return error("AcceptToMemoryPool : CheckTransaction failed"); @@ -1124,22 +1063,6 @@ void CTxMemPool::queryHashes(std::vector& vtxid) vtxid.push_back((*mi).first); } -void CTxMemPool::DiscardVersion1() -{ - LOCK(cs); - - // Recursively remove all version 1 transactions from the memory pool for - // the switch to transaction version 2 at the block version 11 threshold: - // - for (const auto& tx_pair : mapTx) { - if (tx_pair.second.nVersion == 1) { - remove(tx_pair.second, true); - } - } -} - - - int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const { if (hashBlock.IsNull() || nIndex == -1) @@ -2302,8 +2225,16 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) } // Validate any contracts published in the transaction: - if (!tx.GetContracts().empty() && !tx.CheckContracts(mapInputs)) { - return false; + if (!tx.GetContracts().empty()) { + if (!tx.CheckContracts(mapInputs)) { + return false; + } + + if (nVersion >= 11 && !GRC::ValidateContracts(tx)) { + return tx.DoS(25, error("%s: invalid contract in tx %s", + __func__, + tx.GetHash().ToString())); + } } if (!tx.ConnectInputs(txdb, mapInputs, mapQueuedChanges, posThisTx, pindex, true, false)) @@ -2514,7 +2445,7 @@ bool ReorganizeChain(CTxDB& txdb, unsigned &cnt_dis, unsigned &cnt_con, CBlock & // Blocks version 11+ do not use the legacy tally system triggered by // block height intervals: // - if (!IsV11Enabled(pcommon->nHeight) && pcommon != pindexBest) + if (pcommon->nVersion <= 10 && pcommon != pindexBest) { pcommon = GRC::Tally::FindLegacyTrigger(pcommon); if(!pcommon) @@ -3024,29 +2955,9 @@ bool CBlock::AcceptBlock(bool generated_by_me) return DoS(100, error("%s: legacy transaction", __func__)); } - // Reject version 2 transactions until mandatory threshold. - // - // CTransaction::CURRENT_VERSION is now 2, but we cannot send version 2 - // transactions with binary contracts until clients can handle them. - // - // TODO: remove this check in the next release after mandatory block. - // - if (nVersion <= 10 && tx.nVersion > 1) { - return DoS(100, error("%s: v2 transaction too early", __func__)); - } - // Check that all transactions are finalized if (!IsFinalTx(tx, nHeight, GetBlockTime())) return DoS(10, error("AcceptBlock() : contains a non-final transaction")); - - if (nVersion >= 9) { - // Perform contextual validation for any contracts: - if (!tx.GetContracts().empty() && !GRC::ValidateContracts(tx)) { - return tx.DoS(25, error("%s: invalid contract in tx %s", - __func__, - tx.GetHash().ToString())); - } - } } // Check that the block chain matches the known block chain up to a checkpoint @@ -3171,12 +3082,6 @@ bool GridcoinServices() return error("GridcoinServices: Failed to prepare tally for v11."); } - // Remove all version 1 transactions from the memory pool for the - // switch to transaction version 2 to prevent nodes from relaying - // legacy transactions that cannot validate: - // - mempool.DiscardVersion1(); - // Set the timestamp for the block version 11 threshold. This // is temporary. Remove this variable in a release that comes // after the hard fork. @@ -3184,6 +3089,19 @@ bool GridcoinServices() g_v11_timestamp = pindexBest->nTime; } + // Fix ability for new CPIDs to accrue research rewards earlier than one + // superblock. + // + // A bug in the snapshot accrual system for block version 11+ requires a + // consensus change to fix. This activates the solution at the following + // height: + // + if (nBestHeight + 1 == GetNewbieSnapshotFixHeight()) { + if (!GRC::Tally::FixNewbieSnapshotAccrual()) { + return error("%s: Failed to fix newbie snapshot accrual", __func__); + } + } + return true; } @@ -3370,7 +3288,7 @@ bool CBlock::CheckBlockSignature() const bool CheckDiskSpace(uint64_t nAdditionalBytes) { - uint64_t nFreeBytesAvailable = filesystem::space(GetDataDir()).available; + uint64_t nFreeBytesAvailable = fs::space(GetDataDir()).available; // Check for nMinDiskSpace bytes (currently 50MB) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) @@ -3386,7 +3304,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes) return true; } -static filesystem::path BlockFilePath(unsigned int nFile) +static fs::path BlockFilePath(unsigned int nFile) { string strBlockFn = strprintf("blk%04u.dat", nFile); return GetDataDir() / strBlockFn; @@ -3452,11 +3370,6 @@ bool LoadBlockIndex(bool fAllowNew) nNewIndex2 = 36500; //1-24-2016 MAX_OUTBOUND_CONNECTIONS = (int)GetArg("-maxoutboundconnections", 8); - - // Temporary transition to version 2 beacons after the block version 11 - // hard-fork: - // - g_v11_legacy_beacon_days = 7; } LogPrintf("Mode=%s", fTestNet ? "TestNet" : "Prod"); @@ -3843,6 +3756,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fDisconnect = true; return false; } + else if (pfrom->nVersion < PROTOCOL_VERSION && nBestHeight > GetNewbieSnapshotFixHeight() + 2000) + { + // Immediately disconnect peers running a protocol version lower than + // the latest hard-fork after a grace period for the transition. + // + // TODO: increment MIN_PEER_PROTO_VERSION and remove this condition in + // the release that follows the mandatory version: + // + LogPrint(BCLog::LogFlags::NOISY, "Disconnecting forked peer protocol version %i: %s", pfrom->nVersion, pfrom->addr.ToString()); + pfrom->fDisconnect = true; + return false; + } if (!vRecv.empty()) vRecv >> addrFrom >> nNonce; @@ -4135,15 +4060,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CBlock block; block.ReadFromDisk((*mi).second); - // TODO: drop legacy "command nonce" removal transition in the next - // release after the mandatory version: - // - if (pfrom->nVersion >= PROTOCOL_VERSION) { - pfrom->PushMessage("encrypt", block); - } else { - std::string acid; - pfrom->PushMessage("encrypt", block, acid); - } + pfrom->PushMessage("encrypt", block); // Trigger them to send a getblocks request for the next batch of inventory if (inv.hash == pfrom->hashContinue) @@ -4369,14 +4286,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CBlock block; vRecv >> block; - // TODO: drop legacy "command nonce" removal transition in the next - // release after the mandatory version: - // - if (pfrom->nVersion < PROTOCOL_VERSION) { - std::string acid; - vRecv >> acid; - } - uint256 hashBlock = block.GetHash(true); LogPrintf(" Received block %s; ", hashBlock.ToString()); @@ -4453,14 +4362,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint64_t nonce = 0; vRecv >> nonce; - // TODO: drop legacy "command nonce" removal transition in the next - // release after the mandatory version: - // - if (pfrom->nVersion < PROTOCOL_VERSION) { - std::string acid; - vRecv >> acid; - } - // Echo the message back with the nonce. This allows for two useful features: // // 1) A remote node can quickly check if the connection is operational @@ -4753,15 +4654,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) pto->nPingUsecStart = GetTimeMicros(); pto->nPingNonceSent = nonce; - // TODO: drop legacy "command nonce" removal transition in the next - // release after the mandatory version: - // - if (pto->nVersion >= PROTOCOL_VERSION) { - pto->PushMessage("ping", nonce); - } else { - std::string acid; - pto->PushMessage("ping", nonce, acid); - } + pto->PushMessage("ping", nonce); } // Resend wallet transactions that haven't gotten in a block yet diff --git a/src/main.h b/src/main.h index d1837efc0d..0f8c299ec4 100644 --- a/src/main.h +++ b/src/main.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_MAIN_H #define BITCOIN_MAIN_H +#include "amount.h" #include "arith_uint256.h" #include "chainparams.h" #include "consensus/consensus.h" @@ -42,9 +43,7 @@ typedef boost::optional ClaimOption; } static const int64_t DEFAULT_CBR = 10 * COIN; -/** 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); } + /** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */ static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC @@ -148,9 +147,6 @@ bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); void ResendWalletTransactions(bool fForce = false); - -std::string DefaultWalletAddress(); - bool OutOfSyncByAge(); /** (try to) add transaction to memory pool **/ @@ -1836,7 +1832,6 @@ class CTxMemPool bool removeConflicts(const CTransaction &tx); void clear(); void queryHashes(std::vector& vtxid); - void DiscardVersion1(); unsigned long size() const { diff --git a/src/miner.cpp b/src/miner.cpp index b70ef68e89..682ff4e97f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -4,6 +4,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "txdb.h" #include "miner.h" #include "main.h" @@ -262,10 +263,6 @@ bool CreateRestOfTheBlock(CBlock &block, CBlockIndex* pindexPrev) assert(CoinBase.vin[0].scriptSig.size() <= 100); CoinBase.vout[0].SetEmpty(); - if (block.nVersion <= 10) { - CoinBase.nVersion = 1; // TODO: remove after mandatory - } - // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: @@ -560,10 +557,6 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key, int64_t StakeWeightMax=0; CTransaction &txnew = blocknew.vtx[1]; // second tx is coinstake - if (blocknew.nVersion <= 10) { - txnew.nVersion = 1; // TODO: remove after mandatory - } - //initialize the transaction txnew.nTime = blocknew.nTime & (~GRC::STAKE_TIMESTAMP_MASK); txnew.vin.clear(); @@ -951,14 +944,6 @@ bool SignStakeBlock(CBlock &block, CKey &key, vector &StakeInp return error("%s: failed to sign claim", __func__); } - // Stringify the claim context for legacy blocks. Version 11+ store claims - // in binary format. - // - if (block.nVersion <= 10) { - block.vtx[0].hashBoinc = block.GetClaim().ToString(block.nVersion); - block.vtx[0].vContracts.clear(); - } - //Sign the whole block block.hashMerkleRoot = block.BuildMerkleTree(); if( !key.Sign(block.GetHash(), block.vchBlockSig) ) @@ -981,72 +966,18 @@ void AddSuperblockContractOrVote(CBlock& blocknew) return; } - if (GRC::Quorum::HasPendingSuperblock()) { - LogPrintf("AddSuperblockContractOrVote: Already pending."); - return; - } - - if (blocknew.nVersion >= 11) { - GRC::Superblock superblock = GRC::Quorum::CreateSuperblock(); - - if (!superblock.WellFormed()) { - LogPrintf("AddSuperblockContractOrVote: Local contract empty."); - return; - } - - // TODO: fix the const cast: - GRC::Claim& claim = const_cast(blocknew.GetClaim()); - - claim.m_quorum_hash = superblock.GetHash(); - claim.m_superblock.Replace(std::move(superblock)); - - LogPrintf( - "AddSuperblockContractOrVote: Added our Superblock (size %" PRIszu ").", - GetSerializeSize(claim.m_superblock, SER_NETWORK, 1)); - - return; - } - - // TODO: remove the rest below after switch to block version 11: - - std::string quorum_address = DefaultWalletAddress(); + GRC::Superblock superblock = GRC::Quorum::CreateSuperblock(); - if (!GRC::Quorum::Participating(quorum_address, blocknew.nTime)) { - LogPrintf("AddSuperblockContractOrVote: Not participating."); + if (!superblock.WellFormed()) { + LogPrintf("AddSuperblockContractOrVote: Local contract empty."); return; } // TODO: fix the const cast: GRC::Claim& claim = const_cast(blocknew.GetClaim()); - // Add our superblock vote - // - // CreateSuperblock() will return an empty superblock when the node has not - // yet received enough scraper data to resolve a convergence locally, so it - // cannot vote for a superblock. - // - claim.m_quorum_hash = GRC::Quorum::CreateSuperblock().GetHash(); - - if (!claim.m_quorum_hash.Valid()) { - LogPrintf("AddSuperblockContractOrVote: Local contract empty."); - return; - } - - claim.m_quorum_address = std::move(quorum_address); - - LogPrintf( - "AddSuperblockContractOrVote: Added our quorum vote: %s", - claim.m_quorum_hash.ToString()); - - const GRC::QuorumHash consensus_hash = GRC::Quorum::FindPopularHash(pindexBest); - - if (claim.m_quorum_hash != consensus_hash) { - LogPrintf("AddSuperblockContractOrVote: Not in consensus."); - return; - } - - // We have consensus, add our superblock contract: - claim.m_superblock.Replace(GRC::Quorum::CreateSuperblock()); + claim.m_quorum_hash = superblock.GetHash(); + claim.m_superblock.Replace(std::move(superblock)); LogPrintf( "AddSuperblockContractOrVote: Added our Superblock (size %" PRIszu ").", @@ -1068,11 +999,6 @@ bool CreateGridcoinReward( GRC::Claim claim; claim.m_mining_id = researcher->Id(); - // Ensure that we sign claims with the legacy hash before block version 11: - if (blocknew.nVersion <= 10) { - claim.m_version = 1; - } - // If a researcher's beacon expired, generate the block as an investor. We // cannot sign a research claim without the beacon key, so this avoids the // issue that prevents a researcher from staking blocks if the beacon does @@ -1092,11 +1018,7 @@ bool CreateGridcoinReward( nReward += nFees; if (const GRC::CpidOption cpid = claim.m_mining_id.TryCpid()) { - CBlockIndex index; - index.nVersion = blocknew.nVersion; - index.nHeight = pindexPrev->nHeight + 1; - - claim.m_research_subsidy = GRC::Tally::GetAccrual(*cpid, blocknew.nTime, &index); + claim.m_research_subsidy = GRC::Tally::GetAccrual(*cpid, blocknew.nTime, pindexPrev); // If no pending research subsidy value exists, build an investor claim. // This avoids polluting the block index with non-research reward blocks @@ -1118,10 +1040,6 @@ bool CreateGridcoinReward( claim.m_client_version = FormatFullVersion().substr(0, GRC::Claim::MAX_VERSION_SIZE); claim.m_organization = GetArgument("org", "").substr(0, GRC::Claim::MAX_ORGANIZATION_SIZE); - if (blocknew.nVersion <= 10) { - claim.m_magnitude_unit = GRC::Tally::GetMagnitudeUnit(pindexPrev); - } - // Do a dry run for the claim signature to ensure that we can sign for a // researcher claim. We generate the final signature when signing all of // the block: @@ -1143,14 +1061,6 @@ bool CreateGridcoinReward( FormatMoney(claim.m_research_subsidy), FormatMoney(claim.m_block_subsidy)); - // Nodes that do not yet support block version 11 will parse the claim - // from the coinbase hashBoinc field. Set the previous block hash that - // old nodes check for research reward claims if necessary: - // - if (blocknew.nVersion <= 10 && claim.HasResearchReward()) { - claim.m_last_block_hash = blocknew.hashPrevBlock; - } - blocknew.vtx[0].vContracts.emplace_back(GRC::MakeContract( GRC::ContractAction::ADD, std::move(claim))); @@ -1345,14 +1255,6 @@ void StakeMiner(CWallet *pwallet) //clear miner messages g_miner_status.ClearReasonsNotStaking(); - - //New versions - if (IsV11Enabled(pindexPrev->nHeight + 1)) { - StakeBlock.nVersion = 11; - } else { - StakeBlock.nVersion = 10; - } - g_miner_status.Version = StakeBlock.nVersion; // This is needed due to early initialization of bitcoingui diff --git a/src/net.cpp b/src/net.cpp index 4bf65e8e32..2918ca2f68 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -13,7 +13,6 @@ #include "init.h" #include "ui_interface.h" #include "util.h" -#include "gridcoin/gridcoin.h" #include // for to_lower() #include @@ -729,39 +728,17 @@ void CNode::PushVersion() LogPrint(BCLog::LogFlags::NOISY, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), addr.ToString()); - // In the version following 180324 (mandatory v5.0.0 - Fern), we can finally - // drop the garbage legacy fields added to the version message: - // - if (PROTOCOL_VERSION > 180324) { - //TODO: change `PushMessage()` to use ServiceFlags so we don't need to cast nLocalServices - PushMessage( - "aries", - PROTOCOL_VERSION, - (uint64_t)nLocalServices, - nTime, - addrYou, - addrMe, - nLocalHostNonce, - FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), - nBestHeight); - } else { - const std::string legacy_dummy; - PushMessage( - "aries", - PROTOCOL_VERSION, - legacy_dummy, // nonce - legacy_dummy, // pw1 - legacy_dummy, // mycpid - legacy_dummy, // enccpid - legacy_dummy, // acid - (uint64_t)nLocalServices, - nTime, - addrYou, - addrMe, - nLocalHostNonce, - FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), - nBestHeight); - } + //TODO: change `PushMessage()` to use ServiceFlags so we don't need to cast nLocalServices + PushMessage( + "aries", + PROTOCOL_VERSION, + (uint64_t)nLocalServices, + nTime, + addrYou, + addrMe, + nLocalHostNonce, + FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()), + nBestHeight); } bool CNode::Misbehaving(int howmuch) @@ -2319,9 +2296,6 @@ void StartNode(void* parg) else if (!netThreads->createThread(ThreadStakeMiner,pwalletMain,"ThreadStakeMiner")) LogPrintf("Error: createThread(ThreadStakeMiner) failed"); - - // Initialize GRC services. - GRC::Initialize(pindexBest); } bool StopNode() diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 3b4b7926ca..9d424f469c 100755 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -357,7 +357,7 @@ int StartGridcoinQt(int argc, char *argv[]) app.installNativeEventFilter(new WinShutdownMonitor()); #endif - if (!boost::filesystem::is_directory(GetDataDir(false))) + if (!fs::is_directory(GetDataDir(false))) { QMessageBox::critical(0, "Gridcoin", QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 8f40fd2012..c38faeee11 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -9,8 +9,6 @@ #include #include -#include - #include "bitcoingui.h" #include "transactiontablemodel.h" #include "addressbookpage.h" @@ -83,7 +81,6 @@ #include "gridcoin/staking/status.h" #include "gridcoin/superblock.h" -#include #include // for to_lower() #include #include "util.h" @@ -181,7 +178,7 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): rpcConsole = new RPCConsole(this); connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show())); - diagnosticsDialog = new DiagnosticsDialog(this); + 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))); @@ -195,6 +192,8 @@ BitcoinGUI::BitcoinGUI(QWidget *parent): QObject::connect(overview_update_timer, SIGNAL(timeout()), this, SLOT(updateGlobalStatus())); + connect(openConfigAction, SIGNAL(triggered()), this, SLOT(openConfigClicked())); + gotoOverviewPage(); } @@ -320,6 +319,9 @@ void BitcoinGUI::createActions() optionsAction = new QAction(tr("&Options..."), this); optionsAction->setToolTip(tr("Modify configuration options for Gridcoin")); optionsAction->setMenuRole(QAction::PreferencesRole); + openConfigAction = new QAction(tr("Open config &file..."), this); + optionsAction->setToolTip(tr("Open the config file in your standard editor")); + openConfigAction->setMenuRole(QAction::PreferencesRole); researcherAction = new QAction(tr("&Researcher Wizard..."), this); researcherAction->setToolTip(tr("Open BOINC and beacon settings for Gridcoin")); researcherAction->setMenuRole(QAction::PreferencesRole); @@ -392,6 +394,7 @@ void BitcoinGUI::setIcons() exportAction->setIcon(QPixmap(":/icons/export")); openRPCConsoleAction->setIcon(QPixmap(":/icons/debugwindow")); snapshotAction->setIcon(QPixmap(":/images/gridcoin")); + openConfigAction->setIcon(QPixmap(":/icons/edit")); } void BitcoinGUI::createMenuBar() @@ -430,6 +433,7 @@ void BitcoinGUI::createMenuBar() settings->addAction(researcherAction); settings->addSeparator(); settings->addAction(optionsAction); + settings->addAction(openConfigAction); QMenu *community = appMenuBar->addMenu(tr("&Community")); community->addAction(bxAction); @@ -731,6 +735,25 @@ void BitcoinGUI::optionsClicked() dlg.exec(); } +void BitcoinGUI::openConfigClicked() +{ + boost::filesystem::path pathConfig = GetConfigFile(); + /* Open gridcoinresearch.conf with the associated application */ + bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathConfig.string()))); + #ifdef Q_OS_WIN + // Workaround for windows specific behaviour + if(!res) { + res = QProcess::startDetached("C:\\Windows\\system32\\notepad.exe", QStringList{QString::fromStdString(pathConfig.string())}); + } + #endif + #ifdef Q_OS_MAC + // Workaround for macOS-specific behaviour; see https://github.com/bitcoin/bitcoin/issues/15409 + if (!res) { + res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", QString::fromStdString(pathConfig.string())}); + } + #endif +} + void BitcoinGUI::researcherClicked() { if (!researcherModel || !walletModel) { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index d65965e816..19035c0e53 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -96,18 +96,19 @@ class BitcoinGUI : public QMainWindow QAction *sendCoinsAction; QAction *addressBookAction; QAction *signMessageAction; - QAction *bxAction; - QAction *websiteAction; - QAction *boincAction; - QAction *chatAction; - QAction *exchangeAction; + QAction *bxAction; + QAction *websiteAction; + QAction *boincAction; + QAction *chatAction; + QAction *exchangeAction; QAction *votingAction; - QAction *diagnosticsAction; + QAction *diagnosticsAction; QAction *verifyMessageAction; QAction *aboutAction; QAction *receiveCoinsAction; QAction *researcherAction; QAction *optionsAction; + QAction *openConfigAction; QAction *toggleHideAction; QAction *exportAction; QAction *encryptWalletAction; @@ -174,7 +175,7 @@ public slots: */ void askFee(qint64 nFeeRequired, bool *payFee); - void askQuestion(std::string caption, std::string body, bool *result); + void askQuestion(std::string caption, std::string body, bool *result); void handleURI(QString strURI); void setOptionsStyleSheet(QString qssFileName); @@ -204,13 +205,15 @@ private slots: void researcherClicked(); /** Show about dialog */ void aboutClicked(); + /** Open config file */ + void openConfigClicked(); - void bxClicked(); - void websiteClicked(); - void exchangeClicked(); - void boincClicked(); + void bxClicked(); + void websiteClicked(); + void exchangeClicked(); + void boincClicked(); void boincStatsClicked(); - void chatClicked(); + void chatClicked(); void diagnosticsClicked(); void peersClicked(); void snapshotClicked(); @@ -245,7 +248,7 @@ private slots: void updateScraperIcon(int scraperEventtype, int status); void updateBeaconIcon(); - QString GetEstimatedStakingFrequency(unsigned int nEstimateTime); + QString GetEstimatedStakingFrequency(unsigned int nEstimateTime); void updateGlobalStatus(); }; diff --git a/src/qt/diagnosticsdialog.cpp b/src/qt/diagnosticsdialog.cpp index 7b7b7ad0fd..b6508c14d3 100644 --- a/src/qt/diagnosticsdialog.cpp +++ b/src/qt/diagnosticsdialog.cpp @@ -2,11 +2,11 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "fs.h" #include "main.h" #include "util.h" #include -#include #include #include "diagnosticsdialog.h" @@ -18,7 +18,6 @@ #include "qt/researcher/researchermodel.h" #include -#include DiagnosticsDialog::DiagnosticsDialog(QWidget *parent, ResearcherModel* researcher_model) : QDialog(parent), @@ -190,14 +189,14 @@ void DiagnosticsDialog::DisplayOverallDiagnosticResult() bool DiagnosticsDialog::VerifyBoincPath() { - boost::filesystem::path boincPath = (boost::filesystem::path) GRC::GetBoincDataDir(); + fs::path boincPath = (fs::path) GRC::GetBoincDataDir(); if (boincPath.empty()) - boincPath = (boost::filesystem::path) GetArgument("boincdatadir", ""); + boincPath = (fs::path) GetArgument("boincdatadir", ""); boincPath = boincPath / "client_state.xml"; - return boost::filesystem::exists(boincPath); + return fs::exists(boincPath); } bool DiagnosticsDialog::VerifyIsCPIDValid() diff --git a/src/qt/forms/researcherwizardbeaconpage.ui b/src/qt/forms/researcherwizardbeaconpage.ui index 60809c34eb..09c6d22cce 100644 --- a/src/qt/forms/researcherwizardbeaconpage.ui +++ b/src/qt/forms/researcherwizardbeaconpage.ui @@ -161,23 +161,6 @@ - - - - - 10 - 75 - true - - - - font-weight: bold; - - - All active beacon holders must send a new beacon for the protocol update. - - - diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 26515fb090..863209134d 100755 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,3 +1,4 @@ +#include "fs.h" #include "guiutil.h" #include "bitcoinaddressvalidator.h" #include "walletmodel.h" @@ -20,9 +21,6 @@ #include #include -#include -#include - #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT @@ -326,10 +324,10 @@ bool isObscured(QWidget *w) void openDebugLogfile() { - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + fs::path pathDebug = GetDataDir() / "debug.log"; /* Open debug.log with the associated application */ - if (boost::filesystem::exists(pathDebug)) + if (fs::exists(pathDebug)) QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(pathDebug.string()))); } @@ -380,7 +378,7 @@ bool WindowContextHelpButtonHintFilter::eventFilter (QObject *obj, QEvent *event struct AutoStartupArguments { std::string link_name_suffix; - boost::filesystem::path data_dir; + fs::path data_dir; std::string arguments; }; @@ -388,12 +386,12 @@ AutoStartupArguments GetAutoStartupArguments(bool fStartMin = true) { // This helper function checks for the presence of certain startup arguments // to the current running instance that should be relevant for automatic restart - // (currently testnet, datadir, scraper, explorer, usenewnn). It adds -testnet + // (currently testnet, datadir, scraper, explorer). It adds -testnet // to the link name as a suffix if -testnet is specified otherwise adds mainnet, // and then adds the other three as arguments if they were specified for the // running instance. This allows two different automatic startups, one for // mainnet, and the other for testnet, and each of them can have different datadir, - // scraper, explorer, and/or usenewnn arguments. + // scraper, and/or explorer arguments. AutoStartupArguments result; @@ -418,24 +416,24 @@ AutoStartupArguments GetAutoStartupArguments(bool fStartMin = true) result.arguments += " -min"; } -for (const auto& flag : { "-scraper", "-explorer", "-usenewnn" }) -{ - if (GetBoolArg(flag)) + for (const auto& flag : { "-scraper", "-explorer" }) { - (result.arguments += " ") += flag; + if (GetBoolArg(flag)) + { + (result.arguments += " ") += flag; + } } -} return result; } #ifdef WIN32 -boost::filesystem::path static StartupShortcutLegacyPath() +fs::path static StartupShortcutLegacyPath() { return GetSpecialFolderPath(CSIDL_STARTUP) / "Gridcoin.lnk"; } -boost::filesystem::path static StartupShortcutPath() +fs::path static StartupShortcutPath() { std::string link_name_suffix = GetAutoStartupArguments().link_name_suffix; std::string link_name_root = "Gridcoin"; @@ -446,16 +444,16 @@ boost::filesystem::path static StartupShortcutPath() bool GetStartOnSystemStartup() { // check for Gridcoin.lnk - return boost::filesystem::exists(StartupShortcutPath()); + return fs::exists(StartupShortcutPath()); } bool SetStartOnSystemStartup(bool fAutoStart, bool fStartMin) { // Remove the legacy shortcut unconditionally. - boost::filesystem::remove(StartupShortcutLegacyPath()); + fs::remove(StartupShortcutLegacyPath()); // If the shortcut exists already, remove it for updating - boost::filesystem::remove(StartupShortcutPath()); + fs::remove(StartupShortcutPath()); // Get auto startup arguments AutoStartupArguments autostartup = GetAutoStartupArguments(fStartMin); @@ -533,10 +531,8 @@ bool SetStartOnSystemStartup(bool fAutoStart, bool fStartMin) // Follow the Desktop Application Autostart Spec: // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html -boost::filesystem::path static GetAutostartDir() +fs::path static GetAutostartDir() { - namespace fs = boost::filesystem; - char* pszConfigHome = getenv("XDG_CONFIG_HOME"); if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; char* pszHome = getenv("HOME"); @@ -544,12 +540,12 @@ boost::filesystem::path static GetAutostartDir() return fs::path(); } -boost::filesystem::path static GetAutostartLegacyFilePath() +fs::path static GetAutostartLegacyFilePath() { return GetAutostartDir() / "gridcoin.desktop"; } -boost::filesystem::path static GetAutostartFilePath() +fs::path static GetAutostartFilePath() { std::string link_name_suffix = GetAutoStartupArguments().link_name_suffix; std::string link_name_root = "gridcoin"; @@ -579,13 +575,13 @@ bool GetStartOnSystemStartup() bool SetStartOnSystemStartup(bool fAutoStart, bool fStartMin) { // Remove legacy autostart path if it exists. - if (boost::filesystem::exists(GetAutostartLegacyFilePath())) + if (fs::exists(GetAutostartLegacyFilePath())) { - boost::filesystem::remove(GetAutostartLegacyFilePath()); + fs::remove(GetAutostartLegacyFilePath()); } if (!fAutoStart) - boost::filesystem::remove(GetAutostartFilePath()); + fs::remove(GetAutostartFilePath()); else { char pszExePath[MAX_PATH+1]; @@ -595,7 +591,7 @@ bool SetStartOnSystemStartup(bool fAutoStart, bool fStartMin) AutoStartupArguments autostartup = GetAutoStartupArguments(fStartMin); - boost::filesystem::create_directories(GetAutostartDir()); + fs::create_directories(GetAutostartDir()); fsbridge::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc); if (!optionFile.good()) @@ -604,7 +600,7 @@ bool SetStartOnSystemStartup(bool fAutoStart, bool fStartMin) optionFile << "[Desktop Entry]\n"; optionFile << "Type=Application\n"; optionFile << "Name=Gridcoin" + autostartup.link_name_suffix + "\n"; - optionFile << "Exec=" << static_cast(pszExePath); + optionFile << "Exec=" << static_cast(pszExePath); if (!autostartup.data_dir.empty()) { diff --git a/src/qt/researcher/researchermodel.cpp b/src/qt/researcher/researchermodel.cpp index 7187f6adb2..4ba9785567 100644 --- a/src/qt/researcher/researchermodel.cpp +++ b/src/qt/researcher/researchermodel.cpp @@ -24,8 +24,6 @@ using namespace GRC; using LogFlags = BCLog::LogFlags; -extern int64_t g_v11_timestamp; - namespace { constexpr double SECONDS_IN_DAY = 24.0 * 60.0 * 60.0; constexpr int64_t BEACON_RENEWAL_WARNING_THRESHOLD = 15 * SECONDS_IN_DAY; @@ -180,7 +178,7 @@ void ResearcherModel::showWizard(WalletModel* wallet_model) wizard->setStartId(ResearcherWizard::PageInvestor); } else if (detectedPoolMode()) { wizard->setStartId(ResearcherWizard::PagePoolSummary); - } else if (hasRenewableBeacon() || needsV2BeaconUpgrade()) { + } else if (hasRenewableBeacon()) { wizard->setStartId(ResearcherWizard::PageBeacon); } else if (!actionNeeded()) { wizard->setStartId(ResearcherWizard::PageSummary); @@ -206,8 +204,7 @@ bool ResearcherModel::actionNeeded() const } if (hasEligibleProjects()) { - return (!hasActiveBeacon() && !hasPendingBeacon()) - || needsV2BeaconUpgrade(); + return !hasActiveBeacon() && !hasPendingBeacon(); } return !hasPoolProjects(); @@ -250,7 +247,7 @@ bool ResearcherModel::hasRAC() const bool ResearcherModel::needsBeaconAuth() const { - if (!hasPendingBeacon() || !IsV11Enabled(nBestHeight + 1)) { + if (!hasPendingBeacon()) { return false; } @@ -261,13 +258,6 @@ bool ResearcherModel::needsBeaconAuth() const return m_beacon->m_public_key != m_pending_beacon->m_public_key; } -bool ResearcherModel::needsV2BeaconUpgrade() const -{ - return m_beacon - && m_beacon->m_timestamp <= g_v11_timestamp - && (!m_pending_beacon || m_pending_beacon->m_timestamp <= g_v11_timestamp); -} - QString ResearcherModel::email() const { return QString::fromStdString(Researcher::Email()); diff --git a/src/qt/researcher/researchermodel.h b/src/qt/researcher/researchermodel.h index 4321fdd820..0b5de28ef9 100644 --- a/src/qt/researcher/researchermodel.h +++ b/src/qt/researcher/researchermodel.h @@ -92,7 +92,6 @@ class ResearcherModel : public QObject bool hasMagnitude() const; bool hasRAC() const; bool needsBeaconAuth() const; - bool needsV2BeaconUpgrade() const; QString email() const; QString formatCpid() const; diff --git a/src/qt/researcher/researcherwizardbeaconpage.cpp b/src/qt/researcher/researcherwizardbeaconpage.cpp index d1364d650e..739c704482 100644 --- a/src/qt/researcher/researcherwizardbeaconpage.cpp +++ b/src/qt/researcher/researcherwizardbeaconpage.cpp @@ -55,10 +55,6 @@ void ResearcherWizardBeaconPage::initializePage() bool ResearcherWizardBeaconPage::isComplete() const { - if (m_researcher_model->needsV2BeaconUpgrade()) { - return m_researcher_model->hasPendingBeacon(); - } - return m_researcher_model->hasActiveBeacon() || m_researcher_model->hasPendingBeacon(); } @@ -85,7 +81,6 @@ void ResearcherWizardBeaconPage::refresh() ui->cpidLabel->setText(m_researcher_model->formatCpid()); ui->sendBeaconButton->setVisible(isEnabled()); - ui->v2BeaconNoticeLabel->setVisible(m_researcher_model->needsV2BeaconUpgrade()); ui->continuePromptWrapper->setVisible(!isEnabled()); emit completeChanged(); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 39f4973bdb..e6017c49f6 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -405,6 +405,17 @@ void RPCConsole::setClientModel(ClientModel *model) ui->boostVersion->setText(model->formatBoostVersion()); ui->porDiff->setText(model->getDifficulty()); + //Setup autocomplete and attach it + QStringList wordList; + std::vector commandList = tableRPC.listCommands(); + for (size_t i = 0; i < commandList.size(); ++i) + { + wordList << commandList[i].c_str(); + } + + autoCompleter = new QCompleter(wordList, this); + ui->lineEdit->setCompleter(autoCompleter); + } } diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index c714453fda..9033ca441c 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -8,6 +8,7 @@ #include #include +#include #include namespace Ui { @@ -109,6 +110,7 @@ public slots: QList cachedNodeids; QMenu *peersTableContextMenu = nullptr; QMenu *banTableContextMenu = nullptr; + QCompleter *autoCompleter; static QString FormatBytes(quint64 bytes); void setTrafficGraphRange(int mins); /** show detailed information on ui about selected node */ diff --git a/src/qt/upgradeqt.cpp b/src/qt/upgradeqt.cpp index 6181ea9afa..851481391c 100644 --- a/src/qt/upgradeqt.cpp +++ b/src/qt/upgradeqt.cpp @@ -338,14 +338,14 @@ void UpgradeQt::DeleteSnapshot() try { - boost::filesystem::path snapshotpath = GetDataDir() / snapshotfile; + fs::path snapshotpath = GetDataDir() / snapshotfile; - if (boost::filesystem::exists(snapshotpath)) - if (boost::filesystem::is_regular_file(snapshotpath)) - boost::filesystem::remove(snapshotpath); + if (fs::exists(snapshotpath)) + if (fs::is_regular_file(snapshotpath)) + fs::remove(snapshotpath); } - catch (boost::filesystem::filesystem_error& e) + catch (fs::filesystem_error& e) { LogPrintf("Snapshot Downloader: Exception occurred while attempting to delete snapshot (%s)", e.code().message()); } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 72efc5148b..bde50523d5 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -622,11 +622,6 @@ UniValue advertisebeacon(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - if (force && !IsV11Enabled(nBestHeight + 1)) { - throw JSONRPCError(RPC_INVALID_REQUEST, - "force not available until block " + std::to_string(Params().GetConsensus().BlockV11Height)); - } - GRC::AdvertiseBeaconResult result = GRC::Researcher::Get()->AdvertiseBeacon(force); if (auto public_key_option = result.TryPublicKey()) { @@ -698,11 +693,6 @@ UniValue revokebeacon(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); - if (!IsV11Enabled(nBestHeight + 1)) { - throw JSONRPCError(RPC_INVALID_REQUEST, - "revokebeacon not available until block " + std::to_string(Params().GetConsensus().BlockV11Height)); - } - const GRC::AdvertiseBeaconResult result = GRC::Researcher::Get()->RevokeBeacon(*cpid); if (auto public_key_option = result.TryPublicKey()) { @@ -1094,40 +1084,6 @@ UniValue magnitude(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "No data for investor."); } -UniValue myneuralhash(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "myneuralhash\n" - "\n" - "Displays information about your node's current superblock hash\n"); - - UniValue res(UniValue::VOBJ); - - LOCK(cs_main); - - res.pushKV("my_hash", GRC::Quorum::CreateSuperblock().GetHash().ToString()); - - return res; -} - -UniValue neuralhash(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "neuralhash\n" - "\n" - "Displays information about the popular superblock hash\n"); - - UniValue res(UniValue::VOBJ); - - LOCK(cs_main); - - res.pushKV("Popular", GRC::Quorum::FindPopularHash(pindexBest).ToString()); - - return res; -} - UniValue resetcpids(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -1289,20 +1245,6 @@ UniValue addkey(const UniValue& params, bool fHelp) GRC::Contract contract; switch (type.Value()) { - case GRC::ContractType::BEACON: { - const auto cpid_option = GRC::MiningId::Parse(params[2].get_str()).TryCpid(); - - if (!cpid_option) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid CPID."); - } - - contract = GRC::MakeContract( - action, - *cpid_option, - GRC::Beacon(ParseHex(params[3].get_str()))); - - break; - } case GRC::ContractType::PROJECT: contract = GRC::MakeContract( action, @@ -1322,20 +1264,6 @@ UniValue addkey(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Not an admin contract type."); } - // TODO: remove this after the v11 mandatory block. We don't need to sign - // version 2 contracts (the signature is discarded after the threshold): - if (!IsV11Enabled(nBestHeight + 1)) { - contract = contract.ToLegacy(); - - if (!contract.Sign(key)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Failed to sign."); - } - - if (!contract.VerifySignature()) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Failed to verify signature."); - } - } - std::pair result = GRC::SendContract(contract); std::string error = result.second; @@ -1660,27 +1588,6 @@ UniValue readdata(const UniValue& params, bool fHelp) return res; } -UniValue refhash(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "refhash \n" - "\n" - " -> GRC address to test against\n" - "\n" - "Tests to see if a GRC Address is a superblock quorum participant along with default wallet address\n"); - - UniValue res(UniValue::VOBJ); - - bool r1 = GRC::Quorum::Participating(params[0].get_str(), GetAdjustedTime()); - bool r2 = GRC::Quorum::Participating(DefaultWalletAddress(), GetAdjustedTime()); - - res.pushKV("nMoneySupply)); diff.pushKV("current", GRC::GetCurrentDifficulty()); diff.pushKV("target", GRC::GetTargetDifficulty()); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 1293294fe2..6c9efa097f 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -18,12 +18,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include diff --git a/src/rpcdataacq.cpp b/src/rpcdataacq.cpp index 78e9981597..56ba548ea8 100644 --- a/src/rpcdataacq.cpp +++ b/src/rpcdataacq.cpp @@ -14,11 +14,8 @@ #include "gridcoin/support/block_finder.h" #include "util.h" -#include -#include #include // for to_lower() #include -#include #include #include @@ -29,7 +26,7 @@ using namespace std; extern GRC::BlockFinder RPCBlockFinder; // Brod -static bool compare_second(const pair &p1, const pair &p2) +static bool compare_second(const pair &p1, const pair &p2) { return p1.second > p2.second; } @@ -40,104 +37,139 @@ UniValue rpc_getblockstats(const UniValue& params, bool fHelp) throw runtime_error( "getblockstats mode [startheight [endheight]]\n" "\n" - "Show stats on what wallets and cpids staked recent blocks.\n"); - long mode= params[0].get_int(); - (void)mode; //TODO - long lowheight= 0; - long highheight= INT_MAX; - long maxblocks= 14000; - if (mode==0) + "Show stats on what wallets and cpids staked recent blocks.\n" + "\n" + "Mode 0: Startheight is the starting height, endheight is the chain head if not specfied.\n" + "Mode 1: Startheight is actually the number of blocks back from endheight or the chain \n" + " head if not specified."); + + unsigned int mode = params[0].get_int(); + + int64_t lowheight = 0; + + // Even though these are typed to int64_t for the future, the max here is set to the max for the integer type, + // because CBlockIndex nHeight is still type int. + int64_t highheight = std::numeric_limits::max(); + + // Default scope to 30000 blocks unless otherwise specified + int64_t maxblocks = 30000; + + if (mode == 0) { - if(params.size()>=2) + if (params.size() >= 2) + { + lowheight = params[1].get_int(); + maxblocks = std::numeric_limits::max(); + } + + if (params.size() >= 3) { - lowheight= params[1].get_int(); - maxblocks= INT_MAX; + highheight = params[2].get_int(); + + int64_t maxblocks = highheight - lowheight + 1; + + if (maxblocks < 2) + { + throw runtime_error("getblockstats: Number of blocks in scope less than two."); + } } - if(params.size()>=3) - highheight= params[2].get_int(); } - else if(mode==1) + else if (mode == 1) { - /* count highheight */ - maxblocks= 30000; - if(params.size()>=2) - maxblocks= params[1].get_int(); - if(params.size()>=3) - highheight= params[2].get_int(); + if (params.size() >= 2) maxblocks = params[1].get_int(); + if (params.size() >= 3) highheight = params[2].get_int(); + + if (maxblocks < 2) + { + throw runtime_error("getblockstats: number of blocks to look back less than two."); + } } - else throw runtime_error("getblockstats: Invalid mode specified"); + else + { + throw runtime_error("getblockstats: Invalid mode specified"); + } + CBlockIndex* cur; UniValue result1(UniValue::VOBJ); { LOCK(cs_main); - cur= pindexBest; + cur = pindexBest; } int64_t blockcount = 0; int64_t transactioncount = 0; - std::map c_blockversion; - std::map c_version; - std::map c_cpid; - std::map c_org; + std::map c_blockversion; + std::map c_version; + std::map c_cpid; + std::map c_org; int64_t researchcount = 0; int64_t researchtotal = 0; int64_t interesttotal = 0; int64_t minttotal = 0; - //int64_t stakeinputtotal = 0; int64_t poscount = 0; int64_t emptyblockscount = 0; - int64_t l_first = INT_MAX; + int64_t l_first = std::numeric_limits::max(); int64_t l_last = 0; unsigned int l_first_time = 0; unsigned int l_last_time = 0; - unsigned size_min_blk=INT_MAX; - unsigned size_max_blk=0; - uint64_t size_sum_blk=0; + unsigned int size_min_blk = std::numeric_limits::max(); + unsigned int size_max_blk = 0; + uint64_t size_sum_blk = 0; double diff_sum = 0; - double diff_max=0; - double diff_min=INT_MAX; + double diff_max = 0; + double diff_min = std::numeric_limits::max(); int64_t super_count = 0; - for( ; (cur - &&( cur->nHeight>=lowheight ) - &&( blockcountpprev - ) + int64_t super_first_time = std::numeric_limits::max(); + int64_t super_last_time = 0; + + for (; cur && cur->nHeight >= lowheight && blockcount < maxblocks; cur = cur->pprev) { - if(cur->nHeight>highheight) - continue; - if(l_first>cur->nHeight) + + // cur is initialized to pIndexBest. This gets us to the starting point. + if (cur->nHeight > highheight) continue; + + if (l_first > cur->nHeight) { - l_first=cur->nHeight; - l_first_time=cur->nTime; + l_first = cur->nHeight; + l_first_time = cur->nTime; } - if(l_lastnHeight) + if (l_last < cur->nHeight) { - l_last=cur->nHeight; - l_last_time=cur->nTime; + l_last = cur->nHeight; + l_last_time = cur->nTime; } + blockcount++; + CBlock block; - if(!block.ReadFromDisk(cur->nFile,cur->nBlockPos,true)) - throw runtime_error("failed to read block"); + if (!block.ReadFromDisk(cur->nFile,cur->nBlockPos,true)) + { + throw runtime_error("getblockstats: failed to read block"); + } + assert(block.vtx.size() > 0); + unsigned txcountinblock = 0; - if(block.vtx.size()>=2) + + if (block.vtx.size() >= 2) { - txcountinblock+=block.vtx.size()-2; - if(block.vtx[1].IsCoinStake()) + txcountinblock += block.vtx.size() - 2; + + if (block.vtx[1].IsCoinStake()) { poscount++; - //stakeinputtotal+=block.vtx[1].vin[0].nValue; double diff = GRC::GetDifficulty(cur); diff_sum += diff; - diff_max=std::max(diff_max,diff); - diff_min=std::min(diff_min,diff); + diff_max = std::max(diff_max, diff); + diff_min = std::min(diff_min, diff); } else - txcountinblock+=1; + { + txcountinblock += 1; + } } - transactioncount+=txcountinblock; - emptyblockscount+=(txcountinblock==0); + + transactioncount += txcountinblock; + emptyblockscount += (txcountinblock == 0); c_blockversion[block.nVersion]++; const Claim claim = block.GetClaim(); c_cpid[claim.m_mining_id.ToString()]++; @@ -146,14 +178,27 @@ UniValue rpc_getblockstats(const UniValue& params, bool fHelp) researchtotal += claim.m_research_subsidy; interesttotal += claim.m_block_subsidy; researchcount += claim.HasResearchReward(); - minttotal+=cur->nMint; + minttotal += cur->nMint; unsigned sizeblock = GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION); - size_min_blk=std::min(size_min_blk,sizeblock); - size_max_blk=std::max(size_max_blk,sizeblock); - size_sum_blk+=sizeblock; - super_count += (claim.ContainsSuperblock()); + size_min_blk = std::min(size_min_blk,sizeblock); + size_max_blk = std::max(size_max_blk,sizeblock); + size_sum_blk += sizeblock; + + if (claim.ContainsSuperblock()) + { + ++super_count; + + super_first_time = std::min(cur->nTime, super_first_time); + super_last_time = std::max(cur->nTime, super_last_time); + } + } + + if (blockcount < 2) + { + throw runtime_error("getblockstats: Blockcount of scope is less than two."); } + // general info { UniValue result(UniValue::VOBJ); result.pushKV("blocks", blockcount); @@ -161,13 +206,23 @@ UniValue rpc_getblockstats(const UniValue& params, bool fHelp) result.pushKV("last_height", l_last); result.pushKV("first_time", TimestampToHRDate(l_first_time)); result.pushKV("last_time", TimestampToHRDate(l_last_time)); - result.pushKV("time_span_hour", ((double)l_last_time-(double)l_first_time)/(double)3600); - result.pushKV("min_blocksizek", size_min_blk/(double)1024); - result.pushKV("max_blocksizek", size_max_blk/(double)1024); + result.pushKV("time_span_hour", (l_last_time - l_first_time) / (double) 3600); + + if (super_count) + { + result.pushKV("super_first_time", TimestampToHRDate(super_first_time)); + result.pushKV("super_last_time", TimestampToHRDate(super_last_time)); + result.pushKV("super_time_span_hour", (super_last_time - super_first_time) / (double) 3600); + } + + result.pushKV("min_blocksizek", size_min_blk / (double) 1024); + result.pushKV("max_blocksizek", size_max_blk / (double) 1024); result.pushKV("min_posdiff", diff_min); result.pushKV("max_posdiff", diff_max); result1.pushKV("general", result); } + + // counts { UniValue result(UniValue::VOBJ); result.pushKV("block", blockcount); @@ -178,17 +233,20 @@ UniValue rpc_getblockstats(const UniValue& params, bool fHelp) result.pushKV("super", super_count); result1.pushKV("counts", result); } + + // totals { UniValue result(UniValue::VOBJ); result.pushKV("block", blockcount); result.pushKV("research", ValueFromAmount(researchtotal)); result.pushKV("interest", ValueFromAmount(interesttotal)); result.pushKV("mint", ValueFromAmount(minttotal)); - //result.pushKV("stake_input", stakeinputtotal/(double)COIN); - result.pushKV("blocksizek", size_sum_blk/(double)1024); + result.pushKV("blocksizek", size_sum_blk / (double) 1024); result.pushKV("posdiff", diff_sum); result1.pushKV("totals", result); } + + // averages { UniValue result(UniValue::VOBJ); @@ -198,59 +256,70 @@ UniValue rpc_getblockstats(const UniValue& params, bool fHelp) result.pushKV("research", ValueFromAmount(research_average)); result.pushKV("interest", ValueFromAmount(interesttotal / blockcount)); result.pushKV("mint", ValueFromAmount(minttotal / blockcount)); - //result.pushKV("stake_input", (stakeinputtotal/(double)poscount)/(double)COIN); - result.pushKV("spacing_sec", ((double)l_last_time-(double)l_first_time)/(double)blockcount); - result.pushKV("block_per_day", ((double)blockcount*86400.0)/((double)l_last_time-(double)l_first_time)); + + double spacing_sec = (l_last_time - l_first_time) / (double) (blockcount - 1); + result.pushKV("spacing_sec", spacing_sec); + result.pushKV("block_per_day", 86400.0 / spacing_sec); // check for zero blockcount-emptyblockscount and if so make transaction average 0. double transaction_average = (blockcount - emptyblockscount) ? transactioncount / (double) (blockcount - emptyblockscount) : 0; - result.pushKV("transaction", transaction_average); - result.pushKV("blocksizek", size_sum_blk/(double)blockcount/(double)1024); - result.pushKV("posdiff", diff_sum/(double)poscount); - if (super_count > 0) - result.pushKV("super_spacing_hrs", ((l_last_time-l_first_time)/(double)super_count)/3600.0); + + result.pushKV("blocksizek", size_sum_blk / (double) blockcount / 1024.0); + + result.pushKV("posdiff", diff_sum / poscount); + + if (super_count > 1) + { + result.pushKV("super_spacing_hrs", (super_last_time - super_first_time) / ((double) super_count - 1) / 3600.0); + } result1.pushKV("averages", result); } + + // wallet versions { UniValue result(UniValue::VOBJ); - std::vector list; + std::vector list; std::copy(c_version.begin(), c_version.end(), back_inserter(list)); - std::sort(list.begin(),list.end(),compare_second); + std::sort(list.begin(), list.end(), compare_second); + for (auto const& item : list) { - result.pushKV(item.first, item.second/(double)blockcount); + result.pushKV(item.first, item.second / (double) blockcount); } result1.pushKV("versions", result); } + + // cpids { UniValue result(UniValue::VOBJ); - std::vector list; + std::vector list; std::copy(c_cpid.begin(), c_cpid.end(), back_inserter(list)); - std::sort(list.begin(),list.end(),compare_second); - int limit=64; + std::sort(list.begin(), list.end(), compare_second); + for (auto const& item : list) { - if(!(limit--)) break; - result.pushKV(item.first, item.second/(double)blockcount); + result.pushKV(item.first, item.second / (double) blockcount); } result1.pushKV("cpids", result); } + + // orgs { UniValue result(UniValue::VOBJ); - std::vector list; + std::vector list; std::copy(c_org.begin(), c_org.end(), back_inserter(list)); - std::sort(list.begin(),list.end(),compare_second); - int limit=64; + std::sort(list.begin(), list.end(), compare_second); + for (auto const& item : list) { - if(!(limit--)) break; - result.pushKV(item.first, item.second/(double)blockcount); + result.pushKV(item.first, item.second / (double) blockcount); } result1.pushKV("orgs", result); } + return result1; } @@ -486,8 +555,8 @@ UniValue rpc_exportstats(const UniValue& params, bool fHelp) unsigned long points = 0; double samples = 0; /* this is double for easy division */ fsbridge::ofstream Output; - boost::filesystem::path o_path = GetDataDir() / "reports" / ( "export_" + std::to_string(GetTime()) + ".txt" ); - boost::filesystem::create_directories(o_path.parent_path()); + fs::path o_path = GetDataDir() / "reports" / ( "export_" + std::to_string(GetTime()) + ".txt" ); + fs::create_directories(o_path.parent_path()); Output.open (o_path); Output.imbue(std::locale::classic()); Output << std::fixed << std::setprecision(4); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index d8a20c80ac..8ce5eb7565 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -453,9 +453,9 @@ UniValue parseaccrualsnapshotfile(const UniValue& params, bool fHelp) UniValue res(UniValue::VOBJ); - boost::filesystem::path snapshot_path = params[0].get_str(); + const fs::path snapshot_path = params[0].get_str(); - if (!boost::filesystem::is_regular_file(snapshot_path)) + if (!fs::is_regular_file(snapshot_path)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid snapshot file specified."); } diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index 0ee00040fc..aaa8a33a1f 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -14,12 +14,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index ab5d3055d8..be129bd2fe 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -176,6 +176,18 @@ UniValue PollPayloadToJson(const GRC::ContractPayload& payload) out.pushKV("response_type", (int)poll.m_poll.m_response_type.Raw()); out.pushKV("duration_days", (int)poll.m_poll.m_duration_days); + UniValue choices(UniValue::VARR); + + for (size_t i = 0; i < poll.m_poll.Choices().size(); ++i) { + UniValue choice(UniValue::VOBJ); + choice.pushKV("id", (int)i); + choice.pushKV("label", poll.m_poll.Choices().At(i)->m_label); + + choices.push_back(choice); + } + + out.pushKV("choices", choices); + return out; } @@ -267,9 +279,6 @@ UniValue ContractToJson(const GRC::Contract& contract) break; } - out.pushKV("public_key", contract.m_public_key.ToString()); - out.pushKV("signature", contract.m_signature.ToString()); - return out; } @@ -1161,7 +1170,7 @@ UniValue scanforunspent(const UniValue& params, bool fHelp) fsbridge::ofstream dataout; // We will place this in wallet backups as a safer location then in main data directory - boost::filesystem::path exportpath; + fs::path exportpath; time_t biTime; struct tm * blTime; @@ -1180,7 +1189,7 @@ UniValue scanforunspent(const UniValue& params, bool fHelp) else exportpath = fs::path(backupdir) / exportfile; - boost::filesystem::create_directory(exportpath.parent_path()); + fs::create_directory(exportpath.parent_path()); dataout.open(exportpath); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2a5ef942b1..7e8c853556 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "init.h" #include "sync.h" #include "ui_interface.h" @@ -16,14 +17,13 @@ #include #include #include -#include #include #include #include #include -#include #include #include +#include #include @@ -355,8 +355,6 @@ static const CRPCCommand vRPCCommands[] = { "getmininginfo", &getmininginfo, cat_mining }, { "lifetime", &lifetime, cat_mining }, { "magnitude", &magnitude, cat_mining }, - { "myneuralhash", &myneuralhash, cat_mining }, - { "neuralhash", &neuralhash, cat_mining }, { "pendingbeaconreport", &pendingbeaconreport, cat_mining }, { "resetcpids", &resetcpids, cat_mining }, { "revokebeacon", &revokebeacon, cat_mining }, @@ -385,7 +383,6 @@ static const CRPCCommand vRPCCommands[] = { "projects", &projects, cat_developer }, { "readconfig", &readconfig, cat_developer }, { "readdata", &readdata, cat_developer }, - { "refhash", &refhash, cat_developer }, { "reorganize", &rpc_reorganize, cat_developer }, { "sendalert", &sendalert, cat_developer }, { "sendalert2", &sendalert2, cat_developer }, @@ -442,6 +439,22 @@ static const CRPCCommand vRPCCommands[] = { "votedetails", &votedetails, cat_voting }, }; +static constexpr const char* DEPRECATED_RPCS[] { + "debug", + "debug10", + "execute" , + "getaccount", + "getaccountaddress", + "getaddressesbyaccount", + "getreceivedbyaccount", + "listaccounts", + "listreceivedbyaccount", + "list", + "move", + "setaccount", + "vote", +}; + CRPCTable::CRPCTable() { unsigned int vcidx; @@ -605,14 +618,14 @@ void StartRPCThreads() { rpc_ssl_context->set_options(ssl::context::no_sslv2); - filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert")); - if (!pathCertFile.is_absolute()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile; - if (filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string()); + fs::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert")); + if (!pathCertFile.is_absolute()) pathCertFile = fs::path(GetDataDir()) / pathCertFile; + if (fs::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string()); else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string()); - filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem")); - if (!pathPKFile.is_absolute()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile; - if (filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem); + fs::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem")); + if (!pathPKFile.is_absolute()) pathPKFile = fs::path(GetDataDir()) / pathPKFile; + if (fs::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem); else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string()); string strCiphers = GetArg("-rpcsslciphers", "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH"); @@ -896,6 +909,22 @@ UniValue CRPCTable::execute(const std::string& strMethod, const UniValue& params } } + +std::vector CRPCTable::listCommands() const +{ + std::vector commandList; + typedef std::map commandMap; + + std::transform( mapCommands.begin(), mapCommands.end(), + std::back_inserter(commandList), + boost::bind(&commandMap::value_type::first,_1) ); + // remove deprecated commands from autocomplete + for(auto &command: DEPRECATED_RPCS) { + std::remove(commandList.begin(), commandList.end(), command); + } + return commandList; +} + #ifdef TEST int main(int argc, char *argv[]) { diff --git a/src/rpcserver.h b/src/rpcserver.h index ce2741a1d2..18007b38dc 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -72,8 +72,14 @@ class CRPCTable * @throws an exception when an error happens. */ UniValue execute(const std::string &method, const UniValue& params) const; -}; + /** + * Returns a list of registered commands + * @returns List of registered commands. + */ + std::vector listCommands() const; + +}; extern const CRPCTable tableRPC; extern int64_t nWalletUnlockTime; @@ -170,8 +176,6 @@ 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); -extern UniValue myneuralhash(const UniValue& params, bool fHelp); -extern UniValue neuralhash(const UniValue& params, bool fHelp); extern UniValue pendingbeaconreport(const UniValue& params, bool fHelp); extern UniValue resetcpids(const UniValue& params, bool fHelp); extern UniValue revokebeacon(const UniValue& params, bool fHelp); @@ -198,7 +202,6 @@ extern UniValue parselegacysb(const UniValue& params, bool fHelp); extern UniValue projects(const UniValue& params, bool fHelp); extern UniValue readconfig(const UniValue& params, bool fHelp); extern UniValue readdata(const UniValue& params, bool fHelp); -extern UniValue refhash(const UniValue& params, bool fHelp); extern UniValue rpc_reorganize(const UniValue& params, bool fHelp); extern UniValue sendalert(const UniValue& params, bool fHelp); extern UniValue sendalert2(const UniValue& params, bool fHelp); diff --git a/src/rpcvoting.cpp b/src/rpcvoting.cpp index 499e25567d..decd0fcea7 100644 --- a/src/rpcvoting.cpp +++ b/src/rpcvoting.cpp @@ -247,21 +247,11 @@ UniValue SubmitVote(const Poll& poll, VoteBuilder builder) UniValue responses(UniValue::VARR); - if (result_tx.nVersion >= 2) { - const auto& vote = payload.As(); + const auto& vote = payload.As(); - for (const auto& offset : vote.m_responses) { - if (const Poll::Choice* choice = poll.Choices().At(offset)) { - responses.push_back(choice->m_label); - } - } - } else { - const auto& vote = payload.As(); - - for (const auto& label : split(vote.m_responses, ";")) { - if (const auto offset_option = poll.Choices().OffsetOf(label)) { - responses.push_back(poll.Choices().At(*offset_option)->m_label); - } + for (const auto& offset : vote.m_responses) { + if (const Poll::Choice* choice = poll.Choices().At(offset)) { + responses.push_back(choice->m_label); } } diff --git a/src/test/gridcoin/claim_tests.cpp b/src/test/gridcoin/claim_tests.cpp index 0c9ad39aef..b9892b2fcd 100644 --- a/src/test/gridcoin/claim_tests.cpp +++ b/src/test/gridcoin/claim_tests.cpp @@ -430,77 +430,6 @@ BOOST_AUTO_TEST_CASE(it_generates_a_hash_for_a_research_reward_claim) BOOST_CHECK(claim.GetHash() == hasher.GetHash()); } -BOOST_AUTO_TEST_CASE(it_represents_itself_as_a_legacy_boincblock_string) -{ - const GRC::Cpid cpid = GRC::Cpid::Parse("00010203040506070809101112131415"); - const std::string quorum_address = "mk8PmpcTGLCZky8YqFHEEwXs5px3hGfQBG"; - - const GRC::Superblock superblock = GetTestSuperblock(1); - - // Legacy claims only contain MD5 quorum hashes: - const GRC::QuorumHash quorum_hash(GRC::QuorumHash::Md5Sum { - 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x09, 0x08, - 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 - }); - - const std::vector signature { - 0x7b, 0x85, 0xc8, 0x3c, 0x92, 0xd9, 0x74, 0x8e, - 0xa3, 0xd2, 0x26, 0x16, 0x6f, 0x9a, 0x00, 0x6c, - 0x6f, 0x0a, 0x97, 0x97, 0xa9, 0x3a, 0x52, 0xd0, - 0xb9, 0x4f, 0xbb, 0x29, 0x61, 0xbe, 0xd5, 0xcc, - }; - - const std::string sig64 = EncodeBase64(signature.data(), signature.size()); - - GRC::Claim claim; - - claim.m_mining_id = cpid; - claim.m_client_version = "v4.0.4.6-unk"; - claim.m_organization = "Example Org"; - claim.m_block_subsidy = 10.0 * COIN; - claim.m_research_subsidy = 47.24638888 * COIN; - claim.m_magnitude = 123; - claim.m_magnitude_unit = 0.123456; - claim.m_signature = signature; - claim.m_quorum_hash = quorum_hash; - claim.m_quorum_address = quorum_address; - claim.m_superblock.Replace(superblock); - - BOOST_CHECK(claim.ToString(8) == - cpid.ToString() + // Mining ID - "<|>" // Project name (obsolete) - "<|>" // AES Skein (obsolete) - "<|>" // Recent average credit (obsolete) - "<|>" // Proof-of-BOINC difficulty (obsolete) - "<|>" // Difficulty bytes (obsolete) - "<|>" // Encrypted CPID (obsolete) - "<|>" // For encrypted CPIDs? (obsolete) - "<|>" // Nonce (obsolete) - "<|>" // Network RAC (obsolete) - "<|>v4.0.4.6-unk" // Client version - "<|>47.24638888" // Research subsidy - "<|>" // Last payment time (obsolete) - "<|>" // RSA weight (obsolete) - "<|>" // CPID "v2" (obsolete) - "<|>123" // Magnitude - "<|>" + quorum_address + // Quorum address - "<|>0" // Last block hash (obsolete) - "<|>10.00000000" // Block subsidy - "<|>Example Org" // Organization - "<|>" // Organization key (obsolete) - "<|>" + quorum_hash.ToString() + // Neural hash - "<|>" + superblock.PackLegacy() +// Superblock - "<|>" // Research subsidy 2 (obsolete) - "<|>" // Research age (obsolete) - "<|>0.123456" // Magnitude unit - "<|>" // Average magnitude (obsolete) - "<|>" // Last PoR block hash (obsolete) - "<|>" // Current Neural hash (obsolete) - "<|>" // Public key (obsolete) - "<|>" + sig64 // Beacon signature - ); -} - BOOST_AUTO_TEST_CASE(it_serializes_to_a_stream_for_investor) { GRC::Claim claim = GetInvestorClaim(); diff --git a/src/test/gridcoin/contract_tests.cpp b/src/test/gridcoin/contract_tests.cpp index 88431b65c3..ed8eb705d2 100644 --- a/src/test/gridcoin/contract_tests.cpp +++ b/src/test/gridcoin/contract_tests.cpp @@ -60,86 +60,6 @@ class TestPayload : public GRC::IContractPayload } }; // TestPayload -//! -//! \brief Provides various public and private key representations for tests. -//! -//! Keys match the shared message keys embedded in the application. -//! -struct TestKey -{ - //! - //! \brief Create a valid private key for tests. - //! - //! \return This is actually the shared message private key. - //! - static CKey Private() - { - std::vector private_key = ParseHex( - "308201130201010420fbd45ffb02ff05a3322c0d77e1e7aea264866c24e81e5ab6" - "a8e150666b4dc6d8a081a53081a2020101302c06072a8648ce3d0101022100ffff" - "fffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604" - "010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959" - "f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47" - "d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03b" - "bfd25e8cd0364141020101a144034200044b2938fbc38071f24bede21e838a0758" - "a52a0085f2e034e7f971df445436a252467f692ec9c5ba7e5eaa898ab99cbd9949" - "496f7e3cafbf56304b1cc2e5bdf06e"); - - CKey key; - key.SetPrivKey(CPrivKey(private_key.begin(), private_key.end())); - - return key; - } - - //! - //! \brief Create a valid public key for tests. - //! - //! \return Complements the private key above. - //! - static CPubKey Public() - { - return CPubKey(std::vector { - 0x04, 0x4b, 0x29, 0x38, 0xfb, 0xc3, 0x80, 0x71, 0xf2, 0x4b, 0xed, - 0xe2, 0x1e, 0x83, 0x8a, 0x07, 0x58, 0xa5, 0x2a, 0x00, 0x85, 0xf2, - 0xe0, 0x34, 0xe7, 0xf9, 0x71, 0xdf, 0x44, 0x54, 0x36, 0xa2, 0x52, - 0x46, 0x7f, 0x69, 0x2e, 0xc9, 0xc5, 0xba, 0x7e, 0x5e, 0xaa, 0x89, - 0x8a, 0xb9, 0x9c, 0xbd, 0x99, 0x49, 0x49, 0x6f, 0x7e, 0x3c, 0xaf, - 0xbf, 0x56, 0x30, 0x4b, 0x1c, 0xc2, 0xe5, 0xbd, 0xf0, 0x6e - }); - } - - //! - //! \brief Create a valid public key for tests. - //! - //! \return Hex-encoded uncompressed key that complements the private key - //! above (and same key as the public key object above). - //! - static std::string PublicString() - { - return "044b2938fbc38071f24bede21e838a0758a52a0085f2e034e7f971df445436a25" - "2467f692ec9c5ba7e5eaa898ab99cbd9949496f7e3cafbf56304b1cc2e5bdf06e"; - } - - //! - //! \brief Create some invalid hex-encoded public key strings for tests. - //! - //! \return A set of various malformed public key strings that should fail - //! validation after parsing. - //! - static std::vector GarbagePublicStrings() - { - return std::vector { - // Too short: 32 bytes (not a real key): - "044b2938fbc38071f24bede21e838a0758a52a0085f2e034e7f971df445436a25", - // Too long: 66 bytes (not a real key): - "044b2938fbc38071f24bede21e838a0758a52a0085f2e034e7f971df445436a252" - "467f692ec9c5ba7e5eaa898ab99cbd9949496f7e3cafbf56304b1cc2e5bdf06e11", - // Garbage: invalid hex characters - "zz4b2938fbc38071f24bede21e838a0758a52a0085f2e034e7f971df445436a252", - }; - } -}; // struct TestKey - //! //! \brief Provides various signature representations for tests. //! @@ -159,25 +79,6 @@ struct TestSig "AiAp7QvHHhf1+xqEB57/k00jZW5RIITaxI9jXaR51Lmfnw=="; } - //! - //! \brief Create a valid signature of a version 1 contract for tests. - //! - //! \return Signature as a vector of bytes. Same signature as the base64 - //! string version above. - //! - static std::vector V1Bytes() - { - return std::vector { - 0x30, 0x44, 0x02, 0x20, 0x70, 0xaf, 0xb6, 0xd6, 0x73, 0x22, 0xb0, - 0x6a, 0x16, 0xdc, 0xbd, 0x10, 0x3f, 0xdf, 0x9f, 0x9c, 0x8c, 0x4b, - 0x34, 0xf3, 0xb9, 0xc8, 0x78, 0x5d, 0xfe, 0x0a, 0xc6, 0x23, 0x49, - 0x8f, 0x0b, 0xcc, 0x02, 0x20, 0x29, 0xed, 0x0b, 0xc7, 0x1e, 0x17, - 0xf5, 0xfb, 0x1a, 0x84, 0x07, 0x9e, 0xff, 0x93, 0x4d, 0x23, 0x65, - 0x6e, 0x51, 0x20, 0x84, 0xda, 0xc4, 0x8f, 0x63, 0x5d, 0xa4, 0x79, - 0xd4, 0xb9, 0x9f, 0x9f - }; - } - //! //! \brief Create an invalid signature for tests. //! @@ -189,47 +90,6 @@ struct TestSig return "MEQCIHCvttZzIrBqFty9ED/fn5yMSzTzuch4Xf4KxiNJjwvM" "AiAp7QvHHhf1+xqEB57/k00jZW5RIITaxI9jXaR51LmfDw=="; } - - //! - //! \brief Create an invalid signature for tests. - //! - //! \return Signature as a vector of bytes. Same signature as the valid - //! version 1 above with the last byte changed. - //! - static std::vector InvalidBytes() - { - return std::vector { - 0x30, 0x44, 0x02, 0x20, 0x70, 0xaf, 0xb6, 0xd6, 0x73, 0x22, 0xb0, - 0x6a, 0x16, 0xdc, 0xbd, 0x10, 0x3f, 0xdf, 0x9f, 0x9c, 0x8c, 0x4b, - 0x34, 0xf3, 0xb9, 0xc8, 0x78, 0x5d, 0xfe, 0x0a, 0xc6, 0x23, 0x49, - 0x8f, 0x0b, 0xcc, 0x02, 0x20, 0x29, 0xed, 0x0b, 0xc7, 0x1e, 0x17, - 0xf5, 0xfb, 0x1a, 0x84, 0x07, 0x9e, 0xff, 0x93, 0x4d, 0x23, 0x65, - 0x6e, 0x51, 0x20, 0x84, 0xda, 0xc4, 0x8f, 0x63, 0x5d, 0xa4, 0x79, - 0xd4, 0xb9, 0x9f, 0x0f - }; - } - - //! - //! \brief Create some invalid base64-encoded signatures for tests. - //! - //! \return A set of various malformed signature strings that should fail - //! validation after parsing. - //! - static std::vector GarbageStrings() - { - return std::vector { - // Too short: 63 bytes, base64-encoded (not a real signature): - "OGU0ZjQwNTE4ODA2NjEyMTIxMDJiYmJlMDMzOTM3ZTJkMTcyNDdjYmQzMDE5OTg5MzI3NTlhNjJkMjNlMGNl", - // Too long: 74 bytes, base64-encoded (not a real signature): - "OGU0ZjQwNTE4ODA2NjEyMTIxMDJiYmJlMDMzOTM3ZTJkMTcyNDdjYmQzMDE5OTg5MzI3NTlhNjJkMjNlMGNlMDk0MGU4Y2EzMjA=", - // Garbage base64-encoded string (one padding removed): - "MEQCIBQji0VFbMdiD5urHGgeq0UaiMB6IfI6+JKCC3Y9gMxCAiBornelAZ2bFusBPiD4DL+HS2SbiVU4j4pmMW4dQiiDIA=", - // Garbage base64-encoded string (one character removed): - "MEQCIBQji0VFbMdiD5urHGgeq0UaiMB6IfI6+JKCC3Y9gMxCAiBornelAZ2bFusBPiD4DL+HS2SbiVU4j4pmMW4dQiiDI==", - // Garbage base64-encoded string (non-base64 character): - "^EQCIBQji0VFbMdiD5urHGgeq0UaiMB6IfI6+JKCC3Y9gMxCAiBornelAZ2bFusBPiD4DL+HS2SbiVU4j4pmMW4dQiiDIA==", - }; - } }; // struct TestSig //! @@ -250,9 +110,7 @@ struct TestMessage GRC::Contract::CURRENT_VERSION, GRC::ContractType::PROJECT, GRC::ContractAction::ADD, - GRC::ContractPayload::Make("test", "test", 123), - GRC::Contract::Signature(), - GRC::Contract::PublicKey()); + GRC::ContractPayload::Make("test", "test", 123)); } //! @@ -263,12 +121,15 @@ struct TestMessage //! static GRC::Contract V1() { - return GRC::MakeLegacyContract( - GRC::ContractType::BEACON, + GRC::Contract contract = GRC::MakeLegacyContract( + GRC::ContractType::PROJECT, GRC::ContractAction::ADD, "test", - "test") - .ToLegacy(); + "test"); + + contract.m_version = 1; + + return contract; } //! @@ -608,159 +469,6 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream) BOOST_AUTO_TEST_SUITE_END() -// ----------------------------------------------------------------------------- -// Contract::Signature -// ----------------------------------------------------------------------------- - -BOOST_AUTO_TEST_SUITE(Contract__Signature) - -BOOST_AUTO_TEST_CASE(it_initializes_to_an_invalid_signature_by_default) -{ - GRC::Contract::Signature signature; - - BOOST_CHECK(signature.Viable() == false); -} - -BOOST_AUTO_TEST_CASE(it_initializes_with_bytes_in_a_signature) -{ - GRC::Contract::Signature signature(std::vector { 0x05 }); - - BOOST_CHECK(signature.Raw() == std::vector { 0x05 }); -} - -BOOST_AUTO_TEST_CASE(it_parses_a_signature_from_a_v1_base64_encoded_string) -{ - std::string input = TestSig::V1String(); - - GRC::Contract::Signature signature = GRC::Contract::Signature::Parse(input); - - BOOST_CHECK(signature.ToString() == input); - BOOST_CHECK(signature.Raw() == TestSig::V1Bytes()); -} - -BOOST_AUTO_TEST_CASE(it_gives_an_invalid_signature_when_parsing_an_empty_string) -{ - GRC::Contract::Signature signature = GRC::Contract::Signature::Parse(""); - - BOOST_CHECK(signature.Viable() == false); - BOOST_CHECK(signature.ToString() == ""); -} - -BOOST_AUTO_TEST_CASE(it_supports_a_basic_check_for_signature_viability) -{ - // OK: 70 bytes - GRC::Contract::Signature signature(TestSig::V1Bytes()); - - BOOST_CHECK(signature.Viable() == true); - - // OK: 70 bytes (not a real signature) - // Invalid signatures with correct length pass but won't verify against the - // public key when checking the contract. This is just an early check. - signature = GRC::Contract::Signature(TestSig::InvalidBytes()); - - BOOST_CHECK(signature.Viable() == true); - - // BAD: Check some invalid base64-encoded inputs: - for (const auto& garbage : TestSig::GarbageStrings()) { - signature = GRC::Contract::Signature::Parse(garbage); - - BOOST_CHECK(signature.Viable() == false); - } -} - -BOOST_AUTO_TEST_CASE(it_provides_the_bytes_in_the_signature) -{ - GRC::Contract::Signature signature(TestSig::V1Bytes()); - - BOOST_CHECK(signature.Raw() == TestSig::V1Bytes()); -} - -BOOST_AUTO_TEST_CASE(it_represents_itself_as_a_string) -{ - std::vector input = TestSig::V1Bytes(); - - GRC::Contract::Signature signature(input); - - BOOST_CHECK(signature.ToString() == TestSig::V1String()); -} - -BOOST_AUTO_TEST_SUITE_END() - -// ----------------------------------------------------------------------------- -// Contract::PublicKey -// ----------------------------------------------------------------------------- - -BOOST_AUTO_TEST_SUITE(Contract__PublicKey) - -BOOST_AUTO_TEST_CASE(it_initializes_to_an_invalid_key_by_default) -{ - GRC::Contract::PublicKey key; - - BOOST_CHECK(key.Key() == CPubKey()); -} - -BOOST_AUTO_TEST_CASE(it_initializes_by_wrapping_a_provided_key_object) -{ - GRC::Contract::PublicKey key(TestKey::Public()); - - BOOST_CHECK(key.Key() == TestKey::Public()); -} - -BOOST_AUTO_TEST_CASE(it_parses_a_public_key_from_a_hex_encoded_string) -{ - std::string input = TestKey::PublicString(); - - GRC::Contract::PublicKey key = GRC::Contract::PublicKey::Parse(input); - - BOOST_CHECK(key.Key() == TestKey::Public()); -} - -BOOST_AUTO_TEST_CASE(it_gives_an_invalid_key_when_parsing_an_empty_string) -{ - GRC::Contract::PublicKey key = GRC::Contract::PublicKey::Parse(""); - - BOOST_CHECK(key.Viable() == false); - BOOST_CHECK(key.ToString() == ""); -} - -BOOST_AUTO_TEST_CASE(it_supports_a_basic_check_for_key_viability) -{ - // OK: 65 bytes, uncompressed - std::string full_length = TestKey::PublicString(); - GRC::Contract::PublicKey key = GRC::Contract::PublicKey::Parse(full_length); - - BOOST_CHECK(key.Viable() == true); - - // OK: 33 bytes, compressed (not a real key) - key = GRC::Contract::PublicKey::Parse( - "044b2938fbc38071f24bede21e838a0758a52a0085f2e034e7f971df445436a252"); - - BOOST_CHECK(key.Viable() == true); - - // BAD: Check some invalid hex-encoded inputs: - for (const auto& garbage : TestKey::GarbagePublicStrings()) { - key = GRC::Contract::PublicKey::Parse(garbage); - - BOOST_CHECK(key.Viable() == false); - } -} - -BOOST_AUTO_TEST_CASE(it_provides_the_wrapped_key) -{ - GRC::Contract::PublicKey key(TestKey::Public()); - - BOOST_CHECK(key.Key() == TestKey::Public()); -} - -BOOST_AUTO_TEST_CASE(it_represents_itself_as_a_string) -{ - GRC::Contract::PublicKey key(TestKey::Public()); - - BOOST_CHECK(key.ToString() == TestKey::PublicString()); -} - -BOOST_AUTO_TEST_SUITE_END() - // ----------------------------------------------------------------------------- // Contract // ----------------------------------------------------------------------------- @@ -775,8 +483,6 @@ BOOST_AUTO_TEST_CASE(it_initializes_to_an_invalid_contract_by_default) BOOST_CHECK(contract.m_type == GRC::ContractType::UNKNOWN); BOOST_CHECK(contract.m_action == GRC::ContractAction::UNKNOWN); BOOST_CHECK(contract.m_body.WellFormed(contract.m_action.Value()) == false); - BOOST_CHECK(contract.m_signature.Raw().empty() == true); - BOOST_CHECK(contract.m_public_key.Key() == CPubKey()); } BOOST_AUTO_TEST_CASE(it_initializes_with_components_for_a_new_contract) @@ -790,8 +496,6 @@ BOOST_AUTO_TEST_CASE(it_initializes_with_components_for_a_new_contract) BOOST_CHECK(contract.m_type == GRC::ContractType::BEACON); BOOST_CHECK(contract.m_action == GRC::ContractAction::ADD); BOOST_CHECK(contract.m_body.WellFormed(contract.m_action.Value()) == true); - BOOST_CHECK(contract.m_signature.Raw().empty() == true); - BOOST_CHECK(contract.m_public_key.Key() == CPubKey()); } BOOST_AUTO_TEST_CASE(it_initializes_with_components_from_a_contract_message) @@ -800,22 +504,12 @@ BOOST_AUTO_TEST_CASE(it_initializes_with_components_from_a_contract_message) GRC::Contract::CURRENT_VERSION, GRC::ContractType::BEACON, GRC::ContractAction::ADD, - GRC::ContractPayload::Make("test data"), - GRC::Contract::Signature(TestSig::V1Bytes()), - GRC::Contract::PublicKey(TestKey::Public())); + GRC::ContractPayload::Make("test data")); BOOST_CHECK(contract.m_version == GRC::Contract::CURRENT_VERSION); BOOST_CHECK(contract.m_type == GRC::ContractType::BEACON); BOOST_CHECK(contract.m_action == GRC::ContractAction::ADD); BOOST_CHECK(contract.m_body.WellFormed(contract.m_action.Value()) == true); - BOOST_CHECK(contract.m_signature.Raw() == TestSig::V1Bytes()); - BOOST_CHECK(contract.m_public_key.Key() == TestKey::Public()); -} - -BOOST_AUTO_TEST_CASE(it_provides_the_legacy_message_keys) -{ - BOOST_CHECK(GRC::Contract::MessagePrivateKey().size() == 279); - BOOST_CHECK(GRC::Contract::MessagePublicKey().Raw().size() == 65); } BOOST_AUTO_TEST_CASE(it_detects_a_contract_in_a_transaction_message) @@ -848,8 +542,6 @@ BOOST_AUTO_TEST_CASE(it_parses_a_legacy_v1_contract_from_a_transaction_message) BOOST_CHECK(contract.m_action == GRC::ContractAction::ADD); BOOST_CHECK(payload->LegacyKeyString() == "test"); BOOST_CHECK(payload->LegacyValueString() == "test"); - BOOST_CHECK(contract.m_signature.Raw().size() == 70); - BOOST_CHECK(contract.m_public_key.Key().Raw().size() == 0); } BOOST_AUTO_TEST_CASE(it_gives_an_invalid_contract_when_parsing_an_empty_message) @@ -860,8 +552,6 @@ BOOST_AUTO_TEST_CASE(it_gives_an_invalid_contract_when_parsing_an_empty_message) BOOST_CHECK(contract.m_type == GRC::ContractType::UNKNOWN); BOOST_CHECK(contract.m_action == GRC::ContractAction::UNKNOWN); BOOST_CHECK(contract.m_body.WellFormed(contract.m_action.Value()) == false); - BOOST_CHECK(contract.m_signature.Raw().size() == 0); - BOOST_CHECK(contract.m_public_key.Key().Raw().size() == 0); } BOOST_AUTO_TEST_CASE(it_gives_an_invalid_contract_when_parsing_a_non_contract) @@ -872,19 +562,12 @@ BOOST_AUTO_TEST_CASE(it_gives_an_invalid_contract_when_parsing_a_non_contract) BOOST_CHECK(contract.m_type == GRC::ContractType::UNKNOWN); BOOST_CHECK(contract.m_action == GRC::ContractAction::UNKNOWN); BOOST_CHECK(contract.m_body.WellFormed(contract.m_action.Value()) == false); - BOOST_CHECK(contract.m_signature.Raw().size() == 0); - BOOST_CHECK(contract.m_public_key.Key().Raw().size() == 0); } BOOST_AUTO_TEST_CASE(it_determines_whether_a_contract_is_complete) { GRC::Contract contract = TestMessage::Current(); BOOST_CHECK(contract.WellFormed() == true); - - // WellFormed() does NOT verify the signature: - contract = TestMessage::Current(); - contract.m_signature = GRC::Contract::Signature(TestSig::InvalidBytes()); - BOOST_CHECK(contract.WellFormed() == true); } BOOST_AUTO_TEST_CASE(it_determines_whether_a_legacy_v1_contract_is_complete) @@ -906,37 +589,6 @@ BOOST_AUTO_TEST_CASE(it_determines_whether_a_legacy_v1_contract_is_complete) BOOST_CHECK(contract.WellFormed() == false); } -BOOST_AUTO_TEST_CASE(it_determines_whether_a_contract_is_valid) -{ - GRC::Contract contract = TestMessage::Current(); - BOOST_CHECK(contract.Validate() == true); - - // Version 2+ contracts rely on the signatures in the transactions instead - // of embedding another signature in the contract: - contract = TestMessage::Current(); - contract.m_signature = GRC::Contract::Signature(TestSig::InvalidBytes()); - BOOST_CHECK(contract.Validate() == true); -} - -BOOST_AUTO_TEST_CASE(it_determines_whether_a_legacy_v1_contract_is_valid) -{ - GRC::Contract contract = GRC::Contract::Parse(TestMessage::V1String()); - BOOST_CHECK(contract.Validate() == true); - - // Valid() DOES verify the signature: - contract = GRC::Contract::Parse(TestMessage::InvalidV1String()); - BOOST_CHECK(contract.Validate() == false); - - contract = GRC::Contract::Parse(TestMessage::PartialV1String()); - BOOST_CHECK(contract.Validate() == false); - - contract = GRC::Contract::Parse(""); - BOOST_CHECK(contract.Validate() == false); - - contract = GRC::Contract::Parse(""); - BOOST_CHECK(contract.Validate() == false); -} - BOOST_AUTO_TEST_CASE(it_determines_the_requred_burn_fee) { const GRC::Contract contract = TestMessage::Current(); @@ -965,7 +617,7 @@ BOOST_AUTO_TEST_CASE(it_casts_known_contract_payloads) BOOST_AUTO_TEST_CASE(it_converts_known_legacy_contract_payloads) { - const GRC::Contract contract = TestMessage::Current().ToLegacy(); + const GRC::Contract contract = TestMessage::V1(); const auto payload = contract.SharePayloadAs(); BOOST_CHECK_EQUAL(payload->m_name, "test"); @@ -996,186 +648,6 @@ BOOST_AUTO_TEST_CASE(it_moves_a_cast_or_converted_payload) BOOST_CHECK(contract.WellFormed() == false); } -BOOST_AUTO_TEST_CASE(it_determines_whether_a_contract_needs_a_special_key) -{ - // Note: currently all contract types require either the master or message - // public/private keys. - - GRC::Contract contract; - - // The following tests are not exhaustive for every type/action pair: - contract.m_type = GRC::ContractType::BEACON; - contract.m_action = GRC::ContractAction::ADD; - - BOOST_CHECK(contract.RequiresSpecialKey() == true); - BOOST_CHECK(contract.RequiresMasterKey() == false); - BOOST_CHECK(contract.RequiresMessageKey() == true); - - contract.m_type = GRC::ContractType::PROJECT; - - BOOST_CHECK(contract.RequiresSpecialKey() == true); - BOOST_CHECK(contract.RequiresMasterKey() == true); - BOOST_CHECK(contract.RequiresMessageKey() == false); -} - -BOOST_AUTO_TEST_CASE(it_resolves_the_appropriate_public_key_for_a_contract) -{ - // Note: currently all contracts types require either the master or message - // public/private keys. - - GRC::Contract contract; - - contract.m_type = GRC::ContractType::BEACON; - contract.m_action = GRC::ContractAction::ADD; - - BOOST_CHECK(contract.ResolvePublicKey() == GRC::Contract::MessagePublicKey()); - - contract.m_type = GRC::ContractType::PROJECT; - - BOOST_CHECK(contract.ResolvePublicKey() == CWallet::MasterPublicKey()); -} - -BOOST_AUTO_TEST_CASE(it_signs_a_message_with_a_supplied_private_key) -{ - GRC::Contract contract( - GRC::ContractType::UNKNOWN, - GRC::ContractAction::ADD, - GRC::ContractPayload::Make("test")); - - CKey private_key = TestKey::Private(); - - BOOST_CHECK(contract.Sign(private_key) == true); - - // Build the message body to hash to verify the new signature: - std::vector body { - 0x02, 0x00, 0x00, 0x00, // Version - 0x00, // ContractType::UNKNOWN - 0x01, // ContractAction::ADD - 0x04, 0x74, 0x65, 0x73, 0x74, // "test" preceded by length - }; - - uint256 hashed = Hash(body.begin(), body.end()); - - BOOST_CHECK(contract.m_signature.Viable() == true); - BOOST_CHECK(TestKey::Private().Verify(hashed, contract.m_signature.Raw())); -} - -BOOST_AUTO_TEST_CASE(it_signs_a_legacy_v1_message_with_a_supplied_private_key) -{ - GRC::Contract contract = TestMessage::V1(); - CKey private_key = TestKey::Private(); - - BOOST_CHECK(contract.Sign(private_key) == true); - - // Build the message body to hash to verify the new signature: - std::string body = "beacontesttest"; - uint256 hashed = Hash(body.begin(), body.end()); - - BOOST_CHECK(TestKey::Private().Verify(hashed, contract.m_signature.Raw())); -} - -BOOST_AUTO_TEST_CASE(it_signs_a_message_with_the_shared_message_private_key) -{ - GRC::Contract contract( - GRC::ContractType::BEACON, - GRC::ContractAction::ADD, - GRC::ContractPayload::Make("test")); - - BOOST_CHECK(contract.SignWithMessageKey() == true); - - // Build the message body to hash to verify the new signature: - std::vector body = { - 0x02, 0x00, 0x00, 0x00, // Version - 0x01, // ContractType::BEACON - 0x01, // ContractAction::ADD - 0x04, 0x74, 0x65, 0x73, 0x74, // "test" preceded by length - }; - - uint256 hashed = Hash(body.begin(), body.end()); - CKey key; - key.SetPrivKey(GRC::Contract::MessagePrivateKey()); - - BOOST_CHECK(key.Verify(hashed, contract.m_signature.Raw())); -} - -BOOST_AUTO_TEST_CASE(it_refuses_to_sign_a_message_with_an_invalid_private_key) -{ - GRC::Contract contract( - GRC::ContractType::BEACON, - GRC::ContractAction::ADD, - GRC::ContractPayload::Make("test")); - - CKey key; // Empty key - - BOOST_CHECK(contract.Sign(key) == false); - BOOST_CHECK(contract.m_signature.Raw().size() == 0); -} - -BOOST_AUTO_TEST_CASE(it_verifies_a_legacy_v1_contract_signature) -{ - // Test a message with a valid signature: - GRC::Contract contract = GRC::Contract::Parse(TestMessage::V1String()); - BOOST_CHECK(contract.VerifySignature() == true); - - // Change the previously-signed content: - contract.m_type = GRC::ContractType::PROJECT; - BOOST_CHECK(contract.VerifySignature() == false); - - // Test a message with an invalid signature: - contract = GRC::Contract::Parse(TestMessage::InvalidV1String()); - BOOST_CHECK(contract.VerifySignature() == false); -} - -BOOST_AUTO_TEST_CASE(it_generates_a_hash_of_a_contract_body) -{ - GRC::Contract contract = TestMessage::Current(); - - CHashWriter hasher(SER_NETWORK, PROTOCOL_VERSION); - - hasher << contract.m_version; - hasher << contract.m_type; - hasher << contract.m_action; - contract.m_body.Serialize(hasher, contract.m_action.Value()); - - BOOST_CHECK(contract.GetHash() == hasher.GetHash()); -} - -BOOST_AUTO_TEST_CASE(it_generates_a_hash_of_a_legacy_v1_contract_body) -{ - GRC::Contract contract = TestMessage::V1(); - - BOOST_CHECK(contract.GetHash() == uint256S( - "484e6c63845cd102b86b75d1c0cb36dd15ae41f8ad00690cdddbdade666b41b6")); -} - -BOOST_AUTO_TEST_CASE(it_converts_itself_into_a_new_legacy_contract) -{ - const GRC::Contract contract = TestMessage::Current(); - const GRC::Contract legacy = contract.ToLegacy(); - - const auto payload = contract.SharePayloadAs(); - const GRC::ContractPayload legacy_payload = legacy.SharePayload(); - - BOOST_CHECK_EQUAL(legacy.m_version, 1); - - BOOST_CHECK(legacy.m_type == contract.m_type.Value()); - BOOST_CHECK(legacy.m_action == contract.m_action.Value()); - - BOOST_CHECK(legacy_payload->LegacyKeyString() == payload->m_name); - BOOST_CHECK(legacy_payload->LegacyValueString() == payload->m_url); - - BOOST_CHECK(legacy.m_signature.Raw() == contract.m_signature.Raw()); - BOOST_CHECK(legacy.m_public_key.Key() == contract.m_public_key.Key()); -} - -BOOST_AUTO_TEST_CASE(it_represents_itself_as_a_legacy_string) -{ - GRC::Contract contract = TestMessage::V1(); - contract.m_signature = TestSig::V1Bytes(); - - BOOST_CHECK(contract.ToString() == TestMessage::V1String()); -} - BOOST_AUTO_TEST_CASE(it_serializes_to_a_stream) { GRC::Contract contract = TestMessage::Current(); @@ -1205,15 +677,11 @@ BOOST_AUTO_TEST_CASE(it_deserializes_from_a_stream) GRC::ContractPayload payload = contract.SharePayload(); - BOOST_CHECK(contract.Validate() == true); // Verifies signature + BOOST_CHECK(contract.WellFormed() == true); BOOST_CHECK(contract.m_version == GRC::Contract::CURRENT_VERSION); BOOST_CHECK(contract.m_type == GRC::ContractType::PROJECT); BOOST_CHECK(contract.m_action == GRC::ContractAction::ADD); BOOST_CHECK(payload->LegacyKeyString() == "test"); - // Version 2+ contracts rely on the signatures in the transactions instead - // of embedding another signature in the contract: - BOOST_CHECK(contract.m_public_key == CPubKey()); - BOOST_CHECK(contract.m_signature.Raw().empty() == true); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/gridcoin/researcher_tests.cpp b/src/test/gridcoin/researcher_tests.cpp index 2597aeda82..7ffbade53c 100644 --- a/src/test/gridcoin/researcher_tests.cpp +++ b/src/test/gridcoin/researcher_tests.cpp @@ -10,7 +10,6 @@ #include "gridcoin/researcher.h" #include "util.h" -#include #include #include #include @@ -23,31 +22,31 @@ namespace { //! //! \return Path to the test data directory containing the stub. //! -boost::filesystem::path ResolveStubDir() +fs::path ResolveStubDir() { - const boost::filesystem::path cwd = boost::filesystem::current_path(); - const boost::filesystem::path data_dir("src/test/data"); + const fs::path cwd = fs::current_path(); + const fs::path data_dir("src/test/data"); const std::string stub = "client_state.xml"; // Test harness run from subdirectory of repo root (src/, build/, etc.): - if (boost::filesystem::exists(cwd / ".." / data_dir / stub)) { - return boost::filesystem::canonical(cwd / ".." / data_dir); + if (fs::exists(cwd / ".." / data_dir / stub)) { + return fs::canonical(cwd / ".." / data_dir); } // Test harness run from platform-specific build sub-directory // (ex: build/gridcoin-x86_64-unknown-linux-gnu/) - if (boost::filesystem::exists(cwd / ".." / ".." / data_dir / stub)) { - return boost::filesystem::canonical(cwd / ".." / ".." / data_dir); + if (fs::exists(cwd / ".." / ".." / data_dir / stub)) { + return fs::canonical(cwd / ".." / ".." / data_dir); } // Test harness run from sub-directory in a platform-specific build sub- // directory (Travis; ex: build/gridcoin-x86_64-unknown-linux-gnu/src) - if (boost::filesystem::exists(cwd / ".." / ".." / ".." / data_dir / stub)) { - return boost::filesystem::canonical(cwd / ".." / ".." / ".." / data_dir); + if (fs::exists(cwd / ".." / ".." / ".." / data_dir / stub)) { + return fs::canonical(cwd / ".." / ".." / ".." / data_dir); } // Test harness run from test directory (src/test/): - if (boost::filesystem::exists(cwd / "data" / stub)) { + if (fs::exists(cwd / "data" / stub)) { return cwd / "data"; } @@ -1589,7 +1588,7 @@ void it_resets_to_investor_mode_when_explicitly_configured() //! BOOST_AUTO_TEST_CASE(client_state_stub_exists) { - if (boost::filesystem::exists(ResolveStubDir() / "client_state.xml")) { + if (fs::exists(ResolveStubDir() / "client_state.xml")) { boost::unit_test::framework::master_test_suite().add(BOOST_TEST_CASE(&it_parses_project_xml_from_a_client_state_xml_file)); boost::unit_test::framework::master_test_suite().add(BOOST_TEST_CASE(&it_resets_to_investor_mode_when_explicitly_configured)); } else { diff --git a/src/test/gridcoin/superblock_tests.cpp b/src/test/gridcoin/superblock_tests.cpp index 513697c5fe..3e4a9e386f 100644 --- a/src/test/gridcoin/superblock_tests.cpp +++ b/src/test/gridcoin/superblock_tests.cpp @@ -1270,58 +1270,6 @@ BOOST_AUTO_TEST_CASE(it_adds_a_cpid_magnitude_to_the_index) BOOST_CHECK(cpids.size() == 1); } -BOOST_AUTO_TEST_CASE(it_adds_a_rounded_cpid_magnitude_to_the_index) -{ - GRC::Superblock::CpidIndex cpids; - - GRC::Cpid cpid1 = GRC::Cpid::Parse("00010203040506070809101112131415"); - GRC::Cpid cpid2 = GRC::Cpid::Parse("15141312111009080706050403020100"); - - cpids.RoundAndAdd(cpid1, 123.5); - cpids.RoundAndAdd(cpid2, 123.4); - - BOOST_CHECK(cpids.MagnitudeOf(cpid1) == 124); - BOOST_CHECK(cpids.MagnitudeOf(cpid2) == 123); -} - -BOOST_AUTO_TEST_CASE(it_adds_a_legacy_rounded_cpid_magnitude_to_the_index) -{ - // Initializing the CPID index with a count of zero-magnitude CPIDs - // switches it to legacy mode: - // - GRC::Superblock::CpidIndex cpids(0); - - GRC::Cpid cpid1 = GRC::Cpid::Parse("11111111111111111111111111111111"); - GRC::Cpid cpid2 = GRC::Cpid::Parse("22222222222222222222222222222222"); - GRC::Cpid cpid3 = GRC::Cpid::Parse("33333333333333333333333333333333"); - GRC::Cpid cpid4 = GRC::Cpid::Parse("44444444444444444444444444444444"); - - // The ScraperGetNeuralContract() function that these classes replace - // rounded magnitude values using a half-away-from-zero rounding mode - // to determine whether floating-point magnitudes round-down to zero, - // but it added the magnitude values to the superblock with half-even - // rounding. This caused legacy superblock contracts to contain CPIDs - // with zero magnitude when the rounding results differed. - // - // To create legacy superblocks from scraper statistics with matching - // hashes, we filter magnitudes using the same rounding rules: - // - // - A magnitude of 0.5 is rounded-down to zero. - // - A magnitude less than 0.5 is omitted from the superblock. - // - cpids.RoundAndAdd(cpid1, 1.1); - cpids.RoundAndAdd(cpid2, 1.5); - cpids.RoundAndAdd(cpid3, 0.5); - cpids.RoundAndAdd(cpid4, 0.4); - - BOOST_CHECK(cpids.size() == 3); // cpid4 is omitted - - BOOST_CHECK(cpids.MagnitudeOf(cpid1) == 1); - BOOST_CHECK(cpids.MagnitudeOf(cpid2) == 2); - BOOST_CHECK(cpids.MagnitudeOf(cpid3) == 0); - BOOST_CHECK(cpids.MagnitudeOf(cpid4) == 0); -} - BOOST_AUTO_TEST_CASE(it_fetches_a_cpid_pair_by_offset) { GRC::Superblock::CpidIndex cpids; diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 30c712c1ce..e9a9f7ea71 100755 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include #include diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp index cf1bcbc3af..6bee408fc7 100644 --- a/src/txdb-leveldb.cpp +++ b/src/txdb-leveldb.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -36,27 +35,27 @@ static leveldb::Options GetOptions() { void init_blockindex(leveldb::Options& options, bool fRemoveOld = false) { // First time init. - filesystem::path directory = GetDataDir() / "txleveldb"; + fs::path directory = GetDataDir() / "txleveldb"; if (fRemoveOld) { - filesystem::remove_all(directory); // remove directory + fs::remove_all(directory); // remove directory unsigned int nFile = 1; while (true) { - filesystem::path strBlockFile = GetDataDir() / strprintf("blk%04u.dat", nFile); + fs::path strBlockFile = GetDataDir() / strprintf("blk%04u.dat", nFile); // Break if no such file - if( !filesystem::exists( strBlockFile ) ) + if( !fs::exists( strBlockFile ) ) break; - filesystem::remove(strBlockFile); + fs::remove(strBlockFile); nFile++; } } - filesystem::create_directory(directory); + fs::create_directory(directory); LogPrintf("Opening LevelDB in %s", directory.string()); leveldb::Status status = leveldb::DB::Open(options, directory.string(), &txdb); if (!status.ok()) { diff --git a/src/util.cpp b/src/util.cpp index 095d5fc043..eaa7897252 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "amount.h" #include "netbase.h" // for AddTimeData #include "sync.h" #include "version.h" diff --git a/src/util.h b/src/util.h index 94ece2dd3d..7dbc88fcec 100644 --- a/src/util.h +++ b/src/util.h @@ -18,12 +18,9 @@ #include #include #include -#include #include #include -#include -#include #include #include #include @@ -50,10 +47,6 @@ #include #include -static const int64_t COIN = 100000000; -static const int64_t COIN_PLACES = 8; -static const int64_t CENT = 1000000; - #define BEGIN(a) ((char*)&(a)) #define END(a) ((char*)&((&(a))[1])) #define UBEGIN(a) ((unsigned char*)&(a)) diff --git a/src/version.h b/src/version.h index 280243dfa2..0bc3899fde 100644 --- a/src/version.h +++ b/src/version.h @@ -43,9 +43,9 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const /////////////////////////////////////////////////////////// // network protocol versioning // // // -static const int PROTOCOL_VERSION = 180324; // +static const int PROTOCOL_VERSION = 180325; // // disconnect from peers older than this proto version // -static const int MIN_PEER_PROTO_VERSION = 180323; // +static const int MIN_PEER_PROTO_VERSION = 180324; // /////////////////////////////////////////////////////////// // initial proto version, to be increased after // // version/verack negotiation // diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 5e6a8c2358..3b481fc1ac 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -2,9 +2,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include - +#include "fs.h" #include "init.h" // for pwalletMain #include "rpcserver.h" #include "rpcprotocol.h" @@ -14,7 +12,6 @@ #include #include #include -#include using namespace std; @@ -187,8 +184,8 @@ UniValue importwallet(const UniValue& params, bool fHelp) "Imports keys from a wallet dump file (see dumpwallet)\n" "If a path is not specified in the filename, the data directory is used."); - boost::filesystem::path PathForImport = boost::filesystem::path(params[0].get_str()); - boost::filesystem::path DefaultPathDataDir = GetDataDir(); + fs::path PathForImport = fs::path(params[0].get_str()); + fs::path DefaultPathDataDir = GetDataDir(); // If provided filename does not have a path, then append parent path, otherwise leave alone. if (PathForImport.parent_path().empty()) @@ -320,8 +317,8 @@ UniValue dumpwallet(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); - boost::filesystem::path PathForDump = boost::filesystem::path(params[0].get_str()); - boost::filesystem::path DefaultPathDataDir = GetDataDir(); + fs::path PathForDump = fs::path(params[0].get_str()); + fs::path DefaultPathDataDir = GetDataDir(); // If provided filename does not have a path, then append parent path, otherwise leave alone. if (PathForDump.parent_path().empty()) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f6971100eb..b3f4d54678 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -109,6 +109,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.pushKV("newmint", ValueFromAmount(pwalletMain->GetNewMint())); obj.pushKV("stake", ValueFromAmount(pwalletMain->GetStake())); obj.pushKV("blocks", nBestHeight); + obj.pushKV("in_sync", !OutOfSyncByAge()); obj.pushKV("timeoffset", GetTimeOffset()); obj.pushKV("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)); obj.pushKV("connections", (int)vNodes.size()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9eb2cbed50..c367293581 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1138,7 +1138,7 @@ void CWalletTx::RelayWalletTransaction(CTxDB& txdb) // requires the consent of the user. Log a message instead so // that the user can take action if needed: // - if (nVersion == 1 && IsV11Enabled(nBestHeight + 1)) + if (nVersion == 1) { if (IsCoinBase() || IsCoinStake()) { @@ -1730,23 +1730,6 @@ bool CWallet::CreateTransaction(const vector >& vecSend, { LOCK2(cs_main, cs_wallet); - // Force version 1 transactions until mandatory threshold. - // - // CTransaction::CURRENT_VERSION is now 2, but we cannot send version 2 - // transactions until clients can handle them. - // - // TODO: remove this check in the next release after mandatory block. - // - if (!IsV11Enabled(nBestHeight + 1)) { - wtxNew.nVersion = 1; - - if (!wtxNew.vContracts.empty() - && wtxNew.vContracts[0].m_type == GRC::ContractType::MESSAGE) - { - wtxNew.hashBoinc = wtxNew.vContracts[0].ToString(); - } - } - // txdb must be opened before the mapWallet lock CTxDB txdb("r"); { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5bd8507a10..5b58f10bbd 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -9,6 +9,8 @@ #include #include #include + +#include "amount.h" #include "gridcoin/staking/status.h" #include "main.h" #include "key.h" diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index cc1107c4bf..c286bf51bf 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -7,10 +7,8 @@ #include "wallet/walletdb.h" #include "wallet/wallet.h" #include "init.h" -#include using namespace std; -using namespace boost; static uint64_t nAccountingEntryNumber = 0; extern bool fWalletUnlockStakingOnly;