diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7fe82c249..b579c79f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,146 +7,237 @@ on: jobs: build-files-linux-x64: - runs-on: ubuntu-22.04 - # if: ${{ false }} # Set condition to false to make the workflow inactive + runs-on: [self-hosted, Linux, X64] steps: - name: Checkout Repository uses: actions/checkout@v4 - - name: Build and Extract Files from Docker Container + - name: Set up environment variables run: | # Extract the name of the repository and use it as the ticker value REPO_NAME="${GITHUB_REPOSITORY##*/}" + # Get the short name of the ref (strip 'refs/heads/', 'refs/tags/', etc.) + SHORT_REF=${GITHUB_REF##*/} + # Get the short commit hash + SHORT_COMMIT_HASH=$(git rev-parse --short HEAD) + # Set environment variables + echo "REPO_NAME=${REPO_NAME}" >> $GITHUB_ENV + echo "SHORT_REF=${SHORT_REF}" >> $GITHUB_ENV + echo "IMAGE_NAME=linux-x64-build-img-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + echo "CONTAINER_NAME=linux-x64-build-ctn-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + + - name: Build and Extract Files from Docker Container + run: | + # Stop and remove any existing container with the same name + docker rm -f ${CONTAINER_NAME} || true + # Build the Docker image from the Dockerfile in the repository - docker build \ + docker buildx build \ + --no-cache \ --build-arg CPU_CORES=$(nproc) \ --build-arg TICKER=$REPO_NAME \ --build-arg NAME=Kyanite \ --build-arg BASE_NAME=kyanite \ - --build-arg TARGET=${{ github.ref }} \ - -t linux-x64-build-img \ + --build-arg TARGET=$SHORT_REF \ + -t ${IMAGE_NAME} \ -f contrib/docker/Dockerfile.dsw-linux-x64-wallet . - # Start the container (if it's not already running) - docker run -d --name linux-x64-build-ctn linux-x64-build-img + # Start the container + docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME} # Create a temporary directory to hold the extracted files mkdir release_files # Copy files from the Docker container to the local filesystem - docker cp linux-x64-build-ctn:/$REPO_NAME/deploy/linux-x64 release_files/ + docker cp ${CONTAINER_NAME}:/$REPO_NAME/deploy/linux-x64 release_files/ - name: Archive and Upload Extracted Files uses: actions/upload-artifact@v4 with: name: release-artifacts-linux-x64 path: release_files + + - name: Cleanup Docker container and image + run: | + # Stop and remove the Docker container + docker rm -f ${CONTAINER_NAME} + # Remove the Docker image + docker rmi ${IMAGE_NAME} + build-files-linux-arm64: - runs-on: ubuntu-22.04 - # if: ${{ false }} # Set condition to false to make the workflow inactive + runs-on: [self-hosted, Linux, X64] steps: - name: Checkout Repository uses: actions/checkout@v4 - - name: Build and Extract Files from Docker Container + - name: Set up environment variables run: | # Extract the name of the repository and use it as the ticker value REPO_NAME="${GITHUB_REPOSITORY##*/}" + # Get the short name of the ref (strip 'refs/heads/', 'refs/tags/', etc.) + SHORT_REF=${GITHUB_REF##*/} + # Get the short commit hash + SHORT_COMMIT_HASH=$(git rev-parse --short HEAD) + # Set environment variables + echo "REPO_NAME=${REPO_NAME}" >> $GITHUB_ENV + echo "SHORT_REF=${SHORT_REF}" >> $GITHUB_ENV + echo "IMAGE_NAME=linux-arm64-build-img-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + echo "CONTAINER_NAME=linux-arm64-build-ctn-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + + - name: Build and Extract Files from Docker Container + run: | + # Stop and remove any existing container with the same name + docker rm -f ${CONTAINER_NAME} || true + # Build the Docker image from the Dockerfile in the repository - docker build \ + docker buildx build \ + --no-cache \ --build-arg CPU_CORES=$(nproc) \ --build-arg TICKER=$REPO_NAME \ --build-arg NAME=Kyanite \ --build-arg BASE_NAME=kyanite \ - --build-arg TARGET=${{ github.ref }} \ - -t linux-arm64-build-img \ + --build-arg TARGET=$SHORT_REF \ + -t ${IMAGE_NAME} \ -f contrib/docker/Dockerfile.dsw-linux-arm64-wallet . - # Start the container (if it's not already running) - docker run -d --name linux-arm64-build-ctn linux-arm64-build-img + # Start the container + docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME} # Create a temporary directory to hold the extracted files mkdir release_files # Copy files from the Docker container to the local filesystem - docker cp linux-arm64-build-ctn:/$REPO_NAME/deploy/linux-arm64 release_files/ + docker cp ${CONTAINER_NAME}:/$REPO_NAME/deploy/linux-arm64 release_files/ - name: Archive and Upload Extracted Files uses: actions/upload-artifact@v4 with: name: release-artifacts-linux-arm64 path: release_files + + - name: Cleanup Docker container and image + run: | + # Stop and remove the Docker container + docker rm -f ${CONTAINER_NAME} + # Remove the Docker image + docker rmi ${IMAGE_NAME} + build-windows-x64: - runs-on: ubuntu-22.04 - # if: ${{ false }} # Set condition to false to make the workflow inactive + runs-on: [self-hosted, Linux, X64] steps: - name: Checkout Repository uses: actions/checkout@v4 - - name: Build and Extract Files from Docker Container + - name: Set up environment variables run: | # Extract the name of the repository and use it as the ticker value REPO_NAME="${GITHUB_REPOSITORY##*/}" + # Get the short name of the ref (strip 'refs/heads/', 'refs/tags/', etc.) + SHORT_REF=${GITHUB_REF##*/} + # Get the short commit hash + SHORT_COMMIT_HASH=$(git rev-parse --short HEAD) + # Set environment variables + echo "REPO_NAME=${REPO_NAME}" >> $GITHUB_ENV + echo "SHORT_REF=${SHORT_REF}" >> $GITHUB_ENV + echo "IMAGE_NAME=windows-x64-build-img-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + echo "CONTAINER_NAME=windows-x64-build-ctn-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + + - name: Build and Extract Files from Docker Container + run: | + # Stop and remove any existing container with the same name + docker rm -f ${CONTAINER_NAME} || true + # Build the Docker image from the Dockerfile in the repository - docker build \ + docker buildx build \ + --no-cache \ --build-arg CPU_CORES=$(nproc) \ --build-arg TICKER=$REPO_NAME \ --build-arg NAME=Kyanite \ --build-arg BASE_NAME=kyanite \ - --build-arg TARGET=${{ github.ref }} \ - -t windows-x64-build-img \ + --build-arg TARGET=$SHORT_REF \ + -t ${IMAGE_NAME} \ -f contrib/docker/Dockerfile.dsw-windows-x64-wallet . - # Start the container (if it's not already running) - docker run -d --name windows-x64-build-ctn windows-x64-build-img + # Start the container + docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME} # Create a temporary directory to hold the extracted files mkdir release_files # Copy files from the Docker container to the local filesystem - docker cp windows-x64-build-ctn:/$REPO_NAME/deploy/windows-x64 release_files/ + docker cp ${CONTAINER_NAME}:/$REPO_NAME/deploy/windows-x64 release_files/ - name: Archive and Upload Extracted Files uses: actions/upload-artifact@v4 with: name: release-artifacts-windows-x64 path: release_files + + - name: Cleanup Docker container and image + run: | + # Stop and remove the Docker container + docker rm -f ${CONTAINER_NAME} + # Remove the Docker image + docker rmi ${IMAGE_NAME} + build-macos-x64: - runs-on: ubuntu-22.04 - # if: ${{ false }} # Set condition to false to make the workflow inactive + runs-on: [self-hosted, Linux, X64] steps: - name: Checkout Repository uses: actions/checkout@v4 - - name: Build and Extract Files from Docker Container + - name: Set up environment variables run: | # Extract the name of the repository and use it as the ticker value REPO_NAME="${GITHUB_REPOSITORY##*/}" + # Get the short name of the ref (strip 'refs/heads/', 'refs/tags/', etc.) + SHORT_REF=${GITHUB_REF##*/} + # Get the short commit hash + SHORT_COMMIT_HASH=$(git rev-parse --short HEAD) + # Set environment variables + echo "REPO_NAME=${REPO_NAME}" >> $GITHUB_ENV + echo "SHORT_REF=${SHORT_REF}" >> $GITHUB_ENV + echo "IMAGE_NAME=macos-x64-build-img-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + echo "CONTAINER_NAME=macos-x64-build-ctn-${SHORT_COMMIT_HASH}" >> $GITHUB_ENV + + - name: Build and Extract Files from Docker Container + run: | + # Stop and remove any existing container with the same name + docker rm -f ${CONTAINER_NAME} || true + # Build the Docker image from the Dockerfile in the repository - docker build \ + docker buildx build \ + --no-cache \ --build-arg CPU_CORES=$(nproc) \ --build-arg TICKER=$REPO_NAME \ --build-arg NAME=Kyanite \ --build-arg BASE_NAME=kyanite \ - --build-arg TARGET=${{ github.ref }} \ - -t macos-x64-build-img \ + --build-arg TARGET=$SHORT_REF \ + -t ${IMAGE_NAME} \ -f contrib/docker/Dockerfile.dsw-macos-x64-wallet . - # Start the container (if it's not already running) - docker run -d --name macos-x64-build-ctn macos-x64-build-img + # Start the container + docker run -d --name ${CONTAINER_NAME} ${IMAGE_NAME} # Create a temporary directory to hold the extracted files mkdir release_files # Copy files from the Docker container to the local filesystem - docker cp macos-x64-build-ctn:/$REPO_NAME/deploy/macos-x64 release_files/ + docker cp ${CONTAINER_NAME}:/$REPO_NAME/deploy/macos-x64 release_files/ - name: Archive and Upload Extracted Files uses: actions/upload-artifact@v4 with: name: release-artifacts-macos-x64 path: release_files + + - name: Cleanup Docker container and image + run: | + # Stop and remove the Docker container + docker rm -f ${CONTAINER_NAME} + # Remove the Docker image + docker rmi ${IMAGE_NAME} diff --git a/.gitignore b/.gitignore index 9adbdcb17..1a2d6f257 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ reset-files.bash *.tar.gz *.exe configure~ +deploy/ # DSW src/__decenomy__ diff --git a/build-aux/m4/ax_boost_json.m4 b/build-aux/m4/ax_boost_json.m4 new file mode 100644 index 000000000..914c356e3 --- /dev/null +++ b/build-aux/m4/ax_boost_json.m4 @@ -0,0 +1,129 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_boost_json.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_JSON +# +# DESCRIPTION +# +# Test for the JSON library from the Boost C++ libraries. The macro +# requires a preceding call to AX_BOOST_BASE. Further documentation is +# available at . +# +# This macro calls: +# +# AC_SUBST(BOOST_JSON_LIB) +# +# And sets: +# +# HAVE_BOOST_JSON +# +# LICENSE +# +# Copyright (c) 2008 Thomas Porschberg +# Copyright (c) 2008 Michael Tindal +# Copyright (c) 2013 Daniel Casimiro +# Copyright (c) 2021 Richard Winters +# Copyright (c) 2022 Luke Mewburn +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_BOOST_JSON], [ + AC_ARG_WITH([boost-json], + AS_HELP_STRING([--with-boost-json@<:@=special-lib@:>@], + [use the JSON library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-json=boost_json-gcc-mt ] + ), [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_json_lib="" + else + want_boost="yes" + ax_boost_user_json_lib="$withval" + fi + ], [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::JSON library is available, + ax_cv_boost_json, [ + AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[@%:@include ]], +dnl XXXLUKEM + [[boost::json::object obj; obj["ax"] = 1; std::string s = boost::json::serialize(obj);]]) + ], + ax_cv_boost_json=yes, + ax_cv_boost_json=no + ) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + + if test "x$ax_cv_boost_json" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_JSON,,[define if the Boost::JSON library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_json_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_json*.so* $BOOSTLIBDIR/libboost_json*.dylib* $BOOSTLIBDIR/libboost_json*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_json.*\)\.so.*$;\1;' -e 's;^lib\(boost_json.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_json.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_JSON_LIB="-l$ax_lib"; AC_SUBST(BOOST_JSON_LIB) link_json="yes"; break], + [link_json="no"] + ) + done + if test "x$link_json" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_json*.dll* $BOOSTLIBDIR/boost_json*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_json.*\)\.dll.*$;\1;' -e 's;^\(boost_json.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_JSON_LIB="-l$ax_lib"; AC_SUBST(BOOST_JSON_LIB) link_json="yes"; break], + [link_json="no"] + ) + done + fi + + else + for ax_lib in $ax_boost_user_json_lib boost_json-$ax_boost_user_json_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_JSON_LIB="-l$ax_lib"; AC_SUBST(BOOST_JSON_LIB) link_json="yes"; break], + [link_json="no"] + ) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the Boost::JSON library!) + fi + if test "x$link_json" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..eb93b4121 --- /dev/null +++ b/build.sh @@ -0,0 +1,302 @@ +#!/bin/bash + +# Sets the number of parallel jobs that can be used on the build process +# Recomended values: 1 job per 1GB of free RAM or 1 job per CPU physical core +CPU_CORES=${CPU_CORES:-""} + +# Architectures that can be built: +# linux-x64 +# linux-arm64 +# macos-x64 +# windows-x64 +ARCHITECTURE=${ARCHITECTURE:-""} + +# Sets variables needed for the build +TICKER=${TICKER:-"KYAN"} +UI_NAME=${UI_NAME:-"Kyanite"} +BASE_NAME=${BASE_NAME:-"kyanite"} + +# Sets the github environment variables +GITHUB_USER="decenomy" +GITHUB_REPO="KYAN" + +# Sets the build environment variable +# 0: The build will use the builder image available on docker hub +# 1: The build will use a locally build image for the builder image +BUILD=${BUILD:-"0"} + +# Sets the verify environment variable +# 0: The wallet is only built but not verified +# 1: The wallet is built at the same commit as the published release on GitHub +# and then verified against the published hash files +# 2: The wallet is built at the same commit as the published release on GitHub +# and then all the files are downloaded and checked against the local ones +VERIFY=${VERIFY:-"0"} + +RED="\e[31m" +GREEN="\e[32m" +YELLOW="\e[33m" +BLUE="\e[34m" +RESET="\e[0m" + +echo -e "${BLUE} +██████╗ ███████╗██╗ ██╗ +██╔══██╗██╔════╝██║ ██║ +██║ ██║███████╗██║ █╗ ██║ +██║ ██║╚════██║██║███╗██║ +██████╔╝███████║╚███╔███╔╝ +╚═════╝ ╚══════╝ ╚══╝╚══╝ + DECENOMY Standard Wallet +Deterministic build script +${RESET}" + +error() { + echo -e "${RED} +███████╗██████╗ ██████╗ ██████╗ ██████╗ +██╔════╝██╔══██╗██╔══██╗██╔═══██╗██╔══██╗ +█████╗ ██████╔╝██████╔╝██║ ██║██████╔╝ +██╔══╝ ██╔══██╗██╔══██╗██║ ██║██╔══██╗ +███████╗██║ ██║██║ ██║╚██████╔╝██║ ██║ +╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ +${YELLOW}$1 +${RESET}" + exit 1 +} + +info() { + echo -e "${GREEN}$1${RESET}" +} + +warn() { + echo -e "${YELLOW}$1${RESET}" +} + +trace() { + echo -e "${BLUE}$1${RESET}" +} + +# Array of commands to test +commands=( + "docker" "wget" "curl" "jq" "lscpu" "grep" + "awk" "sha256sum" "unzip" "basename" "free" +) + +# Loop through the array and check each command +for cmd in "${commands[@]}" +do + if ! command -v $cmd &> /dev/null + then + error "${cmd} is not installed, please install before running again." + fi +done + +# Check if docker buildx is installed +docker buildx version &> /dev/null +if [ $? -ne 0 ]; then + error "Docker Buildx is not installed, please install before running again." +fi + +# Check if the CPU_CORES environment variable needs to be calculated +if [ "$CPU_CORES" = "" ]; then + + # Getting the number of sockets + sockets=$(lscpu | grep "Socket(s):" | awk '{print $2}') + + # Getting the number of cores per socket + cores_per_socket=$(lscpu | grep "Core(s) per socket:" | awk '{print $4}') + + # Calculating total physical cores + total_physical_cores=$((sockets * cores_per_socket)) + + # Getting the free RAM in gigabytes + free_ram_gb=$(free --giga | awk '/Mem:/ {print $7}') + + trace " +Total sockets (physical CPUs): $sockets +Cores per socket: $cores_per_socket +Total physical cores: $total_physical_cores +Free ram (GB): $free_ram_gb" + + # Calculating the default number of CPUs to use + CPU_CORES=$( + if [ $total_physical_cores -le $free_ram_gb ]; then + echo "$total_physical_cores" + else + echo "$free_ram_gb" + fi + ) +fi + +info "Using $CPU_CORES cores" + +# Check if the ARCHITECTURE environment variable needs to be chosen +if [ "$ARCHITECTURE" = "" ]; then + warn "Select an architecture from the list:" + + # List of architectures + options=("linux-x64" "linux-arm64" "macos-x64" "windows-x64") + + # Use select to present a menu and store the selection in a variable + select opt in "${options[@]}" + do + case $opt in + "linux-x64"|"linux-arm64"|"macos-x64"|"windows-x64") + break + ;; + *) + error "Invalid option $REPLY" + ;; + esac + done + + # Store the selection in a variable + ARCHITECTURE=$opt +fi + +info "Selected architecture: $ARCHITECTURE" + +WALLET_DOCKER_FILE="./contrib/docker/Dockerfile.dsw-$ARCHITECTURE-wallet" + +cp $WALLET_DOCKER_FILE $WALLET_DOCKER_FILE.tmp + +# Check if the FULL_BUILD environment variable is already set +if [ "$BUILD" = "1" ]; then + # The value of FULL_BUILD is 1, proceed with Docker build for the builder + docker buildx build \ + --no-cache \ + --build-arg CPU_CORES=$CPU_CORES \ + -t decenomy/dsw-$ARCHITECTURE-builder \ + -f ./contrib/docker/Dockerfile.dsw-$ARCHITECTURE-builder . + + if [ $? -ne 0 ]; then + error "Error: Docker build failed." + fi + + sed -i "s|^FROM decenomy/dsw-$ARCHITECTURE-builder.*|FROM decenomy/dsw-$ARCHITECTURE-builder:latest|" "$WALLET_DOCKER_FILE.tmp" +fi + +if [ "$VERIFY" = "0" ]; then + TARGET=$(git branch --show-current) +fi + +if [ "$VERIFY" -ge 1 ]; then + # Fetch the latest release data using GitHub API + response=$(curl -s "https://api.github.com/repos/$GITHUB_USER/$GITHUB_REPO/releases/latest") + + # Parse JSON response to get the browser_download_url of the asset + PACKAGE_URL=$(echo "$response" | jq -r ".assets[] | select(.name | ascii_downcase | test(\"$ARCHITECTURE.zip\")) | .browser_download_url") + + # Check if download_url is empty or null + if [ -z "$PACKAGE_URL" ] || [ "$PACKAGE_URL" == "null" ]; then + error "No matching asset found." + fi + + trace "Download URL for the package asset is: $PACKAGE_URL" + + # Parse JSON response to get the browser_download_url of the hash file asset + PACKAGE_SHA256_URL=$(echo "$response" | jq -r ".assets[] | select(.name | ascii_downcase | test(\"$ARCHITECTURE.asc\")) | .browser_download_url") + + # Check if download_url is empty or null + if [ -z "$PACKAGE_SHA256_URL" ] || [ "$PACKAGE_SHA256_URL" == "null" ]; then + error "No matching asset found." + fi + + trace "Download URL for the hash file asset is: $PACKAGE_SHA256_URL" + + sha256_file_contents=$(curl -sL "$PACKAGE_SHA256_URL") + + # Check if the download was successful + if [ -z "$sha256_file_contents" ]; then + error "Failed to download the file or the file is empty." + fi + + TARGET=$(echo "$sha256_file_contents" | grep "commit" | awk '{print $1}') + + # Check if the target was successfully obtained + if [ -z "$TARGET" ]; then + error "Failed to get the target or the target is empty." + fi +fi + +image_tag=${TICKER,,}-${UI_NAME,,}-${TARGET,,} + +docker buildx build \ + --no-cache \ + --build-arg CPU_CORES=$CPU_CORES \ + --build-arg TICKER=$TICKER \ + --build-arg NAME=$UI_NAME \ + --build-arg BASE_NAME=$BASE_NAME \ + --build-arg TARGET=$TARGET \ + -f $WALLET_DOCKER_FILE.tmp \ + -t $image_tag \ + . + +# Check if docker build was successful +if [ $? -ne 0 ]; then + error "Error: Docker build failed." +fi + +info "Successful build" + +# Create a temporary container from the image +container_id=$(docker create $image_tag) + +trace "Container ID: $container_id" + +# Copy files from the container to the current directory +mkdir -p deploy +rm -rf deploy/$ARCHITECTURE +docker cp "$container_id":/${TICKER}/deploy/. ./deploy/ + +# Main verification process +if [ "$VERIFY" -ge 1 ]; then + files_to_check=("${ARCHITECTURE}.zip" "${BASE_NAME}d" "${BASE_NAME}-cli" "${BASE_NAME}-tx" "${BASE_NAME}-qt") + + for file_to_check in "${files_to_check[@]}"; do + remote_hash="$(echo "$sha256_file_contents" | grep -i "${file_to_check}" | awk '{print $1}')" + local_hash="$(sha256sum "$(find "./deploy/$ARCHITECTURE" -type f | grep -i "${file_to_check}")" | awk '{print $1}')" + + if [ "$remote_hash" != "$local_hash" ]; then + error "${file_to_check^} file hashes don't match" + fi + done + + if [ "$VERIFY" -ge 2 ]; then + rm -rf "deploy/$ARCHITECTURE/download" + mkdir -p "deploy/$ARCHITECTURE/download" + cd "deploy/$ARCHITECTURE/download" + + wget "$PACKAGE_URL" + filename=$(basename "$PACKAGE_URL") + unzip "$filename" + + for file_to_check in "${files_to_check[@]}"; do + filename="$(find "./" -type f | grep -i "$file_to_check" | xargs -n1 basename)" + download_hash="$(sha256sum "./$filename" | awk '{print $1}')" + local_hash="$(sha256sum "../$filename" | awk '{print $1}')" + + if [ "$download_hash" != "$local_hash" ]; then + error "Download $file_to_check file hashes don't match" + fi + done + + cd ../../.. + fi + + info "Binaries verified successfully" +fi + +info " +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⢠⣤⣤⣤⡀⠀⢀⣼⣿⣿⣿⣿⣿⣿⣧⣤⣤⣤⣤⣤⣤⣤⣤⣄⡀⠀ +⢸⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄ +⢸⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇ +⢸⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀ +⢸⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀ +⢸⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀ +⢸⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀ +⢸⣿⣿⣿⡇⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀ +" \ No newline at end of file diff --git a/build_linux.sh b/build_linux.sh deleted file mode 100755 index 87b9333be..000000000 --- a/build_linux.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -echo -e "\033[0;32mHow many CPU cores do you want to be used in compiling process? (Default is 1. Press enter for default.)\033[0m" -read -e CPU_CORES -if [ -z "$CPU_CORES" ] -then - CPU_CORES=1 -fi - -echo -e "\033[0;32mDo you want to disable the tests? (yes/no)\033[0m" -read -e TEST_ANSWER -case "$TEST_ANSWER" in - [nN] | [n|N][O|o] ) TEST_STATUS='--enable-tests' # qt tests still have some problems - ;; # so use --without-gui - [yY] | [yY][Ee][Ss] ) TEST_STATUS='--disable-tests' - ;; - *) TEST_STATUS='--disable-tests' - ;; -esac - -echo -e "\033[0;32mDo you want to disable the debug? (yes/no)\033[0m" -read -e DEBUG_ANSWER -case "$DEBUG_ANSWER" in - [nN] | [n|N][O|o] ) DEBUG_STATUS='--enable-debug' # qt tests still have some problems - ;; # so use --without-gui - [yY] | [yY][Ee][Ss] ) DEBUG_STATUS='--disable-debug' - ;; - *) DEBUG_STATUS='--disable-debug' - ;; -esac - -# Upgrade the system and install required dependencies - sudo apt update - sudo apt install git zip unzip build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 libqt5svg5-dev -y - -# Clone code from official Github repository - rm -rf KYAN - git clone https://github.com/kyancoin/KYAN.git - -# Entering directory - cd KYAN - -# Compile dependencies - cd depends - make -j$(echo $CPU_CORES) HOST=x86_64-pc-linux-gnu - cd .. - -# Compile - ./autogen.sh - ./configure --enable-glibc-back-compat --prefix=$(pwd)/depends/x86_64-pc-linux-gnu LDFLAGS="-static-libstdc++" --enable-cxx --enable-static --disable-shared $(echo $DEBUG_STATUS) $(echo $TEST_STATUS) --disable-bench --with-pic --enable-upnp-default CPPFLAGS="-fPIC -O3 --param ggc-min-expand=1 --param ggc-min-heapsize=32768" CXXFLAGS="-fPIC -O3 --param ggc-min-expand=1 --param ggc-min-heapsize=32768" - make -j$(echo $CPU_CORES) HOST=x86_64-pc-linux-gnu - cd .. - -# Create zip file of binaries - cp KYAN/src/kyanited KYAN/src/kyanite-cli KYAN/src/kyanite-tx KYAN/src/qt/kyanite-qt . - zip KYAN-Linux.zip kyanited kyanite-cli kyanite-tx kyanite-qt - rm -f kyanited kyanite-cli kyanite-tx kyanite-qt diff --git a/build_macos.sh b/build_macos.sh deleted file mode 100755 index ca6e5c9f4..000000000 --- a/build_macos.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -echo -e "\033[0;32mHow many CPU cores do you want to be used in compiling process? (Default is 1. Press enter for default.)\033[0m" -read -e CPU_CORES -if [ -z "$CPU_CORES" ] -then - CPU_CORES=1 -fi - -# Clone code from official Github repository - rm -rf KYAN - git clone https://github.com/kyancoin/KYAN.git - -# Entering directory - cd KYAN - -# Compile dependencies - cd depends - mkdir SDKs - cd SDKs - wget -c https://cloudflare-ipfs.com/ipfs/QmYv9wHqKa5gZE1kL4ZpcVqKp1coS5tS9cYKGe4mUxxrqL/SDKs/MacOSX10.11.sdk.tar.xz - tar -xf MacOSX10.11.sdk.tar.xz - cd .. - make -j$(echo $CPU_CORES) HOST=x86_64-apple-darwin14 - cd .. - -# Compile - ./autogen.sh - ./configure --prefix=$(pwd)/depends/x86_64-apple-darwin14 --enable-cxx --enable-static --disable-shared --disable-debug --disable-tests --disable-bench --disable-online-rust --enable-upnp-default - make -j$(echo $CPU_CORES) HOST=x86_64-apple-darwin14 - make deploy - cd .. - -# Create zip file of binaries - cp KYAN/src/kyanited KYAN/src/kyanite-cli KYAN/src/kyanite-tx KYAN/src/qt/kyanite-qt KYAN/Kyanite-Core.dmg . - zip KYAN-MacOS.zip kyanited kyanite-cli kyanite-tx kyanite-qt Kyanite-Core.dmg - rm -f kyanited kyanite-cli kyanite-tx kyanite-qt Kyanite-Core.dmg diff --git a/build_windows.sh b/build_windows.sh deleted file mode 100755 index ca647da7c..000000000 --- a/build_windows.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -echo -e "\033[0;32mHow many CPU cores do you want to be used in compiling process? (Default is 1. Press enter for default.)\033[0m" -read -e CPU_CORES -if [ -z "$CPU_CORES" ] -then - CPU_CORES=1 -fi - -# Upgrade the system and install required dependencies - sudo apt update - sudo apt install git zip unzip build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 curl g++-mingw-w64-x86-64 g++-mingw-w64-x86-64-posix libqt5svg5-dev -y - echo "1" | sudo update-alternatives --config x86_64-w64-mingw32-g++ - -# Clone code from official Github repository - rm -rf KYAN - git clone https://github.com/kyancoin/KYAN.git - -# Entering directory - cd KYAN - -# Disable WSL support for Win32 applications. -sudo bash -c "echo 0 > /proc/sys/fs/binfmt_misc/status" - -# Compile dependencies - cd depends - make -j$(echo $CPU_CORES) HOST=x86_64-w64-mingw32 - cd .. - -# Compile - ./autogen.sh - ./configure --prefix=$(pwd)/depends/x86_64-w64-mingw32 --disable-debug --disable-tests --disable-bench --disable-online-rust --enable-upnp-default CFLAGS="-O3" CXXFLAGS="-O3" - make -j$(echo $CPU_CORES) HOST=x86_64-w64-mingw32 - cd .. - -# Create zip file of binaries - cp KYAN/src/kyanited.exe KYAN/src/kyanite-cli.exe KYAN/src/kyanite-tx.exe KYAN/src/qt/kyanite-qt.exe . - zip KYAN-Windows.zip kyanited.exe kyanite-cli.exe kyanite-tx.exe kyanite-qt.exe - rm -f kyanited.exe kyanite-cli.exe kyanite-tx.exe kyanite-qt.exe - -# Enable WSL support for Win32 applications. - sudo bash -c "echo 1 > /proc/sys/fs/binfmt_misc/status" diff --git a/configure.ac b/configure.ac index 9e2b812c5..d271859a6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 1) -define(_CLIENT_VERSION_REVISION, 5) -define(_CLIENT_VERSION_BUILD, 2) +define(_CLIENT_VERSION_REVISION, 6) +define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_RC, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2024) @@ -1017,6 +1017,7 @@ AX_BOOST_FILESYSTEM AX_BOOST_PROGRAM_OPTIONS AX_BOOST_THREAD AX_BOOST_CHRONO +AX_BOOST_JSON dnl Boost 1.56 through 1.62 allow using std::atomic instead of its own atomic dnl counter implementations. In 1.63 and later the std::atomic approach is default. @@ -1067,7 +1068,7 @@ if test x$use_tests = xyes; then fi if test x$use_boost = xyes; then - BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" + BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB $BOOST_JSON_LIB" fi if test x$use_pkgconfig = xyes; then diff --git a/contrib/docker/Dockerfile.dsw-linux-arm64-wallet b/contrib/docker/Dockerfile.dsw-linux-arm64-wallet index 725e6c984..cb7e2cfa0 100644 --- a/contrib/docker/Dockerfile.dsw-linux-arm64-wallet +++ b/contrib/docker/Dockerfile.dsw-linux-arm64-wallet @@ -1,5 +1,5 @@ # FROM decenomy/dsw-linux-arm64-builder:latest -FROM decenomy/dsw-linux-arm64-builder@sha256:ff64795ac415846c3576ba98526266ec0cf8c9810c695e2644f460f6070de678 +FROM decenomy/dsw-linux-arm64-builder@sha256:33f849b0d55eedd0f3d971d790a0fe008b4efa92066362f2f9eb4bed3bfb4ecb # ARG for specifying the number of cores ARG CPU_CORES=1 @@ -10,6 +10,8 @@ ARG NAME=Kyanite ARG BASE_NAME=kyanite ARG TARGET=master +RUN sleep 30 + # Clone the repository RUN if [ ! -d $TICKER ]; then \ git clone https://github.com/decenomy/$TICKER; \ @@ -18,9 +20,11 @@ fi # Switch to the repository directory WORKDIR /$TICKER -# Check out a specific version if needed -RUN git checkout -B $TARGET -RUN git pull origin $TARGET +# Check out the $TARGET +RUN git stash --include-untracked && \ + git fetch --all && \ + (git checkout $TARGET || git checkout -B $TARGET) && \ + (git reset --hard origin/$TARGET || git reset --hard $TARGET) # Run Git commands to extract the timestamps RUN git log -1 --format="%at" | xargs -I{} date -d @{} "+%Y-%m-%d %H:%M:%S" > /git_timestamp @@ -63,6 +67,7 @@ RUN cp src/$(echo $BASE_NAME)d src/$(echo $BASE_NAME)-cli src/$(echo $BASE_NAME) RUN find /$TICKER/deploy/linux-arm64 -type f -exec touch -t $(cat /git_timestamp_touch) {} + WORKDIR /$TICKER/deploy/linux-arm64 RUN PATH=${WRAP_DIR}:${PATH} zip -X $TICKER-$(cat /wallet_version)-Linux-arm64.zip $(echo $BASE_NAME)d $(echo $BASE_NAME)-cli $(echo $BASE_NAME)-tx $(echo $BASE_NAME)-qt +RUN echo "$(git rev-parse HEAD) commit" >> SHA256SUMS-Linux-arm64.ASC RUN sha256sum $(echo $BASE_NAME)d >> SHA256SUMS-Linux-arm64.ASC RUN sha256sum $(echo $BASE_NAME)-cli >> SHA256SUMS-Linux-arm64.ASC RUN sha256sum $(echo $BASE_NAME)-tx >> SHA256SUMS-Linux-arm64.ASC diff --git a/contrib/docker/Dockerfile.dsw-linux-x64-wallet b/contrib/docker/Dockerfile.dsw-linux-x64-wallet index ae42f48a7..a07ace511 100644 --- a/contrib/docker/Dockerfile.dsw-linux-x64-wallet +++ b/contrib/docker/Dockerfile.dsw-linux-x64-wallet @@ -1,5 +1,5 @@ # FROM decenomy/dsw-linux-x64-builder:latest -FROM decenomy/dsw-linux-x64-builder@sha256:49894f78ac27318ed1c018c80e674f99e6b45ac382c9b98a2aa0c94d8bd755a4 +FROM decenomy/dsw-linux-x64-builder@sha256:5b4550b5dc7b37e13b1b8b3a01443689dcd391578940068998fa3a137b845b58 # ARG for specifying the number of cores @@ -11,6 +11,8 @@ ARG NAME=Kyanite ARG BASE_NAME=kyanite ARG TARGET=master +RUN sleep 30 + # Clone the repository RUN if [ ! -d $TICKER ]; then \ git clone https://github.com/decenomy/$TICKER; \ @@ -19,9 +21,11 @@ fi # Switch to the repository directory WORKDIR /$TICKER -# Check out a specific version if needed -RUN git checkout -B $TARGET -RUN git pull origin $TARGET +# Check out the $TARGET +RUN git stash --include-untracked && \ + git fetch --all && \ + (git checkout $TARGET || git checkout -B $TARGET) && \ + (git reset --hard origin/$TARGET || git reset --hard $TARGET) # Run Git commands to extract the timestamps RUN git log -1 --format="%at" | xargs -I{} date -d @{} "+%Y-%m-%d %H:%M:%S" > /git_timestamp @@ -61,6 +65,7 @@ RUN cp src/$(echo $BASE_NAME)d src/$(echo $BASE_NAME)-cli src/$(echo $BASE_NAME) RUN find /$TICKER/deploy/linux-x64 -type f -exec touch -t $(cat /git_timestamp_touch) {} + WORKDIR /$TICKER/deploy/linux-x64 RUN PATH=${WRAP_DIR}:${PATH} zip -X $TICKER-$(cat /wallet_version)-Linux-x64.zip $(echo $BASE_NAME)d $(echo $BASE_NAME)-cli $(echo $BASE_NAME)-tx $(echo $BASE_NAME)-qt +RUN echo "$(git rev-parse HEAD) commit" >> SHA256SUMS-Linux-x64.ASC RUN sha256sum $(echo $BASE_NAME)d >> SHA256SUMS-Linux-x64.ASC RUN sha256sum $(echo $BASE_NAME)-cli >> SHA256SUMS-Linux-x64.ASC RUN sha256sum $(echo $BASE_NAME)-tx >> SHA256SUMS-Linux-x64.ASC diff --git a/contrib/docker/Dockerfile.dsw-macos-x64-wallet b/contrib/docker/Dockerfile.dsw-macos-x64-wallet index 3ed1d744c..d923945bc 100644 --- a/contrib/docker/Dockerfile.dsw-macos-x64-wallet +++ b/contrib/docker/Dockerfile.dsw-macos-x64-wallet @@ -1,5 +1,5 @@ #FROM decenomy/dsw-macos-x64-builder:latest -FROM decenomy/dsw-macos-x64-builder@sha256:395f7c9cc2ec9767674c0a226ca86855253f8558f94e367d02cfff45fa909f94 +FROM decenomy/dsw-macos-x64-builder@sha256:3977226e7d631af8f65d2d1903c34bf7452f359e76a0ee14e8f72a1feb3de40c # ARG for specifying the number of cores ARG CPU_CORES=1 @@ -10,6 +10,8 @@ ARG NAME=Kyanite ARG BASE_NAME=kyanite ARG TARGET=master +RUN sleep 30 + # Clone the repository RUN if [ ! -d $TICKER ]; then \ git clone https://github.com/decenomy/$TICKER; \ @@ -18,9 +20,11 @@ fi # Switch to the repository directory WORKDIR /$TICKER -# Check out a specific version if needed -RUN git checkout -B $TARGET -RUN git pull origin $TARGET +# Check out the $TARGET +RUN git stash --include-untracked && \ + git fetch --all && \ + (git checkout $TARGET || git checkout -B $TARGET) && \ + (git reset --hard origin/$TARGET || git reset --hard $TARGET) RUN git log -1 --format="%at" | xargs -I{} date -d @{} "+%Y-%m-%d %H:%M:%S" > /git_timestamp RUN git log -1 --format="%at" | xargs -I{} date -d @{} "+%Y%m%d%H%M.%S" > /git_timestamp_touch @@ -65,6 +69,7 @@ RUN cp src/$(echo $BASE_NAME)d src/$(echo $BASE_NAME)-cli src/$(echo $BASE_NAME) RUN find /$TICKER/deploy/macos-x64 -type f -exec touch -t $(cat /git_timestamp_touch) {} + WORKDIR /$TICKER/deploy/macos-x64 RUN PATH=${WRAP_DIR}:${PATH} zip -X $TICKER-$(cat /wallet_version)-MacOS-x64.zip $(echo $BASE_NAME)d $(echo $BASE_NAME)-cli $(echo $BASE_NAME)-tx $(echo $BASE_NAME)-qt $(echo $NAME)-Core.dmg +RUN echo "$(git rev-parse HEAD) commit" >> SHA256SUMS-MacOS-x64.ASC RUN sha256sum $(echo $BASE_NAME)d >> SHA256SUMS-MacOS-x64.ASC RUN sha256sum $(echo $BASE_NAME)-cli >> SHA256SUMS-MacOS-x64.ASC RUN sha256sum $(echo $BASE_NAME)-tx >> SHA256SUMS-MacOS-x64.ASC diff --git a/contrib/docker/Dockerfile.dsw-windows-x64-wallet b/contrib/docker/Dockerfile.dsw-windows-x64-wallet index e798a0222..54f9616f9 100644 --- a/contrib/docker/Dockerfile.dsw-windows-x64-wallet +++ b/contrib/docker/Dockerfile.dsw-windows-x64-wallet @@ -1,5 +1,5 @@ #FROM decenomy/dsw-windows-x64-builder:latest -FROM decenomy/dsw-windows-x64-builder@sha256:c5102edf92fba810de6596cc9593729b79ab00ca8d88656d4613a3cfa1fecf78 +FROM decenomy/dsw-windows-x64-builder@sha256:3bbdc2380c3e0c7409fe4dc54ad6f99d53fc1110d9f9a236d6e78a79e7067ccb # ARG for specifying the number of cores ARG CPU_CORES=1 @@ -10,6 +10,8 @@ ARG NAME=Kyanite ARG BASE_NAME=kyanite ARG TARGET=master +RUN sleep 30 + # Clone the repository RUN if [ ! -d $TICKER ]; then \ git clone https://github.com/decenomy/$TICKER; \ @@ -18,9 +20,11 @@ fi # Switch to the repository directory WORKDIR /$TICKER -# Check out a specific version if needed -RUN git checkout -B $TARGET -RUN git pull origin $TARGET +# Check out the $TARGET +RUN git stash --include-untracked && \ + git fetch --all && \ + (git checkout $TARGET || git checkout -B $TARGET) && \ + (git reset --hard origin/$TARGET || git reset --hard $TARGET) RUN git log -1 --format="%at" | xargs -I{} date -d @{} "+%Y-%m-%d %H:%M:%S" > /git_timestamp RUN git log -1 --format="%at" | xargs -I{} date -d @{} "+%Y%m%d%H%M.%S" > /git_timestamp_touch @@ -75,6 +79,7 @@ RUN PATH=${WRAP_DIR}:${PATH} zip -X $TICKER-$(cat /wallet_version)-Windows-x64.z $(echo $BASE_NAME)-tx.exe \ $(echo $BASE_NAME)-qt.exe +RUN echo "$(git rev-parse HEAD) commit" >> SHA256SUMS-Windows-x64.ASC RUN sha256sum $(echo $BASE_NAME)d.exe >> SHA256SUMS-Windows-x64.ASC RUN sha256sum $(echo $BASE_NAME)-cli.exe >> SHA256SUMS-Windows-x64.ASC RUN sha256sum $(echo $BASE_NAME)-tx.exe >> SHA256SUMS-Windows-x64.ASC diff --git a/contrib/pivx-qt.pro b/contrib/pivx-qt.pro index 022888f91..014d8d49c 100644 --- a/contrib/pivx-qt.pro +++ b/contrib/pivx-qt.pro @@ -89,6 +89,7 @@ HEADERS += src/activemasternode.h \ src/keepass.h \ src/key.h \ src/keystore.h \ + src/curl.h \ src/leveldbwrapper.h \ src/limitedmap.h \ src/main.h \ @@ -129,6 +130,7 @@ HEADERS += src/activemasternode.h \ src/utilstrencodings.h \ src/utiltime.h \ src/version.h \ + src/zip.h \ src/wallet.h \ src/wallet_ismine.h \ src/walletdb.h \ @@ -340,7 +342,7 @@ HEADERS += src/activemasternode.h \ src/qt/intro.moc \ src/qt/overviewpage.moc \ src/qt/rpcconsole.moc \ - src/secp256k1/src/secp256k1.c + src/secp256k1/src/secp256k1.c FORMS += src/qt/forms/addressbookpage.ui \ src/qt/forms/askpassphrasedialog.ui \ src/qt/forms/coincontroldialog.ui \ diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 7425963dd..90153882f 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,10 +1,9 @@ package=boost -$(package)_version=1_71_0 +$(package)_version=1_85_0 # $(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$(subst _,.,$($(package)_version))/source/ $(package)_download_path=https://github.com/decenomy/depends/raw/main/ $(package)_file_name=boost_$($(package)_version).tar.bz2 -$(package)_sha256_hash=d73a8da01e8bf8c7eda40b4c84915071a8c8a0df4a6734537ddde4a8580524ee -$(package)_patches=fix_gcc_11_3_compile.patch +$(package)_sha256_hash=7009fe1faa1697476bdc7027703a2badb84e849b7b0baad5086b087b971f8617 define $(package)_set_vars $(package)_config_opts_release=variant=release @@ -25,14 +24,13 @@ $(package)_toolset_$(host_os)=gcc $(package)_archiver_$(host_os)=$($(package)_ar) $(package)_toolset_darwin=darwin $(package)_archiver_darwin=$($(package)_libtool) -$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test +$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,json $(package)_cxxflags=-std=c++11 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC endef define $(package)_preprocess_cmds - echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam && \ - patch -p1 -i $($(package)_patch_dir)/fix_gcc_11_3_compile.patch + echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam endef define $(package)_config_cmds diff --git a/depends/patches/boost/fix_gcc_11_3_compile.patch b/depends/patches/boost/fix_gcc_11_3_compile.patch deleted file mode 100644 index 8be985815..000000000 --- a/depends/patches/boost/fix_gcc_11_3_compile.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Naur old/boost/thread/pthread/thread_data.hpp new/boost/thread/pthread/thread_data.hpp ---- old/boost/thread/pthread/thread_data.hpp 2019-08-14 14:03:38.000000000 +0200 -+++ new/boost/thread/pthread/thread_data.hpp 2022-10-08 21:33:40.351898197 +0200 -@@ -57,7 +57,7 @@ - #else - std::size_t page_size = ::sysconf( _SC_PAGESIZE); - #endif --#if PTHREAD_STACK_MIN > 0 -+#ifdef PTHREAD_STACK_MIN - if (size " - echo "Usage: $0 DSW __Decenomy__ __decenomy__ develop 3.0.0.0 Linux" - exit 1 -fi - -#Available architectures before 1.5.2.2 version - # - Windows - # - MacOS - # - Linux - # - aarch64 - # - aarch32 - - #Available architectures after - # - linux-arm64 - # - linux-x64 - # - macos-x64 - # - windows-x64 - -# Assign command-line arguments to variables -TICKER="$1" -NAME="$2" -BASE_NAME="$3" -TARGET="$4" -VERSION="$5" -ARCHITECTURE="$6" -ARCHITECTURE2="linux-x64" - -# Run docker build command and capture the output -docker build \ - --no-cache \ - --build-arg CPU_CORES=4 \ - --build-arg TICKER=$TICKER \ - --build-arg NAME=$NAME \ - --build-arg BASE_NAME=$BASE_NAME \ - --build-arg TARGET=$TARGET \ - -f ./contrib/docker/Dockerfile.dsw-${ARCHITECTURE2}-wallet \ - -t own_build . > build_output.txt - -# Check if docker build was successful -if [ $? -ne 0 ]; then - echo "Error: Docker build failed." - exit 1 -fi - -# Create a temporary container from the image -container_id=$(docker create own_build) - -echo "Container ID: $container_id" - -# Copy files from the container to the current directory -docker cp "$container_id":/${TICKER}/deploy/. . - -# Remove the temporary container -docker rm "$container_id" - -if [ "$TICKER" == "DSW" ]; then - echo "We are in DSW dev repo.." - # Change directory to the second architecture - cd "$ARCHITECTURE2" || { echo "Error: Unable to change directory to $ARCHITECTURE2"; exit 1; } - - FILENAME2="${TICKER}-${VERSION}-${ARCHITECTURE}-x64.zip" - local_=$(sha256sum "$FILENAME2") - cd .. - echo "sha256 local: $local_" -else - # Make HTTP request to GitHub API to get latest release info - response=$(curl -s https://api.github.com/repos/decenomy/${TICKER}/releases/latest) - - # Parse JSON and extract browser_download_url - browser_download_url=$(echo "$response" | jq -r --arg TICKER "$TICKER" --arg VERSION "$VERSION" --arg ARCHITECTURE "$ARCHITECTURE" '.assets[] | select(.name == "\($TICKER)-\($VERSION)-\($ARCHITECTURE).zip") | .browser_download_url') - - # Output the extracted URL - echo "Browser Download URL: $browser_download_url" - - # Define the filename based on the provided arguments - FILENAME="${TICKER}-${VERSION}-${ARCHITECTURE}.zip" - FILENAME2="${TICKER}-${VERSION}-${ARCHITECTURE}-x64.zip" - - # Check if the file already exists - if [ ! -e "$FILENAME" ]; then - wget "$browser_download_url" - fi - # Download the file - - origin=$(sha256sum "$FILENAME") - - # Change directory to the second architecture - cd "$ARCHITECTURE2" || { echo "Error: Unable to change directory to $ARCHITECTURE2"; exit 1; } - local_=$(sha256sum "$FILENAME2") - cd .. - - echo "sha256 origin: $origin" - echo "sha256 local: $local_" - - if [ "$origin" = "$local_" ]; then - echo "Build Successfully" - else - echo "Builds don't match" - fi -fi diff --git a/src/Makefile.am b/src/Makefile.am index 3f46c498a..17e3b33bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,9 +87,9 @@ BITCOIN_CORE_H = \ bip38.h \ bloom.h \ blocksignature.h \ - bootstrap/bootstrap.h \ - bootstrap/minizip/ioapi.h \ - bootstrap/minizip/unzip.h \ + bootstrap.h \ + minizip/ioapi.h \ + minizip/unzip.h \ chain.h \ chainparams.h \ chainparamsbase.h \ @@ -129,6 +129,7 @@ BITCOIN_CORE_H = \ key.h \ key_io.h \ keystore.h \ + curl.h \ dbwrapper.h \ limitedmap.h \ logging.h \ @@ -201,6 +202,7 @@ BITCOIN_CORE_H = \ utiltime.h \ validationinterface.h \ version.h \ + zip.h \ wallet/hdchain.h \ wallet/rpcwallet.h \ wallet/scriptpubkeyman.h \ @@ -232,6 +234,7 @@ libbitcoin_server_a_SOURCES = \ httprpc.cpp \ httpserver.cpp \ init.cpp \ + curl.cpp \ dbwrapper.cpp \ main.cpp \ merkleblock.cpp \ @@ -258,6 +261,11 @@ libbitcoin_server_a_SOURCES = \ txdb.cpp \ txmempool.cpp \ validationinterface.cpp \ + zip.cpp \ + bootstrap.cpp \ + minizip/ioapi.c \ + minizip/unzip.c \ + sqlite3/sqlite3.c \ $(BITCOIN_CORE_H) if ENABLE_ZMQ @@ -278,9 +286,6 @@ libbitcoin_wallet_a_SOURCES = \ activemasternodeconfig.cpp \ activemasternodeman.cpp \ bip38.cpp \ - bootstrap/bootstrap.cpp \ - bootstrap/minizip/ioapi.c \ - bootstrap/minizip/unzip.c \ interface/wallet.cpp \ addressbook.cpp \ crypter.cpp \ @@ -301,7 +306,6 @@ libbitcoin_wallet_a_SOURCES = \ wallet/wallet.cpp \ wallet/walletdb.cpp \ stakeinput.cpp \ - sqlite3/sqlite3.c \ $(BITCOIN_CORE_H) # crypto primitives library diff --git a/src/bootstrap.cpp b/src/bootstrap.cpp new file mode 100644 index 000000000..fc4182048 --- /dev/null +++ b/src/bootstrap.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2024 The DECENOMY Core Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bootstrap.h" + +#ifdef HAVE_CONFIG_H +#include "config/pivx-config.h" +#endif + +#include "amount.h" +#include "chainparams.h" +#include "curl.h" +#include "guiinterface.h" +#include "util.h" +#include "zip.h" + +#include + +namespace fs = boost::filesystem; + +std::string extractFilenameFromURL(const std::string& url) +{ + // Find the last '/' in the URL, which is expected to precede the filename + size_t last_slash_pos = url.find_last_of("/"); + + // Check if the last slash position is valid and there are characters after the '/' + if (last_slash_pos != std::string::npos && last_slash_pos + 1 < url.size()) { + return url.substr(last_slash_pos + 1); + } + + // If no '/' found, or there is nothing after the last '/', return an empty string + return ""; +} + +int progressCallback( + void* clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow) +{ + static int progress = 0; + const auto currentProgress = dltotal > 0 ? (int)((dlnow * 100) / dltotal) : 0; + + if (currentProgress > progress) { + progress = currentProgress; + LogPrintf("CBootstrap::%s: Download: %d%%\n", __func__, progress); + uiInterface.ShowProgress(_("Download: "), progress); + } + + return 0; +} + +bool CBootstrap::DownloadAndApply() +{ + const auto url = + std::string(BOOTSTRAP_URL) + + (Params().IsTestNet() ? "T" : "") + std::string(CURRENCY_UNIT) + + "/bootstrap.zip"; + const auto datadir = GetDataDir(); + const auto fileName = datadir / extractFilenameFromURL(url); + const auto blocks = datadir / "blocks"; + const auto chainstate = datadir / "chainstate"; + const auto sporks = datadir / "sporks"; + const auto banlist = datadir / "banlist.dat"; + + try { + // Step 1: Download the bootstrap file + if (!CCurlWrapper::DownloadFile(url, fileName.string(), progressCallback)) { + LogPrintf( + "CBootstrap::%s: Failed to download the bootstrap file: %s\n", + __func__, + fileName.string()); + return false; + } + + // Step 2: Cleanup the existing folders and files + try { + fs::remove_all(blocks); + fs::remove_all(chainstate); + fs::remove_all(sporks); + fs::remove_all(banlist); + } catch (const boost::filesystem::filesystem_error& e) { + LogPrintf("CBootstrap::%s: Error removing: %s\n", __func__, e.what()); + return false; + } + + // Step 3: Unzip the downloaded file + if (!CZipWrapper::ExtractZip(fileName.string(), datadir.string())) { + LogPrintf( + "CBootstrap::%s: Failed to unzip the bootstrap file: %s into: %s\n", + __func__, fileName.string(), datadir.string()); + fs::remove_all(fileName); + fs::remove_all(blocks); + fs::remove_all(chainstate); + fs::remove_all(sporks); + fs::remove_all(banlist); + + return false; + } + + // Step 4: Cleanup the bootstrap file + fs::remove_all(fileName); + + } catch (const std::exception& e) { + LogPrintf( + "CBootstrap::%s: Error downloading bootstrap file: %s\n", + __func__, e.what()); + + fs::remove_all(fileName); + fs::remove_all(blocks); + fs::remove_all(chainstate); + fs::remove_all(sporks); + fs::remove_all(banlist); + + return false; + } + + return true; +} diff --git a/src/bootstrap.h b/src/bootstrap.h new file mode 100644 index 000000000..fe43e983f --- /dev/null +++ b/src/bootstrap.h @@ -0,0 +1,16 @@ +// Copyright (c) 2024 The DECENOMY Core Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BOOTSTRAP_H +#define BOOTSTRAP_H + +#define APPLE_CA_PATH "/etc/ssl/cert.pem" + +class CBootstrap +{ +public: + static bool DownloadAndApply(); +}; + +#endif diff --git a/src/bootstrap/Dockerfile.linux-x64 b/src/bootstrap/Dockerfile.linux-x64 deleted file mode 100644 index ba80b76cb..000000000 --- a/src/bootstrap/Dockerfile.linux-x64 +++ /dev/null @@ -1,10 +0,0 @@ -FROM decenomy/dsw-linux-x64-builder@sha256:49894f78ac27318ed1c018c80e674f99e6b45ac382c9b98a2aa0c94d8bd755a4 - -# Set up a development tools directory -WORKDIR /home/app - -COPY . /home/app - -RUN make docker_linux_test - -RUN export PATH="/wrapped:$PATH" diff --git a/src/bootstrap/Dockerfile.macos-x64 b/src/bootstrap/Dockerfile.macos-x64 deleted file mode 100644 index 9dc5cbe8d..000000000 --- a/src/bootstrap/Dockerfile.macos-x64 +++ /dev/null @@ -1,10 +0,0 @@ -FROM decenomy/dsw-macos-x64-builder@sha256:395f7c9cc2ec9767674c0a226ca86855253f8558f94e367d02cfff45fa909f94 - -# Set up a development tools directory -WORKDIR /home/app - -COPY . /home/app - -RUN make docker_macos_test - -RUN export PATH="/wrapped:$PATH" diff --git a/src/bootstrap/Dockerfile.windows-x64 b/src/bootstrap/Dockerfile.windows-x64 deleted file mode 100644 index 3a3147e80..000000000 --- a/src/bootstrap/Dockerfile.windows-x64 +++ /dev/null @@ -1,10 +0,0 @@ -FROM decenomy/dsw-windows-x64-builder@sha256:c5102edf92fba810de6596cc9593729b79ab00ca8d88656d4613a3cfa1fecf78 - -# Set up a development tools directory -WORKDIR /home/app - -COPY . /home/app - -RUN make docker_windows_test - -RUN export PATH="/wrapped:$PATH" diff --git a/src/bootstrap/bootstrap.cpp b/src/bootstrap/bootstrap.cpp deleted file mode 100644 index 4e48a6665..000000000 --- a/src/bootstrap/bootstrap.cpp +++ /dev/null @@ -1,223 +0,0 @@ - -#include "bootstrap.h" - -namespace fs = boost::filesystem; -static bool log_flag = false; - -bool Bootstrap::rmDirectory(const std::string& directory_path) { - - try { - // Check if the directory exists - if (fs::exists(directory_path)) { - // Remove the directory and its contents - fs::remove_all(directory_path); - //LogPrintf("-bootstrap: Directory removed successfully."); - } else { - //LogPrintf("-bootstrap: Directory does not exist."); - } - } catch (const fs::filesystem_error& ex) { - //LogPrintf("-bootstrap: Error removing directory: " << ex.what()); - return false; - } - - return true; -} - -bool Bootstrap::isDirectory(const std::string& directory_path) { - - if (fs::exists(directory_path)) return true; - - return false; -} - -// Callback function to write downloaded data to a file -size_t Bootstrap::WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { - size_t total_size = size * nmemb; - std::ofstream* file = static_cast(userp); - file->write(static_cast(contents), total_size); - return total_size; -} - -// Define a function to handle progress updates -int Bootstrap::ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { - // Calculate progress percentage - double progress = (dlnow > 0) ? (dlnow / dltotal) * 100.0 : 0.0; - - auto now = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast(now.time_since_epoch()); - if(!log_flag && duration.count() % 2 == 0){ - log_flag = true; - LogPrintf("-bootstrap: Download: %d%%\n", (uint8_t)progress); - //uiInterface.ShowProgress(_("Download: "), (uint8_t)progress); - }else if(duration.count() % 2 != 0) log_flag = false; - - return 0; -} - -// Function to download a file using libcurl -bool Bootstrap::DownloadFile(const std::string& url, const std::string& outputFileName, curl_progress_callback func) { - - CURL* curl = curl_easy_init(); - if (!curl) { - //LogPrintf("-bootstrap: Error initializing libcurl."); - return false; - } - - curl_version_info_data *info = curl_version_info(CURLVERSION_NOW); - - if (info) { - // Print libcurl version information - LogPrintf("-bootstrap: libcurl version: %s \n", info->version); - LogPrintf("-bootstrap: libcurl SSL version: %s \n", info->ssl_version); - //LogPrintf("-bootstrap: libcurl zlib version: %s \n", info->libz_version); - } else { - LogPrintf("-bootstrap: Failed to retrieve libcurl version information.\n"); - } - - std::ofstream outputFile(outputFileName, std::ios::binary); - if (!outputFile.is_open()) { - LogPrintf("-bootstrap: Error opening output file."); - return false; - } - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // Verify the peer's SSL certificate - curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outputFile); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); - if(func == nullptr) - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, ProgressCallback); - else - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, func); - - #if defined(__APPLE__) - LogPrintf("-bootstrap: apple ca path: %s \n",(const char*)APPLE_CA_PATH); - curl_easy_setopt(curl, CURLOPT_CAINFO, (const char*)APPLE_CA_PATH); - #elif defined(__linux__) - //LogPrintf("-bootstrap: linux ca path: " << (const char*)LINUX_CA_PATH); - //curl_easy_setopt(curl, CURLOPT_CAINFO, (const char*)LINUX_CA_PATH); - #elif defined(_WIN32) - ///LogPrintf("-bootstrap: windows ca path: " << (const char*)WIN_CA_PATH); - //curl_easy_setopt(curl, CURLOPT_CAINFO, (const char*)WIN_CA_PATH); - #else - LogPrintf("-bootstrap: OS not recognized, CA Path not defined"); - #endif - - CURLcode res = curl_easy_perform(curl); - - curl_easy_cleanup(curl); - outputFile.close(); - - if (res != CURLE_OK) { - LogPrintf("-bootstrap: Error downloading file: %s \n",curl_easy_strerror(res)); - return false; - } - - return true; -} - -bool Bootstrap::extractZip(const std::string& zipFilePath, const std::string& outputFolderPath) { - - // Open the zip file - unzFile zipFile = unzOpen(zipFilePath.c_str()); - if (!zipFile) { - LogPrintf("-bootstrap: Error opening zip file: %s \n",zipFilePath); - return false; - } - - // Create the output folder if it doesn't exist - if (!ensureOutputFolder(outputFolderPath)) { - LogPrintf("-bootstrap: Error creating output folder: %s \n",outputFolderPath); - unzClose(zipFile); - return false; - } - - // Go through each file in the zip and extract it - unz_global_info globalInfo; - if (unzGetGlobalInfo(zipFile, &globalInfo) != UNZ_OK) { - LogPrintf("-bootstrap: Error getting global info from zip file."); - unzClose(zipFile); - return false; - } - - for (uLong i = 0; i < globalInfo.number_entry; ++i) { - char fileName[256]; - unz_file_info fileInfo; - - if (unzGetCurrentFileInfo(zipFile, &fileInfo, fileName, sizeof(fileName), nullptr, 0, nullptr, 0) != UNZ_OK) { - LogPrintf("-bootstrap: Error getting file info from zip file."); - unzClose(zipFile); - return false; - } - - if (unzOpenCurrentFile(zipFile) != UNZ_OK) { - LogPrintf("-bootstrap: Error opening current file in zip."); - unzClose(zipFile); - return false; - } - - std::string outputPath = std::string(outputFolderPath) + "/" + fileName; - LogPrintf("-bootstrap: extract file: %s \n",fileName); - - if(endsWithSlash(outputPath)) - ensureOutputFolder(outputPath); - else{ - std::ofstream outFile(outputPath, std::ios::binary); - if (!outFile.is_open()) { - LogPrintf("-bootstrap: Error creating output file: %s \n",outputPath); - unzCloseCurrentFile(zipFile); - unzClose(zipFile); - return false; - } - - // Read and write the file data - char buffer[4096]; - int bytesRead; - - while ((bytesRead = unzReadCurrentFile(zipFile, buffer, sizeof(buffer))) > 0) { - outFile.write(buffer, bytesRead); - } - outFile.close(); - } - - - unzCloseCurrentFile(zipFile); - - if (unzGoToNextFile(zipFile) != UNZ_OK) { - break; // Reached the end of the zip file - } - } - - // Close the zip file - unzClose(zipFile); - - LogPrintf("-bootstrap: Zip extraction successful."); - - return true; - -} - -bool Bootstrap::ensureOutputFolder(const std::string& outputPath) { - try { - if (!fs::exists(outputPath)) { - // Create the directory if it doesn't exist - fs::create_directories(outputPath); - } else if (!fs::is_directory(outputPath)) { - // If it exists but is not a directory, print an error - LogPrintf("-bootstrap: Error: Output path %s is not a directory.", outputPath); - return false; - } - } catch (const std::exception& e) { - // Handle any exceptions that may occur during filesystem operations - LogPrintf("-bootstrap: Error creating output folder: %s \n",e.what()); - return false; - } - - return true; -} - -bool Bootstrap::endsWithSlash(const std::string& str) { - // Check if the string ends with '/' - return !str.empty() && str.back() == '/'; -} diff --git a/src/bootstrap/bootstrap.h b/src/bootstrap/bootstrap.h deleted file mode 100644 index ec90caebf..000000000 --- a/src/bootstrap/bootstrap.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef BOOTSTRAP_H -#define BOOTSTRAP_H - -#include -#include // For perror -#include // For strerror -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "minizip/unzip.h" -#ifdef BOOTSTRAPTEST - #include "logging.h" -#else - #include "../logging.h" -#endif - -#ifndef TICKER -#define TICKER "KYAN" -#endif - -#define APPLE_CA_PATH "/etc/ssl/cert.pem" -//#define LINUX_CA_PATH "/etc/ssl/certs/ca-certificates.crt" -//#define WIN_CA_PATH "" - -class Bootstrap{ - -public: - // Define the function pointer type - //using ProgressCallbackFunc = std::function; - static int ProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); - static bool init(const char* path); - static bool rmDirectory(const std::string& path); - static bool isDirectory(const std::string& path); - static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp); - static bool DownloadFile(const std::string& url, const std::string& outputFileName, curl_progress_callback); - static bool extractZip(const std::string& inputPath, const std::string& outputPath); - -private: - - static bool ensureOutputFolder(const std::string& outputPath); - static bool endsWithSlash(const std::string& str); -}; - -#endif diff --git a/src/bootstrap/depends/install_curl.sh b/src/bootstrap/depends/install_curl.sh deleted file mode 100644 index 74111b486..000000000 --- a/src/bootstrap/depends/install_curl.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -work_dir=$(pwd) - -# Define default variables -install_dir="${work_dir}/dist" -openssl_dir="${work_dir}/openssl" - -# Parse command line options -while [[ $# -gt 0 ]]; do - key="$1" - case $key in - --prefix) - install_dir="$2" - shift # past argument - shift # past value - ;; - --openssl) - openssl_dir="$2" - shift # past argument - shift # past value - ;; - *) # unknown option - echo "Unknown option: $1" - exit 1 - ;; - esac -done - -# Define variables -curl_version="8.4.0" -curl_download_url="https://curl.se/download/curl-${curl_version}.tar.gz" -curl_tar="curl-${curl_version}.tar.gz" -curl_dir="curl-${curl_version}" - -# Download curl source -# Check if the file exists -if [ ! -f "$curl_tar" ]; then - wget "$curl_download_url" - if [ $? -ne 0 ]; then - echo "Failed to download curl source" - exit 1 - fi -fi - -if [ ! -d "$curl_dir" ]; then - # Extract the downloaded tarball - tar -xf "$curl_tar" - if [ $? -ne 0 ]; then - echo "Failed to extract curl source" - exit 1 - fi -fi - -# Configure curl with OpenSSL support if OpenSSL path is provided -cd "$curl_dir" || exit 1 -if [ -n "$openssl_dir" ]; then - echo "Using ssl: $openssl_dir" - ./configure --prefix="$install_dir" --with-ssl="$openssl_dir" -else - ./configure --prefix="$install_dir" -fi - -if [ $? -ne 0 ]; then - echo "Failed to configure curl" - exit 1 -fi - -# Compile and install curl -make -j2 -if [ $? -ne 0 ]; then - echo "Failed to compile curl" - exit 1 -fi - -make install -if [ $? -ne 0 ]; then - echo "Failed to install curl" - exit 1 -fi - -echo "curl successfully installed to $install_dir" diff --git a/src/bootstrap/depends/install_openssl.sh b/src/bootstrap/depends/install_openssl.sh deleted file mode 100644 index a8cb2fb29..000000000 --- a/src/bootstrap/depends/install_openssl.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -work_dir=$(pwd) - -# Define variables -openssl_version="3.2.1" -openssl_download_url="https://github.com/openssl/openssl/releases/download/openssl-3.2.1/openssl-${openssl_version}.tar.gz" -openssl_tar="openssl-${openssl_version}.tar.gz" -openssl_dir="openssl-${openssl_version}" -install_dir="${work_dir}/dist/" - -# Check if the file exists -if [ ! -f "$openssl_tar" ]; then - # Download OpenSSL source - wget "$openssl_download_url" - if [ $? -ne 0 ]; then - echo "Failed to download OpenSSL source" - fi - exit 1 -fi - -if [ ! -d "$openssl_dir" ]; then - # Extract the downloaded tarball - tar -xf "$openssl_tar" - if [ $? -ne 0 ]; then - echo "Failed to extract OpenSSL source" - exit 1 - fi -fi - -echo "Compiling openssl: ${openssl_version}" -# Configure OpenSSL -cd "$openssl_dir" || exit 1 -./config --prefix="$install_dir" --openssldir="$install_dir" -if [ $? -ne 0 ]; then - echo "Failed to configure OpenSSL" - exit 1 -fi - -# Compile and install OpenSSL -make -j2 -if [ $? -ne 0 ]; then - echo "Failed to compile OpenSSL" - exit 1 -fi - -make install_sw -if [ $? -ne 0 ]; then - echo "Failed to install OpenSSL" - exit 1 -fi - -echo "OpenSSL successfully installed to $install_dir" diff --git a/src/bootstrap/linux-build.sh b/src/bootstrap/linux-build.sh deleted file mode 100755 index f33e001cb..000000000 --- a/src/bootstrap/linux-build.sh +++ /dev/null @@ -1,31 +0,0 @@ - -TAG=linux-x64-builder - -#To compile and build the container execute docker in this way: -docker build \ - -f Dockerfile.linux-x64 \ - -t $TAG . - -# Check if docker build was successful -if [ $? -ne 0 ]; then - echo "Error: Docker build failed." - exit 1 -fi - -# Create a temporary container from the image -container_id=$(docker create $TAG) - -echo "Container ID: $container_id" - -# Copy files from the container to the current directory -docker cp "$container_id":home/app/test . - -# Remove the temporary container -docker rm "$container_id" - - -# To run the container use: -#docker run \ -# -it \ -# -v "$(pwd):/home/app" \ -# ${TAG}:latest diff --git a/src/bootstrap/logging.h b/src/bootstrap/logging.h deleted file mode 100644 index 2ea9214ff..000000000 --- a/src/bootstrap/logging.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef BITCOIN_LOGGING_H -#define BITCOIN_LOGGING_H - -#include "tinyformat.h" -#include // For perror -#include // For strerror -#include -#include - -/** Get format string from VA_ARGS for error reporting */ -template std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } - -#define LogPrintf(...) do { \ - if(true) { \ - std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ - try { \ - _log_msg_ = tfm::format(__VA_ARGS__); \ - } catch (tinyformat::format_error &e) { \ - /* Original format string will have newline so don't add one here */ \ - _log_msg_ = "Error \"" + std::string(e.what()) + \ - "\" while formatting log message: " + \ - FormatStringFromLogArgs(__VA_ARGS__); \ - } \ - std::cout << _log_msg_; \ - } \ -} while(0) - -#define LogPrint(category, ...) do { \ - if (LogAcceptCategory((category))) { \ - LogPrintf(__VA_ARGS__); \ - } \ -} while(0) - -#endif \ No newline at end of file diff --git a/src/bootstrap/macos-build.sh b/src/bootstrap/macos-build.sh deleted file mode 100755 index 2731ab8e6..000000000 --- a/src/bootstrap/macos-build.sh +++ /dev/null @@ -1,31 +0,0 @@ - -TAG=macos-x64-builder - -#To compile and build the container execute docker in this way: -docker build \ - -f Dockerfile.macos-x64 \ - -t $TAG . - -# Check if docker build was successful -if [ $? -ne 0 ]; then - echo "Error: Docker build failed." - exit 1 -fi - -# Create a temporary container from the image -container_id=$(docker create $TAG) - -echo "Container ID: $container_id" - -# Copy files from the container to the current directory -docker cp "$container_id":home/app/a.out . - -# Remove the temporary container -docker rm "$container_id" - - -# To run the container use: -#docker run \ -# -it \ -# -v "$(pwd):/home/app" \ -# ${TAG}:latest diff --git a/src/bootstrap/makefile b/src/bootstrap/makefile deleted file mode 100644 index 5420ef50e..000000000 --- a/src/bootstrap/makefile +++ /dev/null @@ -1,59 +0,0 @@ -work_dir := $(shell pwd) -CXX := g++ # Default compiler -CXXFLAGS := -std=c++11 -Wall -Wextra -LDFLAGS := -arch := x86_64-pc-linux-gnu - -ifdef linux_arm64 - CXX := aarch64-linux-gnu-g++ - arch := aarch64-linux-gnu -endif - - -all: test - -#test is working - .so files had to be deleted !!!! -curl_test: - $(CXX) \ - -I$(work_dir)/depends/dist/include \ - -L$(work_dir)/depends/dist/lib \ - -L$(work_dir)/depends/dist/lib64 \ - -o curl_test curl_test.cpp \ - -lcurl -lssl -lcrypto -lz - -#linux_x86=true make test -test: - $(CXX) -DBOOTSTRAPTEST \ - -I$(work_dir)/../../depends/$(arch)/include \ - -L$(work_dir)/../../depends/$(arch)/lib \ - -L$(work_dir)/../../depends/$(arch)/lib64 \ - -o test test.cpp bootstrap.h bootstrap.cpp minizip/unzip.h minizip/unzip.c minizip/ioapi.h minizip/ioapi.c \ - -lcurl -pthread -lz -lssl -lcrypto -lboost_system-mt-x64 -lboost_filesystem-mt-x64 - -docker_macos_test: - /DSW/depends/x86_64-apple-darwin14/native/bin/clang++ -DBOOTSTRAPTEST \ - -target x86_64-apple-darwin14 -mmacosx-version-min=10.10 --sysroot /DSW/depends/SDKs/MacOSX10.11.sdk -mlinker-version=253.9 -stdlib=libc++ \ - -I/DSW/depends/x86_64-apple-darwin14/include \ - -L/DSW/depends/x86_64-apple-darwin14/lib \ - -L/DSW/depends/x86_64-apple-darwin14/lib64 \ - test.cpp logging.h tinyformat.h bootstrap.h bootstrap.cpp minizip/unzip.h minizip/unzip.c minizip/ioapi.h minizip/ioapi.c \ - -lcurl -DCURL_STATICLIB `/DSW/depends/x86_64-apple-darwin14/bin/curl-config --cflags --static-libs` -pthread -lz -lssl -lcrypto -lboost_system-mt-x64 -lboost_filesystem-mt-x64 - -docker_linux_test: - $(CXX) -DBOOTSTRAPTEST \ - -I/DSW/depends/x86_64-pc-linux-gnu/include \ - -L/DSW/depends/x86_64-pc-linux-gnu/lib \ - -L/DSW/depends/x86_64-pc-linux-gnu/lib64 \ - -o test test.cpp logging.h tinyformat.h bootstrap.h bootstrap.cpp minizip/unzip.h minizip/unzip.c minizip/ioapi.h minizip/ioapi.c \ - -lcurl -pthread -lz -lssl -lcrypto -ldl -lboost_system-mt-x64 -lboost_filesystem-mt-x64 - -docker_windows_test: - /usr/bin/x86_64-w64-mingw32-g++ -DBOOTSTRAPTEST -static \ - -I/DSW/depends/x86_64-w64-mingw32/include \ - -L/DSW/depends/x86_64-w64-mingw32/lib \ - -L/DSW/depends/x86_64-w64-mingw32/lib64 \ - -o test.exe test.cpp logging.h tinyformat.h bootstrap.h bootstrap.cpp minizip/unzip.h minizip/unzip.c minizip/ioapi.h minizip/ioapi.c \ - -lcurl -DCURL_STATICLIB `/DSW/depends/x86_64-w64-mingw32/bin/curl-config --cflags --static-libs` -pthread -lz -lssl -lcrypto -lboost_system-mt-s-x64 -lboost_filesystem-mt-s-x64 - -clean: - rm test test.exe curl_test bootstrap.zip \ No newline at end of file diff --git a/src/bootstrap/test.cpp b/src/bootstrap/test.cpp deleted file mode 100644 index e83c54657..000000000 --- a/src/bootstrap/test.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#define COIN "777" - -#include "bootstrap.h" -namespace fs = boost::filesystem; - -// Define the progress callback function -static int downloadProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { - - // Calculate progress percentage - double progress = (dlnow > 0) ? (dlnow / dltotal) * 100.0 : 0.0; - - auto now = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast(now.time_since_epoch()); - static bool log_flag = false; // Declare log_flag as static - if (!log_flag && duration.count() % 2 == 0) { - log_flag = true; - std::printf("-bootstrap: Download: %d%%\n", (uint8_t)progress); - // LogPrintf("-Bootstrap: Download: %d%%\n", (uint8_t)progress); - // uiInterface.ShowProgress(_("Download: "), (uint8_t)progress); - } else if (duration.count() % 2 != 0) { - log_flag = false; - } - - return 0; -} - -int main() { - - /* File src/init.cpp - line 1206 - if (GetBoolArg("-bootstrap", false)) { - uiInterface.InitMessage(_("Preparing for bootstrap...")); - // Delete the local blockchain folders to force a bootstrap from scratch to get a consitent blockchain-state - fs::path blocksDir = GetDataDir() / "blocks"; - fs::path chainstateDir = GetDataDir() / "chainstate"; - fs::path sporksDir = GetDataDir() / "sporks"; - - LogPrintf("Deleting blockchain folders blocks, chainstate, and sporks\n"); - // We delete in 4 individual steps in case one of the folder is missing already - try { - if (fs::exists(blocksDir)){ - fs::remove_all(blocksDir); - LogPrintf("-bootstrap: folder deleted: %s\n", blocksDir.string().c_str()); - } - - if (fs::exists(chainstateDir)){ - fs::remove_all(chainstateDir); - LogPrintf("-bootstrap: folder deleted: %s\n", chainstateDir.string().c_str()); - } - - if (fs::exists(sporksDir)){ - fs::remove_all(sporksDir); - LogPrintf("-bootstrap: folder deleted: %s\n", sporksDir.string().c_str()); - } - } catch (const fs::filesystem_error& error) { - LogPrintf("Failed to delete blockchain folders %s\n", error.what()); - } - } - */ - - const std::string url = "https://bootstraps.decenomy.net/"+std::string(COIN)+"/bootstrap.zip"; - //const std::string url = std::string(BOOTSTRAP_URL)+std::string(TICKER)+"/bootstrap.zip"; - const std::string outputFileName = "bootstrap.zip"; - const std::string extractPath = "bootstrap_"; - - std::cout << "Download: " << url << std::endl; - - if(Bootstrap::isDirectory(extractPath)) - Bootstrap::rmDirectory(extractPath); - - if (Bootstrap::DownloadFile(url, outputFileName, downloadProgressCallback)) { - std::cout << "File downloaded successfully." << std::endl; - - if (Bootstrap::extractZip(outputFileName, extractPath)) { - std::cout << "Zip file extracted successfully." << std::endl; - } else { - std::cerr << "Error extracting zip file." << std::endl; - } - - if(Bootstrap::isDirectory(extractPath)) - Bootstrap::rmDirectory(extractPath); - - } else { - std::cerr << "Error downloading file." << std::endl; - } - - fs::remove(outputFileName); - - return 0; -} diff --git a/src/bootstrap/tinyformat.h b/src/bootstrap/tinyformat.h deleted file mode 100644 index 00114eae9..000000000 --- a/src/bootstrap/tinyformat.h +++ /dev/null @@ -1,1059 +0,0 @@ -// tinyformat.h -// Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com] -// -// Boost Software License - Version 1.0 -// -// Permission is hereby granted, free of charge, to any person or organization -// obtaining a copy of the software and accompanying documentation covered by -// this license (the "Software") to use, reproduce, display, distribute, -// execute, and transmit the Software, and to prepare derivative works of the -// Software, and to permit third-parties to whom the Software is furnished to -// do so, all subject to the following: -// -// The copyright notices in the Software and this entire statement, including -// the above license grant, this restriction and the following disclaimer, -// must be included in all copies of the Software, in whole or in part, and -// all derivative works of the Software, unless such copies or derivative -// works are solely in the form of machine-executable object code generated by -// a source language processor. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//------------------------------------------------------------------------------ -// Tinyformat: A minimal type safe printf replacement -// -// tinyformat.h is a type safe printf replacement library in a single C++ -// header file. Design goals include: -// -// * Type safety and extensibility for user defined types. -// * C99 printf() compatibility, to the extent possible using std::ostream -// * Simplicity and minimalism. A single header file to include and distribute -// with your projects. -// * Augment rather than replace the standard stream formatting mechanism -// * C++98 support, with optional C++11 niceties -// -// -// Main interface example usage -// ---------------------------- -// -// To print a date to std::cout: -// -// std::string weekday = "Wednesday"; -// const char* month = "July"; -// size_t day = 27; -// long hour = 14; -// int min = 44; -// -// tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min); -// -// The strange types here emphasize the type safety of the interface; it is -// possible to print a std::string using the "%s" conversion, and a -// size_t using the "%d" conversion. A similar result could be achieved -// using either of the tfm::format() functions. One prints on a user provided -// stream: -// -// tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n", -// weekday, month, day, hour, min); -// -// The other returns a std::string: -// -// std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n", -// weekday, month, day, hour, min); -// std::cout << date; -// -// These are the three primary interface functions. There is also a -// convenience function printfln() which appends a newline to the usual result -// of printf() for super simple logging. -// -// -// User defined format functions -// ----------------------------- -// -// Simulating variadic templates in C++98 is pretty painful since it requires -// writing out the same function for each desired number of arguments. To make -// this bearable tinyformat comes with a set of macros which are used -// internally to generate the API, but which may also be used in user code. -// -// The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and -// TINYFORMAT_PASSARGS(n) will generate a list of n argument types, -// type/name pairs and argument names respectively when called with an integer -// n between 1 and 16. We can use these to define a macro which generates the -// desired user defined function with n arguments. To generate all 16 user -// defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM. For an -// example, see the implementation of printf() at the end of the source file. -// -// Sometimes it's useful to be able to pass a list of format arguments through -// to a non-template function. The FormatList class is provided as a way to do -// this by storing the argument list in a type-opaque way. Continuing the -// example from above, we construct a FormatList using makeFormatList(): -// -// FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour, min); -// -// The format list can now be passed into any non-template function and used -// via a call to the vformat() function: -// -// tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList); -// -// -// Additional API information -// -------------------------- -// -// Error handling: Define TINYFORMAT_ERROR to customize the error handling for -// format strings which are unsupported or have the wrong number of format -// specifiers (calls assert() by default). -// -// User defined types: Uses operator<< for user defined types by default. -// Overload formatValue() for more control. - - -#ifndef TINYFORMAT_H_INCLUDED -#define TINYFORMAT_H_INCLUDED - -namespace tinyformat -{ -} -//------------------------------------------------------------------------------ -// Config section. Customize to your liking! - -// Namespace alias to encourage brevity -namespace tfm = tinyformat; - -// Error handling; calls assert() by default. -#define TINYFORMAT_ERROR(reasonString) throw tinyformat::format_error(reasonString) - -// Define for C++11 variadic templates which make the code shorter & more -// general. If you don't define this, C++11 support is autodetected below. -#ifndef __APPLE__ -#define TINYFORMAT_USE_VARIADIC_TEMPLATES -#endif - -//------------------------------------------------------------------------------ -// Implementation details. -#include -#include -#include -#include -#include - -#ifndef TINYFORMAT_ERROR -#define TINYFORMAT_ERROR(reason) assert(0 && reason) -#endif - -#if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) && !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES) -#ifdef __GXX_EXPERIMENTAL_CXX0X__ -#define TINYFORMAT_USE_VARIADIC_TEMPLATES -#endif -#endif - -#if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201 -// std::showpos is broken on old libstdc++ as provided with OSX. See -// http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html -#define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND -#endif - -#ifdef __APPLE__ -// Workaround OSX linker warning: xcode uses different default symbol -// visibilities for static libs vs executables (see bitcoin's issue #25) -# define TINYFORMAT_HIDDEN __attribute__((visibility("hidden"))) -#else -# define TINYFORMAT_HIDDEN -#endif - -namespace tinyformat -{ - -class format_error: public std::runtime_error -{ -public: - format_error(const std::string &what): std::runtime_error(what) { - } -}; - -//------------------------------------------------------------------------------ -namespace detail -{ -// Test whether type T1 is convertible to type T2 -template -struct is_convertible { -private: - // two types of different size - struct fail { - char dummy[2]; - }; - struct succeed { - char dummy; - }; - // Try to convert a T1 to a T2 by plugging into tryConvert - static fail tryConvert(...); - static succeed tryConvert(const T2&); - static const T1& makeT1(); - -public: -#ifdef _MSC_VER -// Disable spurious loss of precision warnings in tryConvert(makeT1()) -#pragma warning(push) -#pragma warning(disable : 4244) -#pragma warning(disable : 4267) -#endif - // Standard trick: the (...) version of tryConvert will be chosen from - // the overload set only if the version taking a T2 doesn't match. - // Then we compare the sizes of the return types to check which - // function matched. Very neat, in a disgusting kind of way :) - static const bool value = - sizeof(tryConvert(makeT1())) == sizeof(succeed); -#ifdef _MSC_VER -#pragma warning(pop) -#endif -}; - - -// Detect when a type is not a wchar_t string -template -struct is_wchar { - typedef int tinyformat_wchar_is_not_supported; -}; -template <> -struct is_wchar { -}; -template <> -struct is_wchar { -}; -template -struct is_wchar { -}; -template -struct is_wchar { -}; - - -// Format the value by casting to type fmtT. This default implementation -// should never be called. -template ::value> -struct formatValueAsType { - static void invoke(std::ostream& /*out*/, const T& /*value*/) { assert(0); } -}; -// Specialized version for types that can actually be converted to fmtT, as -// indicated by the "convertible" template parameter. -template -struct formatValueAsType { - static void invoke(std::ostream& out, const T& value) - { - out << static_cast(value); - } -}; - -#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND -template ::value> -struct formatZeroIntegerWorkaround { - static bool invoke(std::ostream& /**/, const T& /**/) { return false; } -}; -template -struct formatZeroIntegerWorkaround { - static bool invoke(std::ostream& out, const T& value) - { - if (static_cast(value) == 0 && out.flags() & std::ios::showpos) { - out << "+0"; - return true; - } - return false; - } -}; -#endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND - -// Convert an arbitrary type to integer. The version with convertible=false -// throws an error. -template ::value> -struct convertToInt { - static int invoke(const T& /*value*/) - { - TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to " - "integer for use as variable width or precision"); - return 0; - } -}; -// Specialization for convertToInt when conversion is possible -template -struct convertToInt { - static int invoke(const T& value) { return static_cast(value); } -}; - -// Format at most ntrunc characters to the given stream. -template -inline void formatTruncated(std::ostream& out, const T& value, int ntrunc) -{ - std::ostringstream tmp; - tmp << value; - std::string result = tmp.str(); - out.write(result.c_str(), (std::min)(ntrunc, static_cast(result.size()))); -} -#define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type) \ -inline void formatTruncated(std::ostream& out, type* value, int ntrunc) \ -{ \ - std::streamsize len = 0; \ - while(len < ntrunc && value[len] != 0) \ - ++len; \ - out.write(value, len); \ -} -// Overload for const char* and char*. Could overload for signed & unsigned -// char too, but these are technically unneeded for printf compatibility. -TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char) -TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char) -#undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR - -} // namespace detail - - -//------------------------------------------------------------------------------ -/// Format a value into a stream, delegating to operator<< by default. -/// -/// Users may override this for their own types. When this function is called, -/// the stream flags will have been modified according to the format string. -/// The format specification is provided in the range [fmtBegin, fmtEnd). For -/// truncating conversions, ntrunc is set to the desired maximum number of -/// characters, for example "%.7s" calls formatValue with ntrunc = 7. -/// -/// By default, formatValue() uses the usual stream insertion operator -/// operator<< to format the type T, with special cases for the %c and %p -/// conversions. -template -inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, - const char* fmtEnd, int ntrunc, const T& value) -{ -#ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS - // Since we don't support printing of wchar_t using "%ls", make it fail at - // compile time in preference to printing as a void* at runtime. - typedef typename detail::is_wchar::tinyformat_wchar_is_not_supported DummyType; - (void)DummyType(); // avoid unused type warning with gcc-4.8 -#endif - // The mess here is to support the %c and %p conversions: if these - // conversions are active we try to convert the type to a char or const - // void* respectively and format that instead of the value itself. For the - // %p conversion it's important to avoid dereferencing the pointer, which - // could otherwise lead to a crash when printing a dangling (const char*). - const bool canConvertToChar = detail::is_convertible::value; - const bool canConvertToVoidPtr = detail::is_convertible::value; - if (canConvertToChar && *(fmtEnd - 1) == 'c') - detail::formatValueAsType::invoke(out, value); - else if (canConvertToVoidPtr && *(fmtEnd - 1) == 'p') - detail::formatValueAsType::invoke(out, value); -#ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND - else if (detail::formatZeroIntegerWorkaround::invoke(out, value)) /**/; -#endif - else if(ntrunc >= 0) - { - // Take care not to overread C strings in truncating conversions like - // "%.4s" where at most 4 characters may be read. - detail::formatTruncated(out, value, ntrunc); - } - else - out << value; -} - - -// Overloaded version for char types to support printing as an integer -#define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType) \ - inline void formatValue(std::ostream& out, const char* /*fmtBegin*/, \ - const char* fmtEnd, int /**/, charType value) \ - { \ - switch (*(fmtEnd - 1)) { \ - case 'u': \ - case 'd': \ - case 'i': \ - case 'o': \ - case 'X': \ - case 'x': \ - out << static_cast(value); \ - break; \ - default: \ - out << value; \ - break; \ - } \ - } -// per 3.9.1: char, signed char and unsigned char are all distinct types -TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char) -TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char) -TINYFORMAT_DEFINE_FORMATVALUE_CHAR(unsigned char) -#undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR - - -//------------------------------------------------------------------------------ -// Tools for emulating variadic templates in C++98. The basic idea here is -// stolen from the boost preprocessor metaprogramming library and cut down to -// be just general enough for what we need. - -#define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_##n -#define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_##n -#define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_##n -#define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_##n - -// To keep it as transparent as possible, the macros below have been generated -// using python via the excellent cog.py code generation script. This avoids -// the need for a bunch of complex (but more general) preprocessor tricks as -// used in boost.preprocessor. -// -// To rerun the code generation in place, use `cog.py -r tinyformat.h` -// (see http://nedbatchelder.com/code/cog). Alternatively you can just create -// extra versions by hand. - -/*[[[cog -maxParams = 16 - -def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1): - for j in range(startInd,maxParams+1): - std::list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)]) - cog.outl(lineTemplate % {'j':j, 'list':list}) - -makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s', - 'class T%(i)d') - -cog.outl() -makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s', - 'const T%(i)d& v%(i)d') - -cog.outl() -makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d') - -cog.outl() -cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1') -makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s', - 'v%(i)d', startInd = 2) - -cog.outl() -cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n ' + - ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)])) -]]]*/ -#define TINYFORMAT_ARGTYPES_1 class T1 -#define TINYFORMAT_ARGTYPES_2 class T1, class T2 -#define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3 -#define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4 -#define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5 -#define TINYFORMAT_ARGTYPES_6 class T1, class T2, class T3, class T4, class T5, class T6 -#define TINYFORMAT_ARGTYPES_7 class T1, class T2, class T3, class T4, class T5, class T6, class T7 -#define TINYFORMAT_ARGTYPES_8 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8 -#define TINYFORMAT_ARGTYPES_9 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9 -#define TINYFORMAT_ARGTYPES_10 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10 -#define TINYFORMAT_ARGTYPES_11 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11 -#define TINYFORMAT_ARGTYPES_12 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12 -#define TINYFORMAT_ARGTYPES_13 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13 -#define TINYFORMAT_ARGTYPES_14 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14 -#define TINYFORMAT_ARGTYPES_15 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15 -#define TINYFORMAT_ARGTYPES_16 class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16 - -#define TINYFORMAT_VARARGS_1 const T1& v1 -#define TINYFORMAT_VARARGS_2 const T1 &v1, const T2 &v2 -#define TINYFORMAT_VARARGS_3 const T1 &v1, const T2 &v2, const T3 &v3 -#define TINYFORMAT_VARARGS_4 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4 -#define TINYFORMAT_VARARGS_5 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5 -#define TINYFORMAT_VARARGS_6 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6 -#define TINYFORMAT_VARARGS_7 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7 -#define TINYFORMAT_VARARGS_8 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8 -#define TINYFORMAT_VARARGS_9 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9 -#define TINYFORMAT_VARARGS_10 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10 -#define TINYFORMAT_VARARGS_11 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, const T11 &v11 -#define TINYFORMAT_VARARGS_12 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, const T11 &v11, const T12 &v12 -#define TINYFORMAT_VARARGS_13 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13 -#define TINYFORMAT_VARARGS_14 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13, const T14 &v14 -#define TINYFORMAT_VARARGS_15 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13, const T14 &v14, const T15 &v15 -#define TINYFORMAT_VARARGS_16 const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13, const T14 &v14, const T15 &v15, const T16 &v16 - -#define TINYFORMAT_PASSARGS_1 v1 -#define TINYFORMAT_PASSARGS_2 v1, v2 -#define TINYFORMAT_PASSARGS_3 v1, v2, v3 -#define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4 -#define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5 -#define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6 -#define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7 -#define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8 -#define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9 -#define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 -#define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 -#define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 -#define TINYFORMAT_PASSARGS_13 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 -#define TINYFORMAT_PASSARGS_14 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 -#define TINYFORMAT_PASSARGS_15 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 -#define TINYFORMAT_PASSARGS_16 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 - -#define TINYFORMAT_PASSARGS_TAIL_1 -#define TINYFORMAT_PASSARGS_TAIL_2 , v2 -#define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3 -#define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4 -#define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5 -#define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6 -#define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7 -#define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8 -#define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9 -#define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10 -#define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 -#define TINYFORMAT_PASSARGS_TAIL_12 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 -#define TINYFORMAT_PASSARGS_TAIL_13 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 -#define TINYFORMAT_PASSARGS_TAIL_14 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 -#define TINYFORMAT_PASSARGS_TAIL_15 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 -#define TINYFORMAT_PASSARGS_TAIL_16 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 - -#define TINYFORMAT_FOREACH_ARGNUM(m) \ - m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) m(15) m(16) -//[[[end]]] - - -namespace detail -{ -// Type-opaque holder for an argument to format(), with associated actions on -// the type held as explicit function pointers. This allows FormatArg's for -// each argument to be allocated as a homogenous array inside FormatList -// whereas a naive implementation based on inheritance does not. -class FormatArg -{ -public: - FormatArg() {} - - template - FormatArg(const T& value) - : m_value(static_cast(&value)), - m_formatImpl(&formatImpl), - m_toIntImpl(&toIntImpl) - { } - - void format(std::ostream& out, const char* fmtBegin, - const char* fmtEnd, int ntrunc) const - { - m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value); - } - - int toInt() const - { - return m_toIntImpl(m_value); - } - -private: - template - TINYFORMAT_HIDDEN static void formatImpl(std::ostream& out, const char* fmtBegin, - const char* fmtEnd, int ntrunc, const void* value) - { - formatValue(out, fmtBegin, fmtEnd, ntrunc, *static_cast(value)); - } - - template - TINYFORMAT_HIDDEN static int toIntImpl(const void* value) - { - return convertToInt::invoke(*static_cast(value)); - } - - const void* m_value; - void (*m_formatImpl)(std::ostream& out, const char* fmtBegin, - const char* fmtEnd, int ntrunc, const void* value); - int (*m_toIntImpl)(const void* value); -}; - - -// Parse and return an integer from the string c, as atoi() -// On return, c is set to one past the end of the integer. -inline int parseIntAndAdvance(const char*& c) -{ - int i = 0; - for(;*c >= '0' && *c <= '9'; ++c) - i = 10*i + (*c - '0'); - return i; -} - -// Print literal part of format string and return next format spec -// position. -// -// Skips over any occurrences of '%%', printing a literal '%' to the -// output. The position of the first % character of the next -// nontrivial format spec is returned, or the end of string. -inline const char* printFormatStringLiteral(std::ostream& out, const char* fmt) -{ - const char* c = fmt; - for(;; ++c) { - switch(*c) - { - case '\0': - out.write(fmt, c - fmt); - return c; - case '%': - out.write(fmt, c - fmt); - if(*(c+1) != '%') - return c; - // for "%%", tack trailing % onto next literal section. - fmt = ++c; - break; - default: - break; - } - } -} - - -// Parse a format string and set the stream state accordingly. -// -// The format mini-language recognized here is meant to be the one from C99, -// with the form "%[flags][width][.precision][length]type". -// -// Formatting options which can't be natively represented using the ostream -// state are returned in spacePadPositive (for space padded positive numbers) -// and ntrunc (for truncating conversions). argIndex is incremented if -// necessary to pull out variable width and precision . The function returns a -// pointer to the character after the end of the current format spec. -inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositive, - int& ntrunc, const char* fmtStart, - const detail::FormatArg* formatters, - int& argIndex, int numFormatters) -{ - if (*fmtStart != '%') { - TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string"); - return fmtStart; - } - // Reset stream state to defaults. - out.width(0); - out.precision(6); - out.fill(' '); - // Reset most flags; ignore irrelevant unitbuf & skipws. - out.unsetf(std::ios::adjustfield | std::ios::basefield | - std::ios::floatfield | std::ios::showbase | std::ios::boolalpha | - std::ios::showpoint | std::ios::showpos | std::ios::uppercase); - bool precisionSet = false; - bool widthSet = false; - int widthExtra = 0; - const char* c = fmtStart + 1; - // 1) Parse flags - for (;; ++c) { - switch (*c) { - case '#': - out.setf(std::ios::showpoint | std::ios::showbase); - continue; - case '0': - // overridden by left alignment ('-' flag) - if (!(out.flags() & std::ios::left)) { - // Use internal padding so that numeric values are - // formatted correctly, eg -00010 rather than 000-10 - out.fill('0'); - out.setf(std::ios::internal, std::ios::adjustfield); - } - continue; - case '-': - out.fill(' '); - out.setf(std::ios::left, std::ios::adjustfield); - continue; - case ' ': - // overridden by show positive sign, '+' flag. - if (!(out.flags() & std::ios::showpos)) - spacePadPositive = true; - continue; - case '+': - out.setf(std::ios::showpos); - spacePadPositive = false; - widthExtra = 1; - continue; - default: - break; - } - break; - } - // 2) Parse width - if (*c >= '0' && *c <= '9') { - widthSet = true; - out.width(parseIntAndAdvance(c)); - } - if (*c == '*') { - widthSet = true; - int width = 0; - if(argIndex < numFormatters) - width = formatters[argIndex++].toInt(); - else - TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width"); - if(width < 0) { - // negative widths correspond to '-' flag set - out.fill(' '); - out.setf(std::ios::left, std::ios::adjustfield); - width = -width; - } - out.width(width); - ++c; - } - // 3) Parse precision - if (*c == '.') { - ++c; - int precision = 0; - if (*c == '*') { - ++c; - if(argIndex < numFormatters) - precision = formatters[argIndex++].toInt(); - else - TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable precision"); - } else { - if (*c >= '0' && *c <= '9') - precision = parseIntAndAdvance(c); - else if (*c == '-') // negative precisions ignored, treated as zero. - parseIntAndAdvance(++c); - } - out.precision(precision); - precisionSet = true; - } - // 4) Ignore any C99 length modifier - while (*c == 'l' || *c == 'h' || *c == 'L' || - *c == 'j' || *c == 'z' || *c == 't') - ++c; - // 5) We're up to the conversion specifier character. - // Set stream flags based on conversion specifier (thanks to the - // boost::format class for forging the way here). - bool intConversion = false; - switch (*c) { - case 'u': - case 'd': - case 'i': - out.setf(std::ios::dec, std::ios::basefield); - intConversion = true; - break; - case 'o': - out.setf(std::ios::oct, std::ios::basefield); - intConversion = true; - break; - case 'X': - out.setf(std::ios::uppercase); - case 'x': - case 'p': - out.setf(std::ios::hex, std::ios::basefield); - intConversion = true; - break; - case 'E': - out.setf(std::ios::uppercase); - case 'e': - out.setf(std::ios::scientific, std::ios::floatfield); - out.setf(std::ios::dec, std::ios::basefield); - break; - case 'F': - out.setf(std::ios::uppercase); - case 'f': - out.setf(std::ios::fixed, std::ios::floatfield); - break; - case 'G': - out.setf(std::ios::uppercase); - case 'g': - out.setf(std::ios::dec, std::ios::basefield); - // As in boost::format, let stream decide float format. - out.flags(out.flags() & ~std::ios::floatfield); - break; - case 'a': - case 'A': - TINYFORMAT_ERROR("tinyformat: the %a and %A conversion specs " - "are not supported"); - break; - case 'c': - // Handled as special case inside formatValue() - break; - case 's': - if (precisionSet) - ntrunc = static_cast(out.precision()); - // Make %s print booleans as "true" and "false" - out.setf(std::ios::boolalpha); - break; - case 'n': - // Not supported - will cause problems! - TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported"); - break; - case '\0': - TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly " - "terminated by end of string"); - return c; - default: - break; - } - if (intConversion && precisionSet && !widthSet) { - // "precision" for integers gives the minimum number of digits (to be - // padded with zeros on the left). This isn't really supported by the - // iostreams, but we can approximately simulate it with the width if - // the width isn't otherwise used. - out.width(out.precision() + widthExtra); - out.setf(std::ios::internal, std::ios::adjustfield); - out.fill('0'); - } - return c + 1; -} - - -//------------------------------------------------------------------------------ -inline void formatImpl(std::ostream& out, const char* fmt, - const detail::FormatArg* formatters, - int numFormatters) -{ - // Saved stream state - std::streamsize origWidth = out.width(); - std::streamsize origPrecision = out.precision(); - std::ios::fmtflags origFlags = out.flags(); - char origFill = out.fill(); - - for (int argIndex = 0; argIndex < numFormatters; ++argIndex) - { - // Parse the format string - fmt = printFormatStringLiteral(out, fmt); - bool spacePadPositive = false; - int ntrunc = -1; - const char* fmtEnd = streamStateFromFormat(out, spacePadPositive, ntrunc, fmt, - formatters, argIndex, numFormatters); - if (argIndex >= numFormatters) - { - // Check args remain after reading any variable width/precision - TINYFORMAT_ERROR("tinyformat: Not enough format arguments"); - return; - } - const FormatArg& arg = formatters[argIndex]; - // Format the arg into the stream. - if(!spacePadPositive) - arg.format(out, fmt, fmtEnd, ntrunc); - else - { - // The following is a special case with no direct correspondence - // between stream formatting and the printf() behaviour. Simulate - // it crudely by formatting into a temporary string stream and - // munging the resulting string. - std::ostringstream tmpStream; - tmpStream.copyfmt(out); - tmpStream.setf(std::ios::showpos); - arg.format(tmpStream, fmt, fmtEnd, ntrunc); - std::string result = tmpStream.str(); // allocates... yuck. - for(size_t i = 0, iend = result.size(); i < iend; ++i) - if(result[i] == '+') result[i] = ' '; - out << result; - } - fmt = fmtEnd; - } - - // Print remaining part of format string. - fmt = printFormatStringLiteral(out, fmt); - if(*fmt != '\0') - TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); - - // Restore stream state - out.width(origWidth); - out.precision(origPrecision); - out.flags(origFlags); - out.fill(origFill); -} - -} // namespace detail - - -/// List of template arguments format(), held in a type-opaque way. -/// -/// A const reference to FormatList (typedef'd as FormatListRef) may be -/// conveniently used to pass arguments to non-template functions: All type -/// information has been stripped from the arguments, leaving just enough of a -/// common interface to perform formatting as required. -class FormatList -{ -public: - FormatList(detail::FormatArg* formatters, int N) - : m_formatters(formatters), m_N(N) { } - - friend void vformat(std::ostream& out, const char* fmt, - const FormatList& list); - -private: - const detail::FormatArg* m_formatters; - int m_N; -}; - -/// Reference to type-opaque format list for passing to vformat() -typedef const FormatList& FormatListRef; - - -namespace detail { - -// Format list subclass with fixed storage to avoid dynamic allocation -template -class FormatListN : public FormatList -{ -public: -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - template - FormatListN(const Args&... args) - : FormatList(&m_formatterStore[0], N), - m_formatterStore { FormatArg(args)... } - { static_assert(sizeof...(args) == N, "Number of args must be N"); } -#else // C++98 version - void init(int) {} -# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \ - \ - template \ - FormatListN(TINYFORMAT_VARARGS(n)) \ - : FormatList(&m_formatterStore[0], n) \ - { assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \ - \ - template \ - void init(int i, TINYFORMAT_VARARGS(n)) \ - { \ - m_formatterStore[i] = FormatArg(v1); \ - init(i+1 TINYFORMAT_PASSARGS_TAIL(n)); \ - } - - TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR) -# undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR -#endif -private: - FormatArg m_formatterStore[N]; -}; - -// Special 0-arg version - MSVC says zero-sized C array in struct is nonstandard -template<> class FormatListN<0> : public FormatList -{ - public: FormatListN() : FormatList(0, 0) {} -}; - -} // namespace detail - - -//------------------------------------------------------------------------------ -// Primary API functions - -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - -/// Make type-agnostic format list from list of template arguments. -/// -/// The exact return type of this function is an implementation detail and -/// shouldn't be relied upon. Instead it should be stored as a FormatListRef: -/// -/// FormatListRef formatList = makeFormatList( /*...*/ ); -template -detail::FormatListN makeFormatList(const Args&... args) -{ - return detail::FormatListN(args...); -} - -#else // C++98 version - -inline detail::FormatListN<0> makeFormatList() -{ - return detail::FormatListN<0>(); -} -#define TINYFORMAT_MAKE_MAKEFORMATLIST(n) \ -template \ -detail::FormatListN makeFormatList(TINYFORMAT_VARARGS(n)) \ -{ \ - return detail::FormatListN(TINYFORMAT_PASSARGS(n)); \ -} -TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST) -#undef TINYFORMAT_MAKE_MAKEFORMATLIST - -#endif - -/// Format list of arguments to the stream according to the given format string. -/// -/// The name vformat() is chosen for the semantic similarity to vprintf(): the -/// list of format arguments is held in a single function argument. -inline void vformat(std::ostream& out, const char* fmt, FormatListRef list) -{ - detail::formatImpl(out, fmt, list.m_formatters, list.m_N); -} - - -#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES - -/// Format list of arguments to the stream according to given format string. -template -void format(std::ostream& out, const char* fmt, const Args&... args) -{ - vformat(out, fmt, makeFormatList(args...)); -} - -/// Format list of arguments according to the given format string and return -/// the result as a string. -template -std::string format(const char* fmt, const Args&... args) -{ - std::ostringstream oss; - format(oss, fmt, args...); - return oss.str(); -} - -/// Format list of arguments to std::cout, according to the given format string -template -void printf(const char* fmt, const Args&... args) -{ - format(std::cout, fmt, args...); -} - -template -void printfln(const char* fmt, const Args&... args) -{ - format(std::cout, fmt, args...); - std::cout << '\n'; -} - -#else // C++98 version - -inline void format(std::ostream& out, const char* fmt) -{ - vformat(out, fmt, makeFormatList()); -} - -inline std::string format(const char* fmt) -{ - std::ostringstream oss; - format(oss, fmt); - return oss.str(); -} - -inline void printf(const char* fmt) -{ - format(std::cout, fmt); -} - -inline void printfln(const char* fmt) -{ - format(std::cout, fmt); - std::cout << '\n'; -} - -#define TINYFORMAT_MAKE_FORMAT_FUNCS(n) \ - \ - template \ - void format(std::ostream& out, const char* fmt, TINYFORMAT_VARARGS(n)) \ - { \ - vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n))); \ - } \ - \ - template \ - std::string format(const char* fmt, TINYFORMAT_VARARGS(n)) \ - { \ - std::ostringstream oss; \ - format(oss, fmt, TINYFORMAT_PASSARGS(n)); \ - return oss.str(); \ - } \ - \ - template \ - void printf(const char* fmt, TINYFORMAT_VARARGS(n)) \ - { \ - format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ - } \ - \ - template \ - void printfln(const char* fmt, TINYFORMAT_VARARGS(n)) \ - { \ - format(std::cout, fmt, TINYFORMAT_PASSARGS(n)); \ - std::cout << '\n'; \ - } - -TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS) -#undef TINYFORMAT_MAKE_FORMAT_FUNCS -#endif - -// Added for Bitcoin Core -template -std::string format(const std::string &fmt, const Args&... args) -{ - std::ostringstream oss; - format(oss, fmt.c_str(), args...); - return oss.str(); -} - -} // namespace tinyformat - -#define strprintf tfm::format - -#endif // TINYFORMAT_H_INCLUDED diff --git a/src/bootstrap/windows-build.sh b/src/bootstrap/windows-build.sh deleted file mode 100755 index acbbd381d..000000000 --- a/src/bootstrap/windows-build.sh +++ /dev/null @@ -1,31 +0,0 @@ - -TAG=windows-x64-builder - -#To compile and build the container execute docker in this way: -docker build \ - -f Dockerfile.windows-x64 \ - -t $TAG . - -# Check if docker build was successful -if [ $? -ne 0 ]; then - echo "Error: Docker build failed." - exit 1 -fi - -# Create a temporary container from the image -container_id=$(docker create $TAG) - -echo "Container ID: $container_id" - -# Copy files from the container to the current directory -docker cp "$container_id":home/app/test.exe . - -# Remove the temporary container -docker rm "$container_id" - - -# To run the container use: -#docker run \ -# -it \ -# -v "$(pwd):/home/app" \ -# ${TAG}:latest diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b1302a8f7..3677c8f07 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -264,7 +264,7 @@ class CMainParams : public CChainParams consensus.vUpgrades[Consensus::UPGRADE_P2PKH_BLOCK_SIGNATURES].nActivationHeight = 1741; consensus.vUpgrades[Consensus::UPGRADE_STAKE_MIN_DEPTH_V2].nActivationHeight = 5001; consensus.vUpgrades[Consensus::UPGRADE_MASTERNODE_RANK_V2].nActivationHeight = 3001; - consensus.vUpgrades[Consensus::UPGRADE_DYNAMIC_REWARDS].nActivationHeight = 1411000; + consensus.vUpgrades[Consensus::UPGRADE_DYNAMIC_REWARDS].nActivationHeight = 1450000; consensus.vUpgrades[Consensus::UPGRADE_DYNAMIC_COLLATERALS].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; consensus.vUpgrades[Consensus::UPGRADE_POS].hashActivationBlock = uint256S("a68286b8dd2d7730ab2025201b38020fa68592010ac3e4bcbeaf066b40533802"); @@ -399,7 +399,7 @@ class CTestNetParams : public CMainParams consensus.nTargetTimespanV2 = 30 * 60; consensus.nTargetSpacing = 1 * 60; consensus.nTimeSlotLength = 15; - consensus.nRewardAdjustmentInterval = 7 * 1440; + consensus.nRewardAdjustmentInterval = 60; // spork keys consensus.strSporkPubKey = "037c650e8f2e175727a69c50d5fb459f09891e8f6d113105033dfa7af472a229e2"; diff --git a/src/chainparams.h b/src/chainparams.h index 43abfb137..30c1a246c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -72,6 +72,7 @@ class CChainParams virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0; CBaseChainParams::Network NetworkID() const { return networkID; } + bool IsTestNet() const { return NetworkID() == CBaseChainParams::TESTNET; } bool IsRegTestNet() const { return NetworkID() == CBaseChainParams::REGTEST; } diff --git a/src/coins.h b/src/coins.h index 651a9246e..c9e73c7b9 100644 --- a/src/coins.h +++ b/src/coins.h @@ -18,7 +18,7 @@ #include #include -#include +#include /** * A UTXO entry. @@ -123,7 +123,7 @@ struct CCoinsCacheEntry { explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {} }; -typedef std::unordered_map CCoinsMap; +typedef boost::unordered_map CCoinsMap; /** Cursor for iterating over CoinsView state */ class CCoinsViewCursor diff --git a/src/curl.cpp b/src/curl.cpp new file mode 100644 index 000000000..fbfea3d99 --- /dev/null +++ b/src/curl.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2024 The DECENOMY Core Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "curl.h" + +#include "init.h" +#include "logging.h" + +// Callback function to write downloaded data to a file +size_t writeCallback(void* data, size_t size, size_t nmemb, void* clientp) +{ + if(ShutdownRequested()) { + LogPrintf( + "CCurlWrapper::%s: Shutdown requested while downloading a file\n", + __func__); + return 0; + } + + size_t total_size = size * nmemb; + std::ofstream* file = static_cast(clientp); + file->write(static_cast(data), total_size); + return total_size; +} + +bool CCurlWrapper::DownloadFile( + const std::string& url, + const std::string& filename, + curl_xferinfo_callback xferinfoCallback) +{ + try { + // Initializes libcurl + const auto curl = curl_easy_init(); + if (!curl) { + LogPrintf( + "CCurlWrapper::%s: Error initializing libcurl.\n", __func__); + return false; + } + + // Gets libcurl version information + const auto info = curl_version_info(CURLVERSION_NOW); + if (info) { + LogPrintf( + "CCurlWrapper::%s: libcurl version: %s\n", + __func__, info->version); + LogPrintf( + "CCurlWrapper::%s: libcurl SSL version: %s\n", + __func__, info->ssl_version); + LogPrintf( + "CCurlWrapper::%s: libcurl zlib version: %s\n", + __func__, info->libz_version); + } else { + LogPrintf( + "CCurlWrapper::%s: Failed to retrieve libcurl version information.\n", + __func__); + return false; + } + + LogPrintf( + "CCurlWrapper::%s: Downloading from %s\n", + __func__, + url); + + // Creates and open the destination file + std::ofstream outputFile(filename, std::ios::binary); + if (!outputFile.is_open()) { + LogPrintf( + "CCurlWrapper::%s: Error opening output file %s\n", + __func__, filename); + return false; + } + + // Sets url parameter + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + + // Sets HTTPS parameters + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA); +#if defined(__APPLE__) + LogPrintf("CCurlWrapper::%s: apple ca path: %s\n", __func__, (const char*)APPLE_CA_PATH); + curl_easy_setopt(curl, CURLOPT_CAINFO, (const char*)APPLE_CA_PATH); +#endif + + // Sets file releated parameters + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outputFile); + + // Sets progress function parameters + if (xferinfoCallback) { + // Enable the progress function + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + // Set up the progress function + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfoCallback); + // Necessary to pass the callback to CURLOPT_XFERINFODATA (not used) + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, NULL); + } + + // HTTP call execution + const auto res = curl_easy_perform(curl); + + // Cleanup + curl_easy_cleanup(curl); + outputFile.close(); + + // Evaluation and return + if (res != CURLE_OK) { + if(!ShutdownRequested()) { + LogPrintf( + "CCurlWrapper::%s: Error downloading file: %s\n", + __func__, curl_easy_strerror(res)); + } + fs::remove_all(filename); + return false; + } + } catch (const std::exception& e) { + LogPrintf( + "CCurlWrapper::%s: Error downloading file: %s\n", + __func__, e.what()); + fs::remove_all(filename); + return false; + } + + return true; +} diff --git a/src/curl.h b/src/curl.h new file mode 100644 index 000000000..f9b7bad3d --- /dev/null +++ b/src/curl.h @@ -0,0 +1,22 @@ +// Copyright (c) 2024 The DECENOMY Core Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef CURL_H +#define CURL_H + +#include +#include + +#define APPLE_CA_PATH "/etc/ssl/cert.pem" + +class CCurlWrapper +{ +public: + static bool DownloadFile( + const std::string& url, + const std::string& filename, + curl_xferinfo_callback xferinfoCallback = nullptr); +}; + +#endif // CURL_H diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 83a7049fb..c70197b12 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/src/init.cpp b/src/init.cpp index 47c819d62..acd61c050 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -20,6 +20,7 @@ #include "activemasternodeconfig.h" #include "addrman.h" #include "amount.h" +#include "bootstrap.h" #include "checkpoints.h" #include "compat/sanity.h" #include "consensus/upgrades.h" @@ -888,28 +889,6 @@ static std::string ResolveErrMsg(const char * const optname, const std::string& return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); } -// Define the progress callback function -static int DownloadProgressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { - - // Calculate progress percentage - double progress = (dlnow > 0) ? (dlnow / dltotal) * 100.0 : 0.0; - - auto now = std::chrono::steady_clock::now(); - auto duration = std::chrono::duration_cast(now.time_since_epoch()); - static bool log_flag = false; // Declare log_flag as static - if (!log_flag && duration.count() % 2 == 0) { - log_flag = true; - //std::printf("-Bootstrap: Download: %d%%\n", (uint8_t)progress); - LogPrintf("-Bootstrap: Download: %d%%\n", (uint8_t)progress); - uiInterface.ShowProgress(_("Download: "), (uint8_t)progress); - } else if (duration.count() % 2 != 0) { - log_flag = false; - } - - return 0; -} - - void InitLogging() { //g_logger->m_print_to_file = !IsArgNegated("-debuglogfile"); @@ -1090,10 +1069,6 @@ bool AppInit2() fReindex = GetBoolArg("-reindex", false); - // Initialize dynamic rewards - if(!CRewards::Init(fReindex)) - return false; - // Initialize elliptic curve code RandomInit(); ECC_Start(); @@ -1235,13 +1210,8 @@ bool AppInit2() } } - if (GetBoolArg("-resync", false) || GetBoolArg("-bootstrap", false) ) { - - if (GetBoolArg("-resync", false)) - uiInterface.InitMessage(_("Preparing for resync...")); - else if (GetBoolArg("-bootstrap", false)) - uiInterface.InitMessage(_("Preparing for bootstrap...")); - + if (GetBoolArg("-resync", false)) { + uiInterface.InitMessage(_("Preparing for resync...")); // Delete the local blockchain folders to force a resync from scratch to get a consitent blockchain-state fs::path blocksDir = GetDataDir() / "blocks"; fs::path chainstateDir = GetDataDir() / "chainstate"; @@ -1264,56 +1234,39 @@ bool AppInit2() fs::remove_all(sporksDir); LogPrintf("-resync: folder deleted: %s\n", sporksDir.string().c_str()); } - #ifdef ENABLE_BOOTSTRAP - if (GetBoolArg("-bootstrap", false)) { - const std::string url = std::string(BOOTSTRAP_URL)+std::string(TICKER)+"/bootstrap.zip"; - const std::string outputFileName = "bootstrap.zip"; - const std::string extractPath = "bootstrap_"; - - LogPrintf("-bootstrap: Download: %s\n", url.c_str()); - - Bootstrap::rmDirectory(extractPath); - - if (Bootstrap::DownloadFile(url, outputFileName, DownloadProgressCallback)) { - LogPrintf("-bootstrap: File downloaded successfully \n"); - - if (Bootstrap::extractZip(outputFileName, extractPath)) { - LogPrintf("-bootstrap: Zip file extracted successfully \n"); - try { - fs::rename(extractPath+"/blocks", blocksDir); - fs::rename(extractPath+"/chainstate", chainstateDir); - LogPrintf("-bootstrap: Folders moved successfully \n"); - } catch (const std::exception& e) { - LogPrintf("-bootstrap: Error moving folder: %s\n",e.what()); - } - - } else { - LogPrintf("-bootstrap: Error extracting zip file"); - } - - Bootstrap::rmDirectory(extractPath); - - } else { - LogPrintf("-bootstrap: Error downloading file"); - } - - if(fs::exists(outputFileName)) - fs::remove(outputFileName); - } - #else - LogPrintf("-bootstrap: not enabled\n"); - #endif } catch (const fs::filesystem_error& error) { LogPrintf("Failed to delete blockchain folders %s\n", error.what()); } } +#ifdef ENABLE_BOOTSTRAP + if (GetBoolArg("-bootstrap", false) ) { + + uiInterface.InitMessage(_("Preparing for bootstrap...")); + + try { + if (!CBootstrap::DownloadAndApply()) { + return UIError(_("Unable to download and apply the bootstrap file. See debug log for details.")); + } + + } catch (const std::exception& e) { + uiInterface.ThreadSafeMessageBox(_("Error downloading and applying the bootstrap file, shutting down."), "", CClientUIInterface::MSG_ERROR); + LogPrintf("Error downloading and applying the bootstrap file: %s\n", e.what()); + return false; + } + } +#endif + if (!CWallet::Verify()) return false; } // (!fDisableWallet) #endif // ENABLE_WALLET + // Initialize dynamic rewards + if(!CRewards::Init(fReindex)) + return false; + // ********************************************************* Step 6: network initialization assert(!g_connman); diff --git a/src/init.h b/src/init.h index a4c796820..aacd86615 100644 --- a/src/init.h +++ b/src/init.h @@ -10,8 +10,6 @@ #include -#include "bootstrap/bootstrap.h" - const bool DEFAULT_PROXYRANDOMIZE = true; const bool DEFAULT_REST_ENABLE = false; const bool DEFAULT_DISABLE_SAFEMODE = false; diff --git a/src/main.cpp b/src/main.cpp index af1d44e05..dce5e7d1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3790,7 +3790,8 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, const CBlock* pblock */ // If turned on Auto Combine will scan wallet for dust to combine - if (pwalletMain->fCombineDust) + // Combine dust every 30 blocks + if (pwalletMain->fCombineDust && newHeight % 30 == 0) pwalletMain->AutoCombineDust(connman); } diff --git a/src/main.h b/src/main.h index 3bd89b86d..75cf6e09a 100644 --- a/src/main.h +++ b/src/main.h @@ -143,7 +143,7 @@ struct BlockHasher { extern CScript COINBASE_FLAGS; extern RecursiveMutex cs_main; extern CTxMemPool mempool; -typedef std::unordered_map BlockMap; +typedef boost::unordered_map BlockMap; extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; diff --git a/src/masternode.cpp b/src/masternode.cpp index 95249eeaa..f5fab0a6b 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -189,17 +189,11 @@ void CMasternode::Check(bool forceCheck) { if (ShutdownRequested()) return; - const Consensus::Params& consensus = Params().GetConsensus(); - - // todo: add LOCK(cs) but be careful with the AcceptableInputs() below that requires cs_main. - - if (!forceCheck && (GetTime() - lastTimeChecked < MASTERNODE_CHECK_SECONDS)) return; - lastTimeChecked = GetTime(); - - //once spent, stop doing the checks if (activeState == MASTERNODE_VIN_SPENT) return; + if (!forceCheck && (GetTime() - lastTimeChecked < MASTERNODE_CHECK_SECONDS)) return; + lastTimeChecked = GetTime(); if (!IsPingedWithin(MASTERNODE_REMOVAL_SECONDS)) { activeState = MASTERNODE_REMOVE; @@ -216,7 +210,10 @@ void CMasternode::Check(bool forceCheck) return; } - if (!unitTest && lastTimeChecked - lastTimeCollateralChecked > MINUTE_IN_SECONDS) { + if (!unitTest && + forceCheck && + lastTimeChecked - lastTimeCollateralChecked > MINUTE_IN_SECONDS + ) { lastTimeCollateralChecked = lastTimeChecked; CValidationState state; CMutableTransaction tx = CMutableTransaction(); @@ -235,6 +232,8 @@ void CMasternode::Check(bool forceCheck) } } + const auto& consensus = Params().GetConsensus(); + // ----------- burn address scanning ----------- if (!consensus.mBurnAddresses.empty()) { @@ -677,7 +676,7 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) //take the newest entry LogPrint(BCLog::MASTERNODE, "mnb - Got updated entry for %s\n", vin.prevout.ToStringShort()); if (pmn->UpdateFromNewBroadcast((*this))) { - pmn->Check(); + pmn->Check(true); if (pmn->IsEnabled()) Relay(); } masternodeSync.AddedMasternodeList(GetHash()); diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index a4203a6fb..d06de3b1b 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -265,18 +265,26 @@ void CMasternodeMan::AskForMN(CNode* pnode, const CTxIn& vin) mWeAskedForMasternodeListEntry[vin.prevout] = askAgain; } -void CMasternodeMan::Check() +void CMasternodeMan::Check(bool forceCheck) { - LOCK2(cs_main, cs); + if(forceCheck) { + LOCK2(cs_main, cs); - for (auto mn : vMasternodes) { - mn->Check(); + for (auto mn : vMasternodes) { + mn->Check(forceCheck); + } + } else { + LOCK(cs); + + for (auto mn : vMasternodes) { + mn->Check(); + } } } void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) { - Check(); + Check(true); LOCK(cs); @@ -442,7 +450,7 @@ int CMasternodeMan::CountEnabled() { int i = 0; - LOCK2(cs_main, cs); + LOCK(cs); for (auto mn : vMasternodes) { mn->Check(); @@ -455,7 +463,7 @@ int CMasternodeMan::CountEnabled() void CMasternodeMan::CountNetworks(int& ipv4, int& ipv6, int& onion) { - LOCK2(cs_main, cs); + LOCK(cs); for (auto mn : vMasternodes) { mn->Check(); @@ -561,7 +569,7 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight vEligibleTxIns.clear(); int nMnCount = 0; { - LOCK2(cs_main, cs); + LOCK(cs); nMnCount = CountEnabled(); for (auto mn : vMasternodes) { @@ -656,7 +664,7 @@ CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight) int64_t score = 0; CMasternode* winner = NULL; - LOCK2(cs_main, cs); + LOCK(cs); // scan for winner for (auto mn : vMasternodes) { @@ -692,7 +700,7 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight) uint256 hash; if (!GetBlockHash(hash, nBlockHeight)) return defaultValue; - LOCK2(cs_main, cs); + LOCK(cs); // scan for winner for (auto mn : vMasternodes) { @@ -1002,10 +1010,7 @@ void ThreadCheckMasternodes() MilliSleep(1000); boost::this_thread::interruption_point(); // try to sync from all available nodes, one step at a time - { - LOCK(cs_main); - masternodeSync.Process(); - } + masternodeSync.Process(); if (masternodeSync.IsBlockchainSynced()) { c++; diff --git a/src/masternodeman.h b/src/masternodeman.h index e5dbe9e28..68145e0b9 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -17,6 +17,8 @@ #include "sync.h" #include "util.h" +#include + #define MASTERNODES_DUMP_SECONDS (15 * 60) #define MASTERNODES_DSEG_SECONDS (3 * 60 * 60) @@ -68,11 +70,11 @@ class CMasternodeMan // vector to hold all MNs std::vector vMasternodes; // map MNs by CScript - std::unordered_map mapScriptMasternodes; + boost::unordered_map mapScriptMasternodes; // map MNs by CTxIn - std::unordered_map mapTxInMasternodes; + boost::unordered_map mapTxInMasternodes; // map MNs by CTxIn - std::unordered_map mapPubKeyMasternodes; + boost::unordered_map mapPubKeyMasternodes; // who's asked for the Masternode list and the last time std::map mAskedUsForMasternodeList; // who we asked for the Masternode list and the last time @@ -157,7 +159,7 @@ class CMasternodeMan void AskForMN(CNode* pnode, const CTxIn& vin); /// Check all Masternodes - void Check(); + void Check(bool forceCheck = false); /// Check all Masternodes and remove inactive void CheckAndRemove(bool forceExpiredRemoval = false); diff --git a/src/memusage.h b/src/memusage.h index 8060f5fac..6fcf39127 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include +#include namespace memusage { @@ -169,13 +169,13 @@ struct unordered_node : private X }; template -static inline size_t DynamicUsage(const std::unordered_set& s) +static inline size_t DynamicUsage(const boost::unordered_set& s) { return MallocUsage(sizeof(unordered_node)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count()); } template -static inline size_t DynamicUsage(const std::unordered_map& m) +static inline size_t DynamicUsage(const boost::unordered_map& m) { return MallocUsage(sizeof(unordered_node >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count()); } diff --git a/src/miner.cpp b/src/miner.cpp index 25b98b1ab..db61fa8a9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -209,8 +209,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, // Collect memory pool transactions into the block CAmount nFees = 0; + LOCK(cs_main); + { - LOCK2(cs_main, mempool.cs); + LOCK(mempool.cs); + CCoinsViewCache view(pcoinsTip); // Priority order to process transactions @@ -408,13 +411,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, return nullptr; } } + } - CValidationState state; - if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) { - LogPrintf("CreateNewBlock() : TestBlockValidity failed\n"); - mempool.clear(); - return nullptr; - } + CValidationState state; + if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) { + LogPrintf("CreateNewBlock() : TestBlockValidity failed\n"); + mempool.clear(); + return nullptr; } return pblocktemplate.release(); diff --git a/src/bootstrap/minizip/ioapi.c b/src/minizip/ioapi.c similarity index 100% rename from src/bootstrap/minizip/ioapi.c rename to src/minizip/ioapi.c diff --git a/src/bootstrap/minizip/ioapi.h b/src/minizip/ioapi.h similarity index 100% rename from src/bootstrap/minizip/ioapi.h rename to src/minizip/ioapi.h diff --git a/src/bootstrap/minizip/unzip.c b/src/minizip/unzip.c similarity index 100% rename from src/bootstrap/minizip/unzip.c rename to src/minizip/unzip.c diff --git a/src/bootstrap/minizip/unzip.h b/src/minizip/unzip.h similarity index 100% rename from src/bootstrap/minizip/unzip.h rename to src/minizip/unzip.h diff --git a/src/net.h b/src/net.h index e69abcbf0..2f0b564f3 100644 --- a/src/net.h +++ b/src/net.h @@ -42,6 +42,8 @@ class CBlockIndex; class CScheduler; class CNode; +extern RecursiveMutex cs_main; + namespace boost { class thread_group; @@ -160,7 +162,7 @@ class CConnman template bool ForEachNodeContinueIf(Callable&& func) { - LOCK(cs_vNodes); + LOCK2(cs_main, cs_vNodes); for (auto&& node : vNodes) if (NodeFullyConnected(node)) { if (!func(node)) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 1278952c4..331e37293 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -29,6 +29,8 @@ #include #include +using namespace boost::placeholders; + static const int64_t nClientStartupTime = GetTime(); // Last tip update notification static int64_t nLastBlockTipUpdateNotification = 0; diff --git a/src/qt/pivx/dashboardwidget.cpp b/src/qt/pivx/dashboardwidget.cpp index c6d5f120f..2391f4758 100644 --- a/src/qt/pivx/dashboardwidget.cpp +++ b/src/qt/pivx/dashboardwidget.cpp @@ -144,7 +144,7 @@ bool hasCharts = false; #ifdef USE_QTCHARTS hasCharts = true; isLoading = false; - setChartShow(YEAR); + setChartShow(MONTH); connect(ui->pushButtonYear, &QPushButton::clicked, [this](){setChartShow(YEAR);}); connect(ui->pushButtonMonth, &QPushButton::clicked, [this](){setChartShow(MONTH);}); connect(ui->pushButtonAll, &QPushButton::clicked, [this](){setChartShow(ALL);}); @@ -424,6 +424,18 @@ void DashboardWidget::showHideEmptyChart(bool showEmpty, bool loading, bool forc ui->pushButtonAll->setEnabled(invLoading); ui->pushButtonYear->setEnabled(invLoading); ui->labelEmptyChart->setText(loading ? tr("Loading chart..") : tr("You have no staking rewards")); + + switch(this->chartShow) { + case MONTH: + ui->pushButtonMonth->setChecked(true); + break; + case YEAR: + ui->pushButtonYear->setChecked(true); + break; + case ALL: + ui->pushButtonAll->setChecked(true); + break; + } } void DashboardWidget::initChart() @@ -599,8 +611,8 @@ bool DashboardWidget::loadChartData(bool withMonthNames) qreal mnrewards = 0; if (chartData->amountsByCache.contains(num)) { QMap pair = chartData->amountsByCache[num]; - piv = (pair["piv"] != 0) ? pair["piv"] / 100000000 : 0; - mnrewards = (pair["mn"] != 0) ? pair["mn"] / 100000000 : 0; + piv = (pair["piv"] != 0) ? pair["piv"] / COIN : 0; + mnrewards = (pair["mn"] != 0) ? pair["mn"] / COIN : 0; chartData->totalPiv += pair["piv"]; chartData->totalMNRewards += pair["mn"]; } diff --git a/src/qt/pivx/forms/topbar.ui b/src/qt/pivx/forms/topbar.ui index cd96ede68..177512a16 100644 --- a/src/qt/pivx/forms/topbar.ui +++ b/src/qt/pivx/forms/topbar.ui @@ -678,7 +678,7 @@ - + 32 diff --git a/src/qt/pivx/pivxgui.cpp b/src/qt/pivx/pivxgui.cpp index f54579d95..c30eeb20d 100644 --- a/src/qt/pivx/pivxgui.cpp +++ b/src/qt/pivx/pivxgui.cpp @@ -36,6 +36,7 @@ #define BASE_WINDOW_MIN_HEIGHT 620 #define BASE_WINDOW_MIN_WIDTH 1100 +using namespace boost::placeholders; const QString PIVXGUI::DEFAULT_WALLET = "~Default"; diff --git a/src/qt/pivx/pivxgui.h b/src/qt/pivx/pivxgui.h index 8e6a99504..7fb198657 100644 --- a/src/qt/pivx/pivxgui.h +++ b/src/qt/pivx/pivxgui.h @@ -10,11 +10,18 @@ #include "config/pivx-config.h" #endif +#pragma GCC diagnostic push +#if defined(__GNUC__) && (__GNUC__ >= 9) +#pragma GCC diagnostic ignored "-Winit-list-lifetime" +#endif + #include #include #include #include +#pragma GCC diagnostic pop + #include "qt/pivx/navmenuwidget.h" #include "qt/pivx/topbar.h" #include "qt/pivx/dashboardwidget.h" diff --git a/src/qt/pivx/qtutils.h b/src/qt/pivx/qtutils.h index 98b0e1afa..24fb7863b 100644 --- a/src/qt/pivx/qtutils.h +++ b/src/qt/pivx/qtutils.h @@ -8,6 +8,11 @@ #include "qt/pivx/pivxgui.h" +#pragma GCC diagnostic push +#if defined(__GNUC__) && (__GNUC__ >= 9) +#pragma GCC diagnostic ignored "-Winit-list-lifetime" +#endif + #include #include #include @@ -20,6 +25,8 @@ #include #include +#pragma GCC diagnostic pop + #include // Repair parameters diff --git a/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui b/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui index 4df7a8f89..d5130ae21 100644 --- a/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui +++ b/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui @@ -109,7 +109,7 @@ - + Qt::Horizontal @@ -411,7 +411,7 @@ - + Qt::Horizontal diff --git a/src/qt/pivx/splash.cpp b/src/qt/pivx/splash.cpp index 393a6a0cf..613185551 100644 --- a/src/qt/pivx/splash.cpp +++ b/src/qt/pivx/splash.cpp @@ -24,6 +24,8 @@ #include +using namespace boost::placeholders; + Splash::Splash(Qt::WindowFlags f, const NetworkStyle* networkStyle) : QWidget(0, f | Qt::SplashScreen), ui(new Ui::Splash) { diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 96c1a27c3..959ddcb12 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -30,6 +30,8 @@ #include #include +using namespace boost::placeholders; + // Amount column is right-aligned it contains numbers static int column_alignments[] = { Qt::AlignLeft | Qt::AlignVCenter, /* status */ @@ -338,7 +340,7 @@ class TransactionTablePriv if (lockMain) { TRY_LOCK(wallet->cs_wallet, lockWallet); if (lockWallet && rec->statusUpdateNeeded()) { - std::map::iterator mi = wallet->mapWallet.find(rec->hash); + auto mi = wallet->mapWallet.find(rec->hash); if (mi != wallet->mapWallet.end()) { rec->updateStatus(mi->second); diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index e1a587e18..23b2b1f6d 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -7,10 +7,17 @@ #ifndef BITCOIN_QT_UTILITYDIALOG_H #define BITCOIN_QT_UTILITYDIALOG_H +#pragma GCC diagnostic push +#if defined(__GNUC__) && (__GNUC__ >= 9) +#pragma GCC diagnostic ignored "-Winit-list-lifetime" +#endif + #include #include #include +#pragma GCC diagnostic pop + class ClientModel; namespace Ui diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index b462e88fd..3f07304b8 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -29,6 +29,7 @@ #include #include +using namespace boost::placeholders; WalletModel::WalletModel(CWallet* wallet, OptionsModel* optionsModel, QObject* parent) : QObject(parent), wallet(wallet), walletWrapper(*wallet), optionsModel(optionsModel), diff --git a/src/rewards.cpp b/src/rewards.cpp index 97c35b1a6..0addde263 100644 --- a/src/rewards.cpp +++ b/src/rewards.cpp @@ -12,13 +12,14 @@ #include "sqlite3/sqlite3.h" #include "timedata.h" #include "utilmoneystr.h" +#include "utiltime.h" #include #include #include -#include +#include -std::unordered_map mDynamicRewards; +boost::unordered_map mDynamicRewards; sqlite3* db = nullptr; sqlite3_stmt* insertStmt = nullptr; @@ -29,107 +30,130 @@ bool CRewards::Init(bool fReindex) std::ostringstream oss; auto ok = true; - try - { - const std::string dirname = (GetDataDir() / "chainstate").string(); - const std::string filename = (GetDataDir() / "chainstate" / "rewards.db").string(); - - // Create the chainstate directory if it doesn't exist - if (!fs::exists(dirname.c_str())) { - // Directory doesn't exist, create it - if (fs::create_directory(dirname.c_str())) { - oss << "CRewards::" << __func__ << " Created directory: " << dirname << std::endl; - } else { - oss << "CRewards::" << __func__ << " Failed to create directory: " << dirname << std::endl; - ok = false; - } - } - - // Delete the database file if it exists when reindexing - if(ok && fReindex) + if(db == nullptr) { + try { - if (auto file = std::fopen(filename.c_str(), "r")) { - std::fclose(file); - // File exists, delete it - if (std::remove(filename.c_str()) == 0) { - oss << "CRewards::" << __func__ << " Deleted existing database file: " << filename << std::endl; + const std::string dirname = (GetDataDir() / "chainstate").string(); + const std::string filename = (GetDataDir() / "chainstate" / "rewards.db").string(); + + // Create the chainstate directory if it doesn't exist + if (!fs::exists(dirname.c_str())) { + // Directory doesn't exist, create it + if (fs::create_directory(dirname.c_str())) { + oss << "Created directory: " << dirname << std::endl; } else { - oss << "CRewards::" << __func__ << " Failed to delete existing database file: " << filename << std::endl; + oss << "Failed to create directory: " << dirname << std::endl; ok = false; } } - } - if(ok) { // Create and/or open the database - oss << "CRewards::" << __func__ << " Opening database: " << filename << std::endl; - auto rc = sqlite3_open(filename.c_str(), &db); - - if (rc) + // Delete the database file if it exists when reindexing + if(ok && fReindex) { - oss << "CRewards::" << __func__ << " Can't open database: " << sqlite3_errmsg(db) << std::endl; - ok = false; + if (auto file = std::fopen(filename.c_str(), "r")) { + std::fclose(file); + // File exists, delete it + if (std::remove(filename.c_str()) == 0) { + oss << "Deleted existing database file: " << filename << std::endl; + } else { + oss << "Failed to delete existing database file: " << filename << std::endl; + ok = false; + } + } + } + + if(ok) { // Create and/or open the database + // the wallet sometimes restarts + // and the restart starts by spawnning a new wallet instance + // before the current instance closes + // so let's try to open it several times before giving up + for (auto attempt = 1; attempt <= DB_OPEN_ATTEMPTS; attempt++) { + oss << "Opening database: " << filename << std::endl; + auto rc = sqlite3_open(filename.c_str(), &db); + + if (rc) { // NOK + if(attempt < DB_OPEN_ATTEMPTS) { + MilliSleep(DB_OPEN_WAITING_TIME); + } else { + oss << "Can't open database: " << sqlite3_errmsg(db) << std::endl; + ok = false; + break; // giving up + } + } else { + break; // all good + } + } } - } - if(ok) { // database is open and working - // Create the rewards table if not exists - const auto create_table_query = "CREATE TABLE IF NOT EXISTS rewards (height INT PRIMARY KEY, amount INTEGER)"; - auto rc = sqlite3_exec(db, create_table_query, NULL, NULL, NULL); + if(ok) { // database is open and working + // Create the rewards table if not exists + const auto create_table_query = "CREATE TABLE IF NOT EXISTS rewards (height INT PRIMARY KEY, amount INTEGER)"; + auto rc = sqlite3_exec(db, create_table_query, NULL, NULL, NULL); - if (rc != SQLITE_OK) { - oss << "CRewards::" << __func__ << " SQL error: " << sqlite3_errmsg(db) << std::endl; - ok = false; + if (rc != SQLITE_OK) { + oss << "SQL error: " << sqlite3_errmsg(db) << std::endl; + ok = false; + } } - } - if(ok) { // Create insert statement - const std::string insertSql = "INSERT OR REPLACE INTO rewards (height, amount) VALUES (?, ?)"; - auto rc = sqlite3_prepare_v2(db, insertSql.c_str(), insertSql.length(), &insertStmt, nullptr); - if (rc != SQLITE_OK) { - oss << "CRewards::" << __func__ << " SQL error: " << sqlite3_errmsg(db) << std::endl; - ok = false; + if(ok) { // Create insert statement + const std::string insertSql = "INSERT OR REPLACE INTO rewards (height, amount) VALUES (?, ?)"; + auto rc = sqlite3_prepare_v2(db, insertSql.c_str(), insertSql.length(), &insertStmt, nullptr); + if (rc != SQLITE_OK) { + oss << "SQL error: " << sqlite3_errmsg(db) << std::endl; + ok = false; + } } - } - if(ok) { // Create delete statement - const std::string deleteSql = "DELETE FROM rewards WHERE height >= ?"; - auto rc = sqlite3_prepare_v2(db, deleteSql.c_str(), deleteSql.length(), &deleteStmt, nullptr); - if (rc != SQLITE_OK) { - oss << "CRewards::" << __func__ << " SQL error: " << sqlite3_errmsg(db) << std::endl; - ok = false; + if(ok) { // Create delete statement + const std::string deleteSql = "DELETE FROM rewards WHERE height >= ?"; + auto rc = sqlite3_prepare_v2(db, deleteSql.c_str(), deleteSql.length(), &deleteStmt, nullptr); + if (rc != SQLITE_OK) { + oss << "SQL error: " << sqlite3_errmsg(db) << std::endl; + ok = false; + } } - } - if(ok) { // Loads the database into the in-memory map - const char* sql = "SELECT height, amount FROM rewards"; - auto rc = sqlite3_exec(db, sql, [](void* data, int argc, char** argv, char** /* azColName */) -> int { - int height = std::stoi(argv[0]); - CAmount amount = std::stoll(argv[1]); - mDynamicRewards[height] = amount; - return 0; - }, nullptr, nullptr); - - if (rc != SQLITE_OK) { - oss << "CRewards::" << __func__ << " SQL error: " << sqlite3_errmsg(db) << std::endl; - ok = false; + if(ok) { // Loads the database into the in-memory map + const char* sql = "SELECT height, amount FROM rewards"; + auto rc = sqlite3_exec(db, sql, [](void* data, int argc, char** argv, char** /* azColName */) -> int { + int height = std::stoi(argv[0]); + CAmount amount = std::stoll(argv[1]); + mDynamicRewards[height] = amount; + return 0; + }, nullptr, nullptr); + + if (rc != SQLITE_OK) { + oss << "SQL error: " << sqlite3_errmsg(db) << std::endl; + ok = false; + } } - } - if(ok && mDynamicRewards.size() > 0) { // Printing the map - oss << "CRewards::" << __func__ << " Dynamic Rewards:" << std::endl; - for (const auto& pair : mDynamicRewards) { - oss << "CRewards::" << __func__ << " Height: " << pair.first << ", Amount: " << FormatMoney(pair.second) << std::endl; + if(ok && mDynamicRewards.size() > 0) { // Printing the map + oss << "Dynamic Rewards:" << std::endl; + for (const auto& pair : mDynamicRewards) { + oss << "Height: " << pair.first << ", Amount: " << FormatMoney(pair.second) << std::endl; + } } } - } - catch(const std::exception& e) - { - oss << "CRewards::" << __func__ << " An exception was thrown: " << e.what() << std::endl; - ok = false; + catch(const std::exception& e) + { + oss << "An exception was thrown: " << e.what() << std::endl; + ok = false; + } + } else { + oss << "Already initialized" << std::endl; } - if (!oss.str().empty()) LogPrintf("%s: %s", __func__, oss.str()); - + std::string log = oss.str(); + if (!log.empty()) { + std::istringstream iss(log); + std::string line; + while (std::getline(iss, line)) { + LogPrintf("CRewards::%s: %s\n", __func__, line); + } + } + return ok; } @@ -163,7 +187,8 @@ bool CRewards::IsDynamicRewardsEpochHeight(int nHeight) bool CRewards::ConnectBlock(CBlockIndex* pindex, CAmount nSubsidy, CCoinsViewCache& coins) { - auto& consensus = Params().GetConsensus(); + auto& params = Params(); + auto& consensus = params.GetConsensus(); const auto nHeight = pindex->nHeight; const auto nEpochHeight = GetDynamicRewardsEpochHeight(nHeight); std::ostringstream oss; @@ -183,7 +208,7 @@ bool CRewards::ConnectBlock(CBlockIndex* pindex, CAmount nSubsidy, CCoinsViewCac // get total money supply const auto nMoneySupply = pindex->nMoneySupply.get(); - oss << "CRewards::" << __func__ << " nMoneySupply: " << FormatMoney(nMoneySupply) << std::endl; + oss << "nMoneySupply: " << FormatMoney(nMoneySupply) << std::endl; // get the current masternode collateral, and the next week collateral auto nCollateralAmount = CMasternode::GetMasternodeNodeCollateral(nHeight); @@ -220,7 +245,7 @@ bool CRewards::ConnectBlock(CBlockIndex* pindex, CAmount nSubsidy, CCoinsViewCac // ----------- UTXOs age related scanning ----------- auto nBlocksDiff = static_cast(nHeight - coin.nHeight); - const auto nMultiplier = 100000000L; + const auto nMultiplier = 100000000LL; // y = mx + b // 3 months old or less => 100% @@ -232,47 +257,67 @@ bool CRewards::ConnectBlock(CBlockIndex* pindex, CAmount nSubsidy, CCoinsViewCac 0LL), 100LL); - nCirculatingSupply += coin.out.nValue * nSupplyWeightRatio / 100L; + nCirculatingSupply += coin.out.nValue * nSupplyWeightRatio / 100LL; } pcursor->Next(); } - oss << "CRewards::" << __func__ << " nCirculatingSupply: " << FormatMoney(nCirculatingSupply) << std::endl; + oss << "nCirculatingSupply: " << FormatMoney(nCirculatingSupply) << std::endl; - // calculate target emissions + // calculate the epoch's average staking power const auto nRewardAdjustmentInterval = consensus.nRewardAdjustmentInterval; - oss << "CRewards::" << __func__ << " nRewardAdjustmentInterval: " << nRewardAdjustmentInterval << std::endl; + oss << "nRewardAdjustmentInterval: " << nRewardAdjustmentInterval << std::endl; + const auto nTimeSlotLength = consensus.TimeSlotLength(nHeight); + oss << "nTimeSlotLength: " << nTimeSlotLength << std::endl; + const auto endBlock = chainActive.Tip(); + const auto startBlock = chainActive[endBlock->nHeight - std::min(nRewardAdjustmentInterval, endBlock->nHeight)]; + const auto nTimeDiff = endBlock->GetBlockTime() - startBlock->GetBlockTime(); + const auto nWorkDiff = endBlock->nChainWork - startBlock->nChainWork; + const auto nNetworkHashPS = static_cast(nWorkDiff.getdouble() / nTimeDiff); + oss << "nNetworkHashPS: " << nNetworkHashPS << std::endl; + const auto nStakedCoins = static_cast(nNetworkHashPS * nTimeSlotLength * 100); + oss << "nStakedCoins: " << FormatMoney(nStakedCoins) << std::endl; + + // Remove the staked supply from circulating supply + nCirculatingSupply = std::max(nCirculatingSupply - nStakedCoins, CAmount(0)); + oss << "nCirculatingSupply without staked coins: " << FormatMoney(nCirculatingSupply) << std::endl; + + // calculate target emissions const auto nTotalEmissionRate = sporkManager.GetSporkValue(SPORK_116_TOT_SPLY_TRGT_EMISSION); - oss << "CRewards::" << __func__ << " nTotalEmissionRate: " << nTotalEmissionRate << std::endl; + oss << "nTotalEmissionRate: " << nTotalEmissionRate << std::endl; const auto nCirculatingEmissionRate = sporkManager.GetSporkValue(SPORK_117_CIRC_SPLY_TRGT_EMISSION); - oss << "CRewards::" << __func__ << " nCirculatingEmissionRate: " << nCirculatingEmissionRate << std::endl; + oss << "nCirculatingEmissionRate: " << nCirculatingEmissionRate << std::endl; const auto nActualEmission = nSubsidy * nRewardAdjustmentInterval; - oss << "CRewards::" << __func__ << " nActualEmission: " << FormatMoney(nActualEmission) << std::endl; - const auto nSupplyTargetEmission = ((nMoneySupply / (365L * nBlocksPerDay)) / 1000000) * nTotalEmissionRate * nRewardAdjustmentInterval; - oss << "CRewards::" << __func__ << " nSupplyTargetEmission: " << FormatMoney(nSupplyTargetEmission) << std::endl; - const auto nCirculatingTargetEmission = ((nCirculatingSupply / (365L * nBlocksPerDay)) / 1000000) * nCirculatingEmissionRate * nRewardAdjustmentInterval; - oss << "CRewards::" << __func__ << " nCirculatingTargetEmission: " << FormatMoney(nCirculatingTargetEmission) << std::endl; + oss << "nActualEmission: " << FormatMoney(nActualEmission) << std::endl; + const auto nSupplyTargetEmission = ((nMoneySupply / (365LL * nBlocksPerDay)) / 1000000) * nTotalEmissionRate * nRewardAdjustmentInterval; + oss << "nSupplyTargetEmission: " << FormatMoney(nSupplyTargetEmission) << std::endl; + const auto nCirculatingTargetEmission = ((nCirculatingSupply / (365LL * nBlocksPerDay)) / 1000000) * nCirculatingEmissionRate * nRewardAdjustmentInterval; + oss << "nCirculatingTargetEmission: " << FormatMoney(nCirculatingTargetEmission) << std::endl; + const auto nTargetEmission = (nSupplyTargetEmission + nCirculatingTargetEmission) / 2LL; + oss << "nTargetEmission: " << FormatMoney(nTargetEmission) << std::endl; // calculate required delta values - const auto nDelta = (nActualEmission - std::max(nSupplyTargetEmission, nCirculatingTargetEmission)) / nRewardAdjustmentInterval; - oss << "CRewards::" << __func__ << " nDelta: " << FormatMoney(nDelta) << std::endl; + const auto nDelta = (nActualEmission - nTargetEmission) / nRewardAdjustmentInterval; + oss << "nDelta: " << FormatMoney(nDelta) << std::endl; // y = mx + b // <= 0% |ratio| => 1% // >= 100% |ratio| => 10% const auto nRatio = std::llabs((nDelta * 100) / nSubsidy); // percentage of the difference on emissions and the current reward - oss << "CRewards::" << __func__ << " nRatio: " << nRatio << std::endl; + oss << "nRatio: " << nRatio << std::endl; const auto nWeightRatio = ((std::min(nRatio, 100LL) * 9LL) / 100LL) + 1LL; const auto nDampedDelta = nDelta * nWeightRatio / 100LL; - oss << "CRewards::" << __func__ << " nDampedDelta: " << FormatMoney(nDampedDelta) << std::endl; + oss << "nDampedDelta: " << FormatMoney(nDampedDelta) << std::endl; // adjust the reward for this epoch nNewSubsidy = nSubsidy - nDampedDelta; + // removes decimal places + nNewSubsidy = (nNewSubsidy / COIN) * COIN; - oss << "CRewards::" << __func__ << " Adjustment at height " << nHeight << ": " << FormatMoney(nSubsidy) << " => " << FormatMoney(nNewSubsidy) << std::endl; + oss << "Adjustment at height " << nHeight << ": " << FormatMoney(nSubsidy) << " => " << FormatMoney(nNewSubsidy) << std::endl; } if ( // if the wallet is syncing get the reward value from the blocks of the epoch @@ -290,14 +335,21 @@ bool CRewards::ConnectBlock(CBlockIndex* pindex, CAmount nSubsidy, CCoinsViewCac sqlite3_bind_int64(insertStmt, 2, nNewSubsidy); auto rc = sqlite3_step(insertStmt); if (rc != SQLITE_DONE) { - oss << "CRewards::" << __func__ << " SQL error: " << sqlite3_errmsg(db) << std::endl; + oss << "SQL error: " << sqlite3_errmsg(db) << std::endl; ok = false; } sqlite3_reset(insertStmt); } } - if (!oss.str().empty()) LogPrintf("%s: %s", __func__, oss.str()); + std::string log = oss.str(); + if (!log.empty()) { + std::istringstream iss(log); + std::string line; + while (std::getline(iss, line)) { + LogPrintf("CRewards::%s: %s\n", __func__, line); + } + } return ok; } @@ -322,7 +374,7 @@ bool CRewards::DisconnectBlock(CBlockIndex* pindex) sqlite3_bind_int(deleteStmt, 1, nHeight); // on the file database auto rc = sqlite3_step(deleteStmt); if (rc != SQLITE_DONE) { - oss << "CRewards::" << __func__ << " SQL error: " << sqlite3_errmsg(db) << std::endl; + oss << "SQL error: " << sqlite3_errmsg(db) << std::endl; ok = false; } sqlite3_reset(deleteStmt); @@ -331,11 +383,18 @@ bool CRewards::DisconnectBlock(CBlockIndex* pindex) } catch(const std::exception& e) { - oss << "CRewards::" << __func__ << " An exception was thrown: " << e.what() << std::endl; + oss << "An exception was thrown: " << e.what() << std::endl; ok = false; } - if (!oss.str().empty()) LogPrintf("%s: %s", __func__, oss.str()); + std::string log = oss.str(); + if (!log.empty()) { + std::istringstream iss(log); + std::string line; + while (std::getline(iss, line)) { + LogPrintf("CRewards::%s: %s\n", __func__, line); + } + } return ok; } diff --git a/src/rewards.h b/src/rewards.h index d7af45457..f8ae3ef8d 100644 --- a/src/rewards.h +++ b/src/rewards.h @@ -11,6 +11,9 @@ class CRewards { +private: + static const int DB_OPEN_ATTEMPTS = 3; // number of attempts + static const int DB_OPEN_WAITING_TIME = 10000; // ms public: static bool Init(bool fReindex); static void Shutdown(); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 90b4d57d8..a337f6d4b 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -677,7 +677,6 @@ UniValue getactivemasternodecount (const JSONRPCRequest& request) return obj; } - UniValue getmasternodestatus(const JSONRPCRequest& request) { if (request.fHelp || (request.params.size() != 0)) @@ -904,6 +903,7 @@ bool DecodeHexMnb(CMasternodeBroadcast& mnb, std::string strHexMnb) { return true; } + UniValue createmasternodebroadcast(const JSONRPCRequest& request) { // wait for reindex and/or import to finish diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index d02c724f0..4d0111626 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -11,9 +11,13 @@ #include "httpserver.h" #include "init.h" #include "main.h" +#include "masternode.h" +#include "masternodeconfig.h" +#include "masternodeman.h" #include "masternode-sync.h" #include "net.h" #include "netbase.h" +#include "rewards.h" #include "rpc/server.h" #include "spork.h" #include "timedata.h" @@ -688,6 +692,7 @@ UniValue getstakingstatus(const JSONRPCRequest& request) " \"stakeablecoins\": n (numeric) number of stakeable UTXOs\n" " \"stakingbalance\": d (numeric) KYAN value of the stakeable coins (minus reserve balance, if any)\n" " \"stakesplitthreshold\": d (numeric) value of the current threshold for stake split\n" + " \"autocombinethreshold\": d (numeric) value of the current threshold for auto combine\n" " \"lastattempt_age\": n (numeric) seconds since last stake attempt\n" " \"lastattempt_depth\": n (numeric) depth of the block on top of which the last stake attempt was made\n" " \"lastattempt_hash\": xxx (hex string) hash of the block on top of which the last stake attempt was made\n" @@ -715,6 +720,7 @@ UniValue getstakingstatus(const JSONRPCRequest& request) obj.push_back(Pair("stakeablecoins", (int)vCoins.size())); obj.push_back(Pair("stakingbalance", ValueFromAmount(pwalletMain->GetStakingBalance()))); obj.push_back(Pair("stakesplitthreshold", ValueFromAmount(pwalletMain->nStakeSplitThreshold))); + obj.push_back(Pair("autocombinethreshold", ValueFromAmount(pwalletMain->fCombineDust ? pwalletMain->nAutoCombineThreshold : 0))); CStakerStatus* ss = pwalletMain->pStakerStatus; if (ss) { obj.push_back(Pair("lastattempt_age", (int)(GetTime() - ss->GetLastTime()))); @@ -725,7 +731,460 @@ UniValue getstakingstatus(const JSONRPCRequest& request) } return obj; } +} + +UniValue getrewardsinfo(const JSONRPCRequest& request) +{ + std::string info_type = "both"; // Default value + + if (request.fHelp || (request.params.size() > 1 || (request.params.size() == 1 && !request.params[0].isStr()))) { + throw std::runtime_error( + "getrewardsinfo ( \"info_type\" )\n" + "\nReturns an object containing ROI information.\n" + + "\nArguments:\n" + "1. \"info_type\" (string, optional, default=\"both\") The type of info to display (\"network\", \"wallet\", or \"both\")\n" + + "\nResult:\n" + "{\n" + " \"network\": {\n" + " \"reward\": d, (numeric) reward per block\n" + " \"allocated_coins\": d, (numeric) total number of allocated coins\n" + " \"allocation\": \"xx.xx%\", (string) percentage of total allocation\n" + " \"blocks\": {\n" + " \"day\": n, (numeric) blocks generated per day\n" + " \"week\": n, (numeric) blocks generated per week\n" + " \"month\": n, (numeric) blocks generated per month\n" + " \"year\": n (numeric) blocks generated per year\n" + " },\n" + " \"staking\": {\n" + " \"reward\": d, (numeric) staking reward per block\n" + " \"hashrate\": {\n" + " \"networkhashps\": \"xxxxx\", (string) network hash rate per second\n" + " \"allocated_coins\": d, (numeric) number of allocated coins for staking\n" + " \"roi\": \"xx.xx%\" (string) return on investment for staking\n" + " },\n" + " \"smooth_hashrate\": {\n" + " \"networkhashps\": \"xxxxx\", (string) smoothed network hash rate per second\n" + " \"allocated_coins\": d, (numeric) number of allocated coins for smoothed staking\n" + " \"roi\": \"xx.xx%\" (string) smoothed return on investment for staking\n" + " },\n" + " \"allocation\": \"xx.xx%\" (string) percentage of staking allocation\n" + " },\n" + " \"masternoding\": {\n" + " \"reward\": d, (numeric) masternode reward per block\n" + " \"collateral\": d, (numeric) required collateral for a masternode\n" + " \"nextweek_collateral\": d, (numeric) next week's required collateral for a masternode\n" + " \"enabled_masternodes\": d, (numeric) number of enabled masternodes\n" + " \"allocated_coins\": d, (numeric) number of allocated coins for masternodes\n" + " \"allocation\": \"xx.xx%\", (string) percentage of masternode allocation\n" + " \"daily\": d, (numeric) daily masternode reward\n" + " \"daily_roi\": \"xx.xx%\", (string) daily return on investment for masternodes\n" + " \"weekly\": d, (numeric) weekly masternode reward\n" + " \"weekly_roi\": \"xx.xx%\", (string) weekly return on investment for masternodes\n" + " \"monthly\": d, (numeric) monthly masternode reward\n" + " \"monthly_roi\": \"xx.xx%\", (string) monthly return on investment for masternodes\n" + " \"yearly\": d, (numeric) yearly masternode reward\n" + " \"yearly_roi\": \"xx.xx%\" (string) yearly return on investment for masternodes\n" + " }\n" + " },\n" + " \"wallet\": {\n" + " \"staking\": {\n" + " \"status\": true|false, (boolean) whether the wallet is staking or not\n" + " \"tries\": n, (numeric) number of tries for staking\n" + " \"allocated_coins\": d, (numeric) number of allocated coins in the wallet for staking\n" + " \"share\": \"xx.xx%\", (string) wallet's share of the staking allocation\n" + " \"stakesplitthreshold\": d, (numeric) value of the current threshold for stake split\n" + " \"autocombinethreshold\": d, (numeric) value of the current threshold for auto combine\n" + " \"regular\": {\n" + " \"daily\": d, (numeric) daily staking reward\n" + " \"daily_roi\": \"xx.xx%\", (string) daily return on investment for staking\n" + " \"weekly\": d, (numeric) weekly staking reward\n" + " \"weekly_roi\": \"xx.xx%\", (string) weekly return on investment for staking\n" + " \"monthly\": d, (numeric) monthly staking reward\n" + " \"monthly_roi\": \"xx.xx%\", (string) monthly return on investment for staking\n" + " \"yearly\": d, (numeric) yearly staking reward\n" + " \"yearly_roi\": \"xx.xx%\" (string) yearly return on investment for staking\n" + " },\n" + " \"compound\": {\n" + " \"daily\": d, (numeric) compounded daily staking reward\n" + " \"daily_roi\": \"xx.xx%\", (string) compounded daily return on investment for staking\n" + " \"weekly\": d, (numeric) compounded weekly staking reward\n" + " \"weekly_roi\": \"xx.xx%\", (string) compounded weekly return on investment for staking\n" + " \"monthly\": d, (numeric) compounded monthly staking reward\n" + " \"monthly_roi\": \"xx.xx%\", (string) compounded monthly return on investment for staking\n" + " \"yearly\": d, (numeric) compounded yearly staking reward\n" + " \"yearly_roi\": \"xx.xx%\" (string) compounded yearly return on investment for staking\n" + " }\n" + " },\n" + " \"masternoding\": {\n" + " \"masternodes\": n, (numeric) number of masternodes owned by the wallet\n" + " \"allocated_coins\": d, (numeric) number of allocated coins in the wallet for masternoding\n" + " \"share\": \"xx.xx%\", (string) wallet's share of the masternode allocation\n" + " \"daily\": d, (numeric) daily masternode reward\n" + " \"daily_roi\": \"xx.xx%\", (string) daily return on investment for masternodes\n" + " \"weekly\": d, (numeric) weekly masternode reward\n" + " \"weekly_roi\": \"xx.xx%\", (string) weekly return on investment for masternodes\n" + " \"monthly\": d, (numeric) monthly masternode reward\n" + " \"monthly_roi\": \"xx.xx%\", (string) monthly return on investment for masternodes\n" + " \"yearly\": d, (numeric) yearly masternode reward\n" + " \"yearly_roi\": \"xx.xx%\" (string) yearly return on investment for masternodes\n" + " }\n" + " }\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("getrewardsinfo", "") + HelpExampleRpc("getrewardsinfo", "")); + } + + if (request.params.size() == 1) { + info_type = request.params[0].get_str(); + if (info_type != "network" && info_type != "wallet" && info_type != "both") { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid info_type parameter, must be \"network\", \"wallet\", or \"both\""); + } + } + + if (pwalletMain) { + if (!masternodeSync.IsSynced()) { + throw JSONRPCError(RPC_IN_WARMUP, "Try again after the chain is fully synced"); + } + + const auto& params = Params(); + const auto& consensus = params.GetConsensus(); + + const auto tip = chainActive.Tip(); + const auto nHeight = tip->nHeight; + + // Fetch consensus parameters + const auto nTargetSpacing = consensus.nTargetSpacing; + const auto nTargetTimespan = consensus.TargetTimespan(nHeight); + const auto nTimeSlotLength = consensus.TimeSlotLength(nHeight); + + // Fetch reward details + const auto nBlockValue = CRewards::GetBlockValue(nHeight); + const auto nMNReward = CMasternode::GetMasternodePayment(nHeight); + const auto nStakeReward = nBlockValue - nMNReward; + + const auto nBlocksPerDay = DAY_IN_SECONDS / nTargetSpacing; + const auto nBlocksPerWeek = WEEK_IN_SECONDS / nTargetSpacing; + const auto nBlocksPerMonth = MONTH_IN_SECONDS / nTargetSpacing; + const auto nBlocksPerYear = YEAR_IN_SECONDS / nTargetSpacing; + + // Fetch the network generated hashes per second + const auto nBlocks = static_cast(nTargetTimespan / nTargetSpacing); + const auto startBlock = chainActive[nHeight - std::min(nBlocks, nHeight)]; + const auto endBlock = tip; + const auto nTimeDiff = endBlock->GetBlockTime() - startBlock->GetBlockTime(); + const auto nWorkDiff = endBlock->nChainWork - startBlock->nChainWork; + const auto nNetworkHashPS = static_cast(nWorkDiff.getdouble() / nTimeDiff); + + const auto nSmoothBlocks = static_cast((3 * HOUR_IN_SECONDS) / nTargetSpacing); + const auto startSmoothBlock = chainActive[nHeight - std::min(nSmoothBlocks, nHeight)]; + const auto nSmoothTimeDiff = endBlock->GetBlockTime() - startSmoothBlock->GetBlockTime(); + const auto nSmoothWorkDiff = endBlock->nChainWork - startSmoothBlock->nChainWork; + const auto nSmoothNetworkHashPS = static_cast(nSmoothWorkDiff.getdouble() / nSmoothTimeDiff); + + // Calculate how many coins are allocated in the entire staking algorithm + const auto nStakedCoins = static_cast(nNetworkHashPS * nTimeSlotLength * 100); + const auto nSmoothStakedCoins = static_cast(nSmoothNetworkHashPS * nTimeSlotLength * 100); + const auto nStakingAllocation = static_cast(nSmoothStakedCoins) / tip->nMoneySupply.get(); + const auto nYearlyStakingRewards = nStakeReward * nBlocksPerYear; + auto nStakingROI = nYearlyStakingRewards / nStakedCoins; + auto nSmoothStakingROI = nYearlyStakingRewards / nSmoothStakedCoins; + + // Fetch the masternode related data + const auto nMNCollateral = CMasternode::GetMasternodeNodeCollateral(nHeight); + const auto nMNNextWeekCollateral = CMasternode::GetNextWeekMasternodeCollateral(); + const auto nMNEnabled = mnodeman.CountEnabled(); + const auto nMNCoins = nMNCollateral * nMNEnabled; + const auto nMNAllocation = static_cast(nMNCoins) / tip->nMoneySupply.get(); + + const auto nTotalAllocationCoins = nSmoothStakedCoins + nMNCoins; + const auto nTotalAllocation = nStakingAllocation + nMNAllocation; + + const auto nYearlyMNRewards = nMNReward * nBlocksPerYear; + const auto nMasternodingRewards = static_cast((nMNReward * nBlocksPerYear) / nMNEnabled); + const auto nDailyMasternodingRewards = nMasternodingRewards / 365; + + const auto fStakingActive = pwalletMain->pStakerStatus->IsActive(); + const auto nStakedBalance = + pwalletMain->mapWallet.empty() ? + 0 : + fStakingActive ? + pwalletMain->pStakerStatus->GetLastValue() : + pwalletMain->GetStakingBalance(); + const auto nStakeShare = static_cast(nStakedBalance) / nSmoothStakedCoins; + + UniValue obj(UniValue::VOBJ); + + if (info_type == "network" || info_type == "both") { + UniValue networkObj(UniValue::VOBJ); + + networkObj.push_back(Pair("reward", ValueFromAmount(nBlockValue))); + networkObj.push_back(Pair("allocated_coins", ValueFromAmount(nTotalAllocationCoins))); + networkObj.push_back(Pair("allocation", strprintf("%4.2f%%", nTotalAllocation * 100))); + + UniValue blocksObj(UniValue::VOBJ); + blocksObj.push_back(Pair("day", nBlocksPerDay)); + blocksObj.push_back(Pair("week", nBlocksPerWeek)); + blocksObj.push_back(Pair("month", nBlocksPerMonth)); + blocksObj.push_back(Pair("year", nBlocksPerYear)); + networkObj.push_back(Pair("blocks", blocksObj)); + + UniValue stakingObj(UniValue::VOBJ); + + stakingObj.push_back(Pair("reward", ValueFromAmount(nStakeReward))); + + UniValue hashRateObj(UniValue::VOBJ); + hashRateObj.push_back(Pair("networkhashps", GetReadableHashRate(nNetworkHashPS))); + hashRateObj.push_back(Pair("allocated_coins", ValueFromAmount(nStakedCoins))); + hashRateObj.push_back(Pair("roi", strprintf("%4.2f%%", nStakingROI * 100))); + stakingObj.push_back(Pair("hashrate", hashRateObj)); + + UniValue smoothHashRateObj(UniValue::VOBJ); + smoothHashRateObj.push_back(Pair("networkhashps", GetReadableHashRate(nSmoothNetworkHashPS))); + smoothHashRateObj.push_back(Pair("allocated_coins", ValueFromAmount(nSmoothStakedCoins))); + smoothHashRateObj.push_back(Pair("roi", strprintf("%4.2f%%", nSmoothStakingROI * 100))); + stakingObj.push_back(Pair("smooth_hashrate", smoothHashRateObj)); + + stakingObj.push_back(Pair("allocation", strprintf("%4.2f%%", nStakingAllocation * 100))); + + { + // Calculate all data for the wallet's staking ROI + UniValue stakingRegularObj(UniValue::VOBJ); + + const auto nStakingRewards = nYearlyStakingRewards; + const auto nStakingDailyRewards = nStakingRewards / 365; + const auto nStakingWeeklyRewards = nStakingDailyRewards * 7; + const auto nStakingMonthlyRewards = nStakingDailyRewards * 30; + const auto nStakingYearlyRewards = nStakingRewards; + + const auto nStakingDailyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nStakingDailyRewards / nSmoothStakedCoins; + const auto nStakingWeeklyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nStakingWeeklyRewards / nSmoothStakedCoins; + const auto nStakingMonthlyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nStakingMonthlyRewards / nSmoothStakedCoins; + const auto nStakingYearlyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nStakingYearlyRewards / nSmoothStakedCoins; + + stakingRegularObj.push_back(Pair("daily", ValueFromAmount(nStakingDailyRewards))); + stakingRegularObj.push_back(Pair("daily_roi", strprintf("%4.2f%%", nStakingDailyRewardsROI * 100))); + stakingRegularObj.push_back(Pair("weekly", ValueFromAmount(nStakingWeeklyRewards))); + stakingRegularObj.push_back(Pair("weekly_roi", strprintf("%4.2f%%", nStakingWeeklyRewardsROI * 100))); + stakingRegularObj.push_back(Pair("monthly", ValueFromAmount(nStakingMonthlyRewards))); + stakingRegularObj.push_back(Pair("monthly_roi", strprintf("%4.2f%%", nStakingMonthlyRewardsROI * 100))); + stakingRegularObj.push_back(Pair("yearly", ValueFromAmount(nStakingYearlyRewards))); + stakingRegularObj.push_back(Pair("yearly_roi", strprintf("%4.2f%%", nStakingYearlyRewardsROI * 100))); + + stakingObj.push_back(Pair("regular", stakingRegularObj)); + + { + // Compounding calculations + UniValue stakingCompoundObj(UniValue::VOBJ); + + auto nStakingBalanceAccumulator = static_cast(nSmoothStakedCoins); + + for (int i = 1; i <= 365; i++) { + nStakingBalanceAccumulator += ((nStakingBalanceAccumulator * nSmoothStakingROI) / 365); + + if (i == 1) { // After a day + const auto nCompoundStakingDailyRewards = nStakingBalanceAccumulator - nSmoothStakedCoins; + const auto nCompoundStakingDailyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nCompoundStakingDailyRewards / nSmoothStakedCoins; + + stakingCompoundObj.push_back(Pair("daily", ValueFromAmount(nCompoundStakingDailyRewards))); + stakingCompoundObj.push_back(Pair("daily_roi", strprintf("%4.2f%%", nCompoundStakingDailyRewardsROI * 100))); + } + + if (i == 7) { // After a week + const auto nCompoundStakingWeeklyRewards = nStakingBalanceAccumulator - nSmoothStakedCoins; + const auto nCompoundStakingWeeklyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nCompoundStakingWeeklyRewards / nSmoothStakedCoins; + stakingCompoundObj.push_back(Pair("weekly", ValueFromAmount(nCompoundStakingWeeklyRewards))); + stakingCompoundObj.push_back(Pair("weekly_roi", strprintf("%4.2f%%", nCompoundStakingWeeklyRewardsROI * 100))); + } + if (i == 30) { // After a month + const auto nCompoundStakingMonthlyRewards = nStakingBalanceAccumulator - nSmoothStakedCoins; + const auto nCompoundStakingMonthlyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nCompoundStakingMonthlyRewards / nSmoothStakedCoins; + + stakingCompoundObj.push_back(Pair("monthly", ValueFromAmount(nCompoundStakingMonthlyRewards))); + stakingCompoundObj.push_back(Pair("monthly_roi", strprintf("%4.2f%%", nCompoundStakingMonthlyRewardsROI * 100))); + } + + if (i == 365) { // After a year + const auto nCompoundStakingYearlyRewards = nStakingBalanceAccumulator - nSmoothStakedCoins; + const auto nCompoundStakingYearlyRewardsROI = nSmoothStakedCoins == 0 ? 0 : nCompoundStakingYearlyRewards / nSmoothStakedCoins; + + stakingCompoundObj.push_back(Pair("yearly", ValueFromAmount(nCompoundStakingYearlyRewards))); + stakingCompoundObj.push_back(Pair("yearly_roi", strprintf("%4.2f%%", nCompoundStakingYearlyRewardsROI * 100))); + } + } + + stakingObj.push_back(Pair("compound", stakingCompoundObj)); + } + } + + networkObj.push_back(Pair("staking", stakingObj)); + + { + UniValue masternodingObj(UniValue::VOBJ); + + masternodingObj.push_back(Pair("reward", ValueFromAmount(nMNReward))); + masternodingObj.push_back(Pair("collateral", ValueFromAmount(nMNCollateral))); + masternodingObj.push_back(Pair("nextweek_collateral", ValueFromAmount(nMNNextWeekCollateral))); + masternodingObj.push_back(Pair("enabled_masternodes", nMNEnabled)); + masternodingObj.push_back(Pair("allocated_coins", ValueFromAmount(nMNCoins))); + masternodingObj.push_back(Pair("allocation", strprintf("%4.2f%%", nMNAllocation * 100))); + + const auto nMasternodingDailyRewards = nDailyMasternodingRewards * nMNEnabled; + const auto nMasternodingWeeklyRewards = nMasternodingDailyRewards * 7; + const auto nMasternodingMonthlyRewards = nMasternodingDailyRewards * 30; + const auto nMasternodingYearlyRewards = nMasternodingRewards * nMNEnabled; + + const auto nMasternodingDailyRewardsROI = nMasternodingDailyRewards / nMNCoins; + const auto nMasternodingWeeklyRewardsROI = nMasternodingWeeklyRewards / nMNCoins; + const auto nMasternodingMonthlyRewardsROI = nMasternodingMonthlyRewards / nMNCoins; + const auto nMasternodingYearlyRewardsROI = nMasternodingYearlyRewards / nMNCoins; + + masternodingObj.push_back(Pair("daily", ValueFromAmount(nMasternodingDailyRewards))); + masternodingObj.push_back(Pair("daily_roi", strprintf("%4.2f%%", nMasternodingDailyRewardsROI * 100))); + masternodingObj.push_back(Pair("weekly", ValueFromAmount(nMasternodingWeeklyRewards))); + masternodingObj.push_back(Pair("weekly_roi", strprintf("%4.2f%%", nMasternodingWeeklyRewardsROI * 100))); + masternodingObj.push_back(Pair("monthly", ValueFromAmount(nMasternodingMonthlyRewards))); + masternodingObj.push_back(Pair("monthly_roi", strprintf("%4.2f%%", nMasternodingMonthlyRewardsROI * 100))); + masternodingObj.push_back(Pair("yearly", ValueFromAmount(nMasternodingYearlyRewards))); + masternodingObj.push_back(Pair("yearly_roi", strprintf("%4.2f%%", nMasternodingYearlyRewardsROI * 100))); + + networkObj.push_back(Pair("masternoding", masternodingObj)); + } + + obj.push_back(Pair("network", networkObj)); + } + + if (info_type == "wallet" || info_type == "both") { + UniValue walletObj(UniValue::VOBJ); + + UniValue walletStakingObj(UniValue::VOBJ); + + walletStakingObj.push_back(Pair("status", fStakingActive)); + walletStakingObj.push_back(Pair("tries", pwalletMain->pStakerStatus->GetLastTries())); + walletStakingObj.push_back(Pair("allocated_coins", ValueFromAmount(nStakedBalance))); + walletStakingObj.push_back(Pair("share", strprintf("%4.2f%%", nStakeShare * 100))); + walletStakingObj.push_back(Pair("stakesplitthreshold", ValueFromAmount(pwalletMain->nStakeSplitThreshold))); + walletStakingObj.push_back(Pair("autocombinethreshold", ValueFromAmount(pwalletMain->fCombineDust ? pwalletMain->nAutoCombineThreshold : 0))); + + { + // Calculate all data for the wallet's staking ROI + UniValue stakingRegularObj(UniValue::VOBJ); + + const auto nStakingRewards = nStakedBalance * nSmoothStakingROI; + const auto nStakingDailyRewards = nStakingRewards / 365; + const auto nStakingWeeklyRewards = nStakingDailyRewards * 7; + const auto nStakingMonthlyRewards = nStakingDailyRewards * 30; + const auto nStakingYearlyRewards = nStakingRewards; + + const auto nStakingDailyRewardsROI = nStakedBalance == 0 ? 0 : nStakingDailyRewards / nStakedBalance; + const auto nStakingWeeklyRewardsROI = nStakedBalance == 0 ? 0 : nStakingWeeklyRewards / nStakedBalance; + const auto nStakingMonthlyRewardsROI = nStakedBalance == 0 ? 0 : nStakingMonthlyRewards / nStakedBalance; + const auto nStakingYearlyRewardsROI = nStakedBalance == 0 ? 0 : nStakingYearlyRewards / nStakedBalance; + + stakingRegularObj.push_back(Pair("daily", ValueFromAmount(nStakingDailyRewards))); + stakingRegularObj.push_back(Pair("daily_roi", strprintf("%4.2f%%", nStakingDailyRewardsROI * 100))); + stakingRegularObj.push_back(Pair("weekly", ValueFromAmount(nStakingWeeklyRewards))); + stakingRegularObj.push_back(Pair("weekly_roi", strprintf("%4.2f%%", nStakingWeeklyRewardsROI * 100))); + stakingRegularObj.push_back(Pair("monthly", ValueFromAmount(nStakingMonthlyRewards))); + stakingRegularObj.push_back(Pair("monthly_roi", strprintf("%4.2f%%", nStakingMonthlyRewardsROI * 100))); + stakingRegularObj.push_back(Pair("yearly", ValueFromAmount(nStakingYearlyRewards))); + stakingRegularObj.push_back(Pair("yearly_roi", strprintf("%4.2f%%", nStakingYearlyRewardsROI * 100))); + + walletStakingObj.push_back(Pair("regular", stakingRegularObj)); + + { + // Compounding calculations + UniValue stakingCompoundObj(UniValue::VOBJ); + + auto nStakingBalanceAccumulator = static_cast(nStakedBalance); + + for (int i = 1; i <= 365; i++) { + nStakingBalanceAccumulator += ((nStakingBalanceAccumulator * nSmoothStakingROI) / 365); + + if (i == 1) { // After a day + const auto nCompoundStakingDailyRewards = nStakingBalanceAccumulator - nStakedBalance; + const auto nCompoundStakingDailyRewardsROI = nStakedBalance == 0 ? 0 : nCompoundStakingDailyRewards / nStakedBalance; + + stakingCompoundObj.push_back(Pair("daily", ValueFromAmount(nCompoundStakingDailyRewards))); + stakingCompoundObj.push_back(Pair("daily_roi", strprintf("%4.2f%%", nCompoundStakingDailyRewardsROI * 100))); + } + + if (i == 7) { // After a week + const auto nCompoundStakingWeeklyRewards = nStakingBalanceAccumulator - nStakedBalance; + const auto nCompoundStakingWeeklyRewardsROI = nStakedBalance == 0 ? 0 : nCompoundStakingWeeklyRewards / nStakedBalance; + + stakingCompoundObj.push_back(Pair("weekly", ValueFromAmount(nCompoundStakingWeeklyRewards))); + stakingCompoundObj.push_back(Pair("weekly_roi", strprintf("%4.2f%%", nCompoundStakingWeeklyRewardsROI * 100))); + } + + if (i == 30) { // After a month + const auto nCompoundStakingMonthlyRewards = nStakingBalanceAccumulator - nStakedBalance; + const auto nCompoundStakingMonthlyRewardsROI = nStakedBalance == 0 ? 0 : nCompoundStakingMonthlyRewards / nStakedBalance; + + stakingCompoundObj.push_back(Pair("monthly", ValueFromAmount(nCompoundStakingMonthlyRewards))); + stakingCompoundObj.push_back(Pair("monthly_roi", strprintf("%4.2f%%", nCompoundStakingMonthlyRewardsROI * 100))); + } + + if (i == 365) { // After a year + const auto nCompoundStakingYearlyRewards = nStakingBalanceAccumulator - nStakedBalance; + const auto nCompoundStakingYearlyRewardsROI = nStakedBalance == 0 ? 0 : nCompoundStakingYearlyRewards / nStakedBalance; + + stakingCompoundObj.push_back(Pair("yearly", ValueFromAmount(nCompoundStakingYearlyRewards))); + stakingCompoundObj.push_back(Pair("yearly_roi", strprintf("%4.2f%%", nCompoundStakingYearlyRewardsROI * 100))); + } + } + + walletStakingObj.push_back(Pair("compound", stakingCompoundObj)); + } + } + + walletObj.push_back(Pair("staking", walletStakingObj)); + + { + // Calculate all data for the wallet's masternoding ROI + UniValue walletMasternodingObj(UniValue::VOBJ); + + const auto nMNs = masternodeConfig.getCount() + 1; // legacy preservation without showing a strange counting + const auto nMNBalance = nMNs * nMNCollateral; + const auto nMNShare = static_cast(nMNBalance) / nMNCoins; + + walletMasternodingObj.push_back(Pair("masternodes", nMNs)); + walletMasternodingObj.push_back(Pair("allocated_coins", ValueFromAmount(nMNBalance))); + walletMasternodingObj.push_back(Pair("share", strprintf("%4.2f%%", nMNShare * 100))); + + const auto nMasternodingDailyRewards = nDailyMasternodingRewards * nMNs; + const auto nMasternodingWeeklyRewards = nMasternodingDailyRewards * 7; + const auto nMasternodingMonthlyRewards = nMasternodingDailyRewards * 30; + const auto nMasternodingYearlyRewards = nMasternodingRewards * nMNs; + + const auto nMasternodingDailyRewardsROI = nMNBalance == 0 ? 0 : nMasternodingDailyRewards / nMNBalance; + const auto nMasternodingWeeklyRewardsROI = nMNBalance == 0 ? 0 : nMasternodingWeeklyRewards / nMNBalance; + const auto nMasternodingMonthlyRewardsROI = nMNBalance == 0 ? 0 : nMasternodingMonthlyRewards / nMNBalance; + const auto nMasternodingYearlyRewardsROI = nMNBalance == 0 ? 0 : nMasternodingYearlyRewards / nMNBalance; + + walletMasternodingObj.push_back(Pair("daily", ValueFromAmount(nMasternodingDailyRewards))); + walletMasternodingObj.push_back(Pair("daily_roi", strprintf("%4.2f%%", nMasternodingDailyRewardsROI * 100))); + walletMasternodingObj.push_back(Pair("weekly", ValueFromAmount(nMasternodingWeeklyRewards))); + walletMasternodingObj.push_back(Pair("weekly_roi", strprintf("%4.2f%%", nMasternodingWeeklyRewardsROI * 100))); + walletMasternodingObj.push_back(Pair("monthly", ValueFromAmount(nMasternodingMonthlyRewards))); + walletMasternodingObj.push_back(Pair("monthly_roi", strprintf("%4.2f%%", nMasternodingMonthlyRewardsROI * 100))); + walletMasternodingObj.push_back(Pair("yearly", ValueFromAmount(nMasternodingYearlyRewards))); + walletMasternodingObj.push_back(Pair("yearly_roi", strprintf("%4.2f%%", nMasternodingYearlyRewardsROI * 100))); + + walletObj.push_back(Pair("masternoding", walletMasternodingObj)); + } + + obj.push_back(Pair("wallet", walletObj)); + } + + return obj; + } else { + throw JSONRPCError(RPC_IN_WARMUP, "Try again after the active chain is loaded"); + } } + #endif // ENABLE_WALLET diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index aec838e37..8725763bb 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -22,7 +22,7 @@ #include "wallet/wallet.h" #endif // ENABLE_WALLET -#include +#include #include #include #include @@ -32,6 +32,7 @@ #include +using namespace boost::placeholders; static bool fRPCRunning = false; static bool fRPCInWarmup = true; @@ -387,6 +388,7 @@ static const CRPCCommand vRPCCommands[] = {"wallet", "bip38decrypt", &bip38decrypt, true }, {"wallet", "getaddressinfo", &getaddressinfo, true }, {"wallet", "getstakingstatus", &getstakingstatus, false }, + {"wallet", "getrewardsinfo", &getrewardsinfo, false }, {"wallet", "multisend", &multisend, false }, #endif // ENABLE_WALLET diff --git a/src/rpc/server.h b/src/rpc/server.h index b09bdc0c3..8187dfac5 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -278,6 +278,7 @@ extern UniValue createmultisig(const JSONRPCRequest& request); extern UniValue verifymessage(const JSONRPCRequest& request); extern UniValue setmocktime(const JSONRPCRequest& request); extern UniValue getstakingstatus(const JSONRPCRequest& request); +extern UniValue getrewardsinfo(const JSONRPCRequest& request); bool StartRPC(); void InterruptRPC(); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 4b2ea1a1c..b641b56d6 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -10,9 +10,11 @@ #include "reverselock.h" #include -#include +#include #include +using namespace boost::placeholders; + CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false) { } diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index 8be155128..48186012c 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -9,6 +9,7 @@ #include "random.h" #include #include +#include /** Test Suite for CuckooCache diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index 96ab6f908..f527ec117 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -6,12 +6,14 @@ #include "reverselock.h" -#include +#include #include #include #include #include +using namespace boost::placeholders; + BOOST_AUTO_TEST_SUITE(reverselock_tests) BOOST_AUTO_TEST_CASE(reverselock_basics) diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 0908f39b1..2c164567e 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -10,12 +10,14 @@ #include "config/pivx-config.h" #endif -#include +#include #include #include #include #include +using namespace boost::placeholders; + BOOST_AUTO_TEST_SUITE(scheduler_tests) static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime) diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 74c76a102..35996cf0a 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -32,6 +32,8 @@ #include #include +using namespace boost::placeholders; + /** Default control port */ const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051"; /** Tor cookie size (from control-spec.txt) */ diff --git a/src/uint256.h b/src/uint256.h index 1e7fb08a9..084f035c0 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -81,6 +81,12 @@ class uint256 : public base_uint<256> } }; +struct uint256CheapHasher { + uint64_t operator()(const uint256& i) const { + return i.GetCheapHash(); + } +}; + /** 512-bit unsigned big integer. */ class uint512 : public base_uint<512> { diff --git a/src/util.cpp b/src/util.cpp index 73ad94285..f65afc685 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -454,6 +454,14 @@ bool TryCreateDirectory(const fs::path& p) return false; } +bool IsDirectory(const std::string& path) { + // Check if the last character in the path is a slash + if (!path.empty() && (path.back() == '/' || path.back() == '\\')) { + return true; + } + return false; +} + void FileCommit(FILE* fileout) { fflush(fileout); // harmless if redundantly called diff --git a/src/util.h b/src/util.h index af4f94e4d..2eac20e12 100644 --- a/src/util.h +++ b/src/util.h @@ -77,6 +77,7 @@ int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length); bool RenameOver(fs::path src, fs::path dest); bool TryCreateDirectory(const fs::path& p); +bool IsDirectory(const std::string& path); fs::path GetDefaultDataDir(); const fs::path &GetDataDir(bool fNetSpecific = true); void ClearDatadirCache(); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 2733f56d2..ca586d564 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -7,6 +7,8 @@ #include "validationinterface.h" +using namespace boost::placeholders; + static CMainSignals g_signals; CMainSignals& GetMainSignals() diff --git a/src/version.h b/src/version.h index 6709258a4..7b6830109 100644 --- a/src/version.h +++ b/src/version.h @@ -12,7 +12,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70226; +static const int PROTOCOL_VERSION = 70227; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5920b0cba..e2c4351e3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -925,7 +925,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) // Tally CAmount nAmount = 0; - for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; @@ -984,7 +984,7 @@ UniValue getreceivedbylabel(const JSONRPCRequest& request) // Tally CAmount nAmount = 0; - for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; @@ -1436,7 +1436,7 @@ UniValue ListReceived(const UniValue& params, bool by_label) // Tally std::map mapTally; - for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || !IsFinalTx(wtx)) @@ -1950,7 +1950,7 @@ UniValue listaccounts(const JSONRPCRequest& request) mapAccountBalances[entry.second.name] = 0; } - for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; CAmount nFee; std::string strSentAccount; @@ -2055,7 +2055,7 @@ UniValue listsinceblock(const JSONRPCRequest& request) UniValue transactions(UniValue::VARR); - for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { + for (auto it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { CWalletTx tx = (*it).second; if (depth == -1 || tx.GetDepthInMainChain(false) < depth) @@ -2672,7 +2672,7 @@ UniValue lockunspent(const JSONRPCRequest& request) const COutPoint outpt(uint256S(txid), nOutput); - const auto it = pwalletMain->mapWallet.find(outpt.hash); + auto it = pwalletMain->mapWallet.find(outpt.hash); if (it == pwalletMain->mapWallet.end()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction"); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ffadf1ce3..7a02c8b02 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -92,7 +92,7 @@ bool CWallet::IsHDEnabled() const const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { LOCK(cs_wallet); - std::map::const_iterator it = mapWallet.find(hash); + auto it = mapWallet.find(hash); if (it == mapWallet.end()) return NULL; return &(it->second); @@ -460,7 +460,7 @@ std::set CWallet::GetConflicts(const uint256& txid) const std::set result; AssertLockHeld(cs_wallet); - std::map::const_iterator it = mapWallet.find(txid); + auto it = mapWallet.find(txid); if (it == mapWallet.end()) return result; const CWalletTx& wtx = it->second; @@ -595,7 +595,7 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const range = mapTxSpends.equal_range(outpoint); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { const uint256& wtxid = it->second; - std::map::const_iterator mit = mapWallet.find(wtxid); + auto mit = mapWallet.find(wtxid); if (mit != mapWallet.end()) { bool fConflicted; const int nDepth = mit->second.GetDepthAndMempool(fConflicted); @@ -764,7 +764,7 @@ int64_t CWallet::IncOrderPosNext(CWalletDB* pwalletdb) bool CWallet::IsKeyUsed(const CPubKey& vchPubKey) { if (vchPubKey.IsValid()) { CScript scriptPubKey = GetScriptForDestination(vchPubKey.GetID()); - for (std::map::iterator it = mapWallet.begin(); + for (auto it = mapWallet.begin(); it != mapWallet.end() && vchPubKey.IsValid(); ++it) { const CWalletTx& wtx = (*it).second; @@ -821,7 +821,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) uint256 hash = wtxIn.GetHash(); // Inserts only if not already there, returns tx inserted or tx found - std::pair::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn)); + auto ret = mapWallet.insert(std::make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; wtx.BindWallet(this); bool fInsertedNew = ret.second; @@ -1099,7 +1099,7 @@ isminetype CWallet::IsMine(const CTxIn& txin) const { { LOCK(cs_wallet); - std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); + auto mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.vout.size()) @@ -1134,7 +1134,7 @@ CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const { { LOCK(cs_wallet); - std::map::const_iterator mi = mapWallet.find(txin.prevout.hash); + auto mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; if (txin.prevout.n < prev.vout.size()) @@ -1794,7 +1794,7 @@ bool CWallet::GetMasternodeVinAndKeys(CTxIn& txinRet, CPubKey& pubKeyRet, CKey& // Find specific vin uint256 txHash = uint256S(strTxHash); - std::map::const_iterator mi = mapWallet.find(txHash); + auto mi = mapWallet.find(txHash); if (mi == mapWallet.end()) { strError = "collateral tx not found in the wallet"; return error("%s: %s", __func__, strError); @@ -1867,7 +1867,7 @@ bool CWallet::AvailableCoins(std::vector* pCoins, // --> populates { LOCK2(cs_main, cs_wallet); - for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const uint256& wtxid = it->first; const CWalletTx* pcoin = &(*it).second; @@ -2107,7 +2107,7 @@ bool CWallet::SelectCoinsToSpend(const std::vector& vAvailableCoins, co if (coinControl) coinControl->ListSelected(vPresetInputs); for (const COutPoint& outpoint : vPresetInputs) { - std::map::const_iterator it = mapWallet.find(outpoint.hash); + auto it = mapWallet.find(outpoint.hash); if (it != mapWallet.end()) { const CWalletTx* pcoin = &it->second; // Clearly invalid input, fail @@ -3061,7 +3061,7 @@ bool CWallet::UpdatedTransaction(const uint256& hashTx) { LOCK(cs_wallet); // Only notify UI if this transaction is in this wallet - std::map::const_iterator mi = mapWallet.find(hashTx); + auto mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) { NotifyTransactionChanged(this, hashTx, CT_UPDATED); return true; @@ -3183,7 +3183,7 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const // find first block that affects those keys, if there are any left std::vector vAffected; - for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { + for (auto it = mapWallet.begin(); it != mapWallet.end(); it++) { // iterate over all wallet transactions... const CWalletTx& wtx = (*it).second; BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); @@ -3238,7 +3238,7 @@ bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, c void CWallet::AutoCombineDust(CConnman* connman) { LOCK2(cs_main, cs_wallet); - const CBlockIndex* tip = chainActive.Tip(); + const auto tip = chainActive.Tip(); if (tip->nTime < (GetAdjustedTime() - 300) || IsLocked()) { return; } @@ -3252,7 +3252,7 @@ void CWallet::AutoCombineDust(CConnman* connman) std::map > mapCoinsByAddress = AvailableCoinsByAddress(true, adjustedAutoCombineThreshold); //coins are sectioned by address. This combination code only wants to combine inputs that belong to the same address - for (std::map >::iterator it = mapCoinsByAddress.begin(); it != mapCoinsByAddress.end(); it++) { + for (auto it = mapCoinsByAddress.begin(); it != mapCoinsByAddress.end(); it++) { std::vector vCoins, vRewardCoins; vCoins = it->second; @@ -3657,7 +3657,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) CWalletDB walletdb(walletFile); for (const CWalletTx& wtxOld : vWtx) { uint256 hash = wtxOld.GetHash(); - std::map::iterator mi = walletInstance->mapWallet.find(hash); + auto mi = walletInstance->mapWallet.find(hash); if (mi != walletInstance->mapWallet.end()) { const CWalletTx* copyFrom = &wtxOld; CWalletTx* copyTo = &mi->second; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a4b516b4e..89200566c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -39,6 +39,8 @@ #include #include +#include + extern CWallet* pwalletMain; /** @@ -333,7 +335,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool isMultiSendEnabled(); void setMultiSendDisabled(); - std::map mapWallet; + boost::unordered_map mapWallet; std::list laccentries; typedef std::pair TxPair; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 2f0f393f0..b16accd5a 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -387,7 +387,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) typedef std::multimap TxItems; TxItems txByTime; - for (std::map::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) { + for (auto it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0))); } @@ -1069,7 +1069,9 @@ bool AttemptBackupWallet(const CWallet& wallet, const fs::path& pathSrc, const f LogPrintf("cannot backup to wallet source file %s\n", pathDest.string()); return false; } -#if BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ +#if BOOST_VERSION >= 107400 /* BOOST_LIB_VERSION 1_74 */ + fs::copy_file(pathSrc.c_str(), pathDest, fs::copy_options::overwrite_existing); +#elif BOOST_VERSION >= 105800 /* BOOST_LIB_VERSION 1_58 */ fs::copy_file(pathSrc.c_str(), pathDest, fs::copy_option::overwrite_if_exists); #else std::ifstream src(pathSrc.c_str(), std::ios::binary | std::ios::in); diff --git a/src/zip.cpp b/src/zip.cpp new file mode 100644 index 000000000..6aaf7510c --- /dev/null +++ b/src/zip.cpp @@ -0,0 +1,143 @@ +// Copyright (c) 2024 The DECENOMY Core Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "zip.h" + +#include "init.h" +#include "logging.h" +#include "minizip/unzip.h" +#include "util.h" + +#include + +namespace fs = boost::filesystem; + +bool CZipWrapper::ExtractZip( + const std::string& zipfile, + const std::string& destinationFolder) +{ + try { + // Open the zip file + unzFile unzip = unzOpen(zipfile.c_str()); + if (!unzip) { + LogPrintf( + "CZipWrapper::%s: Error opening zip file: %s\n", + __func__, + zipfile); + return false; + } + + // Create the output folder if it doesn't exist + if (!fs::exists(destinationFolder) && + !fs::create_directory(destinationFolder)) + { + LogPrintf( + "CZipWrapper::%s: Error creating output folder: %s\n", + __func__, + destinationFolder); + unzClose(unzip); + return false; + } + + // Get info from the zip file + unz_global_info globalInfo; + if (unzGetGlobalInfo(unzip, &globalInfo) != UNZ_OK) { + LogPrintf( + "CZipWrapper::%s: Error getting global info from zip file: %s\n", + __func__, + zipfile); + unzClose(unzip); + return false; + } + + // Extract each file one by one + for (uLong i = 0; i < globalInfo.number_entry; ++i) { + + if(ShutdownRequested()) { + LogPrintf( + "CZipWrapper::%s: Shutdown requested while unzipping the zip file: %s\n", + __func__, + zipfile); + unzClose(unzip); + return false; + } + + char filename[256]; + unz_file_info fileInfo; + + // Get info about the current file being extracted + if (unzGetCurrentFileInfo( + unzip, &fileInfo, filename, sizeof(filename), + nullptr, 0, nullptr, 0) != UNZ_OK) + { + LogPrintf( + "CZipWrapper::%s: Error getting file info from zip file: %s\n", + __func__, + zipfile); + unzClose(unzip); + return false; + } + + // Open the current file inside the zip file + if (unzOpenCurrentFile(unzip) != UNZ_OK) { + LogPrintf( + "CZipWrapper::%s: Error opening current file in zip file: %s\n", + __func__, + zipfile); + unzClose(unzip); + return false; + } + + const auto fullpath = destinationFolder + "/" + filename; + LogPrintf("CZipWrapper::%s: Extracting file: %s\n", __func__, fullpath); + + // Is it a directory? + if (IsDirectory(fullpath)) { + fs::create_directory(fullpath); + } else { // It is a file! + std::ofstream output(fullpath, std::ios::binary); + if (!output.is_open()) { + LogPrintf( + "CZipWrapper::%s: Error creating output file: %s\n", + __func__, fullpath); + unzCloseCurrentFile(unzip); + unzClose(unzip); + return false; + } + + // Read and write the file data + char buffer[4096]; + int bytesRead; + + while ((bytesRead = unzReadCurrentFile(unzip, buffer, sizeof(buffer))) > 0) { + output.write(buffer, bytesRead); + } + output.close(); + } + + // Close the current file in the zip, and move to the next + unzCloseCurrentFile(unzip); + + if (unzGoToNextFile(unzip) != UNZ_OK) { + break; // Reached the end of the zip file + } + } + + // Close the zip file + if (unzClose(unzip) != UNZ_OK) { + LogPrintf( + "CZipWrapper::%s: Error closing zip file: %s\n", + __func__, zipfile); + return false; + } + + } catch (const std::exception& e) { + LogPrintf( + "CZipWrapper::%s: Error extracting zip file: %s\n", + __func__, e.what()); + return false; + } + + return true; +} diff --git a/src/zip.h b/src/zip.h new file mode 100644 index 000000000..14c23022b --- /dev/null +++ b/src/zip.h @@ -0,0 +1,18 @@ +// Copyright (c) 2024 The DECENOMY Core Developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ZIP_H +#define ZIP_H + +#include + +class CZipWrapper +{ +public: + static bool ExtractZip( + const std::string& zipfile, + const std::string& outputPath); +}; + +#endif // ZIP_H