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