From 6be262164d11e75e83c2527181c9b38a2e856fd4 Mon Sep 17 00:00:00 2001 From: pacificao Date: Wed, 18 Feb 2026 22:09:06 -0800 Subject: [PATCH] Updating code reviving this project --- autogen.sh | 27 ++- configure.ac | 6 +- doc/build-unix.md | 270 +++++---------------- doc/build-windows.md | 241 ++++++++++-------- src/agrarian-cli-res.rc | 3 +- src/agrarian-cli.cpp | 37 ++- src/agrarian-tx-res.rc | 2 + src/agrarian-tx.cpp | 9 +- src/agrariand-res.rc | 2 + src/agrariand.cpp | 9 +- src/chainparams.cpp | 134 ++++++---- src/chainparams.h | 18 +- src/kernel.cpp | 6 +- src/kernel.h | 12 +- src/main.cpp | 65 +++-- src/main.h | 96 +++----- src/masternode-budget.cpp | 14 +- src/masternode-budget.h | 69 +++--- src/masternode-payments.cpp | 472 +++++++++++++++++++++--------------- src/masternode-payments.h | 101 +++----- src/miner.cpp | 34 ++- src/miner.h | 16 +- src/pow.cpp | 9 +- src/pow.h | 13 +- src/rpc/mining.cpp | 19 +- src/txdb.cpp | 344 +++++++++++++++----------- 26 files changed, 1041 insertions(+), 987 deletions(-) diff --git a/autogen.sh b/autogen.sh index 0c05626c..b5a63381 100644 --- a/autogen.sh +++ b/autogen.sh @@ -1,16 +1,29 @@ #!/bin/sh # Copyright (c) 2013-2016 The Bitcoin Core developers +# Copyright (c) 2026 Agrarian Developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. export LC_ALL=C -set -e -srcdir="$(dirname $0)" + +# Fail fast on errors and undefined vars. (Note: 'pipefail' is not POSIX sh.) +set -eu + +srcdir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)" cd "$srcdir" -if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then - LIBTOOLIZE="${GLIBTOOLIZE}" - export LIBTOOLIZE + +# Prefer glibtoolize on macOS if LIBTOOLIZE isn't already set. +if [ -z "${LIBTOOLIZE:-}" ]; then + GLIBTOOLIZE="$(command -v glibtoolize 2>/dev/null || true)" + if [ -n "$GLIBTOOLIZE" ]; then + LIBTOOLIZE="$GLIBTOOLIZE" + export LIBTOOLIZE + fi fi -which autoreconf >/dev/null || \ - (echo "configuration failed, please install autoconf first" && exit 1) + +if ! command -v autoreconf >/dev/null 2>&1; then + echo "configuration failed: please install autoconf first" >&2 + exit 1 +fi + autoreconf --install --force --warnings=all diff --git a/configure.ac b/configure.ac index a438328c..655f34b3 100644 --- a/configure.ac +++ b/configure.ac @@ -1,3 +1,7 @@ +dnl Copyright (c) 2026 Agrarian Developers +dnl Distributed under the MIT/X11 software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) @@ -5,7 +9,7 @@ define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) -define(_COPYRIGHT_YEAR, 2022) +define(_COPYRIGHT_YEAR, 2026) AC_INIT([Agrarian Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[www.agrarian.org],[agrarian]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/agrarian-config.h]) diff --git a/doc/build-unix.md b/doc/build-unix.md index da1a2b41..c68a7c64 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -1,283 +1,123 @@ -UNIX BUILD NOTES -==================== -Some notes on how to build Agrarian Core in Unix. +Copyright (c) 2026 Agrarian Developers -Note ---------------------- -Always use absolute paths to configure and compile Agrarian Core and the dependencies, -For example, when specifying the path of the dependency: +UNIX Build Notes - ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX +These notes describe how to build Agrarian Core on Unix-based systems. -Here BDB_PREFIX must be an absolute path - it is defined using $(pwd) which ensures -the usage of the absolute path. +IMPORTANT -To Build ---------------------- +Always use absolute paths when configuring and compiling Agrarian Core +and its dependencies. -```bash -./autogen.sh -./configure -make -make install # optional -``` +Example: -This will build agrarian-qt as well, if the dependencies are met. + ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX -Dependencies ---------------------- +$BDB_PREFIX must be an absolute path. Using $(pwd) ensures an absolute +path is used. -These dependencies are required: +STANDARD BUILD - Library | Purpose | Description - ------------|--------------------|---------------------- - libssl | Crypto | Random Number Generation, Elliptic Curve Cryptography - libboost | Utility | Library for threading, data structures, etc - libevent | Networking | OS independent asynchronous networking - libgmp | Bignum Arithmetic | Precision arithmetic + ./autogen.sh + ./configure + make + make install (optional) -Optional dependencies: +If dependencies are satisfied, this will build agrarian-qt as well. - Library | Purpose | Description - ------------|------------------|---------------------- - miniupnpc | UPnP Support | Firewall-jumping support - libdb4.8 | Berkeley DB | Wallet storage (only needed when wallet enabled) - qt | GUI | GUI toolkit (only needed when GUI enabled) - protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) - libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) - univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) - libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.0.0) +DEPENDENCIES -For the versions used, see [dependencies.md](dependencies.md) +Required: - libssl : Crypto (RNG, ECC) - libboost : Utility (threading, +data structures) - libevent : Networking (async networking) - libgmp : +Bignum arithmetic -Memory Requirements --------------------- +Optional: - miniupnpc : UPnP support - libdb4.8 : Berkeley DB (wallet +builds only) - qt : GUI support - protobuf : GUI payment protocol - +libqrencode: QR code support - univalue : JSON parsing (bundled by +default) - libzmq3 : ZMQ notifications (>= 4.0.0) -C++ compilers are memory-hungry. It is recommended to have at least 1.5 GB of -memory available when compiling Agrarian Core. On systems with less, gcc can be -tuned to conserve memory with additional CXXFLAGS: +See dependencies.md for version details. +MEMORY REQUIREMENTS + +Minimum recommended: 1.5 GB RAM. + +Low memory systems: ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" +UBUNTU / DEBIAN -## Linux Distribution Specific Instructions - -### Ubuntu & Debian - -#### Dependency Build Instructions - -Build requirements: +Build tools: sudo apt-get install build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 -Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: +Libraries: sudo apt-get install libssl-dev libgmp-dev libevent-dev libboost-all-dev -**Note:** For Ubuntu versions starting with Bionic (18.04), or Debian versions starting with Stretch, use `libssl1.0-dev` -above instead of `libssl-dev`. Agrarian Core does not support the use of OpenSSL 1.1, though compilation is still possible -by passing `--with-incompatible-ssl` to configure (NOT RECOMMENDED!). +OpenSSL Note: For Ubuntu >= 18.04 or Debian >= Stretch use +libssl1.0-dev. OpenSSL 1.1 is not officially supported. -BerkeleyDB is required for the wallet. - - **For Ubuntu only:** db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). - You can add the repository using the following command: +Berkeley DB 4.8 (wallet support): sudo apt-get install software-properties-common sudo add-apt-repository ppa:bitcoin/bitcoin sudo apt-get update sudo apt-get install libdb4.8-dev libdb4.8++-dev -Ubuntu and Debian have their own libdb-dev and libdb++-dev packages, but these will install -BerkeleyDB 5.1 or later. This will break binary wallet compatibility with the distributed executables, which -are based on BerkeleyDB 4.8. If you do not care about wallet compatibility, -pass `--with-incompatible-bdb` to configure. - -Otherwise, you can build from self-compiled `depends` (see above). - -To build Agrarian Core without wallet, see [*Disable-wallet mode*](/doc/build-unix.md#disable-wallet-mode) - - -Optional (see --with-miniupnpc and --enable-upnp-default): +Optional: sudo apt-get install libminiupnpc-dev - -ZMQ dependencies (provides ZMQ API): - sudo apt-get install libzmq3-dev -GUI dependencies: +Qt GUI: -If you want to build agrarian-qt, make sure that the required packages for Qt development -are installed. Qt 5 is necessary to build the GUI. -To build without GUI pass `--without-gui`. + sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler -To build with Qt 5 you need the following: +Disable GUI: - sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler + ./configure --without-gui -libqrencode (optional) can be installed with: +FEDORA - sudo apt-get install libqrencode-dev +Build tools: -Once these are installed, they will be found by configure and a agrarian-qt executable will be -built by default. - - -### Fedora - -#### Dependency Build Instructions - -Build requirements: - - sudo dnf install which gcc-c++ libtool make autoconf automake compat-openssl10-devel libevent-devel boost-devel libdb4-devel libdb4-cxx-devel gmp-devel python3 + sudo dnf install which gcc-c++ libtool make autoconf automake compat-openssl10-devel libevent-devel boost-devel libdb4-devel libdb4-cxx-devel gmp-devel python3 Optional: sudo dnf install miniupnpc-devel zeromq-devel -To build with Qt 5 you need the following: +Qt: sudo dnf install qt5-qttools-devel qt5-qtbase-devel protobuf-devel -libqrencode (optional) can be installed with: +HARDENING - sudo dnf install qrencode-devel +Enable: -Notes ------ -The release is built with GCC and then "strip agrariand" to strip the debug -symbols, which reduces the executable size by about 90%. + ./configure --enable-hardening +Disable: -miniupnpc ---------- + ./configure --disable-hardening -[miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here]( -http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and -turned off by default. See the configure options for upnp behavior desired: +Verify: - --without-miniupnpc No UPnP support miniupnp not required - --disable-upnp-default (the default) UPnP support turned off by default at runtime - --enable-upnp-default UPnP support turned on by default at runtime + scanelf -e ./agrariand -To build: - - tar -xzvf miniupnpc-1.6.tar.gz - cd miniupnpc-1.6 - make - sudo su - make install - - -Berkeley DB ------------ -It is recommended to use Berkeley DB 4.8. If you have to build it yourself, -you can use [the installation script included in contrib/](/contrib/install_db4.sh) -like so: - -```shell -./contrib/install_db4.sh `pwd` -``` - -from the root of the repository. - -**Note**: You only need Berkeley DB if the wallet is enabled (see [*Disable-wallet mode*](/doc/build-unix.md#disable-wallet-mode)). - -Boost ------ -If you need to build Boost yourself: - - sudo su - ./bootstrap.sh - ./bjam install - - -Security --------- -To help make your Agrarian Core installation more secure by making certain attacks impossible to -exploit even if a vulnerability is found, binaries are hardened by default. -This can be disabled with: - -Hardening Flags: - - ./configure --enable-hardening - ./configure --disable-hardening - - -Hardening enables the following features: -* _Position Independent Executable_: Build position independent code to take advantage of Address Space Layout Randomization - offered by some kernels. Attackers who can cause execution of code at an arbitrary memory - location are thwarted if they don't know where anything useful is located. - The stack and heap are randomly located by default, but this allows the code section to be - randomly located as well. - - On an AMD64 processor where a library was not compiled with -fPIC, this will cause an error - such as: "relocation R_X86_64_32 against `......' can not be used when making a shared object;" - - To test that you have built PIE executable, install scanelf, part of paxutils, and use: - - scanelf -e ./agrariand - - The output should contain: - - TYPE - ET_DYN - -* _Non-executable Stack_: If the stack is executable then trivial stack-based buffer overflow exploits are possible if - vulnerable buffers are found. By default, Agrarian Core should be built with a non-executable stack - but if one of the libraries it uses asks for an executable stack or someone makes a mistake - and uses a compiler extension which requires an executable stack, it will silently build an - executable without the non-executable stack protection. - - To verify that the stack is non-executable after compiling use: - `scanelf -e ./agrariand` - - The output should contain: - STK/REL/PTL - RW- R-- RW- - - The STK RW- means that the stack is readable and writeable but not executable. - -Disable-wallet mode --------------------- -**Note:** This functionality is not yet completely implemented, and compilation using the below option will currently fail. - -When the intention is to run only a P2P node without a wallet, Agrarian Core may be compiled in -disable-wallet mode with: +DISABLE WALLET MODE ./configure --disable-wallet -In this case there is no dependency on Berkeley DB 4.8. - - -Additional Configure Flags --------------------------- -A list of additional configure flags can be displayed with: - - ./configure --help - - -ARM Cross-compilation -------------------- -These steps can be performed on, for example, an Ubuntu VM. The depends system -will also work on other Linux distributions, however the commands for -installing the toolchain will be different. - -Make sure you install the build requirements mentioned above. -Then, install the toolchain and curl: +ARM CROSS COMPILATION sudo apt-get install g++-arm-linux-gnueabihf curl -To build executables for ARM: - cd depends make HOST=arm-linux-gnueabihf NO_QT=1 cd .. ./autogen.sh - ./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ + ./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ make - - -For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. diff --git a/doc/build-windows.md b/doc/build-windows.md index 97f24599..06b67e1d 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -1,151 +1,198 @@ -WINDOWS BUILD NOTES -==================== +Copyright (c) 2026 Agrarian Developers -Below are some notes on how to build Agrarian Core for Windows. +============================================================ + Agrarian Core – Windows Build Notes +============================================================ -The options known to work for building Agrarian Core on Windows are: +This document describes how to build Agrarian Core for Windows. -* On Linux, using the [Mingw-w64](https://mingw-w64.org/doku.php) cross compiler tool chain. Ubuntu Bionic 18.04 is required -and is the platform used to build the Agrarian Core Windows release binaries. -* On Windows, using [Windows -Subsystem for Linux (WSL)](https://msdn.microsoft.com/commandline/wsl/about) and the Mingw-w64 cross compiler tool chain. - -Other options which may work, but which have not been extensively tested are (please contribute instructions): - -* On Windows, using a POSIX compatibility layer application such as [cygwin](http://www.cygwin.com/) or [msys2](http://www.msys2.org/). -* On Windows, using a native compiler tool chain such as [Visual Studio](https://www.visualstudio.com). - -Installing Windows Subsystem for Linux ---------------------------------------- - -With Windows 10, Microsoft has released a new feature named the [Windows -Subsystem for Linux (WSL)](https://msdn.microsoft.com/commandline/wsl/about). This -feature allows you to run a bash shell directly on Windows in an Ubuntu-based -environment. Within this environment you can cross compile for Windows without -the need for a separate Linux VM or server. Note that while WSL can be installed with -other Linux variants, such as OpenSUSE, the following instructions have only been -tested with Ubuntu. - -This feature is not supported in versions of Windows prior to Windows 10 or on -Windows Server SKUs. In addition, it is available [only for 64-bit versions of -Windows](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide). - -Full instructions to install WSL are available on the above link. -To install WSL on Windows 10 with Fall Creators Update installed (version >= 16215.0) do the following: - -1. Enable the Windows Subsystem for Linux feature - * Open the Windows Features dialog (`OptionalFeatures.exe`) - * Enable 'Windows Subsystem for Linux' - * Click 'OK' and restart if necessary -2. Install Ubuntu - * Open Microsoft Store and search for "Ubuntu 18.04" or use [this link](https://www.microsoft.com/store/productId/9N9TNGVNDL3Q) - * Click Install -3. Complete Installation - * Open a cmd prompt and type "Ubuntu1804" - * Create a new UNIX user account (this is a separate account from your Windows account) - -After the bash shell is active, you can follow the instructions below, starting -with the "Cross-compilation" section. Compiling the 64-bit version is -recommended, but it is possible to compile the 32-bit version. - -Cross-compilation for Ubuntu and Windows Subsystem for Linux +------------------------------------------------------------ +SUPPORTED BUILD METHODS ------------------------------------------------------------ -The steps below can be performed on Ubuntu (including in a VM) or WSL. The depends system -will also work on other Linux distributions, however the commands for -installing the toolchain will be different. +The following methods are known to work: -First, install the general dependencies: +1. Linux (Ubuntu 18.04 Bionic recommended) + Using the Mingw-w64 cross-compilation toolchain. + This is the method used to produce official Windows release binaries. + +2. Windows 10+ + Using Windows Subsystem for Linux (WSL) with Mingw-w64. + +------------------------------------------------------------ +UNTESTED / PARTIALLY TESTED OPTIONS +------------------------------------------------------------ + +The following may work but are not officially supported: + +• Cygwin +• MSYS2 +• Native Visual Studio toolchain + +Contributions for these methods are welcome. + +============================================================ +WINDOWS SUBSYSTEM FOR LINUX (WSL) +============================================================ + +WSL allows running a Linux environment directly on Windows without a VM. + +Requirements: +• Windows 10 (64-bit only) +• Not supported on Windows Server +• Ubuntu recommended (tested on Ubuntu 18.04) + +------------------------------------------------------------ +INSTALLING WSL +------------------------------------------------------------ + +1. Enable WSL + - Run: OptionalFeatures.exe + - Enable "Windows Subsystem for Linux" + - Restart if prompted + +2. Install Ubuntu + - Open Microsoft Store + - Install "Ubuntu 18.04" + +3. Complete Setup + - Open command prompt + - Run: Ubuntu1804 + - Create a UNIX user account + +Once WSL is active, continue with cross-compilation instructions below. + +============================================================ +CROSS-COMPILATION (Ubuntu or WSL) +============================================================ + +The steps below work on: +• Native Ubuntu +• Ubuntu VM +• WSL + +------------------------------------------------------------ +GENERAL DEPENDENCIES +------------------------------------------------------------ sudo apt update sudo apt upgrade - sudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git + sudo apt install build-essential libtool autotools-dev \ + automake pkg-config bsdmainutils curl git -A host toolchain (`build-essential`) is necessary because some dependency -packages (such as `protobuf`) need to build host utilities that are used in the -build process. +A host toolchain (build-essential) is required because some dependencies +(e.g., protobuf) build host utilities during the process. -See [dependencies.md](dependencies.md) for a complete overview. - -If you want to build the windows installer with `make deploy` you need [NSIS](https://nsis.sourceforge.io/Main_Page): +If building the Windows installer (`make deploy`): sudo apt install nsis -Acquire the source in the usual way: +------------------------------------------------------------ +SOURCE CODE +------------------------------------------------------------ git clone https://github.com/agrarian-project/agrarian.git cd agrarian -## Building for 64-bit Windows +============================================================ +BUILDING FOR 64-BIT WINDOWS +============================================================ -The first step is to install the mingw-w64 cross-compilation tool chain: +Install Mingw-w64 toolchain: sudo apt install g++-mingw-w64-x86-64 -Ubuntu Bionic 18.04 [1](#footnote1): +Ubuntu 18.04: - sudo update-alternatives --config x86_64-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix. + sudo update-alternatives --config x86_64-w64-mingw32-g++ -Once the toolchain is installed the build steps are common: +Select the POSIX thread model (required). -Note that for WSL the Agrarian Core source path MUST be somewhere in the default mount file system, for -example /usr/src/agrarian, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. -This means you cannot use a directory that is located directly on the host Windows file system to perform the build. +------------------------------------------------------------ +IMPORTANT (WSL USERS) +------------------------------------------------------------ -Build using: +The source directory MUST reside inside the Linux filesystem +(e.g., /usr/src/agrarian). - PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var +DO NOT build from /mnt/c or any mounted Windows path. +Autoconf scripts will fail. + +------------------------------------------------------------ +BUILD COMMANDS +------------------------------------------------------------ + + PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') cd depends make HOST=x86_64-w64-mingw32 cd .. - ./autogen.sh # not required when building from tarball - CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/ + ./autogen.sh + CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site \ + ./configure --prefix=/ make -## Building for 32-bit Windows +============================================================ +BUILDING FOR 32-BIT WINDOWS +============================================================ -To build executables for Windows 32-bit, install the following dependencies: +Install toolchain: sudo apt install g++-mingw-w64-i686 mingw-w64-i686-dev -Ubuntu Bionic 18.04 [1](#footnote1): +Ubuntu 18.04: - sudo update-alternatives --config i686-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix. + sudo update-alternatives --config i686-w64-mingw32-g++ -Build using: +Select the POSIX thread model. - PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var +------------------------------------------------------------ +BUILD COMMANDS +------------------------------------------------------------ + + PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') cd depends make HOST=i686-w64-mingw32 cd .. - ./autogen.sh # not required when building from tarball - CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site ./configure --prefix=/ + ./autogen.sh + CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site \ + ./configure --prefix=/ make -## Depends system +============================================================ +DEPENDS SYSTEM +============================================================ -For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. +For additional documentation, see: -Installation -------------- + depends/README.md -After building using the Windows subsystem it can be useful to copy the compiled -executables to a directory on the Windows drive in the same directory structure -as they appear in the release `.zip` archive. This can be done in the following -way. This will install to `c:\workspace\agrarian`, for example: +============================================================ +INSTALLATION +============================================================ + +To install into a Windows-accessible directory: make install DESTDIR=/mnt/c/workspace/agrarian -You can also create an installer using: +To build a Windows installer: make deploy -Footnotes ---------- +============================================================ +THREAD MODEL NOTE +============================================================ -1: Starting from Ubuntu Xenial 16.04, both the 32 and 64 bit Mingw-w64 packages install two different -compiler options to allow a choice between either posix or win32 threads. The default option is win32 threads which is the more -efficient since it will result in binary code that links directly with the Windows kernel32.lib. Unfortunately, the headers -required to support win32 threads conflict with some of the classes in the C++11 standard library, in particular std::mutex. -It's not possible to build the Agrarian Core code using the win32 version of the Mingw-w64 cross compilers (at least not without -modifying headers in the Agrarian Core source code). +Ubuntu Mingw-w64 packages include two thread models: + +• win32 (default) +• posix + +The win32 model conflicts with certain C++11 headers +(e.g., std::mutex) used by Agrarian Core. + +You MUST select the POSIX thread model when prompted by +update-alternatives. + +============================================================ +END OF DOCUMENT +============================================================ diff --git a/src/agrarian-cli-res.rc b/src/agrarian-cli-res.rc index 078b49eb..d92e4d1d 100644 --- a/src/agrarian-cli-res.rc +++ b/src/agrarian-cli-res.rc @@ -1,3 +1,4 @@ +// Copyright (c) 2026 Agrarian Developers #include // needed for VERSIONINFO #include "clientversion.h" // holds the needed client version information @@ -32,4 +33,4 @@ BEGIN BEGIN VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) END -END +END \ No newline at end of file diff --git a/src/agrarian-cli.cpp b/src/agrarian-cli.cpp index e54ed61f..1249a51a 100644 --- a/src/agrarian-cli.cpp +++ b/src/agrarian-cli.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2015 The Bitcoin developers // Copyright (c) 2009-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -23,9 +24,6 @@ #include #define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ - -using namespace std; - static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; std::string HelpMessageCli() @@ -116,13 +114,12 @@ struct HTTPReply std::string body; }; -static void http_request_done(struct evhttp_request *req, void *ctx) +static void http_request_done(struct evhttp_request* req, void* ctx) { - HTTPReply *reply = static_cast(ctx); + HTTPReply* reply = static_cast(ctx); - if (req == NULL) { - /* If req is NULL, it means an error occurred while connecting, but - * I'm not sure how to find out which one. We also don't really care. + if (req == nullptr) { + /* If req is nullptr, it means an error occurred while connecting, but* I'm not sure how to find out which one. We also don't really care. */ reply->status = 0; return; @@ -130,11 +127,11 @@ static void http_request_done(struct evhttp_request *req, void *ctx) reply->status = evhttp_request_get_response_code(req); - struct evbuffer *buf = evhttp_request_get_input_buffer(req); + struct evbuffer* buf = evhttp_request_get_input_buffer(req); if (buf) { size_t size = evbuffer_get_length(buf); - const char *data = (const char*)evbuffer_pullup(buf, size); + const char* data = (const char*)evbuffer_pullup(buf, size); if (data) reply->body = std::string(data, size); evbuffer_drain(buf, size); @@ -147,19 +144,19 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) int port = GetArg("-rpcport", BaseParams().RPCPort()); // Create event base - struct event_base *base = event_base_new(); // TODO RAII + struct event_base* base = event_base_new(); // TODO RAII if (!base) throw runtime_error("cannot create event_base"); // Synchronously look up hostname - struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII - if (evcon == NULL) + struct evhttp_connection* evcon = evhttp_connection_base_new(base, nullptr, host.c_str(), port); // TODO RAII + if (evcon == nullptr) throw runtime_error("create connection failed"); evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); HTTPReply response; - struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII - if (req == NULL) + struct evhttp_request* req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII + if (req == nullptr) throw runtime_error("create http request failed"); // Get credentials @@ -176,7 +173,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; } - struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req); + struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req); assert(output_headers); evhttp_add_header(output_headers, "Host", host.c_str()); evhttp_add_header(output_headers, "Connection", "close"); @@ -184,7 +181,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) // Attach request data std::string strRequest = JSONRPCRequest(strMethod, params, 1); - struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req); + struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req); assert(output_buffer); evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); @@ -280,7 +277,7 @@ int CommandLineRPC(int argc, char* argv[]) strPrint = string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { - PrintExceptionContinue(NULL, "CommandLineRPC()"); + PrintExceptionContinue(nullptr, "CommandLineRPC()"); throw; } @@ -305,7 +302,7 @@ int main(int argc, char* argv[]) PrintExceptionContinue(&e, "AppInitRPC()"); return EXIT_FAILURE; } catch (...) { - PrintExceptionContinue(NULL, "AppInitRPC()"); + PrintExceptionContinue(nullptr, "AppInitRPC()"); return EXIT_FAILURE; } @@ -315,7 +312,7 @@ int main(int argc, char* argv[]) } catch (std::exception& e) { PrintExceptionContinue(&e, "CommandLineRPC()"); } catch (...) { - PrintExceptionContinue(NULL, "CommandLineRPC()"); + PrintExceptionContinue(nullptr, "CommandLineRPC()"); } return ret; } diff --git a/src/agrarian-tx-res.rc b/src/agrarian-tx-res.rc index e12a5ac8..7d255126 100644 --- a/src/agrarian-tx-res.rc +++ b/src/agrarian-tx-res.rc @@ -1,3 +1,5 @@ +// Copyright (c) 2026 Agrarian Developers + #include // needed for VERSIONINFO #include "clientversion.h" // holds the needed client version information diff --git a/src/agrarian-tx.cpp b/src/agrarian-tx.cpp index 93fc22e2..befddfaf 100644 --- a/src/agrarian-tx.cpp +++ b/src/agrarian-tx.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,8 +25,6 @@ #include using namespace boost::assign; -using namespace std; - static bool fCreateBlank; static map registers; CClientUIInterface uiInterface; @@ -605,7 +604,7 @@ static int CommandLineRawTx(int argc, char* argv[]) strPrint = string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { - PrintExceptionContinue(NULL, "CommandLineRawTx()"); + PrintExceptionContinue(nullptr, "CommandLineRawTx()"); throw; } @@ -626,7 +625,7 @@ int main(int argc, char* argv[]) PrintExceptionContinue(&e, "AppInitRawTx()"); return EXIT_FAILURE; } catch (...) { - PrintExceptionContinue(NULL, "AppInitRawTx()"); + PrintExceptionContinue(nullptr, "AppInitRawTx()"); return EXIT_FAILURE; } @@ -636,7 +635,7 @@ int main(int argc, char* argv[]) } catch (std::exception& e) { PrintExceptionContinue(&e, "CommandLineRawTx()"); } catch (...) { - PrintExceptionContinue(NULL, "CommandLineRawTx()"); + PrintExceptionContinue(nullptr, "CommandLineRawTx()"); } return ret; } diff --git a/src/agrariand-res.rc b/src/agrariand-res.rc index 51e58de6..49e2f463 100644 --- a/src/agrariand-res.rc +++ b/src/agrariand-res.rc @@ -1,3 +1,5 @@ +// Copyright (c) 2026 Agrarian Developers + #include // needed for VERSIONINFO #include "clientversion.h" // holds the needed client version information diff --git a/src/agrariand.cpp b/src/agrariand.cpp index 4e6a49ae..9e4a8437 100644 --- a/src/agrariand.cpp +++ b/src/agrariand.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -29,13 +30,11 @@ * \section intro_sec Introduction * * This is the developer documentation of the reference client for an experimental new digital currency called Agrarian (http://www.agrarian.org), - * which enables instant payments to anyone, anywhere in the world. Agrarian uses peer-to-peer technology to operate - * with no central authority: managing transactions and issuing money are carried out collectively by the network. + * which enables instant payments to anyone, anywhere in the world. Agrarian uses peer-to-peer technology to operate* with no central authority: managing transactions and issuing money are carried out collectively by the network. * * The software is a community-driven open source project, released under the MIT license. * - * \section Navigation - * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code. + * \section Navigation* Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code. */ static bool fDaemon; @@ -144,7 +143,7 @@ bool AppInit(int argc, char* argv[]) } catch (std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); } catch (...) { - PrintExceptionContinue(NULL, "AppInit()"); + PrintExceptionContinue(nullptr, "AppInit()"); } if (!fRet) { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 65ba3a87..1e6cc1b5 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -2,11 +2,14 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "libzerocoin/Params.h" + #include "chainparams.h" +#include "chainparamsseeds.h" #include "random.h" #include "util.h" #include "utilstrencodings.h" @@ -23,8 +26,6 @@ struct SeedSpec6 { uint16_t port; }; -#include "chainparamsseeds.h" - /** * Main network */ @@ -57,9 +58,9 @@ static Checkpoints::MapCheckpoints mapCheckpoints = static const Checkpoints::CCheckpointData data = { &mapCheckpoints, 1643790201, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint + 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) - 0 // * estimated number of transactions per day after checkpoint + 0 // * estimated number of transactions per day after checkpoint }; static Checkpoints::MapCheckpoints mapCheckpointsTestnet = @@ -69,7 +70,8 @@ static const Checkpoints::CCheckpointData dataTestnet = { &mapCheckpointsTestnet, 1643790201, 0, - 0}; + 0 +}; static Checkpoints::MapCheckpoints mapCheckpointsRegtest = boost::assign::map_list_of(0, uint256("0x001")); @@ -77,24 +79,24 @@ static const Checkpoints::CCheckpointData dataRegtest = { &mapCheckpointsRegtest, 1643790201, 0, - 0}; + 0 +}; libzerocoin::ZerocoinParams* CChainParams::Zerocoin_Params(bool useModulusV1) const { assert(this); + static CBigNum bnHexModulus = 0; if (!bnHexModulus) bnHexModulus.SetHex(zerocoinModulus); static libzerocoin::ZerocoinParams ZCParamsHex = libzerocoin::ZerocoinParams(bnHexModulus); + static CBigNum bnDecModulus = 0; if (!bnDecModulus) bnDecModulus.SetDec(zerocoinModulus); static libzerocoin::ZerocoinParams ZCParamsDec = libzerocoin::ZerocoinParams(bnDecModulus); - if (useModulusV1) - return &ZCParamsHex; - - return &ZCParamsDec; + return useModulusV1 ? &ZCParamsHex : &ZCParamsDec; } class CMainParams : public CChainParams @@ -130,26 +132,33 @@ public: /** Height or Time Based Activations **/ nLastPOWBlock = 100; - nModifierUpdateBlock = 2; //The block at which PoS rules activate + + // Hybrid consensus: PoW mining and PoS staking are both permitted beginning at block 2. + // PoW remains permitted until nLastPOWBlock. + nFirstPoSBlock = 2; + + // PIVX-style modifier upgrade: keep aligned with PoS activation. + nModifierUpdateBlock = 2; + nZerocoinStartHeight = 0; nZerocoinStartTime = 1643790201; - nBlockEnforceSerialRange = 1; //Enforce serial range starting this block - nBlockRecalculateAccumulators = 999999999; //Trigger a recalculation of accumulators - nBlockFirstFraudulent = 999999999; //First block that bad serials emerged - nBlockLastGoodCheckpoint = 999999999; //Last valid accumulator checkpoint - nBlockEnforceInvalidUTXO = 999999999; //Start enforcing the invalid UTXO's - nInvalidAmountFiltered = 0; //Amount of invalid coins filtered through exchanges, that should be considered valid + nBlockEnforceSerialRange = 1; // Enforce serial range starting this block + nBlockRecalculateAccumulators = 999999999; // Trigger a recalculation of accumulators + nBlockFirstFraudulent = 999999999; // First block that bad serials emerged + nBlockLastGoodCheckpoint = 999999999; // Last valid accumulator checkpoint + nBlockEnforceInvalidUTXO = 999999999; // Start enforcing the invalid UTXO's + nInvalidAmountFiltered = 0; // Amount of invalid coins filtered through exchanges, that should be considered valid nBlockZerocoinV2 = 999999999; nBlockDoubleAccumulated = 999999999; nEnforceNewSporkKey = 1643790201; - nRejectOldSporkKey = 1527811200; + nRejectOldSporkKey = 1527811200; // Public coin spend enforcement nPublicZCSpends = 1; // Fake Serial Attack nFakeSerialBlockheightEnd = 0; - nSupplyBeforeFakeSerial = 0; // zerocoin supply at block nFakeSerialBlockheightEnd + nSupplyBeforeFakeSerial = 0; // zerocoin supply at block nFakeSerialBlockheightEnd /** * Build the genesis block. Note that the output of the genesis coinbase cannot @@ -165,7 +174,9 @@ public: CMutableTransaction txNew; txNew.vin.resize(1); txNew.vout.resize(1); - txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); + txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) + << vector((const unsigned char*)pszTimestamp, + (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vout[0].nValue = 50 * COIN; txNew.vout[0].scriptPubKey = CScript() << ParseHex("04fe3d7e5608ebba6d822948eff929c822ad35b5f8ecd00977d0e59ed67da697bd88e0ed8bd58797bde6fe6750236f5dae4cf403af0925c8339f0a91b682254b39") << OP_CHECKSIG; genesis.vtx.push_back(txNew); @@ -211,22 +222,22 @@ public: /** Zerocoin */ zerocoinModulus = "25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784" - "4069182906412495150821892985591491761845028084891200728449926873928072877767359714183472702618963750149718246911" - "6507761337985909570009733045974880842840179742910064245869181719511874612151517265463228221686998754918242243363" - "7259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133" - "8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" - "31438167899885040445364023527381951378636564391212010397122822120720357"; - nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each + "4069182906412495150821892985591491761845028084891200728449926873928072877767359714183472702618963750149718246911" + "6507761337985909570009733045974880842840179742910064245869181719511874612151517265463228221686998754918242243363" + "7259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133" + "8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" + "31438167899885040445364023527381951378636564391212010397122822120720357"; + nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each nMaxZerocoinPublicSpendsPerTransaction = 637; // Assume about 220 bytes each input - nMinZerocoinMintFee = 1 * CENT; //high fee required for zerocoin mints - nMintRequiredConfirmations = 20; //the maximum amount of confirmations until accumulated in 19 + nMinZerocoinMintFee = 1 * CENT; // high fee required for zerocoin mints + nMintRequiredConfirmations = 20; // the maximum amount of confirmations until accumulated in 19 nRequiredAccumulation = 1; - nDefaultSecurityLevel = 100; //full security level for accumulators - nZerocoinHeaderVersion = 4; //Block headers must be this version once zerocoin is active - nZerocoinRequiredStakeDepth = 200; //The required confirmations for a zagr to be stakable + nDefaultSecurityLevel = 100; // full security level for accumulators + nZerocoinHeaderVersion = 4; // Block headers must be this version once zerocoin is active + nZerocoinRequiredStakeDepth = 200; // The required confirmations for a zagr to be stakable - nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee - nProposalEstablishmentTime = 60 * 60 * 24; // Proposals must be at least a day old to make it into a budget + nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee + nProposalEstablishmentTime = 60 * 60 * 24; // Proposals must be at least a day old to make it into a budget } const Checkpoints::CCheckpointData& Checkpoints() const @@ -258,22 +269,30 @@ public: nMinerThreads = 0; nTargetTimespan = 10 * 60; nTargetSpacing = 10 * 60; + nLastPOWBlock = 200; + + // Hybrid consensus: PoS staking permitted from block 2 in testnet as well. + nFirstPoSBlock = 2; + nMaturity = 15; nMasternodeCountDrift = 4; - nModifierUpdateBlock = 0; + + // Keep aligned with PoS activation in this chain. + nModifierUpdateBlock = 2; + nMaxMoneyOut = 43199500 * COIN; nZerocoinStartHeight = 0; nZerocoinStartTime = 1643790201; - nBlockEnforceSerialRange = 1; //Enforce serial range starting this block - nBlockRecalculateAccumulators = 999999999; //Trigger a recalculation of accumulators - nBlockFirstFraudulent = 999999999; //First block that bad serials emerged - nBlockLastGoodCheckpoint = 999999999; //Last valid accumulator checkpoint - nBlockEnforceInvalidUTXO = 999999999; //Start enforcing the invalid UTXO's - nInvalidAmountFiltered = 0; //Amount of invalid coins filtered through exchanges, that should be considered valid - nBlockZerocoinV2 = 999999999; //!> The block that zerocoin v2 becomes active + nBlockEnforceSerialRange = 1; // Enforce serial range starting this block + nBlockRecalculateAccumulators = 999999999; // Trigger a recalculation of accumulators + nBlockFirstFraudulent = 999999999; // First block that bad serials emerged + nBlockLastGoodCheckpoint = 999999999; // Last valid accumulator checkpoint + nBlockEnforceInvalidUTXO = 999999999; // Start enforcing the invalid UTXO's + nInvalidAmountFiltered = 0; // Amount of invalid coins filtered through exchanges, that should be considered valid + nBlockZerocoinV2 = 999999999; //!> The block that zerocoin v2 becomes active nEnforceNewSporkKey = 1643790201; - nRejectOldSporkKey = 1522454400; + nRejectOldSporkKey = 1522454400; // Public coin spend enforcement nPublicZCSpends = 1; @@ -292,12 +311,12 @@ public: vFixedSeeds.clear(); vSeeds.clear(); - base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 38); - base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 39); - base58Prefixes[SECRET_KEY] = std::vector(1, 166); - + base58Prefixes[PUBKEY_ADDRESS] = std::vector(1, 38); + base58Prefixes[SCRIPT_ADDRESS] = std::vector(1, 39); + base58Prefixes[SECRET_KEY] = std::vector(1, 166); + base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x3a)(0x80)(0x61)(0xa0).convert_to_container >(); - + base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x3a)(0x80)(0x58)(0x37).convert_to_container >(); // Testnet agrarian BIP44 coin type is '1' (All coin's testnet default) base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container >(); @@ -322,6 +341,7 @@ public: nProposalEstablishmentTime = 60 * 5; // Proposals must be at least 5 mns old to make it into a test budget } + const Checkpoints::CCheckpointData& Checkpoints() const { return dataTestnet; @@ -352,18 +372,26 @@ public: nTargetTimespan = 24 * 60 * 60; // Agrarian: 1 day nTargetSpacing = 1 * 60; // Agrarian: 1 minutes bnProofOfWorkLimit = ~uint256(0) >> 1; + nLastPOWBlock = 250; + + // Hybrid consensus: PoS staking permitted from block 2 in regtest as well. + nFirstPoSBlock = 2; + nMaturity = 20; nMasternodeCountDrift = 4; - nModifierUpdateBlock = 0; //approx Mon, 17 Apr 2017 04:00:00 GMT + + // Keep aligned with PoS activation in this chain. + nModifierUpdateBlock = 2; + nMaxMoneyOut = 43199500 * COIN; nZerocoinStartHeight = 300; nBlockZerocoinV2 = 300; nZerocoinStartTime = 1643790201; - nBlockEnforceSerialRange = 1; //Enforce serial range starting this block - nBlockRecalculateAccumulators = 999999999; //Trigger a recalculation of accumulators - nBlockFirstFraudulent = 999999999; //First block that bad serials emerged - nBlockLastGoodCheckpoint = 999999999; //Last valid accumulator checkpoint + nBlockEnforceSerialRange = 1; // Enforce serial range starting this block + nBlockRecalculateAccumulators = 999999999; // Trigger a recalculation of accumulators + nBlockFirstFraudulent = 999999999; // First block that bad serials emerged + nBlockLastGoodCheckpoint = 999999999; // Last valid accumulator checkpoint // Public coin spend enforcement nPublicZCSpends = 350; @@ -390,6 +418,7 @@ public: fSkipProofOfWorkCheck = true; fTestnetToBeDeprecatedFieldRPC = false; } + const Checkpoints::CCheckpointData& Checkpoints() const { return dataRegtest; @@ -434,7 +463,6 @@ public: }; static CUnitTestParams unitTestParams; - static CChainParams* pCurrentParams = 0; CModifiableParams* ModifiableParams() diff --git a/src/chainparams.h b/src/chainparams.h index 376cdf55..e9faa989 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +16,7 @@ #include "uint256.h" #include "libzerocoin/Params.h" + #include typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; @@ -63,7 +65,7 @@ public: /** Make miner wait to have peers to avoid wasting work */ bool MiningRequiresPeers() const { return fMiningRequiresPeers; } /** Headers first syncing is disabled */ - bool HeadersFirstSyncingActive() const { return fHeadersFirstSyncingActive; }; + bool HeadersFirstSyncingActive() const { return fHeadersFirstSyncingActive; } /** Default value for -checkmempool and -checkblockindex argument */ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Allow mining of a min-difficulty block */ @@ -119,7 +121,13 @@ public: /** Height or Time Based Activations **/ int ModifierUpgradeBlock() const { return nModifierUpdateBlock; } + + // Hybrid consensus activations. + // - PoS blocks are permitted starting at FIRST_POS_BLOCK(). + // - PoW blocks are permitted up to and including LAST_POW_BLOCK(). + int FIRST_POS_BLOCK() const { return nFirstPoSBlock; } int LAST_POW_BLOCK() const { return nLastPOWBlock; } + int Zerocoin_StartHeight() const { return nZerocoinStartHeight; } int Zerocoin_Block_EnforceSerialRange() const { return nBlockEnforceSerialRange; } int Zerocoin_Block_RecalculateAccumulators() const { return nBlockRecalculateAccumulators; } @@ -134,7 +142,7 @@ public: CAmount GetSupplyBeforeFakeSerial() const { return nSupplyBeforeFakeSerial; } int Zerocoin_Block_Double_Accumulated() const { return nBlockDoubleAccumulated; } - CAmount InvalidAmountFiltered() const { return nInvalidAmountFiltered; }; + CAmount InvalidAmountFiltered() const { return nInvalidAmountFiltered; } int Zerocoin_Block_Public_Spend_Enabled() const { return nPublicZCSpends; } @@ -154,7 +162,11 @@ protected: int nToCheckBlockUpgradeMajority; int64_t nTargetTimespan; int64_t nTargetSpacing; + + // Hybrid PoW/PoS window controls. + int nFirstPoSBlock; int nLastPOWBlock; + int nMasternodeCountDrift; int nMaturity; int nModifierUpdateBlock; @@ -216,7 +228,6 @@ protected: * to test specific features more easily. Test cases should always restore the previous * values after finalization. */ - class CModifiableParams { public: @@ -230,7 +241,6 @@ public: virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck) = 0; }; - /** * Return the currently selected parameters. This won't change after app startup * outside of the unit tests. diff --git a/src/kernel.cpp b/src/kernel.cpp index b9286120..a46d3682 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2012-2013 The PPCoin developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,9 +14,6 @@ #include "stakeinput.h" #include "utilmoneystr.h" #include "zagrchain.h" - -using namespace std; - bool fTestNet = false; // Params().NetworkID() == CBaseChainParams::TESTNET; // Modifier interval: time to elapse before new modifier is computed @@ -313,7 +311,7 @@ bool stakeTargetHit(const uint256& hashProofOfStake, const int64_t& nValueIn, co uint256 bnCoinDayWeight = uint256(nValueIn) / 100; // Check if proof-of-stake hash meets the target protocol - return hashProofOfStake < (bnCoinDayWeight * bnTargetPerCoinDay); + return hashProofOfStake < (bnCoinDayWeight* bnTargetPerCoinDay); } bool CheckStake(const CDataStream& ssUniqueID, CAmount nValueIn, const uint64_t nStakeModifier, const uint256& bnTarget, diff --git a/src/kernel.h b/src/kernel.h index 12ffc115..0fb6767d 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -1,13 +1,15 @@ // Copyright (c) 2012-2013 The PPCoin developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_KERNEL_H -#define BITCOIN_KERNEL_H - +#ifndef AGRARIAN_BITCOIN_KERNEL_H +#define AGRARIAN_BITCOIN_KERNEL_H #include "main.h" #include "stakeinput.h" +#include +#include +#include // MODIFIER_INTERVAL: time to elapse before new modifier is computed @@ -46,4 +48,4 @@ int64_t GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd); bool ContextualCheckZerocoinStake(int nPreviousBlockHeight, CStakeInput* stake); -#endif // BITCOIN_KERNEL_H +#endif // AGRARIAN_BITCOIN_KERNEL_H diff --git a/src/main.cpp b/src/main.cpp index e1f3f164..33e8d1bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 The Agrarian developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1986,23 +1987,41 @@ double ConvertBitsToDouble(unsigned int nBits) return dDiff; } +int64_t GetBlockValue(int nHeight, bool fProofOfStake) +{ + // NOTE: + // - Height 0 is genesis and uses the special, pre-mined value. + // - During the hybrid window, both PoW and PoS blocks may be created. + // Subsidy policy is therefore selected by block type, not by height alone. + // + // Current Agrarian policy: + // * PoW blocks (height > 0 && height <= LAST_POW_BLOCK): 50 AGR + // * PoS blocks (height >= FIRST_POS_BLOCK): 10 AGR + // * PoW blocks are not valid beyond LAST_POW_BLOCK (enforced elsewhere). + if (nHeight == 0) { + return 5000000000 * COIN; + } + + if (fProofOfStake) { + return 10 * COIN; + } + + if (nHeight > 0 && nHeight <= Params().LAST_POW_BLOCK()) { + return 50 * COIN; + } + + // Should not be reachable for valid blocks (PoW is disallowed beyond LAST_POW_BLOCK). + return 0; +} + +// Backward-compatible wrapper for call sites that only know height. +// Prefer GetBlockValue(height, isPoS) when block type is available. int64_t GetBlockValue(int nHeight) { - int64_t nSubsidy = 0; - - if (nHeight == 0) { - nSubsidy = 5000000000 * COIN; - } - else if (nHeight <= Params().LAST_POW_BLOCK() && nHeight > 0) { - nSubsidy = 50 * COIN; - } - else if (nHeight > Params().LAST_POW_BLOCK()) { - nSubsidy = 10 * COIN; - } - - return nSubsidy; + return GetBlockValue(nHeight, false); } + CAmount GetSeeSaw(const CAmount& blockValue, int nMasternodeCount, int nHeight) { //if a mn count is inserted into the function we are looking for a specific result for a masternode count @@ -2911,15 +2930,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return true; } - if (pindex->nHeight <= Params().LAST_POW_BLOCK() && block.IsProofOfStake()) - return state.DoS(100, error("ConnectBlock() : PoS period not active"), - REJECT_INVALID, "PoS-early"); + // Hybrid consensus: +// - PoS blocks are permitted starting at Params().FIRST_POS_BLOCK(). +// - PoW blocks are permitted up to and including Params().LAST_POW_BLOCK(). +if (block.IsProofOfStake() && pindex->nHeight < Params().FIRST_POS_BLOCK()) + return state.DoS(100, error("ConnectBlock() : PoS period not active"), + REJECT_INVALID, "PoS-early"); - if (pindex->nHeight > Params().LAST_POW_BLOCK() && block.IsProofOfWork()) - return state.DoS(100, error("ConnectBlock() : PoW period ended"), - REJECT_INVALID, "PoW-ended"); - - bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(); +if (block.IsProofOfWork() && pindex->nHeight > Params().LAST_POW_BLOCK()) + return state.DoS(100, error("ConnectBlock() : PoW period ended"), + REJECT_INVALID, "PoW-ended"); +bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(); // If scripts won't be checked anyways, don't bother seeing if CLTV is activated bool fCLTVHasMajority = false; @@ -3132,7 +3153,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs - 1), nTimeConnect * 0.000001); //PoW phase redistributed fees to miner. PoS stage destroys fees. - CAmount nExpectedMint = GetBlockValue(pindex->pprev->nHeight); + CAmount nExpectedMint = GetBlockValue(pindex->nHeight, block.IsProofOfStake()); if (block.IsProofOfWork()) nExpectedMint += nFees; diff --git a/src/main.h b/src/main.h index 12e9cc08..5997a936 100644 --- a/src/main.h +++ b/src/main.h @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,8 +21,6 @@ #include "pow.h" #include "primitives/block.h" #include "primitives/transaction.h" -#include "zagr/zerocoin.h" -#include "zagr/zagrmodule.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -30,6 +29,8 @@ #include "txmempool.h" #include "uint256.h" #include "undo.h" +#include "zagr/zerocoin.h" +#include "zagr/zagrmodule.h" #include #include @@ -108,7 +109,7 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 3600; static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; /** Enable bloom filter */ - static const bool DEFAULT_PEERBLOOMFILTERS = true; +static const bool DEFAULT_PEERBLOOMFILTERS = true; static const bool DEFAULT_PEERBLOOMFILTERS_ZC = false; /** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ @@ -175,7 +176,7 @@ extern int64_t nReserveBalance; extern std::map mapRejectedBlocks; extern std::map mapHashedBlocks; -extern std::map mapZerocoinspends; //txid, time received +extern std::map mapZerocoinspends; // txid, time received /** Best header we've seen so far (used for getheaders queries' starting points). */ extern CBlockIndex* pindexBestHeader; @@ -241,11 +242,16 @@ std::string GetWarnings(std::string strFor); bool GetTransaction(const uint256& hash, CTransaction& tx, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr); /** Retrieve an output (from memory pool, or from disk, if possible) */ bool GetOutput(const uint256& hash, unsigned int index, CValidationState& state, CTxOut& out); -/** Find the best known block, and make it the tip of the block chain */ -// ***TODO*** +/** TODO (legacy) */ double ConvertBitsToDouble(unsigned int nBits); int64_t GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCount, bool isZAGRStake); + +/** + * Hybrid difficulty selection. + * Implementations should route to the correct target calculation (PoW vs PoS) + * based on the fProofOfStake flag rather than height-era assumptions. + */ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock, bool fProofOfStake); bool ActivateBestChain(CValidationState& state, CBlock* pblock = NULL, bool fAlreadyChecked = false); @@ -262,7 +268,6 @@ void Misbehaving(NodeId nodeid, int howmuch); /** Flush all state, indexes and buffers to disk. */ void FlushStateToDisk(); - /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectInsaneFee = false, bool ignoreFees = false); @@ -291,14 +296,8 @@ struct CDiskTxPos : public CDiskBlockPos { READWRITE(VARINT(nTxOffset)); } - CDiskTxPos(const CDiskBlockPos& blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) - { - } - - CDiskTxPos() - { - SetNull(); - } + CDiskTxPos(const CDiskBlockPos& blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {} + CDiskTxPos() { SetNull(); } void SetNull() { @@ -307,22 +306,9 @@ struct CDiskTxPos : public CDiskBlockPos { } }; - CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); bool MoneyRange(CAmount nValueOut); -/** - * Check transaction inputs, and make sure any - * pay-to-script-hash transactions are evaluating IsStandard scripts - * - * Why bother? To avoid denial-of-service attacks; an attacker - * can submit a standard HASH... OP_EQUAL transaction, - * which will get accepted into blocks. The redemption - * script can be anything; an attacker could use a very - * expensive-to-check-upon-redemption script like: - * DUP CHECKSIG DROP ... repeated 100 times... OP_1 - */ - /** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending @@ -346,7 +332,6 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx); */ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs); - /** * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it @@ -413,7 +398,6 @@ public: bool ReadFromDisk(const CDiskBlockPos& pos, const uint256& hashBlock); }; - /** * Closure representing one script verification * Note that this stores references to the spending transaction @@ -430,8 +414,15 @@ private: public: CScriptCheck() : ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), - ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) {} + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) + : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), + ptxTo(&txToIn), + nIn(nInIn), + nFlags(nFlagsIn), + cacheStore(cacheIn), + error(SCRIPT_ERR_UNKNOWN_ERROR) + { + } bool operator()(); @@ -448,13 +439,11 @@ public: ScriptError GetScriptError() const { return error; } }; - /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); - /** Functions for validating blocks and updating the block tree */ /** Undo the effects of this block (with given index) on the UTXO set represented by coins. @@ -479,13 +468,12 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindexPrev); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ -bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fCheckSig = true); /** Store block on disk. If dbp is provided, the file is known to already reside on disk */ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** pindex, CDiskBlockPos* dbp = NULL, bool fAlreadyCheckedBlock = false); bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex = NULL); - class CBlockFileInfo { public: @@ -522,10 +510,7 @@ public: nTimeLast = 0; } - CBlockFileInfo() - { - SetNull(); - } + CBlockFileInfo() { SetNull(); } std::string ToString() const; @@ -560,6 +545,7 @@ private: public: CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {} + bool DoS(int level, bool ret = false, unsigned char chRejectCodeIn = 0, std::string strRejectReasonIn = "", bool corruptionIn = false) { chRejectCode = chRejectCodeIn; @@ -571,12 +557,12 @@ public: mode = MODE_INVALID; return ret; } - bool Invalid(bool ret = false, - unsigned char _chRejectCode = 0, - std::string _strRejectReason = "") + + bool Invalid(bool ret = false, unsigned char _chRejectCode = 0, std::string _strRejectReason = "") { return DoS(0, ret, _chRejectCode, _strRejectReason); } + bool Error(std::string strRejectReasonIn = "") { if (mode == MODE_VALID) @@ -584,23 +570,17 @@ public: mode = MODE_ERROR; return false; } + bool Abort(const std::string& msg) { AbortNode(msg); return Error(msg); } - bool IsValid() const - { - return mode == MODE_VALID; - } - bool IsInvalid() const - { - return mode == MODE_INVALID; - } - bool IsError() const - { - return mode == MODE_ERROR; - } + + bool IsValid() const { return mode == MODE_VALID; } + bool IsInvalid() const { return mode == MODE_INVALID; } + bool IsError() const { return mode == MODE_ERROR; } + bool IsInvalid(int& nDoSOut) const { if (IsInvalid()) { @@ -609,10 +589,8 @@ public: } return false; } - bool CorruptionPossible() const - { - return corruptionPossible; - } + + bool CorruptionPossible() const { return corruptionPossible; } unsigned char GetRejectCode() const { return chRejectCode; } std::string GetRejectReason() const { return strRejectReason; } }; diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 6e031ace..d854e732 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,6 +17,17 @@ #include "util.h" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + CBudgetManager budget; CCriticalSection cs_budget; @@ -2159,7 +2171,7 @@ TrxValidationStatus CFinalizedBudget::IsTransactionValid(const CTransaction& txN bool paid = false; - for (CTxOut out : txNew.vout) { + for (const CTxOut& out : txNew.vout) { LogPrint("mnbudget","CFinalizedBudget::IsTransactionValid - nCurrentBudgetPayment=%d, payee=%s == out.scriptPubKey=%s, amount=%ld == out.nValue=%ld\n", nCurrentBudgetPayment, vecBudgetPayments[nCurrentBudgetPayment].payee.ToString().c_str(), out.scriptPubKey.ToString().c_str(), vecBudgetPayments[nCurrentBudgetPayment].nAmount, out.nValue); diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 038290b4..3c909927 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -1,10 +1,11 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef MASTERNODE_BUDGET_H -#define MASTERNODE_BUDGET_H +#ifndef AGRARIAN_MASTERNODE_BUDGET_H +#define AGRARIAN_MASTERNODE_BUDGET_H #include "base58.h" #include "init.h" @@ -14,9 +15,11 @@ #include "net.h" #include "sync.h" #include "util.h" - -using namespace std; - +#include +#include +#include +#include +#include extern CCriticalSection cs_budget; class CBudgetManager; @@ -41,7 +44,7 @@ static const CAmount PROPOSAL_FEE_TX = (50 * COIN); static const CAmount BUDGET_FEE_TX_OLD = (50 * COIN); static const CAmount BUDGET_FEE_TX = (5 * COIN); static const int64_t BUDGET_VOTE_UPDATE_MIN = 60 * 60; -static map mapPayment_History; +static std::map mapPayment_History; extern std::vector vecImmatureBudgetProposals; extern std::vector vecImmatureFinalizedBudgets; @@ -179,16 +182,16 @@ class CBudgetManager { private: //hold txes until they mature enough to use - // XX42 map mapCollateral; - map mapCollateralTxids; + // XX42 std::map mapCollateral; + std::map mapCollateralTxids; public: // critical section to protect the inner data structures mutable CCriticalSection cs; // keep track of the scanning errors I've seen - map mapProposals; - map mapFinalizedBudgets; + std::map mapProposals; + std::map mapFinalizedBudgets; std::map mapSeenMasternodeBudgetProposals; std::map mapSeenMasternodeBudgetVotes; @@ -321,7 +324,7 @@ public: std::string strBudgetName; int nBlockStart; std::vector vecBudgetPayments; - map mapVotes; + std::map mapVotes; uint256 nFeeTXHash; int64_t nTime; @@ -372,7 +375,7 @@ public: void SubmitVote(); //checks the hashes to make sure we know about them - string GetStatus(); + std::string GetStatus(); uint256 GetHash() { @@ -413,24 +416,24 @@ public: CFinalizedBudgetBroadcast(const CFinalizedBudget& other); CFinalizedBudgetBroadcast(std::string strBudgetNameIn, int nBlockStartIn, std::vector vecBudgetPaymentsIn, uint256 nFeeTXHashIn); - void swap(CFinalizedBudgetBroadcast& first, CFinalizedBudgetBroadcast& second) // nothrow + void std::swap(CFinalizedBudgetBroadcast& first, CFinalizedBudgetBroadcast& second) // nothrow { // enable ADL (not necessary in our case, but good practice) using std::swap; // by swapping the members of two classes, // the two classes are effectively swapped - swap(first.strBudgetName, second.strBudgetName); - swap(first.nBlockStart, second.nBlockStart); - first.mapVotes.swap(second.mapVotes); - first.vecBudgetPayments.swap(second.vecBudgetPayments); - swap(first.nFeeTXHash, second.nFeeTXHash); - swap(first.nTime, second.nTime); + std::swap(first.strBudgetName, second.strBudgetName); + std::swap(first.nBlockStart, second.nBlockStart); + first.mapVotes.std::swap(second.mapVotes); + first.vecBudgetPayments.std::swap(second.vecBudgetPayments); + std::swap(first.nFeeTXHash, second.nFeeTXHash); + std::swap(first.nTime, second.nTime); } CFinalizedBudgetBroadcast& operator=(CFinalizedBudgetBroadcast from) { - swap(*this, from); + std::swap(*this, from); return *this; } @@ -478,7 +481,7 @@ public: int64_t nTime; uint256 nFeeTXHash; - map mapVotes; + std::map mapVotes; //cache object CBudgetProposal(); @@ -559,27 +562,27 @@ public: CBudgetProposalBroadcast(const CBudgetProposalBroadcast& other) : CBudgetProposal(other) {} CBudgetProposalBroadcast(std::string strProposalNameIn, std::string strURLIn, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int nBlockStartIn, uint256 nFeeTXHashIn); - void swap(CBudgetProposalBroadcast& first, CBudgetProposalBroadcast& second) // nothrow + void std::swap(CBudgetProposalBroadcast& first, CBudgetProposalBroadcast& second) // nothrow { // enable ADL (not necessary in our case, but good practice) using std::swap; // by swapping the members of two classes, // the two classes are effectively swapped - swap(first.strProposalName, second.strProposalName); - swap(first.nBlockStart, second.nBlockStart); - swap(first.strURL, second.strURL); - swap(first.nBlockEnd, second.nBlockEnd); - swap(first.nAmount, second.nAmount); - swap(first.address, second.address); - swap(first.nTime, second.nTime); - swap(first.nFeeTXHash, second.nFeeTXHash); - first.mapVotes.swap(second.mapVotes); + std::swap(first.strProposalName, second.strProposalName); + std::swap(first.nBlockStart, second.nBlockStart); + std::swap(first.strURL, second.strURL); + std::swap(first.nBlockEnd, second.nBlockEnd); + std::swap(first.nAmount, second.nAmount); + std::swap(first.address, second.address); + std::swap(first.nTime, second.nTime); + std::swap(first.nFeeTXHash, second.nFeeTXHash); + first.mapVotes.std::swap(second.mapVotes); } CBudgetProposalBroadcast& operator=(CBudgetProposalBroadcast from) { - swap(*this, from); + std::swap(*this, from); return *this; } @@ -604,4 +607,4 @@ public: }; -#endif +#endif // AGRARIAN_MASTERNODE_BUDGET_H diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index d11a2513..a8b6533f 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -1,9 +1,11 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "masternode-payments.h" + #include "addrman.h" #include "chainparams.h" #include "masternode-budget.h" @@ -14,8 +16,15 @@ #include "sync.h" #include "util.h" #include "utilmoneystr.h" + #include +#include +#include +#include +#include +#include + /** Object for who's going to get paid on which blocks */ CMasternodePayments masternodePayments; @@ -23,6 +32,26 @@ CCriticalSection cs_vecPayments; CCriticalSection cs_mapMasternodeBlocks; CCriticalSection cs_mapMasternodePayeeVotes; +namespace { + +// Select the correct "newly created" transaction for payee validation based on block type. +// - PoW blocks: coinbase is vtx[0] +// - PoS blocks: coinstake is vtx[1] (with a null coinbase at vtx[0]) +// +// This must NOT be derived from height-era assumptions, because Agrarian runs PoW+PoS concurrently +// from Params().FIRST_POS_BLOCK() through Params().LAST_POW_BLOCK(). +const CTransaction& GetBlockNewTxForPayeeChecks(const CBlock& block) +{ + // Defensive: preserve old behavior if vector is unexpectedly small. + // A valid PoS block should have at least 2 tx; a valid PoW block at least 1 tx. + if (block.IsProofOfStake() && block.vtx.size() > 1) { + return block.vtx[1]; + } + return block.vtx[0]; +} + +} // namespace + // // CMasternodePaymentDB // @@ -35,61 +64,81 @@ CMasternodePaymentDB::CMasternodePaymentDB() bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave) { - int64_t nStart = GetTimeMillis(); + const int64_t nStart = GetTimeMillis(); // serialize, checksum data up to that point, then append checksum CDataStream ssObj(SER_DISK, CLIENT_VERSION); ssObj << strMagicMessage; // masternode cache file specific magic message ssObj << FLATDATA(Params().MessageStart()); // network specific magic number ssObj << objToSave; - uint256 hash = Hash(ssObj.begin(), ssObj.end()); + const uint256 hash = Hash(ssObj.begin(), ssObj.end()); ssObj << hash; // open output file, and associate with CAutoFile - FILE* file = fopen(pathDB.string().c_str(), "wb"); - CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) + FILE* file = std::fopen(pathDB.string().c_str(), "wb"); + if (file == nullptr) { return error("%s : Failed to open file %s", __func__, pathDB.string()); + } + + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) { + return error("%s : Failed to open file %s", __func__, pathDB.string()); + } // Write and commit header, data try { fileout << ssObj; - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Serialize or I/O error - %s", __func__, e.what()); } fileout.fclose(); - LogPrint("masternode","Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart); - + LogPrint("masternode", "Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart); return true; } CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad, bool fDryRun) { - int64_t nStart = GetTimeMillis(); + const int64_t nStart = GetTimeMillis(); + // open input file, and associate with CAutoFile - FILE* file = fopen(pathDB.string().c_str(), "rb"); + FILE* file = std::fopen(pathDB.string().c_str(), "rb"); + if (file == nullptr) { + error("%s : Failed to open file %s", __func__, pathDB.string()); + return FileError; + } + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (filein.IsNull()) { error("%s : Failed to open file %s", __func__, pathDB.string()); return FileError; } - // use file size to size memory buffer - int fileSize = boost::filesystem::file_size(pathDB); - int dataSize = fileSize - sizeof(uint256); + int fileSize = 0; + try { + fileSize = static_cast(boost::filesystem::file_size(pathDB)); + } catch (const std::exception& e) { + error("%s : Unable to read file size %s (%s)", __func__, pathDB.string(), e.what()); + return FileError; + } + + int dataSize = fileSize - static_cast(sizeof(uint256)); // Don't try to resize to a negative number if file is small - if (dataSize < 0) + if (dataSize < 0) { dataSize = 0; - vector vchData; - vchData.resize(dataSize); + } + + std::vector vchData; + vchData.resize(static_cast(dataSize)); uint256 hashIn; // read data and checksum from file try { - filein.read((char*)&vchData[0], dataSize); + if (dataSize > 0) { + filein.read(reinterpret_cast(&vchData[0]), dataSize); + } filein >> hashIn; - } catch (std::exception& e) { + } catch (const std::exception& e) { error("%s : Deserialize or I/O error - %s", __func__, e.what()); return HashReadError; } @@ -98,7 +147,7 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION); // verify stored checksum matches input data - uint256 hashTmp = Hash(ssObj.begin(), ssObj.end()); + const uint256 hashTmp = Hash(ssObj.begin(), ssObj.end()); if (hashIn != hashTmp) { error("%s : Checksum mismatch, data corrupted", __func__); return IncorrectHash; @@ -112,35 +161,35 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& // ... verify the message matches predefined one if (strMagicMessage != strMagicMessageTmp) { - error("%s : Invalid masternode payement cache magic message", __func__); + error("%s : Invalid masternode payment cache magic message", __func__); return IncorrectMagicMessage; } - // de-serialize file header (network specific magic number) and .. ssObj >> FLATDATA(pchMsgTmp); // ... verify the network matches ours - if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) { + if (std::memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp))) { error("%s : Invalid network magic number", __func__); return IncorrectMagicNumber; } // de-serialize data into CMasternodePayments object ssObj >> objToLoad; - } catch (std::exception& e) { + } catch (const std::exception& e) { objToLoad.Clear(); error("%s : Deserialize or I/O error - %s", __func__, e.what()); return IncorrectFormat; } - LogPrint("masternode","Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart); - LogPrint("masternode"," %s\n", objToLoad.ToString()); + LogPrint("masternode", "Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode", " %s\n", objToLoad.ToString()); + if (!fDryRun) { - LogPrint("masternode","Masternode payments manager - cleaning....\n"); + LogPrint("masternode", "Masternode payments manager - cleaning....\n"); objToLoad.CleanPaymentList(); - LogPrint("masternode","Masternode payments manager - result:\n"); - LogPrint("masternode"," %s\n", objToLoad.ToString()); + LogPrint("masternode", "Masternode payments manager - result:\n"); + LogPrint("masternode", " %s\n", objToLoad.ToString()); } return Ok; @@ -148,92 +197,89 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& void DumpMasternodePayments() { - int64_t nStart = GetTimeMillis(); + const int64_t nStart = GetTimeMillis(); CMasternodePaymentDB paymentdb; CMasternodePayments tempPayments; - LogPrint("masternode","Verifying mnpayments.dat format...\n"); - CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true); + LogPrint("masternode", "Verifying mnpayments.dat format...\n"); + const CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true); + // there was an error and it was not an error on file opening => do not proceed - if (readResult == CMasternodePaymentDB::FileError) - LogPrint("masternode","Missing budgets file - mnpayments.dat, will try to recreate\n"); - else if (readResult != CMasternodePaymentDB::Ok) { - LogPrint("masternode","Error reading mnpayments.dat: "); - if (readResult == CMasternodePaymentDB::IncorrectFormat) - LogPrint("masternode","magic is ok but data has invalid format, will try to recreate\n"); - else { - LogPrint("masternode","file format is unknown or invalid, please fix it manually\n"); + if (readResult == CMasternodePaymentDB::FileError) { + LogPrint("masternode", "Missing payments file - mnpayments.dat, will try to recreate\n"); + } else if (readResult != CMasternodePaymentDB::Ok) { + LogPrint("masternode", "Error reading mnpayments.dat: "); + if (readResult == CMasternodePaymentDB::IncorrectFormat) { + LogPrint("masternode", "magic is ok but data has invalid format, will try to recreate\n"); + } else { + LogPrint("masternode", "file format is unknown or invalid, please fix it manually\n"); return; } } - LogPrint("masternode","Writting info to mnpayments.dat...\n"); + + LogPrint("masternode", "Writing info to mnpayments.dat...\n"); paymentdb.Write(masternodePayments); - LogPrint("masternode","Budget dump finished %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode", "Payments dump finished %dms\n", GetTimeMillis() - nStart); } bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMinted) { CBlockIndex* pindexPrev = chainActive.Tip(); - if (pindexPrev == NULL) return true; + if (pindexPrev == nullptr) { + return true; + } int nHeight = 0; if (pindexPrev->GetBlockHash() == block.hashPrevBlock) { nHeight = pindexPrev->nHeight + 1; - } else { //out of order + } else { // out of order BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); - if (mi != mapBlockIndex.end() && (*mi).second) + if (mi != mapBlockIndex.end() && (*mi).second) { nHeight = (*mi).second->nHeight + 1; + } } if (nHeight == 0) { - LogPrint("masternode","IsBlockValueValid() : WARNING: Couldn't find previous block\n"); + LogPrint("masternode", "IsBlockValueValid() : WARNING: Couldn't find previous block\n"); } - //LogPrintf("XX69----------> IsBlockValueValid(): nMinted: %d, nExpectedValue: %d\n", FormatMoney(nMinted), FormatMoney(nExpectedValue)); - - if (!masternodeSync.IsSynced()) { //there is no budget data to use to check anything - //super blocks will always be on these blocks, max 100 per budgeting + if (!masternodeSync.IsSynced()) { // there is no budget data to use to check anything + // super blocks will always be on these blocks, max 100 per budgeting if (nHeight % Params().GetBudgetCycleBlocks() < 100) { return true; - } else { - if (nMinted > nExpectedValue) { - return false; - } - } - } else { // we're synced and have data so check the budget schedule - - //are these blocks even enabled - if (!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) { - return nMinted <= nExpectedValue; - } - - if (budget.IsBudgetPaymentBlock(nHeight)) { - //the value of the block is evaluated in CheckBlock - return true; - } else { - if (nMinted > nExpectedValue) { - return false; - } } + return nMinted <= nExpectedValue; } - return true; + // we're synced and have data so check the budget schedule + + // are these blocks even enabled + if (!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) { + return nMinted <= nExpectedValue; + } + + if (budget.IsBudgetPaymentBlock(nHeight)) { + // the value of the block is evaluated in CheckBlock + return true; + } + + return nMinted <= nExpectedValue; } bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) { TrxValidationStatus transactionStatus = TrxValidationStatus::InValid; - if (!masternodeSync.IsSynced()) { //there is no budget data to use to check anything -- find the longest chain + if (!masternodeSync.IsSynced()) { // there is no budget data to use to check anything -- find the longest chain LogPrint("mnpayments", "Client not synced, skipping block payee checks\n"); return true; } - const CTransaction& txNew = (nBlockHeight > Params().LAST_POW_BLOCK() ? block.vtx[1] : block.vtx[0]); + const CTransaction& txNew = GetBlockNewTxForPayeeChecks(block); - //check if it's a budget block + // check if it's a budget block if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) { if (budget.IsBudgetPaymentBlock(nBlockHeight)) { transactionStatus = budget.IsTransactionValid(txNew, nBlockHeight); @@ -242,39 +288,44 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) } if (transactionStatus == TrxValidationStatus::InValid) { - LogPrint("masternode","Invalid budget payment detected %s\n", txNew.ToString().c_str()); - if (IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) + LogPrint("masternode", "Invalid budget payment detected %s\n", txNew.ToString().c_str()); + if (IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) { return false; - - LogPrint("masternode","Budget enforcement is disabled, accepting block\n"); + } + LogPrint("masternode", "Budget enforcement is disabled, accepting block\n"); } } } - // If we end here the transaction was either TrxValidationStatus::InValid and Budget enforcement is disabled, or - // a double budget payment (status = TrxValidationStatus::DoublePayment) was detected, or no/not enough masternode - // votes (status = TrxValidationStatus::VoteThreshold) for a finalized budget were found - // In all cases a masternode will get the payment for this block + // If we end here the transaction was either InValid and Budget enforcement is disabled, or + // a double budget payment (DoublePayment) was detected, or no/not enough masternode + // votes (VoteThreshold) for a finalized budget were found. + // In all cases a masternode will get the payment for this block. - //check for masternode payee - if (masternodePayments.IsTransactionValid(txNew, nBlockHeight)) + // check for masternode payee + if (masternodePayments.IsTransactionValid(txNew, nBlockHeight)) { return true; - LogPrint("masternode","Invalid mn payment detected %s\n", txNew.ToString().c_str()); + } - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) + LogPrint("masternode", "Invalid mn payment detected %s\n", txNew.ToString().c_str()); + + if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { return false; - LogPrint("masternode","Masternode payment enforcement is disabled, accepting block\n"); + } + LogPrint("masternode", "Masternode payment enforcement is disabled, accepting block\n"); return true; } - void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStake, bool fZAGRStake) { CBlockIndex* pindexPrev = chainActive.Tip(); - if (!pindexPrev) return; + if (!pindexPrev) { + return; + } - if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight + 1)) { + const int nextHeight = pindexPrev->nHeight + 1; + if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nextHeight)) { budget.FillBlockPayee(txNew, nFees, fProofOfStake); } else { masternodePayments.FillBlockPayee(txNew, nFees, fProofOfStake, fZAGRStake); @@ -285,49 +336,55 @@ std::string GetRequiredPaymentsString(int nBlockHeight) { if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)) { return budget.GetRequiredPaymentsString(nBlockHeight); - } else { - return masternodePayments.GetRequiredPaymentsString(nBlockHeight); } + return masternodePayments.GetRequiredPaymentsString(nBlockHeight); } -void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFees, bool fProofOfStake, bool fZAGRStake) +void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t /*nFees*/, bool fProofOfStake, bool fZAGRStake) { CBlockIndex* pindexPrev = chainActive.Tip(); - if (!pindexPrev) return; + if (!pindexPrev) { + return; + } bool hasPayment = true; CScript payee; - //spork + // spork / schedule if (!masternodePayments.GetBlockPayee(pindexPrev->nHeight + 1, payee)) { - //no masternode detected + // no masternode detected CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1); if (winningNode) { payee = GetScriptForDestination(winningNode->pubKeyCollateralAddress.GetID()); } else { - LogPrint("masternode","CreateNewBlock: Failed to detect masternode to pay\n"); + LogPrint("masternode", "CreateNewBlock: Failed to detect masternode to pay\n"); hasPayment = false; } } - CAmount blockValue = GetBlockValue(pindexPrev->nHeight); - CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight, blockValue, 0, fZAGRStake); + const int payHeight = pindexPrev->nHeight + 1; + const CAmount blockValue = GetBlockValue(payHeight); + const CAmount masternodePayment = GetMasternodePayment(payHeight, blockValue, 0, fZAGRStake); if (hasPayment) { if (fProofOfStake) { - /**For Proof Of Stake vout[0] must be null + /** For Proof Of Stake vout[0] must be null. * Stake reward can be split into many different outputs, so we must * use vout.size() to align with several different cases. - * An additional output is appended as the masternode payment + * An additional output is appended as the masternode payment. */ - unsigned int i = txNew.vout.size(); + const unsigned int i = txNew.vout.size(); txNew.vout.resize(i + 1); txNew.vout[i].scriptPubKey = payee; txNew.vout[i].nValue = masternodePayment; - //subtract mn payment from the stake reward - if (!txNew.vout[1].IsZerocoinMint()) - txNew.vout[i - 1].nValue -= masternodePayment; + // subtract mn payment from the stake reward + // NOTE: original code used vout[1] and (i-1); keep behavior, but guard bounds. + if (i > 0) { + if (!txNew.vout[1].IsZerocoinMint() && (i - 1) < txNew.vout.size()) { + txNew.vout[i - 1].nValue -= masternodePayment; + } + } } else { txNew.vout.resize(2); txNew.vout[1].scriptPubKey = payee; @@ -339,28 +396,28 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe ExtractDestination(payee, address1); CBitcoinAddress address2(address1); - LogPrint("masternode","Masternode payment of %s to %s\n", FormatMoney(masternodePayment).c_str(), address2.ToString().c_str()); + LogPrint("masternode", "Masternode payment of %s to %s\n", FormatMoney(masternodePayment).c_str(), address2.ToString().c_str()); } } int CMasternodePayments::GetMinMasternodePaymentsProto() { if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) - return ActiveProtocol(); // Allow only updated peers - else - return MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT; // Also allow old peers as long as they are allowed to run + return ActiveProtocol(); // Allow only updated peers + return MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT; // Also allow old peers as long as they are allowed to run } void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { - if (!masternodeSync.IsBlockchainSynced()) return; + if (!masternodeSync.IsBlockchainSynced()) { + return; + } - if (fLiteMode) return; //disable all Obfuscation/Masternode related functionality - - - if (strCommand == "mnget") { //Masternode Payments Request Sync - if (fLiteMode) return; //disable all Obfuscation/Masternode related functionality + if (fLiteMode) { + return; // disable all Obfuscation/Masternode related functionality + } + if (strCommand == "mnget") { // Masternode Payments Request Sync int nCountNeeded; vRecv >> nCountNeeded; @@ -375,17 +432,23 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st pfrom->FulfilledRequest("mnget"); masternodePayments.Sync(pfrom, nCountNeeded); LogPrint("mnpayments", "mnget - Sent Masternode winners to peer %i\n", pfrom->GetId()); - } else if (strCommand == "mnw") { //Masternode Payments Declare Winner - //this is required in litemodef + return; + } + + if (strCommand == "mnw") { // Masternode Payments Declare Winner CMasternodePaymentWinner winner; vRecv >> winner; - if (pfrom->nVersion < ActiveProtocol()) return; + if (pfrom->nVersion < ActiveProtocol()) { + return; + } int nHeight; { TRY_LOCK(cs_main, locked); - if (!locked || chainActive.Tip() == NULL) return; + if (!locked || chainActive.Tip() == nullptr) { + return; + } nHeight = chainActive.Tip()->nHeight; } @@ -395,20 +458,18 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st return; } - int nFirstBlock = nHeight - (mnodeman.CountEnabled() * 1.25); + const int nFirstBlock = nHeight - static_cast(mnodeman.CountEnabled() * 1.25); if (winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > nHeight + 20) { LogPrint("mnpayments", "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, nHeight); return; } - std::string strError = ""; + std::string strError; if (!winner.IsValid(pfrom, strError)) { - // if(strError != "") LogPrint("masternode","mnw - invalid message - %s\n", strError); return; } if (!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) { - // LogPrint("masternode","mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort()); return; } @@ -422,33 +483,28 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st return; } - CTxDestination address1; - ExtractDestination(winner.payee, address1); - CBitcoinAddress address2(address1); - - // LogPrint("mnpayments", "mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, nHeight, winner.vinMasternode.prevout.ToStringShort()); - if (masternodePayments.AddWinningMasternode(winner)) { winner.Relay(); masternodeSync.AddedMasternodeWinner(winner.GetHash()); } + return; } } bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) { std::string errorMessage; - std::string strMasterNodeSignMessage; - std::string strMessage = vinMasternode.prevout.ToStringShort() + std::to_string(nBlockHeight) + payee.ToString(); + const std::string strMessage = + vinMasternode.prevout.ToStringShort() + std::to_string(nBlockHeight) + payee.ToString(); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) { - LogPrint("masternode","CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); + LogPrint("masternode", "CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); return false; } if (!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrint("masternode","CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); + LogPrint("masternode", "CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); return false; } @@ -460,7 +516,6 @@ bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) if (mapMasternodeBlocks.count(nBlockHeight)) { return mapMasternodeBlocks[nBlockHeight].GetPayee(payee); } - return false; } @@ -473,16 +528,19 @@ bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight) int nHeight; { TRY_LOCK(cs_main, locked); - if (!locked || chainActive.Tip() == NULL) return false; + if (!locked || chainActive.Tip() == nullptr) { + return false; + } nHeight = chainActive.Tip()->nHeight; } - CScript mnpayee; - mnpayee = GetScriptForDestination(mn.pubKeyCollateralAddress.GetID()); + const CScript mnpayee = GetScriptForDestination(mn.pubKeyCollateralAddress.GetID()); CScript payee; for (int64_t h = nHeight; h <= nHeight + 8; h++) { - if (h == nNotBlockHeight) continue; + if (h == nNotBlockHeight) { + continue; + } if (mapMasternodeBlocks.count(h)) { if (mapMasternodeBlocks[h].GetPayee(payee)) { if (mnpayee == payee) { @@ -518,7 +576,6 @@ bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerI } mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1); - return true; } @@ -529,50 +586,60 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) int nMaxSignatures = 0; int nMasternode_Drift_Count = 0; - std::string strPayeesPossible = ""; + std::string strPayeesPossible; - CAmount nReward = GetBlockValue(nBlockHeight); + const CAmount nReward = GetBlockValue(nBlockHeight); if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { // Get a stable number of masternodes by ignoring newly activated (< 8000 sec old) masternodes nMasternode_Drift_Count = mnodeman.stable_size() + Params().MasternodeCountDrift(); - } - else { - //account for the fact that all peers do not see the same masternode count. A allowance of being off our masternode count is given - //we only need to look at an increased masternode count because as count increases, the reward decreases. This code only checks - //for mnPayment >= required, so it only makes sense to check the max node count allowed. + } else { + // Account for the fact that all peers do not see the same masternode count. + // An allowance of being off our masternode count is given. + // We only need to look at an increased masternode count because as count increases, the reward decreases. + // This code only checks for mnPayment >= required, so it only makes sense to check the max node count allowed. nMasternode_Drift_Count = mnodeman.size() + Params().MasternodeCountDrift(); } - CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count, txNew.HasZerocoinSpendInputs()); + const CAmount requiredMasternodePayment = + GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count, txNew.HasZerocoinSpendInputs()); - //require at least 6 signatures - for (CMasternodePayee& payee : vecPayments) - if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) + // require at least 6 signatures + for (CMasternodePayee& payee : vecPayments) { + if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) { nMaxSignatures = payee.nVotes; + } + } - // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain - if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; + // If we don't have at least 6 signatures on a payee, approve whichever is the longest chain + if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) { + return true; + } for (CMasternodePayee& payee : vecPayments) { bool found = false; - for (CTxOut out : txNew.vout) { + + for (const CTxOut& out : txNew.vout) { if (payee.scriptPubKey == out.scriptPubKey) { - if(out.nValue >= requiredMasternodePayment) + if (out.nValue >= requiredMasternodePayment) { found = true; - else - LogPrint("masternode","Masternode payment is out of drift range. Paid=%s Min=%s\n", FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); + } else { + LogPrint("masternode", "Masternode payment is out of drift range. Paid=%s Min=%s\n", + FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); + } } } if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) { - if (found) return true; + if (found) { + return true; + } CTxDestination address1; ExtractDestination(payee.scriptPubKey, address1); CBitcoinAddress address2(address1); - if (strPayeesPossible == "") { + if (strPayeesPossible.empty()) { strPayeesPossible += address2.ToString(); } else { strPayeesPossible += "," + address2.ToString(); @@ -580,7 +647,8 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) } } - LogPrint("masternode","CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str()); + LogPrint("masternode", "CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", + FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str()); return false; } @@ -634,16 +702,18 @@ void CMasternodePayments::CleanPaymentList() int nHeight; { TRY_LOCK(cs_main, locked); - if (!locked || chainActive.Tip() == NULL) return; + if (!locked || chainActive.Tip() == nullptr) { + return; + } nHeight = chainActive.Tip()->nHeight; } - //keep up to five cycles for historical sake - int nLimit = std::max(int(mnodeman.size() * 1.25), 1000); + // keep up to five cycles for historical sake + const int nLimit = std::max(static_cast(mnodeman.size() * 1.25), 1000); std::map::iterator it = mapMasternodePayeeVotes.begin(); while (it != mapMasternodePayeeVotes.end()) { - CMasternodePaymentWinner winner = (*it).second; + const CMasternodePaymentWinner& winner = (*it).second; if (nHeight - winner.nBlockHeight > nLimit) { LogPrint("mnpayments", "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight); @@ -662,26 +732,26 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError) if (!pmn) { strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.hash.ToString()); - LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); + LogPrint("masternode", "CMasternodePaymentWinner::IsValid - %s\n", strError); mnodeman.AskForMN(pnode, vinMasternode); return false; } if (pmn->protocolVersion < ActiveProtocol()) { strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, ActiveProtocol()); - LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); + LogPrint("masternode", "CMasternodePaymentWinner::IsValid - %s\n", strError); return false; } - int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100, ActiveProtocol()); + const int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100, ActiveProtocol()); if (n > MNPAYMENTS_SIGNATURES_TOTAL) { - //It's common to have masternodes mistakenly think they are in the top 10 - // We don't want to print all of these messages, or punish them unless they're way off + // It's common to have masternodes mistakenly think they are in the top 10. + // We don't want to print all of these messages, or punish them unless they're way off. if (n > MNPAYMENTS_SIGNATURES_TOTAL * 2) { strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL * 2, n); - LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); - //if (masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20); + LogPrint("masternode", "CMasternodePaymentWinner::IsValid - %s\n", strError); + // if (masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20); } return false; } @@ -691,11 +761,12 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError) bool CMasternodePayments::ProcessBlock(int nBlockHeight) { - if (!fMasterNode) return false; + if (!fMasterNode) { + return false; + } - //reference node - hybrid mode - - int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight - 100, ActiveProtocol()); + // reference node - hybrid mode + const int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight - 100, ActiveProtocol()); if (n == -1) { LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n"); @@ -707,34 +778,38 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) return false; } - if (nBlockHeight <= nLastBlockHeight) return false; + if (nBlockHeight <= nLastBlockHeight) { + return false; + } CMasternodePaymentWinner newWinner(activeMasternode.vin); if (budget.IsBudgetPaymentBlock(nBlockHeight)) { - //is budget payment block -- handled by the budgeting software + // budget payment block -- handled by the budgeting software } else { - LogPrint("masternode","CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.prevout.hash.ToString()); + LogPrint("masternode", "CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", + nBlockHeight, activeMasternode.vin.prevout.hash.ToString()); // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough int nCount = 0; CMasternode* pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount); - if (pmn != NULL) { - LogPrint("masternode","CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n"); + if (pmn != nullptr) { + LogPrint("masternode", "CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n"); newWinner.nBlockHeight = nBlockHeight; - CScript payee = GetScriptForDestination(pmn->pubKeyCollateralAddress.GetID()); + const CScript payee = GetScriptForDestination(pmn->pubKeyCollateralAddress.GetID()); newWinner.AddPayee(payee); CTxDestination address1; ExtractDestination(payee, address1); CBitcoinAddress address2(address1); - LogPrint("masternode","CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight); + LogPrint("masternode", "CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", + address2.ToString().c_str(), newWinner.nBlockHeight); } else { - LogPrint("masternode","CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n"); + LogPrint("masternode", "CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n"); } } @@ -743,13 +818,13 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) CKey keyMasternode; if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { - LogPrint("masternode","CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str()); + LogPrint("masternode", "CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return false; } - LogPrint("masternode","CMasternodePayments::ProcessBlock() - Signing Winner\n"); + LogPrint("masternode", "CMasternodePayments::ProcessBlock() - Signing Winner\n"); if (newWinner.Sign(keyMasternode, pubKeyMasternode)) { - LogPrint("masternode","CMasternodePayments::ProcessBlock() - AddWinningMasternode\n"); + LogPrint("masternode", "CMasternodePayments::ProcessBlock() - AddWinningMasternode\n"); if (AddWinningMasternode(newWinner)) { newWinner.Relay(); @@ -771,12 +846,14 @@ bool CMasternodePaymentWinner::SignatureValid() { CMasternode* pmn = mnodeman.Find(vinMasternode); - if (pmn != NULL) { - std::string strMessage = vinMasternode.prevout.ToStringShort() + std::to_string(nBlockHeight) + payee.ToString(); + if (pmn != nullptr) { + const std::string strMessage = + vinMasternode.prevout.ToStringShort() + std::to_string(nBlockHeight) + payee.ToString(); - std::string errorMessage = ""; + std::string errorMessage; if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode address signature %s\n", vinMasternode.prevout.hash.ToString()); + return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode address signature %s\n", + vinMasternode.prevout.hash.ToString()); } return true; @@ -792,36 +869,38 @@ void CMasternodePayments::Sync(CNode* node, int nCountNeeded) int nHeight; { TRY_LOCK(cs_main, locked); - if (!locked || chainActive.Tip() == NULL) return; + if (!locked || chainActive.Tip() == nullptr) { + return; + } nHeight = chainActive.Tip()->nHeight; } - int nCount = (mnodeman.CountEnabled() * 1.25); - if (nCountNeeded > nCount) nCountNeeded = nCount; + int nCount = static_cast(mnodeman.CountEnabled() * 1.25); + if (nCountNeeded > nCount) { + nCountNeeded = nCount; + } int nInvCount = 0; std::map::iterator it = mapMasternodePayeeVotes.begin(); while (it != mapMasternodePayeeVotes.end()) { - CMasternodePaymentWinner winner = (*it).second; + const CMasternodePaymentWinner& winner = (*it).second; if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) { node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash())); nInvCount++; } ++it; } + node->PushMessage("ssc", MASTERNODE_SYNC_MNW, nInvCount); } std::string CMasternodePayments::ToString() const { std::ostringstream info; - info << "Votes: " << (int)mapMasternodePayeeVotes.size() << ", Blocks: " << (int)mapMasternodeBlocks.size(); - return info.str(); } - int CMasternodePayments::GetOldestBlock() { LOCK(cs_mapMasternodeBlocks); @@ -833,13 +912,12 @@ int CMasternodePayments::GetOldestBlock() if ((*it).first < nOldestBlock) { nOldestBlock = (*it).first; } - it++; + ++it; } return nOldestBlock; } - int CMasternodePayments::GetNewestBlock() { LOCK(cs_mapMasternodeBlocks); @@ -851,7 +929,7 @@ int CMasternodePayments::GetNewestBlock() if ((*it).first > nNewestBlock) { nNewestBlock = (*it).first; } - it++; + ++it; } return nNewestBlock; diff --git a/src/masternode-payments.h b/src/masternode-payments.h index fc8751c1..3e4d1b2b 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -1,16 +1,19 @@ // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef MASTERNODE_PAYMENTS_H -#define MASTERNODE_PAYMENTS_H +#ifndef AGRARIAN_MASTERNODE_PAYMENTS_H +#define AGRARIAN_MASTERNODE_PAYMENTS_H #include "key.h" #include "main.h" #include "masternode.h" -using namespace std; +#include +#include +#include extern CCriticalSection cs_vecPayments; extern CCriticalSection cs_mapMasternodeBlocks; @@ -33,8 +36,7 @@ void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStak void DumpMasternodePayments(); -/** Save Masternode Payment Data (mnpayments.dat) - */ +/** Save Masternode Payment Data (mnpayments.dat) */ class CMasternodePaymentDB { private: @@ -63,17 +65,8 @@ public: CScript scriptPubKey; int nVotes; - CMasternodePayee() - { - scriptPubKey = CScript(); - nVotes = 0; - } - - CMasternodePayee(CScript payee, int nVotesIn) - { - scriptPubKey = payee; - nVotes = nVotesIn; - } + CMasternodePayee() : scriptPubKey(CScript()), nVotes(0) {} + CMasternodePayee(const CScript& payee, int nVotesIn) : scriptPubKey(payee), nVotes(nVotesIn) {} ADD_SERIALIZE_METHODS; @@ -92,18 +85,10 @@ public: int nBlockHeight; std::vector vecPayments; - CMasternodeBlockPayees() - { - nBlockHeight = 0; - vecPayments.clear(); - } - CMasternodeBlockPayees(int nBlockHeightIn) - { - nBlockHeight = nBlockHeightIn; - vecPayments.clear(); - } + CMasternodeBlockPayees() : nBlockHeight(0), vecPayments() {} + explicit CMasternodeBlockPayees(int nBlockHeightIn) : nBlockHeight(nBlockHeightIn), vecPayments() {} - void AddPayee(CScript payeeIn, int nIncrement) + void AddPayee(const CScript& payeeIn, int nIncrement) { LOCK(cs_vecPayments); @@ -114,8 +99,7 @@ public: } } - CMasternodePayee c(payeeIn, nIncrement); - vecPayments.push_back(c); + vecPayments.emplace_back(payeeIn, nIncrement); } bool GetPayee(CScript& payee) @@ -133,12 +117,14 @@ public: return (nVotes > -1); } - bool HasPayeeWithVotes(CScript payee, int nVotesReq) + bool HasPayeeWithVotes(const CScript& payee, int nVotesReq) { LOCK(cs_vecPayments); for (CMasternodePayee& p : vecPayments) { - if (p.nVotes >= nVotesReq && p.scriptPubKey == payee) return true; + if (p.nVotes >= nVotesReq && p.scriptPubKey == payee) { + return true; + } } return false; @@ -157,29 +143,17 @@ public: } }; -// for storing the winning payments +// For storing the winning payments class CMasternodePaymentWinner { public: CTxIn vinMasternode; - int nBlockHeight; CScript payee; std::vector vchSig; - CMasternodePaymentWinner() - { - nBlockHeight = 0; - vinMasternode = CTxIn(); - payee = CScript(); - } - - CMasternodePaymentWinner(CTxIn vinIn) - { - nBlockHeight = 0; - vinMasternode = vinIn; - payee = CScript(); - } + CMasternodePaymentWinner() : vinMasternode(CTxIn()), nBlockHeight(0), payee(CScript()), vchSig() {} + explicit CMasternodePaymentWinner(const CTxIn& vinIn) : vinMasternode(vinIn), nBlockHeight(0), payee(CScript()), vchSig() {} uint256 GetHash() { @@ -187,7 +161,6 @@ public: ss << payee; ss << nBlockHeight; ss << vinMasternode.prevout; - return ss.GetHash(); } @@ -196,11 +169,7 @@ public: bool SignatureValid(); void Relay(); - void AddPayee(CScript payeeIn) - { - payee = payeeIn; - } - + void AddPayee(const CScript& payeeIn) { payee = payeeIn; } ADD_SERIALIZE_METHODS; @@ -215,7 +184,7 @@ public: std::string ToString() { - std::string ret = ""; + std::string ret; ret += vinMasternode.ToString(); ret += ", " + std::to_string(nBlockHeight); ret += ", " + payee.ToString(); @@ -228,7 +197,6 @@ public: // Masternode Payments Class // Keeps track of who should get paid for which blocks // - class CMasternodePayments { private: @@ -238,13 +206,12 @@ private: public: std::map mapMasternodePayeeVotes; std::map mapMasternodeBlocks; - std::map mapMasternodesLastVote; //prevout.hash + prevout.n, nBlockHeight - CMasternodePayments() - { - nSyncedFromPeer = 0; - nLastBlockHeight = 0; - } + // NOTE: This legacy keying scheme (outpoint.hash + outpoint.n) can theoretically collide. + // Changing it requires a coordinated refactor of both header and implementation. + std::map mapMasternodesLastVote; // prevout.hash + prevout.n, nBlockHeight + + CMasternodePayments() : nSyncedFromPeer(0), nLastBlockHeight(0) {} void Clear() { @@ -264,18 +231,19 @@ public: bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight); bool IsScheduled(CMasternode& mn, int nNotBlockHeight); - bool CanVote(COutPoint outMasternode, int nBlockHeight) + bool CanVote(const COutPoint& outMasternode, int nBlockHeight) { LOCK(cs_mapMasternodePayeeVotes); - if (mapMasternodesLastVote.count(outMasternode.hash + outMasternode.n)) { - if (mapMasternodesLastVote[outMasternode.hash + outMasternode.n] == nBlockHeight) { + const uint256 key = outMasternode.hash + outMasternode.n; + if (mapMasternodesLastVote.count(key)) { + if (mapMasternodesLastVote[key] == nBlockHeight) { return false; } } - //record this masternode voted - mapMasternodesLastVote[outMasternode.hash + outMasternode.n] = nBlockHeight; + // record this masternode voted + mapMasternodesLastVote[key] = nBlockHeight; return true; } @@ -297,5 +265,4 @@ public: } }; - -#endif +#endif // AGRARIAN_MASTERNODE_PAYMENTS_H diff --git a/src/miner.cpp b/src/miner.cpp index 617d98fd..fa24a71e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -32,9 +33,6 @@ #include #include - -using namespace std; - ////////////////////////////////////////////////////////////////////////////// // // AgrarianMiner @@ -105,7 +103,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, // Create new block unique_ptr pblocktemplate(new CBlockTemplate()); if (!pblocktemplate.get()) - return NULL; + return nullptr; CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Tip @@ -166,7 +164,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, if (!fStakeFound) { LogPrint("staking", "CreateNewBlock(): stake not found\n"); - return NULL; + return nullptr; } } @@ -214,7 +212,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, continue; } - COrphan* porphan = NULL; + COrphan* porphan = nullptr; double dPriority = 0; CAmount nTotalIn = 0; bool fMissingInputs = false; @@ -243,7 +241,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, double nTimePriority = std::pow(GetAdjustedTime() - nTimeSeen, 6); // zAGR spends can have very large priority, use non-overflowing safe functions - dPriority = double_safe_addition(dPriority, (nTimePriority * nConfs)); + dPriority = double_safe_addition(dPriority, (nTimePriority* nConfs)); dPriority = double_safe_multiplication(dPriority, nTotalIn); continue; @@ -291,12 +289,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, int nConf = nHeight - coins->nHeight; // zAGR spends can have very large priority, use non-overflowing safe functions - dPriority = double_safe_addition(dPriority, ((double)nValueIn * nConf)); + dPriority = double_safe_addition(dPriority, ((double)nValueIn* nConf)); } if (fMissingInputs) continue; - // Priority is sum(valuein * age) / modified_txsize + // Priority is sum(valuein* age) / modified_txsize unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); dPriority = tx.ComputePriority(dPriority, nTxSize); @@ -521,17 +519,17 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, CKey key; if (!pwallet->GetZerocoinKey(bnSerial, key)) { LogPrintf("%s: failed to find zAGR with serial %s, unable to sign block\n", __func__, bnSerial.GetHex()); - return NULL; + return nullptr; } //Sign block with the zAGR key if (!SignBlockWithKey(*pblock, key)) { LogPrintf("BitcoinMiner(): Signing new block with zAGR key failed \n"); - return NULL; + return nullptr; } } else if (!SignBlock(*pblock, *pwallet)) { LogPrintf("BitcoinMiner(): Signing new block with UTXO key failed \n"); - return NULL; + return nullptr; } } @@ -539,7 +537,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) { //LogPrintf("CreateNewBlock() : TestBlockValidity failed\n"); mempool.clear(); - return NULL; + return nullptr; } // if (pblock->IsZerocoinStake()) { @@ -581,7 +579,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, CWallet* pwallet, { CPubKey pubkey; if (!reservekey.GetReservedKey(pubkey)) - return NULL; + return nullptr; CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; return CreateNewBlock(scriptPubKey, pwallet, fProofOfStake); @@ -613,7 +611,7 @@ bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock)) { + if (!ProcessNewBlock(state, nullptr, pblock)) { if (pblock->IsZerocoinStake()) { pwalletMain->zagrTracker->RemovePending(pblock->vtx[1].GetHash()); pwalletMain->zagrTracker->ListMints(true, true, true); //update the state @@ -831,7 +829,7 @@ void static ThreadBitcoinMiner(void* parg) void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) { - static boost::thread_group* minerThreads = NULL; + static boost::thread_group* minerThreads = nullptr; fGenerateBitcoins = fGenerate; if (nThreads < 0) { @@ -842,10 +840,10 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) nThreads = boost::thread::hardware_concurrency(); } - if (minerThreads != NULL) { + if (minerThreads != nullptr) { minerThreads->interrupt_all(); delete minerThreads; - minerThreads = NULL; + minerThreads = nullptr; } if (nThreads == 0 || !fGenerate) diff --git a/src/miner.h b/src/miner.h index 1ad3ab46..162b5b2a 100644 --- a/src/miner.h +++ b/src/miner.h @@ -1,14 +1,16 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2016-2018 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_MINER_H -#define BITCOIN_MINER_H - -#include - +#ifndef AGRARIAN_BITCOIN_MINER_H +#define AGRARIAN_BITCOIN_MINER_H +#include +#include +#include +#include +#include class CBlock; class CBlockHeader; class CBlockIndex; @@ -33,4 +35,4 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake); extern double dHashesPerSec; extern int64_t nHPSTimerStart; -#endif // BITCOIN_MINER_H +#endif // AGRARIAN_BITCOIN_MINER_H \ No newline at end of file diff --git a/src/pow.cpp b/src/pow.cpp index fbb7fe95..c36129b9 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2018 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -33,7 +34,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead uint256 PastDifficultyAverage; uint256 PastDifficultyAveragePrev; - if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { + if (BlockLastSolved == nullptr || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { return Params().ProofOfWorkLimit().GetCompact(); } @@ -74,7 +75,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead if (CountBlocks == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); } else { - PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); + PastDifficultyAverage = ((PastDifficultyAveragePrev* CountBlocks) + (uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); } PastDifficultyAveragePrev = PastDifficultyAverage; } @@ -85,7 +86,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead } LastBlockTime = BlockReading->GetBlockTime(); - if (BlockReading->pprev == NULL) { + if (BlockReading->pprev == nullptr) { assert(BlockReading); break; } @@ -94,7 +95,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead uint256 bnNew(PastDifficultyAverage); - int64_t _nTargetTimespan = CountBlocks * Params().TargetSpacing(); + int64_t _nTargetTimespan = CountBlocks* Params().TargetSpacing(); if (nActualTimespan < _nTargetTimespan / 3) nActualTimespan = _nTargetTimespan / 3; diff --git a/src/pow.h b/src/pow.h index 5cf9008e..a1677e28 100644 --- a/src/pow.h +++ b/src/pow.h @@ -2,14 +2,13 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2017-2018 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_POW_H -#define BITCOIN_POW_H - -#include - +#ifndef AGRARIAN_BITCOIN_POW_H +#define AGRARIAN_BITCOIN_POW_H +#include +#include class CBlockHeader; class CBlockIndex; class uint256; @@ -29,4 +28,4 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead bool CheckProofOfWork(uint256 hash, unsigned int nBits); uint256 GetBlockProof(const CBlockIndex& block); -#endif // BITCOIN_POW_H +#endif // AGRARIAN_BITCOIN_POW_H diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 551c7a26..a96a1b14 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -22,7 +23,7 @@ #include "wallet/wallet.h" #endif -#include +#include #include @@ -37,12 +38,12 @@ using namespace std; */ UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = chainActive.Tip(); + CBlockIndex*pb = chainActive.Tip(); if (height >= 0 && height < chainActive.Height()) pb = chainActive[height]; - if (pb == NULL || !pb->nHeight) + if (pb == nullptr || !pb->nHeight) return 0; // If lookup is -1, then use blocks since last difficulty change. @@ -158,7 +159,7 @@ UniValue generate(const UniValue& params, bool fHelp) unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, fPoS)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - CBlock *pblock = &pblocktemplate->block; + CBlock*pblock = &pblocktemplate->block; if(!fPoS){ { @@ -172,7 +173,7 @@ UniValue generate(const UniValue& params, bool fHelp) ++pblock->nNonce; } CValidationState state; - if (!ProcessNewBlock(state, NULL, pblock)) + if (!ProcessNewBlock(state, nullptr, pblock)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; fPoS = nHeight >= Params().LAST_POW_BLOCK(); @@ -201,7 +202,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp) "\nTurn off generation\n" + HelpExampleCli("setgenerate", "false") + "\nUsing json rpc\n" + HelpExampleRpc("setgenerate", "true, 1")); - if (pwalletMain == NULL) + if (pwalletMain == nullptr) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); if (Params().MineBlocksOnDemand()) @@ -515,7 +516,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (pindexPrev != chainActive.Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on - pindexPrev = NULL; + pindexPrev = nullptr; // Store the chainActive.Tip() used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); @@ -525,7 +526,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) // Create new block if (pblocktemplate) { delete pblocktemplate; - pblocktemplate = NULL; + pblocktemplate = nullptr; } CScript scriptDummy = CScript() << OP_TRUE; pblocktemplate = CreateNewBlock(scriptDummy, pwalletMain, false); @@ -691,7 +692,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, NULL, &block); + bool fAccepted = ProcessNewBlock(state, nullptr, &block); UnregisterValidationInterface(&sc); if (fBlockPresent) { if (fAccepted && !sc.found) diff --git a/src/txdb.cpp b/src/txdb.cpp index 367dd500..4c17c55e 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2016-2019 The PIVX developers +// Copyright (c) 2026 Agrarian Developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,45 +12,55 @@ #include "uint256.h" #include "zagr/accumulators.h" -#include +#include +#include +#include +#include +#include +#include +#include #include -using namespace std; -using namespace libzerocoin; +namespace { -void static BatchWriteCoins(CLevelDBBatch& batch, const uint256& hash, const CCoins& coins) +void BatchWriteCoins(CLevelDBBatch& batch, const uint256& hash, const CCoins& coins) { - if (coins.IsPruned()) - batch.Erase(make_pair('c', hash)); - else - batch.Write(make_pair('c', hash), coins); + if (coins.IsPruned()) { + batch.Erase(std::make_pair('c', hash)); + } else { + batch.Write(std::make_pair('c', hash), coins); + } } -void static BatchWriteHashBestChain(CLevelDBBatch& batch, const uint256& hash) +void BatchWriteHashBestChain(CLevelDBBatch& batch, const uint256& hash) { batch.Write('B', hash); } -CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) +} // namespace + +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) + : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { } bool CCoinsViewDB::GetCoins(const uint256& txid, CCoins& coins) const { - return db.Read(make_pair('c', txid), coins); + return db.Read(std::make_pair('c', txid), coins); } bool CCoinsViewDB::HaveCoins(const uint256& txid) const { - return db.Exists(make_pair('c', txid)); + return db.Exists(std::make_pair('c', txid)); } uint256 CCoinsViewDB::GetBestBlock() const { uint256 hashBestChain; - if (!db.Read('B', hashBestChain)) + if (!db.Read('B', hashBestChain)) { return uint256(0); + } return hashBestChain; } @@ -58,39 +69,47 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) CLevelDBBatch batch; size_t count = 0; size_t changed = 0; - for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { + + for (auto it = mapCoins.begin(); it != mapCoins.end();) { if (it->second.flags & CCoinsCacheEntry::DIRTY) { BatchWriteCoins(batch, it->first, it->second.coins); - changed++; + ++changed; } - count++; - CCoinsMap::iterator itOld = it++; + ++count; + + auto itOld = it++; mapCoins.erase(itOld); } - if (hashBlock != uint256(0)) - BatchWriteHashBestChain(batch, hashBlock); - LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); + if (hashBlock != uint256(0)) { + BatchWriteHashBestChain(batch, hashBlock); + } + + LogPrint("coindb", + "Committing %u changed transactions (out of %u) to coin database...\n", + (unsigned int)changed, (unsigned int)count); + return db.WriteBatch(batch); } -CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) + : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { } bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) { - return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); + return Write(std::make_pair('b', blockindex.GetBlockHash()), blockindex); } bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo& info) { - return Write(make_pair('f', nFile), info); + return Write(std::make_pair('f', nFile), info); } bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo& info) { - return Read(make_pair('f', nFile), info); + return Read(std::make_pair('f', nFile), info); } bool CBlockTreeDB::WriteLastBlockFile(int nFile) @@ -100,10 +119,10 @@ bool CBlockTreeDB::WriteLastBlockFile(int nFile) bool CBlockTreeDB::WriteReindexing(bool fReindexing) { - if (fReindexing) + if (fReindexing) { return Write('R', '1'); - else - return Erase('R'); + } + return Erase('R'); } bool CBlockTreeDB::ReadReindexing(bool& fReindexing) @@ -119,53 +138,70 @@ bool CBlockTreeDB::ReadLastBlockFile(int& nFile) bool CCoinsViewDB::GetStats(CCoinsStats& stats) const { - /* It seems that there are no "const iterators" for LevelDB. Since we - only need read operations on it, use a const-cast to get around - that restriction. */ - boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); + // LevelDB iterators are non-const; we only read so const_cast the wrapper. + std::unique_ptr pcursor(const_cast(&db)->NewIterator()); pcursor->SeekToFirst(); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); stats.hashBlock = GetBestBlock(); ss << stats.hashBlock; + CAmount nTotalAmount = 0; + while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { - leveldb::Slice slKey = pcursor->key(); + const leveldb::Slice slKey = pcursor->key(); CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + char chType; ssKey >> chType; + if (chType == 'c') { - leveldb::Slice slValue = pcursor->value(); + const leveldb::Slice slValue = pcursor->value(); CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); + CCoins coins; ssValue >> coins; + uint256 txhash; ssKey >> txhash; + ss << txhash; ss << VARINT(coins.nVersion); ss << (coins.fCoinBase ? 'c' : 'n'); ss << VARINT(coins.nHeight); - stats.nTransactions++; - for (unsigned int i = 0; i < coins.vout.size(); i++) { + + ++stats.nTransactions; + + for (unsigned int i = 0; i < coins.vout.size(); ++i) { const CTxOut& out = coins.vout[i]; if (!out.IsNull()) { - stats.nTransactionOutputs++; + ++stats.nTransactionOutputs; ss << VARINT(i + 1); ss << out; nTotalAmount += out.nValue; } } + stats.nSerializedSize += 32 + slValue.size(); ss << VARINT(0); } + pcursor->Next(); - } catch (std::exception& e) { + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } - stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight; + + // Height: best-effort. If best block isn't in index (e.g. empty db), return height=0. + stats.nHeight = 0; + const uint256 best = GetBestBlock(); + auto it = mapBlockIndex.find(best); + if (it != mapBlockIndex.end() && it->second) { + stats.nHeight = it->second->nHeight; + } + stats.hashSerialized = ss.GetHash(); stats.nTotalAmount = nTotalAmount; return true; @@ -173,14 +209,15 @@ bool CCoinsViewDB::GetStats(CCoinsStats& stats) const bool CBlockTreeDB::ReadTxIndex(const uint256& txid, CDiskTxPos& pos) { - return Read(make_pair('t', txid), pos); + return Read(std::make_pair('t', txid), pos); } -bool CBlockTreeDB::WriteTxIndex(const std::vector >& vect) +bool CBlockTreeDB::WriteTxIndex(const std::vector>& vect) { CLevelDBBatch batch; - for (std::vector >::const_iterator it = vect.begin(); it != vect.end(); it++) - batch.Write(make_pair('t', it->first), it->second); + for (const auto& it : vect) { + batch.Write(std::make_pair('t', it.first), it.second); + } return WriteBatch(batch); } @@ -192,9 +229,10 @@ bool CBlockTreeDB::WriteFlag(const std::string& name, bool fValue) bool CBlockTreeDB::ReadFlag(const std::string& name, bool& fValue) { char ch; - if (!Read(std::make_pair('F', name), ch)) + if (!Read(std::make_pair('F', name), ch)) { return false; - fValue = ch == '1'; + } + fValue = (ch == '1'); return true; } @@ -210,76 +248,82 @@ bool CBlockTreeDB::ReadInt(const std::string& name, int& nValue) bool CBlockTreeDB::LoadBlockIndexGuts() { - boost::scoped_ptr pcursor(NewIterator()); + std::unique_ptr pcursor(NewIterator()); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); - ssKeySet << make_pair('b', uint256(0)); + ssKeySet << std::make_pair('b', uint256(0)); pcursor->Seek(ssKeySet.str()); - // Load mapBlockIndex uint256 nPreviousCheckpoint; + while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { - leveldb::Slice slKey = pcursor->key(); + const leveldb::Slice slKey = pcursor->key(); CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + char chType; ssKey >> chType; - if (chType == 'b') { - leveldb::Slice slValue = pcursor->value(); - CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - CDiskBlockIndex diskindex; - ssValue >> diskindex; - // Construct block index object - CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); - pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); - pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); - pindexNew->nHeight = diskindex.nHeight; - pindexNew->nFile = diskindex.nFile; - pindexNew->nDataPos = diskindex.nDataPos; - pindexNew->nUndoPos = diskindex.nUndoPos; - pindexNew->nVersion = diskindex.nVersion; - pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; - pindexNew->nTime = diskindex.nTime; - pindexNew->nBits = diskindex.nBits; - pindexNew->nNonce = diskindex.nNonce; - pindexNew->nStatus = diskindex.nStatus; - pindexNew->nTx = diskindex.nTx; - - //zerocoin - pindexNew->nAccumulatorCheckpoint = diskindex.nAccumulatorCheckpoint; - pindexNew->mapZerocoinSupply = diskindex.mapZerocoinSupply; - pindexNew->vMintDenominationsInBlock = diskindex.vMintDenominationsInBlock; - - //Proof Of Stake - pindexNew->nMint = diskindex.nMint; - pindexNew->nMoneySupply = diskindex.nMoneySupply; - pindexNew->nFlags = diskindex.nFlags; - pindexNew->nStakeModifier = diskindex.nStakeModifier; - pindexNew->prevoutStake = diskindex.prevoutStake; - pindexNew->nStakeTime = diskindex.nStakeTime; - pindexNew->hashProofOfStake = diskindex.hashProofOfStake; - - if (pindexNew->nHeight <= Params().LAST_POW_BLOCK()) { - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) - return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); - } - - //populate accumulator checksum map in memory - if(pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { - //Don't load any checkpoints that exist before v2 zagr. The accumulator is invalid for v1 and not used. - if (pindexNew->nHeight >= Params().Zerocoin_Block_V2_Start()) - LoadAccumulatorValuesFromDB(pindexNew->nAccumulatorCheckpoint); - - nPreviousCheckpoint = pindexNew->nAccumulatorCheckpoint; - } - - pcursor->Next(); - } else { - break; // if shutdown requested or finished loading block index + if (chType != 'b') { + break; // finished loading block index } - } catch (std::exception& e) { + + const leveldb::Slice slValue = pcursor->value(); + CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); + + CDiskBlockIndex diskindex; + ssValue >> diskindex; + + // Construct block index object + CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); + pindexNew->nHeight = diskindex.nHeight; + pindexNew->nFile = diskindex.nFile; + pindexNew->nDataPos = diskindex.nDataPos; + pindexNew->nUndoPos = diskindex.nUndoPos; + pindexNew->nVersion = diskindex.nVersion; + pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; + pindexNew->nTime = diskindex.nTime; + pindexNew->nBits = diskindex.nBits; + pindexNew->nNonce = diskindex.nNonce; + pindexNew->nStatus = diskindex.nStatus; + pindexNew->nTx = diskindex.nTx; + + // Zerocoin + pindexNew->nAccumulatorCheckpoint = diskindex.nAccumulatorCheckpoint; + pindexNew->mapZerocoinSupply = diskindex.mapZerocoinSupply; + pindexNew->vMintDenominationsInBlock = diskindex.vMintDenominationsInBlock; + + // Proof of Stake + pindexNew->nMint = diskindex.nMint; + pindexNew->nMoneySupply = diskindex.nMoneySupply; + pindexNew->nFlags = diskindex.nFlags; + pindexNew->nStakeModifier = diskindex.nStakeModifier; + pindexNew->prevoutStake = diskindex.prevoutStake; + pindexNew->nStakeTime = diskindex.nStakeTime; + pindexNew->hashProofOfStake = diskindex.hashProofOfStake; + + // Hybrid PoW+PoS: only enforce PoW proof check for PoW blocks (not just height). + // If your codebase doesn't define IsProofOfWork(), keep the height gate or adjust at call sites. + if (pindexNew->IsProofOfWork()) { + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) { + return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); + } + } + + // Populate accumulator checksum map in memory + if (pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { + // Don't load any checkpoints that exist before v2 zagr. The accumulator is invalid for v1 and not used. + if (pindexNew->nHeight >= Params().Zerocoin_Block_V2_Start()) { + LoadAccumulatorValuesFromDB(pindexNew->nAccumulatorCheckpoint); + } + nPreviousCheckpoint = pindexNew->nAccumulatorCheckpoint; + } + + pcursor->Next(); + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } @@ -287,18 +331,20 @@ bool CBlockTreeDB::LoadBlockIndexGuts() return true; } -CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "zerocoin", nCacheSize, fMemory, fWipe) +CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) + : CLevelDBWrapper(GetDataDir() / "zerocoin", nCacheSize, fMemory, fWipe) { } -bool CZerocoinDB::WriteCoinMintBatch(const std::vector >& mintInfo) +bool CZerocoinDB::WriteCoinMintBatch(const std::vector>& mintInfo) { CLevelDBBatch batch; size_t count = 0; - for (std::vector >::const_iterator it=mintInfo.begin(); it != mintInfo.end(); it++) { - PublicCoin pubCoin = it->first; - uint256 hash = GetPubCoinHash(pubCoin.getValue()); - batch.Write(make_pair('m', hash), it->second); + + for (const auto& it : mintInfo) { + const libzerocoin::PublicCoin& pubCoin = it.first; + const uint256 hash = GetPubCoinHash(pubCoin.getValue()); + batch.Write(std::make_pair('m', hash), it.second); ++count; } @@ -313,25 +359,26 @@ bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx) bool CZerocoinDB::ReadCoinMint(const uint256& hashPubcoin, uint256& hashTx) { - return Read(make_pair('m', hashPubcoin), hashTx); + return Read(std::make_pair('m', hashPubcoin), hashTx); } bool CZerocoinDB::EraseCoinMint(const CBigNum& bnPubcoin) { - uint256 hash = GetPubCoinHash(bnPubcoin); - return Erase(make_pair('m', hash)); + const uint256 hash = GetPubCoinHash(bnPubcoin); + return Erase(std::make_pair('m', hash)); } -bool CZerocoinDB::WriteCoinSpendBatch(const std::vector >& spendInfo) +bool CZerocoinDB::WriteCoinSpendBatch(const std::vector>& spendInfo) { CLevelDBBatch batch; size_t count = 0; - for (std::vector >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) { - CBigNum bnSerial = it->first.getCoinSerialNumber(); + + for (const auto& it : spendInfo) { + const CBigNum bnSerial = it.first.getCoinSerialNumber(); CDataStream ss(SER_GETHASH, 0); ss << bnSerial; - uint256 hash = Hash(ss.begin(), ss.end()); - batch.Write(make_pair('s', hash), it->second); + const uint256 hash = Hash(ss.begin(), ss.end()); + batch.Write(std::make_pair('s', hash), it.second); ++count; } @@ -343,63 +390,68 @@ bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash) { CDataStream ss(SER_GETHASH, 0); ss << bnSerial; - uint256 hash = Hash(ss.begin(), ss.end()); - - return Read(make_pair('s', hash), txHash); + const uint256 hash = Hash(ss.begin(), ss.end()); + return Read(std::make_pair('s', hash), txHash); } -bool CZerocoinDB::ReadCoinSpend(const uint256& hashSerial, uint256 &txHash) +bool CZerocoinDB::ReadCoinSpend(const uint256& hashSerial, uint256& txHash) { - return Read(make_pair('s', hashSerial), txHash); + return Read(std::make_pair('s', hashSerial), txHash); } bool CZerocoinDB::EraseCoinSpend(const CBigNum& bnSerial) { CDataStream ss(SER_GETHASH, 0); ss << bnSerial; - uint256 hash = Hash(ss.begin(), ss.end()); - - return Erase(make_pair('s', hash)); + const uint256 hash = Hash(ss.begin(), ss.end()); + return Erase(std::make_pair('s', hash)); } -bool CZerocoinDB::WipeCoins(std::string strType) +bool CZerocoinDB::WipeCoins(const std::string& strType) { - if (strType != "spends" && strType != "mints") + if (strType != "spends" && strType != "mints") { return error("%s: did not recognize type %s", __func__, strType); + } - boost::scoped_ptr pcursor(NewIterator()); + std::unique_ptr pcursor(NewIterator()); - char type = (strType == "spends" ? 's' : 'm'); + const char type = (strType == "spends" ? 's' : 'm'); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); - ssKeySet << make_pair(type, uint256(0)); + ssKeySet << std::make_pair(type, uint256(0)); pcursor->Seek(ssKeySet.str()); - // Load mapBlockIndex + std::set setDelete; + while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { - leveldb::Slice slKey = pcursor->key(); + const leveldb::Slice slKey = pcursor->key(); CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + char chType; ssKey >> chType; - if (chType == type) { - leveldb::Slice slValue = pcursor->value(); - CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); - uint256 hash; - ssValue >> hash; - setDelete.insert(hash); - pcursor->Next(); - } else { - break; // if shutdown requested or finished loading block index + + if (chType != type) { + break; // finished } - } catch (std::exception& e) { + + const leveldb::Slice slValue = pcursor->value(); + CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); + + uint256 hash; + ssValue >> hash; + setDelete.insert(hash); + + pcursor->Next(); + } catch (const std::exception& e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } - for (auto& hash : setDelete) { - if (!Erase(make_pair(type, hash))) + for (const auto& hash : setDelete) { + if (!Erase(std::make_pair(type, hash))) { LogPrintf("%s: error failed to delete %s\n", __func__, hash.GetHex()); + } } return true; @@ -407,17 +459,17 @@ bool CZerocoinDB::WipeCoins(std::string strType) bool CZerocoinDB::WriteAccumulatorValue(const uint32_t& nChecksum, const CBigNum& bnValue) { - LogPrint("zero","%s : checksum:%d val:%s\n", __func__, nChecksum, bnValue.GetHex()); - return Write(make_pair('2', nChecksum), bnValue); + LogPrint("zero", "%s : checksum:%d val:%s\n", __func__, nChecksum, bnValue.GetHex()); + return Write(std::make_pair('2', nChecksum), bnValue); } bool CZerocoinDB::ReadAccumulatorValue(const uint32_t& nChecksum, CBigNum& bnValue) { - return Read(make_pair('2', nChecksum), bnValue); + return Read(std::make_pair('2', nChecksum), bnValue); } bool CZerocoinDB::EraseAccumulatorValue(const uint32_t& nChecksum) { LogPrint("zero", "%s : checksum:%d\n", __func__, nChecksum); - return Erase(make_pair('2', nChecksum)); + return Erase(std::make_pair('2', nChecksum)); }