Updating code

reviving this project
This commit is contained in:
2026-02-18 22:09:06 -08:00
parent c4f5a9ede1
commit 6be262164d
26 changed files with 1041 additions and 987 deletions
+20 -7
View File
@@ -1,16 +1,29 @@
#!/bin/sh #!/bin/sh
# Copyright (c) 2013-2016 The Bitcoin Core developers # Copyright (c) 2013-2016 The Bitcoin Core developers
# Copyright (c) 2026 Agrarian Developers
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C 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" cd "$srcdir"
if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then
LIBTOOLIZE="${GLIBTOOLIZE}" # Prefer glibtoolize on macOS if LIBTOOLIZE isn't already set.
export LIBTOOLIZE if [ -z "${LIBTOOLIZE:-}" ]; then
GLIBTOOLIZE="$(command -v glibtoolize 2>/dev/null || true)"
if [ -n "$GLIBTOOLIZE" ]; then
LIBTOOLIZE="$GLIBTOOLIZE"
export LIBTOOLIZE
fi
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 autoreconf --install --force --warnings=all
+5 -1
View File
@@ -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) dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MAJOR, 1)
@@ -5,7 +9,7 @@ define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true) 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_INIT([Agrarian Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[www.agrarian.org],[agrarian])
AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_SRCDIR([src/main.cpp])
AC_CONFIG_HEADERS([src/config/agrarian-config.h]) AC_CONFIG_HEADERS([src/config/agrarian-config.h])
+55 -215
View File
@@ -1,283 +1,123 @@
UNIX BUILD NOTES Copyright (c) 2026 Agrarian Developers
====================
Some notes on how to build Agrarian Core in Unix.
Note UNIX Build Notes
---------------------
Always use absolute paths to configure and compile Agrarian Core and the dependencies,
For example, when specifying the path of the dependency:
../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 IMPORTANT
the usage of the absolute path.
To Build Always use absolute paths when configuring and compiling Agrarian Core
--------------------- and its dependencies.
```bash Example:
./autogen.sh
./configure
make
make install # optional
```
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 ./autogen.sh
------------|--------------------|---------------------- ./configure
libssl | Crypto | Random Number Generation, Elliptic Curve Cryptography make
libboost | Utility | Library for threading, data structures, etc make install (optional)
libevent | Networking | OS independent asynchronous networking
libgmp | Bignum Arithmetic | Precision arithmetic
Optional dependencies: If dependencies are satisfied, this will build agrarian-qt as well.
Library | Purpose | Description DEPENDENCIES
------------|------------------|----------------------
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)
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 See dependencies.md for version details.
memory available when compiling Agrarian Core. On systems with less, gcc can be
tuned to conserve memory with additional CXXFLAGS:
MEMORY REQUIREMENTS
Minimum recommended: 1.5 GB RAM.
Low memory systems:
./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768"
UBUNTU / DEBIAN
## Linux Distribution Specific Instructions Build tools:
### Ubuntu & Debian
#### Dependency Build Instructions
Build requirements:
sudo apt-get install build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 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 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` OpenSSL Note: For Ubuntu >= 18.04 or Debian >= Stretch use
above instead of `libssl-dev`. Agrarian Core does not support the use of OpenSSL 1.1, though compilation is still possible libssl1.0-dev. OpenSSL 1.1 is not officially supported.
by passing `--with-incompatible-ssl` to configure (NOT RECOMMENDED!).
BerkeleyDB is required for the wallet. Berkeley DB 4.8 (wallet support):
**For Ubuntu only:** db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin).
You can add the repository using the following command:
sudo apt-get install software-properties-common sudo apt-get install software-properties-common
sudo add-apt-repository ppa:bitcoin/bitcoin sudo add-apt-repository ppa:bitcoin/bitcoin
sudo apt-get update sudo apt-get update
sudo apt-get install libdb4.8-dev libdb4.8++-dev 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 Optional:
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):
sudo apt-get install libminiupnpc-dev sudo apt-get install libminiupnpc-dev
ZMQ dependencies (provides ZMQ API):
sudo apt-get install libzmq3-dev 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 sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
are installed. Qt 5 is necessary to build the GUI.
To build without GUI pass `--without-gui`.
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 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
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
Optional: Optional:
sudo dnf install miniupnpc-devel zeromq-devel 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 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 ./configure --enable-hardening
-----
The release is built with GCC and then "strip agrariand" to strip the debug
symbols, which reduces the executable size by about 90%.
Disable:
miniupnpc ./configure --disable-hardening
---------
[miniupnpc](http://miniupnp.free.fr/) may be used for UPnP port mapping. It can be downloaded from [here]( Verify:
http://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and
turned off by default. See the configure options for upnp behavior desired:
--without-miniupnpc No UPnP support miniupnp not required scanelf -e ./agrariand
--disable-upnp-default (the default) UPnP support turned off by default at runtime
--enable-upnp-default UPnP support turned on by default at runtime
To build: DISABLE WALLET MODE
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:
./configure --disable-wallet ./configure --disable-wallet
In this case there is no dependency on Berkeley DB 4.8. ARM CROSS COMPILATION
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:
sudo apt-get install g++-arm-linux-gnueabihf curl sudo apt-get install g++-arm-linux-gnueabihf curl
To build executables for ARM:
cd depends cd depends
make HOST=arm-linux-gnueabihf NO_QT=1 make HOST=arm-linux-gnueabihf NO_QT=1
cd .. cd ..
./autogen.sh ./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 make
For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory.
+144 -97
View File
@@ -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. SUPPORTED BUILD METHODS
* 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
------------------------------------------------------------ ------------------------------------------------------------
The steps below can be performed on Ubuntu (including in a VM) or WSL. The depends system The following methods are known to work:
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
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 update
sudo apt upgrade 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 A host toolchain (build-essential) is required because some dependencies
packages (such as `protobuf`) need to build host utilities that are used in the (e.g., protobuf) build host utilities during the process.
build process.
See [dependencies.md](dependencies.md) for a complete overview. If building the Windows installer (`make deploy`):
If you want to build the windows installer with `make deploy` you need [NSIS](https://nsis.sourceforge.io/Main_Page):
sudo apt install nsis sudo apt install nsis
Acquire the source in the usual way: ------------------------------------------------------------
SOURCE CODE
------------------------------------------------------------
git clone https://github.com/agrarian-project/agrarian.git git clone https://github.com/agrarian-project/agrarian.git
cd agrarian 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 sudo apt install g++-mingw-w64-x86-64
Ubuntu Bionic 18.04 <sup>[1](#footnote1)</sup>: 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. IMPORTANT (WSL USERS)
This means you cannot use a directory that is located directly on the host Windows file system to perform the build. ------------------------------------------------------------
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 cd depends
make HOST=x86_64-w64-mingw32 make HOST=x86_64-w64-mingw32
cd .. cd ..
./autogen.sh # not required when building from tarball ./autogen.sh
CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/ CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site \
./configure --prefix=/
make 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 sudo apt install g++-mingw-w64-i686 mingw-w64-i686-dev
Ubuntu Bionic 18.04 <sup>[1](#footnote1)</sup>: 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 cd depends
make HOST=i686-w64-mingw32 make HOST=i686-w64-mingw32
cd .. cd ..
./autogen.sh # not required when building from tarball ./autogen.sh
CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site ./configure --prefix=/ CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site \
./configure --prefix=/
make 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 INSTALLATION
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:
To install into a Windows-accessible directory:
make install DESTDIR=/mnt/c/workspace/agrarian make install DESTDIR=/mnt/c/workspace/agrarian
You can also create an installer using: To build a Windows installer:
make deploy make deploy
Footnotes ============================================================
--------- THREAD MODEL NOTE
============================================================
<a name="footnote1">1</a>: Starting from Ubuntu Xenial 16.04, both the 32 and 64 bit Mingw-w64 packages install two different Ubuntu Mingw-w64 packages include two thread models:
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 • win32 (default)
required to support win32 threads conflict with some of the classes in the C++11 standard library, in particular std::mutex. • posix
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). 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
============================================================
+2 -1
View File
@@ -1,3 +1,4 @@
// Copyright (c) 2026 Agrarian Developers
#include <windows.h> // needed for VERSIONINFO #include <windows.h> // needed for VERSIONINFO
#include "clientversion.h" // holds the needed client version information #include "clientversion.h" // holds the needed client version information
@@ -32,4 +33,4 @@ BEGIN
BEGIN BEGIN
VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal)
END END
END END
+17 -20
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2015 The Bitcoin developers // Copyright (c) 2009-2015 The Bitcoin developers
// Copyright (c) 2009-2015 The Dash developers // Copyright (c) 2009-2015 The Dash developers
// Copyright (c) 2015-2018 The PIVX developers // Copyright (c) 2015-2018 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -23,9 +24,6 @@
#include <univalue.h> #include <univalue.h>
#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ #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; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
std::string HelpMessageCli() std::string HelpMessageCli()
@@ -116,13 +114,12 @@ struct HTTPReply
std::string body; 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<HTTPReply*>(ctx); HTTPReply* reply = static_cast<HTTPReply*>(ctx);
if (req == NULL) { if (req == nullptr) {
/* If req is NULL, it means an error occurred while connecting, but /* 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.
* I'm not sure how to find out which one. We also don't really care.
*/ */
reply->status = 0; reply->status = 0;
return; return;
@@ -130,11 +127,11 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
reply->status = evhttp_request_get_response_code(req); 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) if (buf)
{ {
size_t size = evbuffer_get_length(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) if (data)
reply->body = std::string(data, size); reply->body = std::string(data, size);
evbuffer_drain(buf, size); evbuffer_drain(buf, size);
@@ -147,19 +144,19 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
int port = GetArg("-rpcport", BaseParams().RPCPort()); int port = GetArg("-rpcport", BaseParams().RPCPort());
// Create event base // Create event base
struct event_base *base = event_base_new(); // TODO RAII struct event_base* base = event_base_new(); // TODO RAII
if (!base) if (!base)
throw runtime_error("cannot create event_base"); throw runtime_error("cannot create event_base");
// Synchronously look up hostname // Synchronously look up hostname
struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII struct evhttp_connection* evcon = evhttp_connection_base_new(base, nullptr, host.c_str(), port); // TODO RAII
if (evcon == NULL) if (evcon == nullptr)
throw runtime_error("create connection failed"); throw runtime_error("create connection failed");
evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
HTTPReply response; HTTPReply response;
struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII struct evhttp_request* req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
if (req == NULL) if (req == nullptr)
throw runtime_error("create http request failed"); throw runtime_error("create http request failed");
// Get credentials // Get credentials
@@ -176,7 +173,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; 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); assert(output_headers);
evhttp_add_header(output_headers, "Host", host.c_str()); evhttp_add_header(output_headers, "Host", host.c_str());
evhttp_add_header(output_headers, "Connection", "close"); evhttp_add_header(output_headers, "Connection", "close");
@@ -184,7 +181,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
// Attach request data // Attach request data
std::string strRequest = JSONRPCRequest(strMethod, params, 1); 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); assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
@@ -280,7 +277,7 @@ int CommandLineRPC(int argc, char* argv[])
strPrint = string("error: ") + e.what(); strPrint = string("error: ") + e.what();
nRet = EXIT_FAILURE; nRet = EXIT_FAILURE;
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "CommandLineRPC()"); PrintExceptionContinue(nullptr, "CommandLineRPC()");
throw; throw;
} }
@@ -305,7 +302,7 @@ int main(int argc, char* argv[])
PrintExceptionContinue(&e, "AppInitRPC()"); PrintExceptionContinue(&e, "AppInitRPC()");
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "AppInitRPC()"); PrintExceptionContinue(nullptr, "AppInitRPC()");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -315,7 +312,7 @@ int main(int argc, char* argv[])
} catch (std::exception& e) { } catch (std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRPC()"); PrintExceptionContinue(&e, "CommandLineRPC()");
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "CommandLineRPC()"); PrintExceptionContinue(nullptr, "CommandLineRPC()");
} }
return ret; return ret;
} }
+2
View File
@@ -1,3 +1,5 @@
// Copyright (c) 2026 Agrarian Developers
#include <windows.h> // needed for VERSIONINFO #include <windows.h> // needed for VERSIONINFO
#include "clientversion.h" // holds the needed client version information #include "clientversion.h" // holds the needed client version information
+4 -5
View File
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -24,8 +25,6 @@
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
using namespace boost::assign; using namespace boost::assign;
using namespace std;
static bool fCreateBlank; static bool fCreateBlank;
static map<string, UniValue> registers; static map<string, UniValue> registers;
CClientUIInterface uiInterface; CClientUIInterface uiInterface;
@@ -605,7 +604,7 @@ static int CommandLineRawTx(int argc, char* argv[])
strPrint = string("error: ") + e.what(); strPrint = string("error: ") + e.what();
nRet = EXIT_FAILURE; nRet = EXIT_FAILURE;
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "CommandLineRawTx()"); PrintExceptionContinue(nullptr, "CommandLineRawTx()");
throw; throw;
} }
@@ -626,7 +625,7 @@ int main(int argc, char* argv[])
PrintExceptionContinue(&e, "AppInitRawTx()"); PrintExceptionContinue(&e, "AppInitRawTx()");
return EXIT_FAILURE; return EXIT_FAILURE;
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "AppInitRawTx()"); PrintExceptionContinue(nullptr, "AppInitRawTx()");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -636,7 +635,7 @@ int main(int argc, char* argv[])
} catch (std::exception& e) { } catch (std::exception& e) {
PrintExceptionContinue(&e, "CommandLineRawTx()"); PrintExceptionContinue(&e, "CommandLineRawTx()");
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "CommandLineRawTx()"); PrintExceptionContinue(nullptr, "CommandLineRawTx()");
} }
return ret; return ret;
} }
+2
View File
@@ -1,3 +1,5 @@
// Copyright (c) 2026 Agrarian Developers
#include <windows.h> // needed for VERSIONINFO #include <windows.h> // needed for VERSIONINFO
#include "clientversion.h" // holds the needed client version information #include "clientversion.h" // holds the needed client version information
+4 -5
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -29,13 +30,11 @@
* \section intro_sec Introduction * \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), * 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 * 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.
* 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. * The software is a community-driven open source project, released under the MIT license.
* *
* \section Navigation * \section Navigation* Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code.
* Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code.
*/ */
static bool fDaemon; static bool fDaemon;
@@ -144,7 +143,7 @@ bool AppInit(int argc, char* argv[])
} catch (std::exception& e) { } catch (std::exception& e) {
PrintExceptionContinue(&e, "AppInit()"); PrintExceptionContinue(&e, "AppInit()");
} catch (...) { } catch (...) {
PrintExceptionContinue(NULL, "AppInit()"); PrintExceptionContinue(nullptr, "AppInit()");
} }
if (!fRet) { if (!fRet) {
+81 -53
View File
@@ -2,11 +2,14 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "libzerocoin/Params.h" #include "libzerocoin/Params.h"
#include "chainparams.h" #include "chainparams.h"
#include "chainparamsseeds.h"
#include "random.h" #include "random.h"
#include "util.h" #include "util.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
@@ -23,8 +26,6 @@ struct SeedSpec6 {
uint16_t port; uint16_t port;
}; };
#include "chainparamsseeds.h"
/** /**
* Main network * Main network
*/ */
@@ -57,9 +58,9 @@ static Checkpoints::MapCheckpoints mapCheckpoints =
static const Checkpoints::CCheckpointData data = { static const Checkpoints::CCheckpointData data = {
&mapCheckpoints, &mapCheckpoints,
1643790201, // * UNIX timestamp of last checkpoint block 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) // (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 = static Checkpoints::MapCheckpoints mapCheckpointsTestnet =
@@ -69,7 +70,8 @@ static const Checkpoints::CCheckpointData dataTestnet = {
&mapCheckpointsTestnet, &mapCheckpointsTestnet,
1643790201, 1643790201,
0, 0,
0}; 0
};
static Checkpoints::MapCheckpoints mapCheckpointsRegtest = static Checkpoints::MapCheckpoints mapCheckpointsRegtest =
boost::assign::map_list_of(0, uint256("0x001")); boost::assign::map_list_of(0, uint256("0x001"));
@@ -77,24 +79,24 @@ static const Checkpoints::CCheckpointData dataRegtest = {
&mapCheckpointsRegtest, &mapCheckpointsRegtest,
1643790201, 1643790201,
0, 0,
0}; 0
};
libzerocoin::ZerocoinParams* CChainParams::Zerocoin_Params(bool useModulusV1) const libzerocoin::ZerocoinParams* CChainParams::Zerocoin_Params(bool useModulusV1) const
{ {
assert(this); assert(this);
static CBigNum bnHexModulus = 0; static CBigNum bnHexModulus = 0;
if (!bnHexModulus) if (!bnHexModulus)
bnHexModulus.SetHex(zerocoinModulus); bnHexModulus.SetHex(zerocoinModulus);
static libzerocoin::ZerocoinParams ZCParamsHex = libzerocoin::ZerocoinParams(bnHexModulus); static libzerocoin::ZerocoinParams ZCParamsHex = libzerocoin::ZerocoinParams(bnHexModulus);
static CBigNum bnDecModulus = 0; static CBigNum bnDecModulus = 0;
if (!bnDecModulus) if (!bnDecModulus)
bnDecModulus.SetDec(zerocoinModulus); bnDecModulus.SetDec(zerocoinModulus);
static libzerocoin::ZerocoinParams ZCParamsDec = libzerocoin::ZerocoinParams(bnDecModulus); static libzerocoin::ZerocoinParams ZCParamsDec = libzerocoin::ZerocoinParams(bnDecModulus);
if (useModulusV1) return useModulusV1 ? &ZCParamsHex : &ZCParamsDec;
return &ZCParamsHex;
return &ZCParamsDec;
} }
class CMainParams : public CChainParams class CMainParams : public CChainParams
@@ -130,26 +132,33 @@ public:
/** Height or Time Based Activations **/ /** Height or Time Based Activations **/
nLastPOWBlock = 100; 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; nZerocoinStartHeight = 0;
nZerocoinStartTime = 1643790201; nZerocoinStartTime = 1643790201;
nBlockEnforceSerialRange = 1; //Enforce serial range starting this block nBlockEnforceSerialRange = 1; // Enforce serial range starting this block
nBlockRecalculateAccumulators = 999999999; //Trigger a recalculation of accumulators nBlockRecalculateAccumulators = 999999999; // Trigger a recalculation of accumulators
nBlockFirstFraudulent = 999999999; //First block that bad serials emerged nBlockFirstFraudulent = 999999999; // First block that bad serials emerged
nBlockLastGoodCheckpoint = 999999999; //Last valid accumulator checkpoint nBlockLastGoodCheckpoint = 999999999; // Last valid accumulator checkpoint
nBlockEnforceInvalidUTXO = 999999999; //Start enforcing the invalid UTXO's nBlockEnforceInvalidUTXO = 999999999; // Start enforcing the invalid UTXO's
nInvalidAmountFiltered = 0; //Amount of invalid coins filtered through exchanges, that should be considered valid nInvalidAmountFiltered = 0; // Amount of invalid coins filtered through exchanges, that should be considered valid
nBlockZerocoinV2 = 999999999; nBlockZerocoinV2 = 999999999;
nBlockDoubleAccumulated = 999999999; nBlockDoubleAccumulated = 999999999;
nEnforceNewSporkKey = 1643790201; nEnforceNewSporkKey = 1643790201;
nRejectOldSporkKey = 1527811200; nRejectOldSporkKey = 1527811200;
// Public coin spend enforcement // Public coin spend enforcement
nPublicZCSpends = 1; nPublicZCSpends = 1;
// Fake Serial Attack // Fake Serial Attack
nFakeSerialBlockheightEnd = 0; 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 * Build the genesis block. Note that the output of the genesis coinbase cannot
@@ -165,7 +174,9 @@ public:
CMutableTransaction txNew; CMutableTransaction txNew;
txNew.vin.resize(1); txNew.vin.resize(1);
txNew.vout.resize(1); txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4)
<< vector<unsigned char>((const unsigned char*)pszTimestamp,
(const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = 50 * COIN; txNew.vout[0].nValue = 50 * COIN;
txNew.vout[0].scriptPubKey = CScript() << ParseHex("04fe3d7e5608ebba6d822948eff929c822ad35b5f8ecd00977d0e59ed67da697bd88e0ed8bd58797bde6fe6750236f5dae4cf403af0925c8339f0a91b682254b39") << OP_CHECKSIG; txNew.vout[0].scriptPubKey = CScript() << ParseHex("04fe3d7e5608ebba6d822948eff929c822ad35b5f8ecd00977d0e59ed67da697bd88e0ed8bd58797bde6fe6750236f5dae4cf403af0925c8339f0a91b682254b39") << OP_CHECKSIG;
genesis.vtx.push_back(txNew); genesis.vtx.push_back(txNew);
@@ -211,22 +222,22 @@ public:
/** Zerocoin */ /** Zerocoin */
zerocoinModulus = "25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784" zerocoinModulus = "25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784"
"4069182906412495150821892985591491761845028084891200728449926873928072877767359714183472702618963750149718246911" "4069182906412495150821892985591491761845028084891200728449926873928072877767359714183472702618963750149718246911"
"6507761337985909570009733045974880842840179742910064245869181719511874612151517265463228221686998754918242243363" "6507761337985909570009733045974880842840179742910064245869181719511874612151517265463228221686998754918242243363"
"7259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133" "7259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133"
"8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" "8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548"
"31438167899885040445364023527381951378636564391212010397122822120720357"; "31438167899885040445364023527381951378636564391212010397122822120720357";
nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each
nMaxZerocoinPublicSpendsPerTransaction = 637; // Assume about 220 bytes each input nMaxZerocoinPublicSpendsPerTransaction = 637; // Assume about 220 bytes each input
nMinZerocoinMintFee = 1 * CENT; //high fee required for zerocoin mints nMinZerocoinMintFee = 1 * CENT; // high fee required for zerocoin mints
nMintRequiredConfirmations = 20; //the maximum amount of confirmations until accumulated in 19 nMintRequiredConfirmations = 20; // the maximum amount of confirmations until accumulated in 19
nRequiredAccumulation = 1; nRequiredAccumulation = 1;
nDefaultSecurityLevel = 100; //full security level for accumulators nDefaultSecurityLevel = 100; // full security level for accumulators
nZerocoinHeaderVersion = 4; //Block headers must be this version once zerocoin is active nZerocoinHeaderVersion = 4; // Block headers must be this version once zerocoin is active
nZerocoinRequiredStakeDepth = 200; //The required confirmations for a zagr to be stakable nZerocoinRequiredStakeDepth = 200; // The required confirmations for a zagr to be stakable
nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee 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 nProposalEstablishmentTime = 60 * 60 * 24; // Proposals must be at least a day old to make it into a budget
} }
const Checkpoints::CCheckpointData& Checkpoints() const const Checkpoints::CCheckpointData& Checkpoints() const
@@ -258,22 +269,30 @@ public:
nMinerThreads = 0; nMinerThreads = 0;
nTargetTimespan = 10 * 60; nTargetTimespan = 10 * 60;
nTargetSpacing = 10 * 60; nTargetSpacing = 10 * 60;
nLastPOWBlock = 200; nLastPOWBlock = 200;
// Hybrid consensus: PoS staking permitted from block 2 in testnet as well.
nFirstPoSBlock = 2;
nMaturity = 15; nMaturity = 15;
nMasternodeCountDrift = 4; nMasternodeCountDrift = 4;
nModifierUpdateBlock = 0;
// Keep aligned with PoS activation in this chain.
nModifierUpdateBlock = 2;
nMaxMoneyOut = 43199500 * COIN; nMaxMoneyOut = 43199500 * COIN;
nZerocoinStartHeight = 0; nZerocoinStartHeight = 0;
nZerocoinStartTime = 1643790201; nZerocoinStartTime = 1643790201;
nBlockEnforceSerialRange = 1; //Enforce serial range starting this block nBlockEnforceSerialRange = 1; // Enforce serial range starting this block
nBlockRecalculateAccumulators = 999999999; //Trigger a recalculation of accumulators nBlockRecalculateAccumulators = 999999999; // Trigger a recalculation of accumulators
nBlockFirstFraudulent = 999999999; //First block that bad serials emerged nBlockFirstFraudulent = 999999999; // First block that bad serials emerged
nBlockLastGoodCheckpoint = 999999999; //Last valid accumulator checkpoint nBlockLastGoodCheckpoint = 999999999; // Last valid accumulator checkpoint
nBlockEnforceInvalidUTXO = 999999999; //Start enforcing the invalid UTXO's nBlockEnforceInvalidUTXO = 999999999; // Start enforcing the invalid UTXO's
nInvalidAmountFiltered = 0; //Amount of invalid coins filtered through exchanges, that should be considered valid nInvalidAmountFiltered = 0; // Amount of invalid coins filtered through exchanges, that should be considered valid
nBlockZerocoinV2 = 999999999; //!> The block that zerocoin v2 becomes active nBlockZerocoinV2 = 999999999; //!> The block that zerocoin v2 becomes active
nEnforceNewSporkKey = 1643790201; nEnforceNewSporkKey = 1643790201;
nRejectOldSporkKey = 1522454400; nRejectOldSporkKey = 1522454400;
// Public coin spend enforcement // Public coin spend enforcement
nPublicZCSpends = 1; nPublicZCSpends = 1;
@@ -292,12 +311,12 @@ public:
vFixedSeeds.clear(); vFixedSeeds.clear();
vSeeds.clear(); vSeeds.clear();
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 38); base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 38);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 39); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 39);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 166); base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 166);
base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x3a)(0x80)(0x61)(0xa0).convert_to_container<std::vector<unsigned char> >(); base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x3a)(0x80)(0x61)(0xa0).convert_to_container<std::vector<unsigned char> >();
base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x3a)(0x80)(0x58)(0x37).convert_to_container<std::vector<unsigned char> >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x3a)(0x80)(0x58)(0x37).convert_to_container<std::vector<unsigned char> >();
// Testnet agrarian BIP44 coin type is '1' (All coin's testnet default) // 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<std::vector<unsigned char> >(); base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container<std::vector<unsigned char> >();
@@ -322,6 +341,7 @@ public:
nProposalEstablishmentTime = 60 * 5; // Proposals must be at least 5 mns old to make it into a test budget nProposalEstablishmentTime = 60 * 5; // Proposals must be at least 5 mns old to make it into a test budget
} }
const Checkpoints::CCheckpointData& Checkpoints() const const Checkpoints::CCheckpointData& Checkpoints() const
{ {
return dataTestnet; return dataTestnet;
@@ -352,18 +372,26 @@ public:
nTargetTimespan = 24 * 60 * 60; // Agrarian: 1 day nTargetTimespan = 24 * 60 * 60; // Agrarian: 1 day
nTargetSpacing = 1 * 60; // Agrarian: 1 minutes nTargetSpacing = 1 * 60; // Agrarian: 1 minutes
bnProofOfWorkLimit = ~uint256(0) >> 1; bnProofOfWorkLimit = ~uint256(0) >> 1;
nLastPOWBlock = 250; nLastPOWBlock = 250;
// Hybrid consensus: PoS staking permitted from block 2 in regtest as well.
nFirstPoSBlock = 2;
nMaturity = 20; nMaturity = 20;
nMasternodeCountDrift = 4; 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; nMaxMoneyOut = 43199500 * COIN;
nZerocoinStartHeight = 300; nZerocoinStartHeight = 300;
nBlockZerocoinV2 = 300; nBlockZerocoinV2 = 300;
nZerocoinStartTime = 1643790201; nZerocoinStartTime = 1643790201;
nBlockEnforceSerialRange = 1; //Enforce serial range starting this block nBlockEnforceSerialRange = 1; // Enforce serial range starting this block
nBlockRecalculateAccumulators = 999999999; //Trigger a recalculation of accumulators nBlockRecalculateAccumulators = 999999999; // Trigger a recalculation of accumulators
nBlockFirstFraudulent = 999999999; //First block that bad serials emerged nBlockFirstFraudulent = 999999999; // First block that bad serials emerged
nBlockLastGoodCheckpoint = 999999999; //Last valid accumulator checkpoint nBlockLastGoodCheckpoint = 999999999; // Last valid accumulator checkpoint
// Public coin spend enforcement // Public coin spend enforcement
nPublicZCSpends = 350; nPublicZCSpends = 350;
@@ -390,6 +418,7 @@ public:
fSkipProofOfWorkCheck = true; fSkipProofOfWorkCheck = true;
fTestnetToBeDeprecatedFieldRPC = false; fTestnetToBeDeprecatedFieldRPC = false;
} }
const Checkpoints::CCheckpointData& Checkpoints() const const Checkpoints::CCheckpointData& Checkpoints() const
{ {
return dataRegtest; return dataRegtest;
@@ -434,7 +463,6 @@ public:
}; };
static CUnitTestParams unitTestParams; static CUnitTestParams unitTestParams;
static CChainParams* pCurrentParams = 0; static CChainParams* pCurrentParams = 0;
CModifiableParams* ModifiableParams() CModifiableParams* ModifiableParams()
+14 -4
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,6 +16,7 @@
#include "uint256.h" #include "uint256.h"
#include "libzerocoin/Params.h" #include "libzerocoin/Params.h"
#include <vector> #include <vector>
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
@@ -63,7 +65,7 @@ public:
/** Make miner wait to have peers to avoid wasting work */ /** Make miner wait to have peers to avoid wasting work */
bool MiningRequiresPeers() const { return fMiningRequiresPeers; } bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
/** Headers first syncing is disabled */ /** Headers first syncing is disabled */
bool HeadersFirstSyncingActive() const { return fHeadersFirstSyncingActive; }; bool HeadersFirstSyncingActive() const { return fHeadersFirstSyncingActive; }
/** Default value for -checkmempool and -checkblockindex argument */ /** Default value for -checkmempool and -checkblockindex argument */
bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
/** Allow mining of a min-difficulty block */ /** Allow mining of a min-difficulty block */
@@ -119,7 +121,13 @@ public:
/** Height or Time Based Activations **/ /** Height or Time Based Activations **/
int ModifierUpgradeBlock() const { return nModifierUpdateBlock; } 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 LAST_POW_BLOCK() const { return nLastPOWBlock; }
int Zerocoin_StartHeight() const { return nZerocoinStartHeight; } int Zerocoin_StartHeight() const { return nZerocoinStartHeight; }
int Zerocoin_Block_EnforceSerialRange() const { return nBlockEnforceSerialRange; } int Zerocoin_Block_EnforceSerialRange() const { return nBlockEnforceSerialRange; }
int Zerocoin_Block_RecalculateAccumulators() const { return nBlockRecalculateAccumulators; } int Zerocoin_Block_RecalculateAccumulators() const { return nBlockRecalculateAccumulators; }
@@ -134,7 +142,7 @@ public:
CAmount GetSupplyBeforeFakeSerial() const { return nSupplyBeforeFakeSerial; } CAmount GetSupplyBeforeFakeSerial() const { return nSupplyBeforeFakeSerial; }
int Zerocoin_Block_Double_Accumulated() const { return nBlockDoubleAccumulated; } 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; } int Zerocoin_Block_Public_Spend_Enabled() const { return nPublicZCSpends; }
@@ -154,7 +162,11 @@ protected:
int nToCheckBlockUpgradeMajority; int nToCheckBlockUpgradeMajority;
int64_t nTargetTimespan; int64_t nTargetTimespan;
int64_t nTargetSpacing; int64_t nTargetSpacing;
// Hybrid PoW/PoS window controls.
int nFirstPoSBlock;
int nLastPOWBlock; int nLastPOWBlock;
int nMasternodeCountDrift; int nMasternodeCountDrift;
int nMaturity; int nMaturity;
int nModifierUpdateBlock; int nModifierUpdateBlock;
@@ -216,7 +228,6 @@ protected:
* to test specific features more easily. Test cases should always restore the previous * to test specific features more easily. Test cases should always restore the previous
* values after finalization. * values after finalization.
*/ */
class CModifiableParams class CModifiableParams
{ {
public: public:
@@ -230,7 +241,6 @@ public:
virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck) = 0; virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck) = 0;
}; };
/** /**
* Return the currently selected parameters. This won't change after app startup * Return the currently selected parameters. This won't change after app startup
* outside of the unit tests. * outside of the unit tests.
+2 -4
View File
@@ -1,5 +1,6 @@
// Copyright (c) 2012-2013 The PPCoin developers // Copyright (c) 2012-2013 The PPCoin developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,9 +14,6 @@
#include "stakeinput.h" #include "stakeinput.h"
#include "utilmoneystr.h" #include "utilmoneystr.h"
#include "zagrchain.h" #include "zagrchain.h"
using namespace std;
bool fTestNet = false; // Params().NetworkID() == CBaseChainParams::TESTNET; bool fTestNet = false; // Params().NetworkID() == CBaseChainParams::TESTNET;
// Modifier interval: time to elapse before new modifier is computed // 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; uint256 bnCoinDayWeight = uint256(nValueIn) / 100;
// Check if proof-of-stake hash meets the target protocol // 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, bool CheckStake(const CDataStream& ssUniqueID, CAmount nValueIn, const uint64_t nStakeModifier, const uint256& bnTarget,
+7 -5
View File
@@ -1,13 +1,15 @@
// Copyright (c) 2012-2013 The PPCoin developers // Copyright (c) 2012-2013 The PPCoin developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef AGRARIAN_BITCOIN_KERNEL_H
#ifndef BITCOIN_KERNEL_H #define AGRARIAN_BITCOIN_KERNEL_H
#define BITCOIN_KERNEL_H
#include "main.h" #include "main.h"
#include "stakeinput.h" #include "stakeinput.h"
#include <cstdint>
#include <cstddef>
#include <cstdint>
// MODIFIER_INTERVAL: time to elapse before new modifier is computed // 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); bool ContextualCheckZerocoinStake(int nPreviousBlockHeight, CStakeInput* stake);
#endif // BITCOIN_KERNEL_H #endif // AGRARIAN_BITCOIN_KERNEL_H
+43 -22
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 The Agrarian developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -1986,23 +1987,41 @@ double ConvertBitsToDouble(unsigned int nBits)
return dDiff; 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 GetBlockValue(int nHeight)
{ {
int64_t nSubsidy = 0; return GetBlockValue(nHeight, false);
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;
} }
CAmount GetSeeSaw(const CAmount& blockValue, int nMasternodeCount, int nHeight) 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 //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; return true;
} }
if (pindex->nHeight <= Params().LAST_POW_BLOCK() && block.IsProofOfStake()) // Hybrid consensus:
return state.DoS(100, error("ConnectBlock() : PoS period not active"), // - PoS blocks are permitted starting at Params().FIRST_POS_BLOCK().
REJECT_INVALID, "PoS-early"); // - 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()) if (block.IsProofOfWork() && pindex->nHeight > Params().LAST_POW_BLOCK())
return state.DoS(100, error("ConnectBlock() : PoW period ended"), return state.DoS(100, error("ConnectBlock() : PoW period ended"),
REJECT_INVALID, "PoW-ended"); REJECT_INVALID, "PoW-ended");
bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate();
bool fScriptChecks = pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate();
// If scripts won't be checked anyways, don't bother seeing if CLTV is activated // If scripts won't be checked anyways, don't bother seeing if CLTV is activated
bool fCLTVHasMajority = false; 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); 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. //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()) if (block.IsProofOfWork())
nExpectedMint += nFees; nExpectedMint += nFees;
+37 -59
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,8 +21,6 @@
#include "pow.h" #include "pow.h"
#include "primitives/block.h" #include "primitives/block.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "zagr/zerocoin.h"
#include "zagr/zagrmodule.h"
#include "script/script.h" #include "script/script.h"
#include "script/sigcache.h" #include "script/sigcache.h"
#include "script/standard.h" #include "script/standard.h"
@@ -30,6 +29,8 @@
#include "txmempool.h" #include "txmempool.h"
#include "uint256.h" #include "uint256.h"
#include "undo.h" #include "undo.h"
#include "zagr/zerocoin.h"
#include "zagr/zagrmodule.h"
#include <algorithm> #include <algorithm>
#include <exception> #include <exception>
@@ -108,7 +109,7 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 3600;
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
/** Enable bloom filter */ /** Enable bloom filter */
static const bool DEFAULT_PEERBLOOMFILTERS = true; static const bool DEFAULT_PEERBLOOMFILTERS = true;
static const bool DEFAULT_PEERBLOOMFILTERS_ZC = false; 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. */ /** 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<uint256, int64_t> mapRejectedBlocks; extern std::map<uint256, int64_t> mapRejectedBlocks;
extern std::map<unsigned int, unsigned int> mapHashedBlocks; extern std::map<unsigned int, unsigned int> mapHashedBlocks;
extern std::map<uint256, int64_t> mapZerocoinspends; //txid, time received extern std::map<uint256, int64_t> mapZerocoinspends; // txid, time received
/** Best header we've seen so far (used for getheaders queries' starting points). */ /** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex* pindexBestHeader; 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); 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) */ /** Retrieve an output (from memory pool, or from disk, if possible) */
bool GetOutput(const uint256& hash, unsigned int index, CValidationState& state, CTxOut& out); 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); double ConvertBitsToDouble(unsigned int nBits);
int64_t GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCount, bool isZAGRStake); 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); unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock, bool fProofOfStake);
bool ActivateBestChain(CValidationState& state, CBlock* pblock = NULL, bool fAlreadyChecked = false); 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. */ /** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk(); void FlushStateToDisk();
/** (try to) add transaction to memory pool **/ /** (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); 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)); READWRITE(VARINT(nTxOffset));
} }
CDiskTxPos(const CDiskBlockPos& blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) CDiskTxPos(const CDiskBlockPos& blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) {}
{ CDiskTxPos() { SetNull(); }
}
CDiskTxPos()
{
SetNull();
}
void SetNull() void SetNull()
{ {
@@ -307,22 +306,9 @@ struct CDiskTxPos : public CDiskBlockPos {
} }
}; };
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
bool MoneyRange(CAmount nValueOut); 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 * Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending * @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); unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
/** /**
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) * 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 * 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); bool ReadFromDisk(const CDiskBlockPos& pos, const uint256& hashBlock);
}; };
/** /**
* Closure representing one script verification * Closure representing one script verification
* Note that this stores references to the spending transaction * Note that this stores references to the spending transaction
@@ -430,8 +414,15 @@ private:
public: public:
CScriptCheck() : ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} 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), CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn)
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) {} : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
ptxTo(&txToIn),
nIn(nInIn),
nFlags(nFlagsIn),
cacheStore(cacheIn),
error(SCRIPT_ERR_UNKNOWN_ERROR)
{
}
bool operator()(); bool operator()();
@@ -448,13 +439,11 @@ public:
ScriptError GetScriptError() const { return error; } ScriptError GetScriptError() const { return error; }
}; };
/** Functions for disk access for blocks */ /** Functions for disk access for blocks */
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
/** Functions for validating blocks and updating the block tree */ /** 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. /** 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); 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) */ /** 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 */ /** 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 AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** pindex, CDiskBlockPos* dbp = NULL, bool fAlreadyCheckedBlock = false);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex = NULL); bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex = NULL);
class CBlockFileInfo class CBlockFileInfo
{ {
public: public:
@@ -522,10 +510,7 @@ public:
nTimeLast = 0; nTimeLast = 0;
} }
CBlockFileInfo() CBlockFileInfo() { SetNull(); }
{
SetNull();
}
std::string ToString() const; std::string ToString() const;
@@ -560,6 +545,7 @@ private:
public: public:
CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {} 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) bool DoS(int level, bool ret = false, unsigned char chRejectCodeIn = 0, std::string strRejectReasonIn = "", bool corruptionIn = false)
{ {
chRejectCode = chRejectCodeIn; chRejectCode = chRejectCodeIn;
@@ -571,12 +557,12 @@ public:
mode = MODE_INVALID; mode = MODE_INVALID;
return ret; return ret;
} }
bool Invalid(bool ret = false,
unsigned char _chRejectCode = 0, bool Invalid(bool ret = false, unsigned char _chRejectCode = 0, std::string _strRejectReason = "")
std::string _strRejectReason = "")
{ {
return DoS(0, ret, _chRejectCode, _strRejectReason); return DoS(0, ret, _chRejectCode, _strRejectReason);
} }
bool Error(std::string strRejectReasonIn = "") bool Error(std::string strRejectReasonIn = "")
{ {
if (mode == MODE_VALID) if (mode == MODE_VALID)
@@ -584,23 +570,17 @@ public:
mode = MODE_ERROR; mode = MODE_ERROR;
return false; return false;
} }
bool Abort(const std::string& msg) bool Abort(const std::string& msg)
{ {
AbortNode(msg); AbortNode(msg);
return Error(msg); return Error(msg);
} }
bool IsValid() const
{ bool IsValid() const { return mode == MODE_VALID; }
return mode == MODE_VALID; bool IsInvalid() const { return mode == MODE_INVALID; }
} bool IsError() const { return mode == MODE_ERROR; }
bool IsInvalid() const
{
return mode == MODE_INVALID;
}
bool IsError() const
{
return mode == MODE_ERROR;
}
bool IsInvalid(int& nDoSOut) const bool IsInvalid(int& nDoSOut) const
{ {
if (IsInvalid()) { if (IsInvalid()) {
@@ -609,10 +589,8 @@ public:
} }
return false; return false;
} }
bool CorruptionPossible() const
{ bool CorruptionPossible() const { return corruptionPossible; }
return corruptionPossible;
}
unsigned char GetRejectCode() const { return chRejectCode; } unsigned char GetRejectCode() const { return chRejectCode; }
std::string GetRejectReason() const { return strRejectReason; } std::string GetRejectReason() const { return strRejectReason; }
}; };
+13 -1
View File
@@ -1,5 +1,6 @@
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -16,6 +17,17 @@
#include "util.h" #include "util.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <algorithm>
#include <cstdint>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
CBudgetManager budget; CBudgetManager budget;
CCriticalSection cs_budget; CCriticalSection cs_budget;
@@ -2159,7 +2171,7 @@ TrxValidationStatus CFinalizedBudget::IsTransactionValid(const CTransaction& txN
bool paid = false; 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", 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(), nCurrentBudgetPayment, vecBudgetPayments[nCurrentBudgetPayment].payee.ToString().c_str(), out.scriptPubKey.ToString().c_str(),
vecBudgetPayments[nCurrentBudgetPayment].nAmount, out.nValue); vecBudgetPayments[nCurrentBudgetPayment].nAmount, out.nValue);
+36 -33
View File
@@ -1,10 +1,11 @@
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef MASTERNODE_BUDGET_H #ifndef AGRARIAN_MASTERNODE_BUDGET_H
#define MASTERNODE_BUDGET_H #define AGRARIAN_MASTERNODE_BUDGET_H
#include "base58.h" #include "base58.h"
#include "init.h" #include "init.h"
@@ -14,9 +15,11 @@
#include "net.h" #include "net.h"
#include "sync.h" #include "sync.h"
#include "util.h" #include "util.h"
#include <cstdint>
using namespace std; #include <std::map>
#include <std::string>
#include <utility>
#include <std::vector>
extern CCriticalSection cs_budget; extern CCriticalSection cs_budget;
class CBudgetManager; 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_OLD = (50 * COIN);
static const CAmount BUDGET_FEE_TX = (5 * COIN); static const CAmount BUDGET_FEE_TX = (5 * COIN);
static const int64_t BUDGET_VOTE_UPDATE_MIN = 60 * 60; static const int64_t BUDGET_VOTE_UPDATE_MIN = 60 * 60;
static map<uint256, int> mapPayment_History; static std::map<uint256, int> mapPayment_History;
extern std::vector<CBudgetProposalBroadcast> vecImmatureBudgetProposals; extern std::vector<CBudgetProposalBroadcast> vecImmatureBudgetProposals;
extern std::vector<CFinalizedBudgetBroadcast> vecImmatureFinalizedBudgets; extern std::vector<CFinalizedBudgetBroadcast> vecImmatureFinalizedBudgets;
@@ -179,16 +182,16 @@ class CBudgetManager
{ {
private: private:
//hold txes until they mature enough to use //hold txes until they mature enough to use
// XX42 map<uint256, CTransaction> mapCollateral; // XX42 std::map<uint256, CTransaction> mapCollateral;
map<uint256, uint256> mapCollateralTxids; std::map<uint256, uint256> mapCollateralTxids;
public: public:
// critical section to protect the inner data structures // critical section to protect the inner data structures
mutable CCriticalSection cs; mutable CCriticalSection cs;
// keep track of the scanning errors I've seen // keep track of the scanning errors I've seen
map<uint256, CBudgetProposal> mapProposals; std::map<uint256, CBudgetProposal> mapProposals;
map<uint256, CFinalizedBudget> mapFinalizedBudgets; std::map<uint256, CFinalizedBudget> mapFinalizedBudgets;
std::map<uint256, CBudgetProposalBroadcast> mapSeenMasternodeBudgetProposals; std::map<uint256, CBudgetProposalBroadcast> mapSeenMasternodeBudgetProposals;
std::map<uint256, CBudgetVote> mapSeenMasternodeBudgetVotes; std::map<uint256, CBudgetVote> mapSeenMasternodeBudgetVotes;
@@ -321,7 +324,7 @@ public:
std::string strBudgetName; std::string strBudgetName;
int nBlockStart; int nBlockStart;
std::vector<CTxBudgetPayment> vecBudgetPayments; std::vector<CTxBudgetPayment> vecBudgetPayments;
map<uint256, CFinalizedBudgetVote> mapVotes; std::map<uint256, CFinalizedBudgetVote> mapVotes;
uint256 nFeeTXHash; uint256 nFeeTXHash;
int64_t nTime; int64_t nTime;
@@ -372,7 +375,7 @@ public:
void SubmitVote(); void SubmitVote();
//checks the hashes to make sure we know about them //checks the hashes to make sure we know about them
string GetStatus(); std::string GetStatus();
uint256 GetHash() uint256 GetHash()
{ {
@@ -413,24 +416,24 @@ public:
CFinalizedBudgetBroadcast(const CFinalizedBudget& other); CFinalizedBudgetBroadcast(const CFinalizedBudget& other);
CFinalizedBudgetBroadcast(std::string strBudgetNameIn, int nBlockStartIn, std::vector<CTxBudgetPayment> vecBudgetPaymentsIn, uint256 nFeeTXHashIn); CFinalizedBudgetBroadcast(std::string strBudgetNameIn, int nBlockStartIn, std::vector<CTxBudgetPayment> 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) // enable ADL (not necessary in our case, but good practice)
using std::swap; using std::swap;
// by swapping the members of two classes, // by swapping the members of two classes,
// the two classes are effectively swapped // the two classes are effectively swapped
swap(first.strBudgetName, second.strBudgetName); std::swap(first.strBudgetName, second.strBudgetName);
swap(first.nBlockStart, second.nBlockStart); std::swap(first.nBlockStart, second.nBlockStart);
first.mapVotes.swap(second.mapVotes); first.mapVotes.std::swap(second.mapVotes);
first.vecBudgetPayments.swap(second.vecBudgetPayments); first.vecBudgetPayments.std::swap(second.vecBudgetPayments);
swap(first.nFeeTXHash, second.nFeeTXHash); std::swap(first.nFeeTXHash, second.nFeeTXHash);
swap(first.nTime, second.nTime); std::swap(first.nTime, second.nTime);
} }
CFinalizedBudgetBroadcast& operator=(CFinalizedBudgetBroadcast from) CFinalizedBudgetBroadcast& operator=(CFinalizedBudgetBroadcast from)
{ {
swap(*this, from); std::swap(*this, from);
return *this; return *this;
} }
@@ -478,7 +481,7 @@ public:
int64_t nTime; int64_t nTime;
uint256 nFeeTXHash; uint256 nFeeTXHash;
map<uint256, CBudgetVote> mapVotes; std::map<uint256, CBudgetVote> mapVotes;
//cache object //cache object
CBudgetProposal(); CBudgetProposal();
@@ -559,27 +562,27 @@ public:
CBudgetProposalBroadcast(const CBudgetProposalBroadcast& other) : CBudgetProposal(other) {} CBudgetProposalBroadcast(const CBudgetProposalBroadcast& other) : CBudgetProposal(other) {}
CBudgetProposalBroadcast(std::string strProposalNameIn, std::string strURLIn, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int nBlockStartIn, uint256 nFeeTXHashIn); 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) // enable ADL (not necessary in our case, but good practice)
using std::swap; using std::swap;
// by swapping the members of two classes, // by swapping the members of two classes,
// the two classes are effectively swapped // the two classes are effectively swapped
swap(first.strProposalName, second.strProposalName); std::swap(first.strProposalName, second.strProposalName);
swap(first.nBlockStart, second.nBlockStart); std::swap(first.nBlockStart, second.nBlockStart);
swap(first.strURL, second.strURL); std::swap(first.strURL, second.strURL);
swap(first.nBlockEnd, second.nBlockEnd); std::swap(first.nBlockEnd, second.nBlockEnd);
swap(first.nAmount, second.nAmount); std::swap(first.nAmount, second.nAmount);
swap(first.address, second.address); std::swap(first.address, second.address);
swap(first.nTime, second.nTime); std::swap(first.nTime, second.nTime);
swap(first.nFeeTXHash, second.nFeeTXHash); std::swap(first.nFeeTXHash, second.nFeeTXHash);
first.mapVotes.swap(second.mapVotes); first.mapVotes.std::swap(second.mapVotes);
} }
CBudgetProposalBroadcast& operator=(CBudgetProposalBroadcast from) CBudgetProposalBroadcast& operator=(CBudgetProposalBroadcast from)
{ {
swap(*this, from); std::swap(*this, from);
return *this; return *this;
} }
@@ -604,4 +607,4 @@ public:
}; };
#endif #endif // AGRARIAN_MASTERNODE_BUDGET_H
+275 -197
View File
@@ -1,9 +1,11 @@
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "masternode-payments.h" #include "masternode-payments.h"
#include "addrman.h" #include "addrman.h"
#include "chainparams.h" #include "chainparams.h"
#include "masternode-budget.h" #include "masternode-budget.h"
@@ -14,8 +16,15 @@
#include "sync.h" #include "sync.h"
#include "util.h" #include "util.h"
#include "utilmoneystr.h" #include "utilmoneystr.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <algorithm>
#include <cstdio>
#include <limits>
#include <string>
#include <vector>
/** Object for who's going to get paid on which blocks */ /** Object for who's going to get paid on which blocks */
CMasternodePayments masternodePayments; CMasternodePayments masternodePayments;
@@ -23,6 +32,26 @@ CCriticalSection cs_vecPayments;
CCriticalSection cs_mapMasternodeBlocks; CCriticalSection cs_mapMasternodeBlocks;
CCriticalSection cs_mapMasternodePayeeVotes; 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 // CMasternodePaymentDB
// //
@@ -35,61 +64,81 @@ CMasternodePaymentDB::CMasternodePaymentDB()
bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave) 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 // serialize, checksum data up to that point, then append checksum
CDataStream ssObj(SER_DISK, CLIENT_VERSION); CDataStream ssObj(SER_DISK, CLIENT_VERSION);
ssObj << strMagicMessage; // masternode cache file specific magic message ssObj << strMagicMessage; // masternode cache file specific magic message
ssObj << FLATDATA(Params().MessageStart()); // network specific magic number ssObj << FLATDATA(Params().MessageStart()); // network specific magic number
ssObj << objToSave; ssObj << objToSave;
uint256 hash = Hash(ssObj.begin(), ssObj.end()); const uint256 hash = Hash(ssObj.begin(), ssObj.end());
ssObj << hash; ssObj << hash;
// open output file, and associate with CAutoFile // open output file, and associate with CAutoFile
FILE* file = fopen(pathDB.string().c_str(), "wb"); FILE* file = std::fopen(pathDB.string().c_str(), "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (file == nullptr) {
if (fileout.IsNull())
return error("%s : Failed to open file %s", __func__, pathDB.string()); 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 // Write and commit header, data
try { try {
fileout << ssObj; fileout << ssObj;
} catch (std::exception& e) { } catch (const std::exception& e) {
return error("%s : Serialize or I/O error - %s", __func__, e.what()); return error("%s : Serialize or I/O error - %s", __func__, e.what());
} }
fileout.fclose(); 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; return true;
} }
CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad, bool fDryRun) CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& objToLoad, bool fDryRun)
{ {
int64_t nStart = GetTimeMillis(); const int64_t nStart = GetTimeMillis();
// open input file, and associate with CAutoFile // 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); CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
if (filein.IsNull()) { if (filein.IsNull()) {
error("%s : Failed to open file %s", __func__, pathDB.string()); error("%s : Failed to open file %s", __func__, pathDB.string());
return FileError; return FileError;
} }
// use file size to size memory buffer int fileSize = 0;
int fileSize = boost::filesystem::file_size(pathDB); try {
int dataSize = fileSize - sizeof(uint256); fileSize = static_cast<int>(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<int>(sizeof(uint256));
// Don't try to resize to a negative number if file is small // Don't try to resize to a negative number if file is small
if (dataSize < 0) if (dataSize < 0) {
dataSize = 0; dataSize = 0;
vector<unsigned char> vchData; }
vchData.resize(dataSize);
std::vector<unsigned char> vchData;
vchData.resize(static_cast<size_t>(dataSize));
uint256 hashIn; uint256 hashIn;
// read data and checksum from file // read data and checksum from file
try { try {
filein.read((char*)&vchData[0], dataSize); if (dataSize > 0) {
filein.read(reinterpret_cast<char*>(&vchData[0]), dataSize);
}
filein >> hashIn; filein >> hashIn;
} catch (std::exception& e) { } catch (const std::exception& e) {
error("%s : Deserialize or I/O error - %s", __func__, e.what()); error("%s : Deserialize or I/O error - %s", __func__, e.what());
return HashReadError; return HashReadError;
} }
@@ -98,7 +147,7 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments&
CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION); CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
// verify stored checksum matches input data // verify stored checksum matches input data
uint256 hashTmp = Hash(ssObj.begin(), ssObj.end()); const uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
if (hashIn != hashTmp) { if (hashIn != hashTmp) {
error("%s : Checksum mismatch, data corrupted", __func__); error("%s : Checksum mismatch, data corrupted", __func__);
return IncorrectHash; return IncorrectHash;
@@ -112,35 +161,35 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments&
// ... verify the message matches predefined one // ... verify the message matches predefined one
if (strMagicMessage != strMagicMessageTmp) { if (strMagicMessage != strMagicMessageTmp) {
error("%s : Invalid masternode payement cache magic message", __func__); error("%s : Invalid masternode payment cache magic message", __func__);
return IncorrectMagicMessage; return IncorrectMagicMessage;
} }
// de-serialize file header (network specific magic number) and .. // de-serialize file header (network specific magic number) and ..
ssObj >> FLATDATA(pchMsgTmp); ssObj >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours // ... 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__); error("%s : Invalid network magic number", __func__);
return IncorrectMagicNumber; return IncorrectMagicNumber;
} }
// de-serialize data into CMasternodePayments object // de-serialize data into CMasternodePayments object
ssObj >> objToLoad; ssObj >> objToLoad;
} catch (std::exception& e) { } catch (const std::exception& e) {
objToLoad.Clear(); objToLoad.Clear();
error("%s : Deserialize or I/O error - %s", __func__, e.what()); error("%s : Deserialize or I/O error - %s", __func__, e.what());
return IncorrectFormat; return IncorrectFormat;
} }
LogPrint("masternode","Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart); LogPrint("masternode", "Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart);
LogPrint("masternode"," %s\n", objToLoad.ToString()); LogPrint("masternode", " %s\n", objToLoad.ToString());
if (!fDryRun) { if (!fDryRun) {
LogPrint("masternode","Masternode payments manager - cleaning....\n"); LogPrint("masternode", "Masternode payments manager - cleaning....\n");
objToLoad.CleanPaymentList(); objToLoad.CleanPaymentList();
LogPrint("masternode","Masternode payments manager - result:\n"); LogPrint("masternode", "Masternode payments manager - result:\n");
LogPrint("masternode"," %s\n", objToLoad.ToString()); LogPrint("masternode", " %s\n", objToLoad.ToString());
} }
return Ok; return Ok;
@@ -148,92 +197,89 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments&
void DumpMasternodePayments() void DumpMasternodePayments()
{ {
int64_t nStart = GetTimeMillis(); const int64_t nStart = GetTimeMillis();
CMasternodePaymentDB paymentdb; CMasternodePaymentDB paymentdb;
CMasternodePayments tempPayments; CMasternodePayments tempPayments;
LogPrint("masternode","Verifying mnpayments.dat format...\n"); LogPrint("masternode", "Verifying mnpayments.dat format...\n");
CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true); const CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true);
// there was an error and it was not an error on file opening => do not proceed // there was an error and it was not an error on file opening => do not proceed
if (readResult == CMasternodePaymentDB::FileError) if (readResult == CMasternodePaymentDB::FileError) {
LogPrint("masternode","Missing budgets file - mnpayments.dat, will try to recreate\n"); LogPrint("masternode", "Missing payments file - mnpayments.dat, will try to recreate\n");
else if (readResult != CMasternodePaymentDB::Ok) { } else if (readResult != CMasternodePaymentDB::Ok) {
LogPrint("masternode","Error reading mnpayments.dat: "); LogPrint("masternode", "Error reading mnpayments.dat: ");
if (readResult == CMasternodePaymentDB::IncorrectFormat) if (readResult == CMasternodePaymentDB::IncorrectFormat) {
LogPrint("masternode","magic is ok but data has invalid format, will try to recreate\n"); LogPrint("masternode", "magic is ok but data has invalid format, will try to recreate\n");
else { } else {
LogPrint("masternode","file format is unknown or invalid, please fix it manually\n"); LogPrint("masternode", "file format is unknown or invalid, please fix it manually\n");
return; return;
} }
} }
LogPrint("masternode","Writting info to mnpayments.dat...\n");
LogPrint("masternode", "Writing info to mnpayments.dat...\n");
paymentdb.Write(masternodePayments); 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) bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMinted)
{ {
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
if (pindexPrev == NULL) return true; if (pindexPrev == nullptr) {
return true;
}
int nHeight = 0; int nHeight = 0;
if (pindexPrev->GetBlockHash() == block.hashPrevBlock) { if (pindexPrev->GetBlockHash() == block.hashPrevBlock) {
nHeight = pindexPrev->nHeight + 1; nHeight = pindexPrev->nHeight + 1;
} else { //out of order } else { // out of order
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi != mapBlockIndex.end() && (*mi).second) if (mi != mapBlockIndex.end() && (*mi).second) {
nHeight = (*mi).second->nHeight + 1; nHeight = (*mi).second->nHeight + 1;
}
} }
if (nHeight == 0) { 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) { if (nHeight % Params().GetBudgetCycleBlocks() < 100) {
return true; 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) bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight)
{ {
TrxValidationStatus transactionStatus = TrxValidationStatus::InValid; 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"); LogPrint("mnpayments", "Client not synced, skipping block payee checks\n");
return true; 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 (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) {
if (budget.IsBudgetPaymentBlock(nBlockHeight)) { if (budget.IsBudgetPaymentBlock(nBlockHeight)) {
transactionStatus = budget.IsTransactionValid(txNew, nBlockHeight); transactionStatus = budget.IsTransactionValid(txNew, nBlockHeight);
@@ -242,39 +288,44 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight)
} }
if (transactionStatus == TrxValidationStatus::InValid) { if (transactionStatus == TrxValidationStatus::InValid) {
LogPrint("masternode","Invalid budget payment detected %s\n", txNew.ToString().c_str()); LogPrint("masternode", "Invalid budget payment detected %s\n", txNew.ToString().c_str());
if (IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) if (IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) {
return false; 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 // If we end here the transaction was either InValid and Budget enforcement is disabled, or
// a double budget payment (status = TrxValidationStatus::DoublePayment) was detected, or no/not enough masternode // a double budget payment (DoublePayment) was detected, or no/not enough masternode
// votes (status = TrxValidationStatus::VoteThreshold) for a finalized budget were found // votes (VoteThreshold) for a finalized budget were found.
// In all cases a masternode will get the payment for this block // In all cases a masternode will get the payment for this block.
//check for masternode payee // check for masternode payee
if (masternodePayments.IsTransactionValid(txNew, nBlockHeight)) if (masternodePayments.IsTransactionValid(txNew, nBlockHeight)) {
return true; 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; return false;
LogPrint("masternode","Masternode payment enforcement is disabled, accepting block\n"); }
LogPrint("masternode", "Masternode payment enforcement is disabled, accepting block\n");
return true; return true;
} }
void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStake, bool fZAGRStake) void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStake, bool fZAGRStake)
{ {
CBlockIndex* pindexPrev = chainActive.Tip(); 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); budget.FillBlockPayee(txNew, nFees, fProofOfStake);
} else { } else {
masternodePayments.FillBlockPayee(txNew, nFees, fProofOfStake, fZAGRStake); masternodePayments.FillBlockPayee(txNew, nFees, fProofOfStake, fZAGRStake);
@@ -285,49 +336,55 @@ std::string GetRequiredPaymentsString(int nBlockHeight)
{ {
if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)) { if (IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(nBlockHeight)) {
return budget.GetRequiredPaymentsString(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(); CBlockIndex* pindexPrev = chainActive.Tip();
if (!pindexPrev) return; if (!pindexPrev) {
return;
}
bool hasPayment = true; bool hasPayment = true;
CScript payee; CScript payee;
//spork // spork / schedule
if (!masternodePayments.GetBlockPayee(pindexPrev->nHeight + 1, payee)) { if (!masternodePayments.GetBlockPayee(pindexPrev->nHeight + 1, payee)) {
//no masternode detected // no masternode detected
CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1); CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
if (winningNode) { if (winningNode) {
payee = GetScriptForDestination(winningNode->pubKeyCollateralAddress.GetID()); payee = GetScriptForDestination(winningNode->pubKeyCollateralAddress.GetID());
} else { } else {
LogPrint("masternode","CreateNewBlock: Failed to detect masternode to pay\n"); LogPrint("masternode", "CreateNewBlock: Failed to detect masternode to pay\n");
hasPayment = false; hasPayment = false;
} }
} }
CAmount blockValue = GetBlockValue(pindexPrev->nHeight); const int payHeight = pindexPrev->nHeight + 1;
CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight, blockValue, 0, fZAGRStake); const CAmount blockValue = GetBlockValue(payHeight);
const CAmount masternodePayment = GetMasternodePayment(payHeight, blockValue, 0, fZAGRStake);
if (hasPayment) { if (hasPayment) {
if (fProofOfStake) { 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 * Stake reward can be split into many different outputs, so we must
* use vout.size() to align with several different cases. * 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.resize(i + 1);
txNew.vout[i].scriptPubKey = payee; txNew.vout[i].scriptPubKey = payee;
txNew.vout[i].nValue = masternodePayment; txNew.vout[i].nValue = masternodePayment;
//subtract mn payment from the stake reward // subtract mn payment from the stake reward
if (!txNew.vout[1].IsZerocoinMint()) // NOTE: original code used vout[1] and (i-1); keep behavior, but guard bounds.
txNew.vout[i - 1].nValue -= masternodePayment; if (i > 0) {
if (!txNew.vout[1].IsZerocoinMint() && (i - 1) < txNew.vout.size()) {
txNew.vout[i - 1].nValue -= masternodePayment;
}
}
} else { } else {
txNew.vout.resize(2); txNew.vout.resize(2);
txNew.vout[1].scriptPubKey = payee; txNew.vout[1].scriptPubKey = payee;
@@ -339,28 +396,28 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe
ExtractDestination(payee, address1); ExtractDestination(payee, address1);
CBitcoinAddress address2(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() int CMasternodePayments::GetMinMasternodePaymentsProto()
{ {
if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES)) if (IsSporkActive(SPORK_10_MASTERNODE_PAY_UPDATED_NODES))
return ActiveProtocol(); // Allow only updated peers 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 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) 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 (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 (strCommand == "mnget") { // Masternode Payments Request Sync
int nCountNeeded; int nCountNeeded;
vRecv >> nCountNeeded; vRecv >> nCountNeeded;
@@ -375,17 +432,23 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st
pfrom->FulfilledRequest("mnget"); pfrom->FulfilledRequest("mnget");
masternodePayments.Sync(pfrom, nCountNeeded); masternodePayments.Sync(pfrom, nCountNeeded);
LogPrint("mnpayments", "mnget - Sent Masternode winners to peer %i\n", pfrom->GetId()); LogPrint("mnpayments", "mnget - Sent Masternode winners to peer %i\n", pfrom->GetId());
} else if (strCommand == "mnw") { //Masternode Payments Declare Winner return;
//this is required in litemodef }
if (strCommand == "mnw") { // Masternode Payments Declare Winner
CMasternodePaymentWinner winner; CMasternodePaymentWinner winner;
vRecv >> winner; vRecv >> winner;
if (pfrom->nVersion < ActiveProtocol()) return; if (pfrom->nVersion < ActiveProtocol()) {
return;
}
int nHeight; int nHeight;
{ {
TRY_LOCK(cs_main, locked); TRY_LOCK(cs_main, locked);
if (!locked || chainActive.Tip() == NULL) return; if (!locked || chainActive.Tip() == nullptr) {
return;
}
nHeight = chainActive.Tip()->nHeight; nHeight = chainActive.Tip()->nHeight;
} }
@@ -395,20 +458,18 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st
return; return;
} }
int nFirstBlock = nHeight - (mnodeman.CountEnabled() * 1.25); const int nFirstBlock = nHeight - static_cast<int>(mnodeman.CountEnabled() * 1.25);
if (winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > nHeight + 20) { 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); LogPrint("mnpayments", "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, nHeight);
return; return;
} }
std::string strError = ""; std::string strError;
if (!winner.IsValid(pfrom, strError)) { if (!winner.IsValid(pfrom, strError)) {
// if(strError != "") LogPrint("masternode","mnw - invalid message - %s\n", strError);
return; return;
} }
if (!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) { if (!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) {
// LogPrint("masternode","mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort());
return; return;
} }
@@ -422,33 +483,28 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st
return; 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)) { if (masternodePayments.AddWinningMasternode(winner)) {
winner.Relay(); winner.Relay();
masternodeSync.AddedMasternodeWinner(winner.GetHash()); masternodeSync.AddedMasternodeWinner(winner.GetHash());
} }
return;
} }
} }
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
{ {
std::string errorMessage; 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)) { 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; return false;
} }
if (!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) { 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; return false;
} }
@@ -460,7 +516,6 @@ bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
if (mapMasternodeBlocks.count(nBlockHeight)) { if (mapMasternodeBlocks.count(nBlockHeight)) {
return mapMasternodeBlocks[nBlockHeight].GetPayee(payee); return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
} }
return false; return false;
} }
@@ -473,16 +528,19 @@ bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
int nHeight; int nHeight;
{ {
TRY_LOCK(cs_main, locked); TRY_LOCK(cs_main, locked);
if (!locked || chainActive.Tip() == NULL) return false; if (!locked || chainActive.Tip() == nullptr) {
return false;
}
nHeight = chainActive.Tip()->nHeight; nHeight = chainActive.Tip()->nHeight;
} }
CScript mnpayee; const CScript mnpayee = GetScriptForDestination(mn.pubKeyCollateralAddress.GetID());
mnpayee = GetScriptForDestination(mn.pubKeyCollateralAddress.GetID());
CScript payee; CScript payee;
for (int64_t h = nHeight; h <= nHeight + 8; h++) { for (int64_t h = nHeight; h <= nHeight + 8; h++) {
if (h == nNotBlockHeight) continue; if (h == nNotBlockHeight) {
continue;
}
if (mapMasternodeBlocks.count(h)) { if (mapMasternodeBlocks.count(h)) {
if (mapMasternodeBlocks[h].GetPayee(payee)) { if (mapMasternodeBlocks[h].GetPayee(payee)) {
if (mnpayee == payee) { if (mnpayee == payee) {
@@ -518,7 +576,6 @@ bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerI
} }
mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1); mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, 1);
return true; return true;
} }
@@ -529,50 +586,60 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
int nMaxSignatures = 0; int nMaxSignatures = 0;
int nMasternode_Drift_Count = 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)) { if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
// Get a stable number of masternodes by ignoring newly activated (< 8000 sec old) masternodes // Get a stable number of masternodes by ignoring newly activated (< 8000 sec old) masternodes
nMasternode_Drift_Count = mnodeman.stable_size() + Params().MasternodeCountDrift(); nMasternode_Drift_Count = mnodeman.stable_size() + Params().MasternodeCountDrift();
} } else {
else { // Account for the fact that all peers do not see the same masternode count.
//account for the fact that all peers do not see the same masternode count. A allowance of being off our masternode count is given // 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 // We only need to look at an increased masternode count because as count increases, the reward decreases.
//for mnPayment >= required, so it only makes sense to check the max node count allowed. // 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(); 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 // require at least 6 signatures
for (CMasternodePayee& payee : vecPayments) for (CMasternodePayee& payee : vecPayments) {
if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) {
nMaxSignatures = payee.nVotes; nMaxSignatures = payee.nVotes;
}
}
// if we don't have at least 6 signatures on a payee, approve whichever is the longest chain // 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 (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) {
return true;
}
for (CMasternodePayee& payee : vecPayments) { for (CMasternodePayee& payee : vecPayments) {
bool found = false; bool found = false;
for (CTxOut out : txNew.vout) {
for (const CTxOut& out : txNew.vout) {
if (payee.scriptPubKey == out.scriptPubKey) { if (payee.scriptPubKey == out.scriptPubKey) {
if(out.nValue >= requiredMasternodePayment) if (out.nValue >= requiredMasternodePayment) {
found = true; found = true;
else } else {
LogPrint("masternode","Masternode payment is out of drift range. Paid=%s Min=%s\n", FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); 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 (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) {
if (found) return true; if (found) {
return true;
}
CTxDestination address1; CTxDestination address1;
ExtractDestination(payee.scriptPubKey, address1); ExtractDestination(payee.scriptPubKey, address1);
CBitcoinAddress address2(address1); CBitcoinAddress address2(address1);
if (strPayeesPossible == "") { if (strPayeesPossible.empty()) {
strPayeesPossible += address2.ToString(); strPayeesPossible += address2.ToString();
} else { } else {
strPayeesPossible += "," + address2.ToString(); 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; return false;
} }
@@ -634,16 +702,18 @@ void CMasternodePayments::CleanPaymentList()
int nHeight; int nHeight;
{ {
TRY_LOCK(cs_main, locked); TRY_LOCK(cs_main, locked);
if (!locked || chainActive.Tip() == NULL) return; if (!locked || chainActive.Tip() == nullptr) {
return;
}
nHeight = chainActive.Tip()->nHeight; nHeight = chainActive.Tip()->nHeight;
} }
//keep up to five cycles for historical sake // keep up to five cycles for historical sake
int nLimit = std::max(int(mnodeman.size() * 1.25), 1000); const int nLimit = std::max(static_cast<int>(mnodeman.size() * 1.25), 1000);
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin(); std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while (it != mapMasternodePayeeVotes.end()) { while (it != mapMasternodePayeeVotes.end()) {
CMasternodePaymentWinner winner = (*it).second; const CMasternodePaymentWinner& winner = (*it).second;
if (nHeight - winner.nBlockHeight > nLimit) { if (nHeight - winner.nBlockHeight > nLimit) {
LogPrint("mnpayments", "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight); 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) { if (!pmn) {
strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.hash.ToString()); 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); mnodeman.AskForMN(pnode, vinMasternode);
return false; return false;
} }
if (pmn->protocolVersion < ActiveProtocol()) { if (pmn->protocolVersion < ActiveProtocol()) {
strError = strprintf("Masternode protocol too old %d - req %d", 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; return false;
} }
int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100, ActiveProtocol()); const int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight - 100, ActiveProtocol());
if (n > MNPAYMENTS_SIGNATURES_TOTAL) { if (n > MNPAYMENTS_SIGNATURES_TOTAL) {
//It's common to have masternodes mistakenly think they are in the top 10 // 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 // We don't want to print all of these messages, or punish them unless they're way off.
if (n > MNPAYMENTS_SIGNATURES_TOTAL * 2) { if (n > MNPAYMENTS_SIGNATURES_TOTAL * 2) {
strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL * 2, n); strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL * 2, n);
LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); LogPrint("masternode", "CMasternodePaymentWinner::IsValid - %s\n", strError);
//if (masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20); // if (masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20);
} }
return false; return false;
} }
@@ -691,11 +761,12 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError)
bool CMasternodePayments::ProcessBlock(int nBlockHeight) bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{ {
if (!fMasterNode) return false; if (!fMasterNode) {
return false;
}
//reference node - hybrid mode // reference node - hybrid mode
const int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight - 100, ActiveProtocol());
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight - 100, ActiveProtocol());
if (n == -1) { if (n == -1) {
LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n"); LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n");
@@ -707,34 +778,38 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
return false; return false;
} }
if (nBlockHeight <= nLastBlockHeight) return false; if (nBlockHeight <= nLastBlockHeight) {
return false;
}
CMasternodePaymentWinner newWinner(activeMasternode.vin); CMasternodePaymentWinner newWinner(activeMasternode.vin);
if (budget.IsBudgetPaymentBlock(nBlockHeight)) { if (budget.IsBudgetPaymentBlock(nBlockHeight)) {
//is budget payment block -- handled by the budgeting software // budget payment block -- handled by the budgeting software
} else { } 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 // 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; int nCount = 0;
CMasternode* pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount); CMasternode* pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount);
if (pmn != NULL) { if (pmn != nullptr) {
LogPrint("masternode","CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n"); LogPrint("masternode", "CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n");
newWinner.nBlockHeight = nBlockHeight; newWinner.nBlockHeight = nBlockHeight;
CScript payee = GetScriptForDestination(pmn->pubKeyCollateralAddress.GetID()); const CScript payee = GetScriptForDestination(pmn->pubKeyCollateralAddress.GetID());
newWinner.AddPayee(payee); newWinner.AddPayee(payee);
CTxDestination address1; CTxDestination address1;
ExtractDestination(payee, address1); ExtractDestination(payee, address1);
CBitcoinAddress address2(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 { } 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; CKey keyMasternode;
if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { 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; return false;
} }
LogPrint("masternode","CMasternodePayments::ProcessBlock() - Signing Winner\n"); LogPrint("masternode", "CMasternodePayments::ProcessBlock() - Signing Winner\n");
if (newWinner.Sign(keyMasternode, pubKeyMasternode)) { if (newWinner.Sign(keyMasternode, pubKeyMasternode)) {
LogPrint("masternode","CMasternodePayments::ProcessBlock() - AddWinningMasternode\n"); LogPrint("masternode", "CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
if (AddWinningMasternode(newWinner)) { if (AddWinningMasternode(newWinner)) {
newWinner.Relay(); newWinner.Relay();
@@ -771,12 +846,14 @@ bool CMasternodePaymentWinner::SignatureValid()
{ {
CMasternode* pmn = mnodeman.Find(vinMasternode); CMasternode* pmn = mnodeman.Find(vinMasternode);
if (pmn != NULL) { if (pmn != nullptr) {
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();
std::string errorMessage = ""; std::string errorMessage;
if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, 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; return true;
@@ -792,36 +869,38 @@ void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
int nHeight; int nHeight;
{ {
TRY_LOCK(cs_main, locked); TRY_LOCK(cs_main, locked);
if (!locked || chainActive.Tip() == NULL) return; if (!locked || chainActive.Tip() == nullptr) {
return;
}
nHeight = chainActive.Tip()->nHeight; nHeight = chainActive.Tip()->nHeight;
} }
int nCount = (mnodeman.CountEnabled() * 1.25); int nCount = static_cast<int>(mnodeman.CountEnabled() * 1.25);
if (nCountNeeded > nCount) nCountNeeded = nCount; if (nCountNeeded > nCount) {
nCountNeeded = nCount;
}
int nInvCount = 0; int nInvCount = 0;
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin(); std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while (it != mapMasternodePayeeVotes.end()) { while (it != mapMasternodePayeeVotes.end()) {
CMasternodePaymentWinner winner = (*it).second; const CMasternodePaymentWinner& winner = (*it).second;
if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) { if (winner.nBlockHeight >= nHeight - nCountNeeded && winner.nBlockHeight <= nHeight + 20) {
node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash())); node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash()));
nInvCount++; nInvCount++;
} }
++it; ++it;
} }
node->PushMessage("ssc", MASTERNODE_SYNC_MNW, nInvCount); node->PushMessage("ssc", MASTERNODE_SYNC_MNW, nInvCount);
} }
std::string CMasternodePayments::ToString() const std::string CMasternodePayments::ToString() const
{ {
std::ostringstream info; std::ostringstream info;
info << "Votes: " << (int)mapMasternodePayeeVotes.size() << ", Blocks: " << (int)mapMasternodeBlocks.size(); info << "Votes: " << (int)mapMasternodePayeeVotes.size() << ", Blocks: " << (int)mapMasternodeBlocks.size();
return info.str(); return info.str();
} }
int CMasternodePayments::GetOldestBlock() int CMasternodePayments::GetOldestBlock()
{ {
LOCK(cs_mapMasternodeBlocks); LOCK(cs_mapMasternodeBlocks);
@@ -833,13 +912,12 @@ int CMasternodePayments::GetOldestBlock()
if ((*it).first < nOldestBlock) { if ((*it).first < nOldestBlock) {
nOldestBlock = (*it).first; nOldestBlock = (*it).first;
} }
it++; ++it;
} }
return nOldestBlock; return nOldestBlock;
} }
int CMasternodePayments::GetNewestBlock() int CMasternodePayments::GetNewestBlock()
{ {
LOCK(cs_mapMasternodeBlocks); LOCK(cs_mapMasternodeBlocks);
@@ -851,7 +929,7 @@ int CMasternodePayments::GetNewestBlock()
if ((*it).first > nNewestBlock) { if ((*it).first > nNewestBlock) {
nNewestBlock = (*it).first; nNewestBlock = (*it).first;
} }
it++; ++it;
} }
return nNewestBlock; return nNewestBlock;
+34 -67
View File
@@ -1,16 +1,19 @@
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef MASTERNODE_PAYMENTS_H #ifndef AGRARIAN_MASTERNODE_PAYMENTS_H
#define MASTERNODE_PAYMENTS_H #define AGRARIAN_MASTERNODE_PAYMENTS_H
#include "key.h" #include "key.h"
#include "main.h" #include "main.h"
#include "masternode.h" #include "masternode.h"
using namespace std; #include <map>
#include <string>
#include <vector>
extern CCriticalSection cs_vecPayments; extern CCriticalSection cs_vecPayments;
extern CCriticalSection cs_mapMasternodeBlocks; extern CCriticalSection cs_mapMasternodeBlocks;
@@ -33,8 +36,7 @@ void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStak
void DumpMasternodePayments(); void DumpMasternodePayments();
/** Save Masternode Payment Data (mnpayments.dat) /** Save Masternode Payment Data (mnpayments.dat) */
*/
class CMasternodePaymentDB class CMasternodePaymentDB
{ {
private: private:
@@ -63,17 +65,8 @@ public:
CScript scriptPubKey; CScript scriptPubKey;
int nVotes; int nVotes;
CMasternodePayee() CMasternodePayee() : scriptPubKey(CScript()), nVotes(0) {}
{ CMasternodePayee(const CScript& payee, int nVotesIn) : scriptPubKey(payee), nVotes(nVotesIn) {}
scriptPubKey = CScript();
nVotes = 0;
}
CMasternodePayee(CScript payee, int nVotesIn)
{
scriptPubKey = payee;
nVotes = nVotesIn;
}
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@@ -92,18 +85,10 @@ public:
int nBlockHeight; int nBlockHeight;
std::vector<CMasternodePayee> vecPayments; std::vector<CMasternodePayee> vecPayments;
CMasternodeBlockPayees() CMasternodeBlockPayees() : nBlockHeight(0), vecPayments() {}
{ explicit CMasternodeBlockPayees(int nBlockHeightIn) : nBlockHeight(nBlockHeightIn), vecPayments() {}
nBlockHeight = 0;
vecPayments.clear();
}
CMasternodeBlockPayees(int nBlockHeightIn)
{
nBlockHeight = nBlockHeightIn;
vecPayments.clear();
}
void AddPayee(CScript payeeIn, int nIncrement) void AddPayee(const CScript& payeeIn, int nIncrement)
{ {
LOCK(cs_vecPayments); LOCK(cs_vecPayments);
@@ -114,8 +99,7 @@ public:
} }
} }
CMasternodePayee c(payeeIn, nIncrement); vecPayments.emplace_back(payeeIn, nIncrement);
vecPayments.push_back(c);
} }
bool GetPayee(CScript& payee) bool GetPayee(CScript& payee)
@@ -133,12 +117,14 @@ public:
return (nVotes > -1); return (nVotes > -1);
} }
bool HasPayeeWithVotes(CScript payee, int nVotesReq) bool HasPayeeWithVotes(const CScript& payee, int nVotesReq)
{ {
LOCK(cs_vecPayments); LOCK(cs_vecPayments);
for (CMasternodePayee& p : 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; return false;
@@ -157,29 +143,17 @@ public:
} }
}; };
// for storing the winning payments // For storing the winning payments
class CMasternodePaymentWinner class CMasternodePaymentWinner
{ {
public: public:
CTxIn vinMasternode; CTxIn vinMasternode;
int nBlockHeight; int nBlockHeight;
CScript payee; CScript payee;
std::vector<unsigned char> vchSig; std::vector<unsigned char> vchSig;
CMasternodePaymentWinner() CMasternodePaymentWinner() : vinMasternode(CTxIn()), nBlockHeight(0), payee(CScript()), vchSig() {}
{ explicit CMasternodePaymentWinner(const CTxIn& vinIn) : vinMasternode(vinIn), nBlockHeight(0), payee(CScript()), vchSig() {}
nBlockHeight = 0;
vinMasternode = CTxIn();
payee = CScript();
}
CMasternodePaymentWinner(CTxIn vinIn)
{
nBlockHeight = 0;
vinMasternode = vinIn;
payee = CScript();
}
uint256 GetHash() uint256 GetHash()
{ {
@@ -187,7 +161,6 @@ public:
ss << payee; ss << payee;
ss << nBlockHeight; ss << nBlockHeight;
ss << vinMasternode.prevout; ss << vinMasternode.prevout;
return ss.GetHash(); return ss.GetHash();
} }
@@ -196,11 +169,7 @@ public:
bool SignatureValid(); bool SignatureValid();
void Relay(); void Relay();
void AddPayee(CScript payeeIn) void AddPayee(const CScript& payeeIn) { payee = payeeIn; }
{
payee = payeeIn;
}
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@@ -215,7 +184,7 @@ public:
std::string ToString() std::string ToString()
{ {
std::string ret = ""; std::string ret;
ret += vinMasternode.ToString(); ret += vinMasternode.ToString();
ret += ", " + std::to_string(nBlockHeight); ret += ", " + std::to_string(nBlockHeight);
ret += ", " + payee.ToString(); ret += ", " + payee.ToString();
@@ -228,7 +197,6 @@ public:
// Masternode Payments Class // Masternode Payments Class
// Keeps track of who should get paid for which blocks // Keeps track of who should get paid for which blocks
// //
class CMasternodePayments class CMasternodePayments
{ {
private: private:
@@ -238,13 +206,12 @@ private:
public: public:
std::map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes; std::map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks; std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks;
std::map<uint256, int> mapMasternodesLastVote; //prevout.hash + prevout.n, nBlockHeight
CMasternodePayments() // NOTE: This legacy keying scheme (outpoint.hash + outpoint.n) can theoretically collide.
{ // Changing it requires a coordinated refactor of both header and implementation.
nSyncedFromPeer = 0; std::map<uint256, int> mapMasternodesLastVote; // prevout.hash + prevout.n, nBlockHeight
nLastBlockHeight = 0;
} CMasternodePayments() : nSyncedFromPeer(0), nLastBlockHeight(0) {}
void Clear() void Clear()
{ {
@@ -264,18 +231,19 @@ public:
bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight); bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight);
bool IsScheduled(CMasternode& mn, int nNotBlockHeight); bool IsScheduled(CMasternode& mn, int nNotBlockHeight);
bool CanVote(COutPoint outMasternode, int nBlockHeight) bool CanVote(const COutPoint& outMasternode, int nBlockHeight)
{ {
LOCK(cs_mapMasternodePayeeVotes); LOCK(cs_mapMasternodePayeeVotes);
if (mapMasternodesLastVote.count(outMasternode.hash + outMasternode.n)) { const uint256 key = outMasternode.hash + outMasternode.n;
if (mapMasternodesLastVote[outMasternode.hash + outMasternode.n] == nBlockHeight) { if (mapMasternodesLastVote.count(key)) {
if (mapMasternodesLastVote[key] == nBlockHeight) {
return false; return false;
} }
} }
//record this masternode voted // record this masternode voted
mapMasternodesLastVote[outMasternode.hash + outMasternode.n] = nBlockHeight; mapMasternodesLastVote[key] = nBlockHeight;
return true; return true;
} }
@@ -297,5 +265,4 @@ public:
} }
}; };
#endif // AGRARIAN_MASTERNODE_PAYMENTS_H
#endif
+16 -18
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -32,9 +33,6 @@
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp> #include <boost/tuple/tuple.hpp>
using namespace std;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// AgrarianMiner // AgrarianMiner
@@ -105,7 +103,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet,
// Create new block // Create new block
unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
if (!pblocktemplate.get()) if (!pblocktemplate.get())
return NULL; return nullptr;
CBlock* pblock = &pblocktemplate->block; // pointer for convenience CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Tip // Tip
@@ -166,7 +164,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet,
if (!fStakeFound) { if (!fStakeFound) {
LogPrint("staking", "CreateNewBlock(): stake not found\n"); LogPrint("staking", "CreateNewBlock(): stake not found\n");
return NULL; return nullptr;
} }
} }
@@ -214,7 +212,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet,
continue; continue;
} }
COrphan* porphan = NULL; COrphan* porphan = nullptr;
double dPriority = 0; double dPriority = 0;
CAmount nTotalIn = 0; CAmount nTotalIn = 0;
bool fMissingInputs = false; bool fMissingInputs = false;
@@ -243,7 +241,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet,
double nTimePriority = std::pow(GetAdjustedTime() - nTimeSeen, 6); double nTimePriority = std::pow(GetAdjustedTime() - nTimeSeen, 6);
// zAGR spends can have very large priority, use non-overflowing safe functions // 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); dPriority = double_safe_multiplication(dPriority, nTotalIn);
continue; continue;
@@ -291,12 +289,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet,
int nConf = nHeight - coins->nHeight; int nConf = nHeight - coins->nHeight;
// zAGR spends can have very large priority, use non-overflowing safe functions // 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; 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); unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
dPriority = tx.ComputePriority(dPriority, nTxSize); dPriority = tx.ComputePriority(dPriority, nTxSize);
@@ -521,17 +519,17 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet,
CKey key; CKey key;
if (!pwallet->GetZerocoinKey(bnSerial, key)) { if (!pwallet->GetZerocoinKey(bnSerial, key)) {
LogPrintf("%s: failed to find zAGR with serial %s, unable to sign block\n", __func__, bnSerial.GetHex()); 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 //Sign block with the zAGR key
if (!SignBlockWithKey(*pblock, key)) { if (!SignBlockWithKey(*pblock, key)) {
LogPrintf("BitcoinMiner(): Signing new block with zAGR key failed \n"); LogPrintf("BitcoinMiner(): Signing new block with zAGR key failed \n");
return NULL; return nullptr;
} }
} else if (!SignBlock(*pblock, *pwallet)) { } else if (!SignBlock(*pblock, *pwallet)) {
LogPrintf("BitcoinMiner(): Signing new block with UTXO key failed \n"); 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)) { if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) {
//LogPrintf("CreateNewBlock() : TestBlockValidity failed\n"); //LogPrintf("CreateNewBlock() : TestBlockValidity failed\n");
mempool.clear(); mempool.clear();
return NULL; return nullptr;
} }
// if (pblock->IsZerocoinStake()) { // if (pblock->IsZerocoinStake()) {
@@ -581,7 +579,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, CWallet* pwallet,
{ {
CPubKey pubkey; CPubKey pubkey;
if (!reservekey.GetReservedKey(pubkey)) if (!reservekey.GetReservedKey(pubkey))
return NULL; return nullptr;
CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
return CreateNewBlock(scriptPubKey, pwallet, fProofOfStake); 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 // Process this block the same as if we had received it from another node
CValidationState state; CValidationState state;
if (!ProcessNewBlock(state, NULL, pblock)) { if (!ProcessNewBlock(state, nullptr, pblock)) {
if (pblock->IsZerocoinStake()) { if (pblock->IsZerocoinStake()) {
pwalletMain->zagrTracker->RemovePending(pblock->vtx[1].GetHash()); pwalletMain->zagrTracker->RemovePending(pblock->vtx[1].GetHash());
pwalletMain->zagrTracker->ListMints(true, true, true); //update the state 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) void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
{ {
static boost::thread_group* minerThreads = NULL; static boost::thread_group* minerThreads = nullptr;
fGenerateBitcoins = fGenerate; fGenerateBitcoins = fGenerate;
if (nThreads < 0) { if (nThreads < 0) {
@@ -842,10 +840,10 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
nThreads = boost::thread::hardware_concurrency(); nThreads = boost::thread::hardware_concurrency();
} }
if (minerThreads != NULL) { if (minerThreads != nullptr) {
minerThreads->interrupt_all(); minerThreads->interrupt_all();
delete minerThreads; delete minerThreads;
minerThreads = NULL; minerThreads = nullptr;
} }
if (nThreads == 0 || !fGenerate) if (nThreads == 0 || !fGenerate)
+9 -7
View File
@@ -1,14 +1,16 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2016-2018 The PIVX developers // Copyright (c) 2016-2018 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef AGRARIAN_BITCOIN_MINER_H
#ifndef BITCOIN_MINER_H #define AGRARIAN_BITCOIN_MINER_H
#define BITCOIN_MINER_H #include <cstdint>
#include <std::string>
#include <stdint.h> #include <std::vector>
#include <memory>
#include <utility>
class CBlock; class CBlock;
class CBlockHeader; class CBlockHeader;
class CBlockIndex; class CBlockIndex;
@@ -33,4 +35,4 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake);
extern double dHashesPerSec; extern double dHashesPerSec;
extern int64_t nHPSTimerStart; extern int64_t nHPSTimerStart;
#endif // BITCOIN_MINER_H #endif // AGRARIAN_BITCOIN_MINER_H
+5 -4
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2018 The PIVX developers // Copyright (c) 2015-2018 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // 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 PastDifficultyAverage;
uint256 PastDifficultyAveragePrev; uint256 PastDifficultyAveragePrev;
if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { if (BlockLastSolved == nullptr || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) {
return Params().ProofOfWorkLimit().GetCompact(); return Params().ProofOfWorkLimit().GetCompact();
} }
@@ -74,7 +75,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
if (CountBlocks == 1) { if (CountBlocks == 1) {
PastDifficultyAverage.SetCompact(BlockReading->nBits); PastDifficultyAverage.SetCompact(BlockReading->nBits);
} else { } else {
PastDifficultyAverage = ((PastDifficultyAveragePrev * CountBlocks) + (uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1); PastDifficultyAverage = ((PastDifficultyAveragePrev* CountBlocks) + (uint256().SetCompact(BlockReading->nBits))) / (CountBlocks + 1);
} }
PastDifficultyAveragePrev = PastDifficultyAverage; PastDifficultyAveragePrev = PastDifficultyAverage;
} }
@@ -85,7 +86,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
} }
LastBlockTime = BlockReading->GetBlockTime(); LastBlockTime = BlockReading->GetBlockTime();
if (BlockReading->pprev == NULL) { if (BlockReading->pprev == nullptr) {
assert(BlockReading); assert(BlockReading);
break; break;
} }
@@ -94,7 +95,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
uint256 bnNew(PastDifficultyAverage); uint256 bnNew(PastDifficultyAverage);
int64_t _nTargetTimespan = CountBlocks * Params().TargetSpacing(); int64_t _nTargetTimespan = CountBlocks* Params().TargetSpacing();
if (nActualTimespan < _nTargetTimespan / 3) if (nActualTimespan < _nTargetTimespan / 3)
nActualTimespan = _nTargetTimespan / 3; nActualTimespan = _nTargetTimespan / 3;
+6 -7
View File
@@ -2,14 +2,13 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2017-2018 The PIVX developers // Copyright (c) 2017-2018 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef AGRARIAN_BITCOIN_POW_H
#ifndef BITCOIN_POW_H #define AGRARIAN_BITCOIN_POW_H
#define BITCOIN_POW_H #include <cstdint>
#include <cstddef>
#include <stdint.h>
class CBlockHeader; class CBlockHeader;
class CBlockIndex; class CBlockIndex;
class uint256; class uint256;
@@ -29,4 +28,4 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
bool CheckProofOfWork(uint256 hash, unsigned int nBits); bool CheckProofOfWork(uint256 hash, unsigned int nBits);
uint256 GetBlockProof(const CBlockIndex& block); uint256 GetBlockProof(const CBlockIndex& block);
#endif // BITCOIN_POW_H #endif // AGRARIAN_BITCOIN_POW_H
+10 -9
View File
@@ -2,6 +2,7 @@
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers // Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,7 +23,7 @@
#include "wallet/wallet.h" #include "wallet/wallet.h"
#endif #endif
#include <stdint.h> #include <cstdint>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
@@ -37,12 +38,12 @@ using namespace std;
*/ */
UniValue GetNetworkHashPS(int lookup, int height) UniValue GetNetworkHashPS(int lookup, int height)
{ {
CBlockIndex *pb = chainActive.Tip(); CBlockIndex*pb = chainActive.Tip();
if (height >= 0 && height < chainActive.Height()) if (height >= 0 && height < chainActive.Height())
pb = chainActive[height]; pb = chainActive[height];
if (pb == NULL || !pb->nHeight) if (pb == nullptr || !pb->nHeight)
return 0; return 0;
// If lookup is -1, then use blocks since last difficulty change. // If lookup is -1, then use blocks since last difficulty change.
@@ -158,7 +159,7 @@ UniValue generate(const UniValue& params, bool fHelp)
unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, fPoS)); unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, fPoS));
if (!pblocktemplate.get()) if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block; CBlock*pblock = &pblocktemplate->block;
if(!fPoS){ if(!fPoS){
{ {
@@ -172,7 +173,7 @@ UniValue generate(const UniValue& params, bool fHelp)
++pblock->nNonce; ++pblock->nNonce;
} }
CValidationState state; CValidationState state;
if (!ProcessNewBlock(state, NULL, pblock)) if (!ProcessNewBlock(state, nullptr, pblock))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight; ++nHeight;
fPoS = nHeight >= Params().LAST_POW_BLOCK(); fPoS = nHeight >= Params().LAST_POW_BLOCK();
@@ -201,7 +202,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
"\nTurn off generation\n" + HelpExampleCli("setgenerate", "false") + "\nTurn off generation\n" + HelpExampleCli("setgenerate", "false") +
"\nUsing json rpc\n" + HelpExampleRpc("setgenerate", "true, 1")); "\nUsing json rpc\n" + HelpExampleRpc("setgenerate", "true, 1"));
if (pwalletMain == NULL) if (pwalletMain == nullptr)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
if (Params().MineBlocksOnDemand()) if (Params().MineBlocksOnDemand())
@@ -515,7 +516,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (pindexPrev != chainActive.Tip() || if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) {
// Clear pindexPrev so future calls make a new block, despite any failures from here on // 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 // Store the chainActive.Tip() used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
@@ -525,7 +526,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
// Create new block // Create new block
if (pblocktemplate) { if (pblocktemplate) {
delete pblocktemplate; delete pblocktemplate;
pblocktemplate = NULL; pblocktemplate = nullptr;
} }
CScript scriptDummy = CScript() << OP_TRUE; CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate = CreateNewBlock(scriptDummy, pwalletMain, false); pblocktemplate = CreateNewBlock(scriptDummy, pwalletMain, false);
@@ -691,7 +692,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
CValidationState state; CValidationState state;
submitblock_StateCatcher sc(block.GetHash()); submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc); RegisterValidationInterface(&sc);
bool fAccepted = ProcessNewBlock(state, NULL, &block); bool fAccepted = ProcessNewBlock(state, nullptr, &block);
UnregisterValidationInterface(&sc); UnregisterValidationInterface(&sc);
if (fBlockPresent) { if (fBlockPresent) {
if (fAccepted && !sc.found) if (fAccepted && !sc.found)
+198 -146
View File
@@ -1,6 +1,7 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers // Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2016-2019 The PIVX developers // Copyright (c) 2016-2019 The PIVX developers
// Copyright (c) 2026 Agrarian Developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,45 +12,55 @@
#include "uint256.h" #include "uint256.h"
#include "zagr/accumulators.h" #include "zagr/accumulators.h"
#include <stdint.h> #include <cstdint>
#include <limits>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <boost/thread.hpp> #include <boost/thread.hpp>
using namespace std; namespace {
using namespace libzerocoin;
void static BatchWriteCoins(CLevelDBBatch& batch, const uint256& hash, const CCoins& coins) void BatchWriteCoins(CLevelDBBatch& batch, const uint256& hash, const CCoins& coins)
{ {
if (coins.IsPruned()) if (coins.IsPruned()) {
batch.Erase(make_pair('c', hash)); batch.Erase(std::make_pair('c', hash));
else } else {
batch.Write(make_pair('c', hash), coins); 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); 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 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 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 CCoinsViewDB::GetBestBlock() const
{ {
uint256 hashBestChain; uint256 hashBestChain;
if (!db.Read('B', hashBestChain)) if (!db.Read('B', hashBestChain)) {
return uint256(0); return uint256(0);
}
return hashBestChain; return hashBestChain;
} }
@@ -58,39 +69,47 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
CLevelDBBatch batch; CLevelDBBatch batch;
size_t count = 0; size_t count = 0;
size_t changed = 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) { if (it->second.flags & CCoinsCacheEntry::DIRTY) {
BatchWriteCoins(batch, it->first, it->second.coins); BatchWriteCoins(batch, it->first, it->second.coins);
changed++; ++changed;
} }
count++; ++count;
CCoinsMap::iterator itOld = it++;
auto itOld = it++;
mapCoins.erase(itOld); 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); 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) 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) 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) 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) bool CBlockTreeDB::WriteLastBlockFile(int nFile)
@@ -100,10 +119,10 @@ bool CBlockTreeDB::WriteLastBlockFile(int nFile)
bool CBlockTreeDB::WriteReindexing(bool fReindexing) bool CBlockTreeDB::WriteReindexing(bool fReindexing)
{ {
if (fReindexing) if (fReindexing) {
return Write('R', '1'); return Write('R', '1');
else }
return Erase('R'); return Erase('R');
} }
bool CBlockTreeDB::ReadReindexing(bool& fReindexing) bool CBlockTreeDB::ReadReindexing(bool& fReindexing)
@@ -119,53 +138,70 @@ bool CBlockTreeDB::ReadLastBlockFile(int& nFile)
bool CCoinsViewDB::GetStats(CCoinsStats& stats) const bool CCoinsViewDB::GetStats(CCoinsStats& stats) const
{ {
/* It seems that there are no "const iterators" for LevelDB. Since we // LevelDB iterators are non-const; we only read so const_cast the wrapper.
only need read operations on it, use a const-cast to get around std::unique_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
that restriction. */
boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
pcursor->SeekToFirst(); pcursor->SeekToFirst();
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = GetBestBlock(); stats.hashBlock = GetBestBlock();
ss << stats.hashBlock; ss << stats.hashBlock;
CAmount nTotalAmount = 0; CAmount nTotalAmount = 0;
while (pcursor->Valid()) { while (pcursor->Valid()) {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
try { try {
leveldb::Slice slKey = pcursor->key(); const leveldb::Slice slKey = pcursor->key();
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
char chType; char chType;
ssKey >> chType; ssKey >> chType;
if (chType == 'c') { 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); CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
CCoins coins; CCoins coins;
ssValue >> coins; ssValue >> coins;
uint256 txhash; uint256 txhash;
ssKey >> txhash; ssKey >> txhash;
ss << txhash; ss << txhash;
ss << VARINT(coins.nVersion); ss << VARINT(coins.nVersion);
ss << (coins.fCoinBase ? 'c' : 'n'); ss << (coins.fCoinBase ? 'c' : 'n');
ss << VARINT(coins.nHeight); 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]; const CTxOut& out = coins.vout[i];
if (!out.IsNull()) { if (!out.IsNull()) {
stats.nTransactionOutputs++; ++stats.nTransactionOutputs;
ss << VARINT(i + 1); ss << VARINT(i + 1);
ss << out; ss << out;
nTotalAmount += out.nValue; nTotalAmount += out.nValue;
} }
} }
stats.nSerializedSize += 32 + slValue.size(); stats.nSerializedSize += 32 + slValue.size();
ss << VARINT(0); ss << VARINT(0);
} }
pcursor->Next(); pcursor->Next();
} catch (std::exception& e) { } catch (const std::exception& e) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what()); 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.hashSerialized = ss.GetHash();
stats.nTotalAmount = nTotalAmount; stats.nTotalAmount = nTotalAmount;
return true; return true;
@@ -173,14 +209,15 @@ bool CCoinsViewDB::GetStats(CCoinsStats& stats) const
bool CBlockTreeDB::ReadTxIndex(const uint256& txid, CDiskTxPos& pos) 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<std::pair<uint256, CDiskTxPos> >& vect) bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos>>& vect)
{ {
CLevelDBBatch batch; CLevelDBBatch batch;
for (std::vector<std::pair<uint256, CDiskTxPos> >::const_iterator it = vect.begin(); it != vect.end(); it++) for (const auto& it : vect) {
batch.Write(make_pair('t', it->first), it->second); batch.Write(std::make_pair('t', it.first), it.second);
}
return WriteBatch(batch); 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) bool CBlockTreeDB::ReadFlag(const std::string& name, bool& fValue)
{ {
char ch; char ch;
if (!Read(std::make_pair('F', name), ch)) if (!Read(std::make_pair('F', name), ch)) {
return false; return false;
fValue = ch == '1'; }
fValue = (ch == '1');
return true; return true;
} }
@@ -210,76 +248,82 @@ bool CBlockTreeDB::ReadInt(const std::string& name, int& nValue)
bool CBlockTreeDB::LoadBlockIndexGuts() bool CBlockTreeDB::LoadBlockIndexGuts()
{ {
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator()); std::unique_ptr<leveldb::Iterator> pcursor(NewIterator());
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
ssKeySet << make_pair('b', uint256(0)); ssKeySet << std::make_pair('b', uint256(0));
pcursor->Seek(ssKeySet.str()); pcursor->Seek(ssKeySet.str());
// Load mapBlockIndex
uint256 nPreviousCheckpoint; uint256 nPreviousCheckpoint;
while (pcursor->Valid()) { while (pcursor->Valid()) {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
try { try {
leveldb::Slice slKey = pcursor->key(); const leveldb::Slice slKey = pcursor->key();
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
char chType; char chType;
ssKey >> 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 if (chType != 'b') {
CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); break; // finished loading block index
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
} }
} 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()); return error("%s : Deserialize or I/O error - %s", __func__, e.what());
} }
} }
@@ -287,18 +331,20 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
return true; 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<std::pair<libzerocoin::PublicCoin, uint256> >& mintInfo) bool CZerocoinDB::WriteCoinMintBatch(const std::vector<std::pair<libzerocoin::PublicCoin, uint256>>& mintInfo)
{ {
CLevelDBBatch batch; CLevelDBBatch batch;
size_t count = 0; size_t count = 0;
for (std::vector<std::pair<libzerocoin::PublicCoin, uint256> >::const_iterator it=mintInfo.begin(); it != mintInfo.end(); it++) {
PublicCoin pubCoin = it->first; for (const auto& it : mintInfo) {
uint256 hash = GetPubCoinHash(pubCoin.getValue()); const libzerocoin::PublicCoin& pubCoin = it.first;
batch.Write(make_pair('m', hash), it->second); const uint256 hash = GetPubCoinHash(pubCoin.getValue());
batch.Write(std::make_pair('m', hash), it.second);
++count; ++count;
} }
@@ -313,25 +359,26 @@ bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx)
bool CZerocoinDB::ReadCoinMint(const uint256& hashPubcoin, 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) bool CZerocoinDB::EraseCoinMint(const CBigNum& bnPubcoin)
{ {
uint256 hash = GetPubCoinHash(bnPubcoin); const uint256 hash = GetPubCoinHash(bnPubcoin);
return Erase(make_pair('m', hash)); return Erase(std::make_pair('m', hash));
} }
bool CZerocoinDB::WriteCoinSpendBatch(const std::vector<std::pair<libzerocoin::CoinSpend, uint256> >& spendInfo) bool CZerocoinDB::WriteCoinSpendBatch(const std::vector<std::pair<libzerocoin::CoinSpend, uint256>>& spendInfo)
{ {
CLevelDBBatch batch; CLevelDBBatch batch;
size_t count = 0; size_t count = 0;
for (std::vector<std::pair<libzerocoin::CoinSpend, uint256> >::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); CDataStream ss(SER_GETHASH, 0);
ss << bnSerial; ss << bnSerial;
uint256 hash = Hash(ss.begin(), ss.end()); const uint256 hash = Hash(ss.begin(), ss.end());
batch.Write(make_pair('s', hash), it->second); batch.Write(std::make_pair('s', hash), it.second);
++count; ++count;
} }
@@ -343,63 +390,68 @@ bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash)
{ {
CDataStream ss(SER_GETHASH, 0); CDataStream ss(SER_GETHASH, 0);
ss << bnSerial; ss << bnSerial;
uint256 hash = Hash(ss.begin(), ss.end()); const uint256 hash = Hash(ss.begin(), ss.end());
return Read(std::make_pair('s', hash), txHash);
return Read(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) bool CZerocoinDB::EraseCoinSpend(const CBigNum& bnSerial)
{ {
CDataStream ss(SER_GETHASH, 0); CDataStream ss(SER_GETHASH, 0);
ss << bnSerial; ss << bnSerial;
uint256 hash = Hash(ss.begin(), ss.end()); const uint256 hash = Hash(ss.begin(), ss.end());
return Erase(std::make_pair('s', hash));
return Erase(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); return error("%s: did not recognize type %s", __func__, strType);
}
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator()); std::unique_ptr<leveldb::Iterator> pcursor(NewIterator());
char type = (strType == "spends" ? 's' : 'm'); const char type = (strType == "spends" ? 's' : 'm');
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION); CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
ssKeySet << make_pair(type, uint256(0)); ssKeySet << std::make_pair(type, uint256(0));
pcursor->Seek(ssKeySet.str()); pcursor->Seek(ssKeySet.str());
// Load mapBlockIndex
std::set<uint256> setDelete; std::set<uint256> setDelete;
while (pcursor->Valid()) { while (pcursor->Valid()) {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
try { try {
leveldb::Slice slKey = pcursor->key(); const leveldb::Slice slKey = pcursor->key();
CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
char chType; char chType;
ssKey >> chType; ssKey >> chType;
if (chType == type) {
leveldb::Slice slValue = pcursor->value(); if (chType != type) {
CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); break; // finished
uint256 hash;
ssValue >> hash;
setDelete.insert(hash);
pcursor->Next();
} else {
break; // if shutdown requested or 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);
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()); return error("%s : Deserialize or I/O error - %s", __func__, e.what());
} }
} }
for (auto& hash : setDelete) { for (const auto& hash : setDelete) {
if (!Erase(make_pair(type, hash))) if (!Erase(std::make_pair(type, hash))) {
LogPrintf("%s: error failed to delete %s\n", __func__, hash.GetHex()); LogPrintf("%s: error failed to delete %s\n", __func__, hash.GetHex());
}
} }
return true; return true;
@@ -407,17 +459,17 @@ bool CZerocoinDB::WipeCoins(std::string strType)
bool CZerocoinDB::WriteAccumulatorValue(const uint32_t& nChecksum, const CBigNum& bnValue) bool CZerocoinDB::WriteAccumulatorValue(const uint32_t& nChecksum, const CBigNum& bnValue)
{ {
LogPrint("zero","%s : checksum:%d val:%s\n", __func__, nChecksum, bnValue.GetHex()); LogPrint("zero", "%s : checksum:%d val:%s\n", __func__, nChecksum, bnValue.GetHex());
return Write(make_pair('2', nChecksum), bnValue); return Write(std::make_pair('2', nChecksum), bnValue);
} }
bool CZerocoinDB::ReadAccumulatorValue(const uint32_t& nChecksum, CBigNum& 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) bool CZerocoinDB::EraseAccumulatorValue(const uint32_t& nChecksum)
{ {
LogPrint("zero", "%s : checksum:%d\n", __func__, nChecksum); LogPrint("zero", "%s : checksum:%d\n", __func__, nChecksum);
return Erase(make_pair('2', nChecksum)); return Erase(std::make_pair('2', nChecksum));
} }