diff --git a/.github/workflows/release-builds.yaml b/.github/workflows/release-builds.yaml index 869965bb5d6..3e8aff873b4 100644 --- a/.github/workflows/release-builds.yaml +++ b/.github/workflows/release-builds.yaml @@ -33,7 +33,7 @@ jobs: docker tag defichain-x86_64-pc-linux-gnu:${{ env.BUILD_VERSION }} defichain-x86_64-pc-linux-gnu:dockerhub-latest - - uses: docker/build-push-action@v1 + - uses: docker/build-push-action@v2 # Make sure to only build on ain repo. Also add in additional restrictions here if needed to # make sure we don't push unnecessary images to docker if: ${{ github.repository == 'DeFiCh/ain' }} diff --git a/build-aux/m4/ax_boost_chrono.m4 b/build-aux/m4/ax_boost_chrono.m4 deleted file mode 100644 index 6ea77b9b3ef..00000000000 --- a/build-aux/m4/ax_boost_chrono.m4 +++ /dev/null @@ -1,118 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_CHRONO -# -# DESCRIPTION -# -# Test for Chrono 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_CHRONO_LIB) -# -# And sets: -# -# HAVE_BOOST_CHRONO -# -# LICENSE -# -# Copyright (c) 2012 Xiyue Deng -# -# 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 4 - -AC_DEFUN([AX_BOOST_CHRONO], -[ - AC_ARG_WITH([boost-chrono], - AS_HELP_STRING([--with-boost-chrono@<:@=special-lib@:>@], - [use the Chrono library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-chrono=boost_chrono-gcc-mt ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_chrono_lib="" - else - want_boost="yes" - ax_boost_user_chrono_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::Chrono library is available, - ax_cv_boost_chrono, - [AC_LANG_PUSH([C++]) - CXXFLAGS_SAVE=$CXXFLAGS - - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::chrono::system_clock::time_point* time = new boost::chrono::system_clock::time_point; delete time;]])], - ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no) - CXXFLAGS=$CXXFLAGS_SAVE - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_chrono" = "xyes"; then - AC_SUBST(BOOST_CPPFLAGS) - - AC_DEFINE(HAVE_BOOST_CHRONO,,[define if the Boost::Chrono library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - - LDFLAGS_SAVE=$LDFLAGS - if test "x$ax_boost_user_chrono_lib" = "x"; then - for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], - [link_chrono="no"]) - done - if test "x$link_chrono" != "xyes"; then - for libextension in `ls $BOOSTLIBDIR/boost_chrono*.dll* $BOOSTLIBDIR/boost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_chrono.*\)\.dll.*$;\1;' -e 's;^\(boost_chrono.*\)\.a.*$;\1;'` ; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], - [link_chrono="no"]) - done - fi - - else - for ax_lib in $ax_boost_user_chrono_lib boost_chrono-$ax_boost_user_chrono_lib; do - AC_CHECK_LIB($ax_lib, exit, - [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], - [link_chrono="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) - fi - if test "x$link_chrono" = "xno"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - fi -]) diff --git a/build-aux/m4/ax_boost_thread.m4 b/build-aux/m4/ax_boost_thread.m4 deleted file mode 100644 index 9f0bd0b23c9..00000000000 --- a/build-aux/m4/ax_boost_thread.m4 +++ /dev/null @@ -1,150 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_thread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_BOOST_THREAD -# -# DESCRIPTION -# -# Test for Thread 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_THREAD_LIB) -# -# And sets: -# -# HAVE_BOOST_THREAD -# -# LICENSE -# -# Copyright (c) 2009 Thomas Porschberg -# Copyright (c) 2009 Michael Tindal -# -# 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 27 - -AC_DEFUN([AX_BOOST_THREAD], -[ - AC_ARG_WITH([boost-thread], - AS_HELP_STRING([--with-boost-thread@<:@=special-lib@:>@], - [use the Thread library from boost - it is possible to specify a certain library for the linker - e.g. --with-boost-thread=boost_thread-gcc-mt ]), - [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ax_boost_user_thread_lib="" - else - want_boost="yes" - ax_boost_user_thread_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::Thread library is available, - ax_cv_boost_thread, - [AC_LANG_PUSH([C++]) - CXXFLAGS_SAVE=$CXXFLAGS - - if test "x$host_os" = "xsolaris" ; then - CXXFLAGS="-pthreads $CXXFLAGS" - elif test "x$host_os" = "xmingw32" ; then - CXXFLAGS="-mthreads $CXXFLAGS" - else - CXXFLAGS="-pthread $CXXFLAGS" - fi - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::thread_group thrds; - return 0;]])], - ax_cv_boost_thread=yes, ax_cv_boost_thread=no) - CXXFLAGS=$CXXFLAGS_SAVE - AC_LANG_POP([C++]) - ]) - if test "x$ax_cv_boost_thread" = "xyes"; then - if test "x$host_os" = "xsolaris" ; then - BOOST_CPPFLAGS="-pthreads $BOOST_CPPFLAGS" - elif test "x$host_os" = "xmingw32" ; then - BOOST_CPPFLAGS="-mthreads $BOOST_CPPFLAGS" - else - BOOST_CPPFLAGS="-pthread $BOOST_CPPFLAGS" - fi - - AC_SUBST(BOOST_CPPFLAGS) - - AC_DEFINE(HAVE_BOOST_THREAD,,[define if the Boost::Thread library is available]) - BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` - - LDFLAGS_SAVE=$LDFLAGS - case "x$host_os" in - *bsd* ) - LDFLAGS="-pthread $LDFLAGS" - break; - ;; - esac - if test "x$ax_boost_user_thread_lib" = "x"; then - ax_lib= - for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], - [link_thread="no"]) - done - if test "x$link_thread" != "xyes"; then - for libextension in `ls -r $BOOSTLIBDIR/boost_thread* 2>/dev/null | sed 's,.*/,,' | sed 's,\..*,,'`; do - ax_lib=${libextension} - AC_CHECK_LIB($ax_lib, exit, - [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], - [link_thread="no"]) - done - fi - - else - for ax_lib in $ax_boost_user_thread_lib boost_thread-$ax_boost_user_thread_lib; do - AC_CHECK_LIB($ax_lib, exit, - [BOOST_THREAD_LIB="-l$ax_lib"; AC_SUBST(BOOST_THREAD_LIB) link_thread="yes"; break], - [link_thread="no"]) - done - - fi - if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the boost_thread library!) - fi - if test "x$link_thread" = "xno"; then - AC_MSG_ERROR(Could not link against $ax_lib !) - else - case "x$host_os" in - *bsd* ) - BOOST_LDFLAGS="-pthread $BOOST_LDFLAGS" - break; - ;; - esac - - fi - fi - - CPPFLAGS="$CPPFLAGS_SAVED" - LDFLAGS="$LDFLAGS_SAVED" - fi -]) diff --git a/build_msvc/defi_config.h b/build_msvc/defi_config.h index 89f27811fd3..02f91daed8d 100644 --- a/build_msvc/defi_config.h +++ b/build_msvc/defi_config.h @@ -43,9 +43,6 @@ /* define if the Boost library is available */ #define HAVE_BOOST /**/ -/* define if the Boost::Chrono library is available */ -#define HAVE_BOOST_CHRONO /**/ - /* define if the Boost::Filesystem library is available */ #define HAVE_BOOST_FILESYSTEM /**/ @@ -55,9 +52,6 @@ /* define if the Boost::System library is available */ #define HAVE_BOOST_SYSTEM /**/ -/* define if the Boost::Thread library is available */ -#define HAVE_BOOST_THREAD /**/ - /* define if the Boost::Unit_Test_Framework library is available */ #define HAVE_BOOST_UNIT_TEST_FRAMEWORK /**/ @@ -330,12 +324,6 @@ /* Define if the visibility attribute is supported. */ #define HAVE_VISIBILITY_ATTRIBUTE 1 -/* Define this symbol if boost sleep works */ -/* #undef HAVE_WORKING_BOOST_SLEEP */ - -/* Define this symbol if boost sleep_for works */ -#define HAVE_WORKING_BOOST_SLEEP_FOR 1 - /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" diff --git a/ci/test/00_setup_env_amd64_asan.sh b/ci/test/00_setup_env_amd64_asan.sh index 4aa3c630c38..a524e276d92 100644 --- a/ci/test/00_setup_env_amd64_asan.sh +++ b/ci/test/00_setup_env_amd64_asan.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export HOST=x86_64-unknown-linux-gnu -export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" +export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" export NO_DEPENDS=1 export GOAL="install" export DEFI_CONFIG="--enable-zmq --with-incompatible-bdb CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++" diff --git a/ci/test/00_setup_env_amd64_fuzz.sh b/ci/test/00_setup_env_amd64_fuzz.sh index bfc46ae7cea..33081a1ab41 100644 --- a/ci/test/00_setup_env_amd64_fuzz.sh +++ b/ci/test/00_setup_env_amd64_fuzz.sh @@ -7,7 +7,7 @@ export LC_ALL=C.UTF-8 export HOST=x86_64-unknown-linux-gnu -export PACKAGES="clang llvm python3 libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev" +export PACKAGES="clang llvm python3 libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev" export NO_DEPENDS=1 export RUN_UNIT_TESTS=false export RUN_FUNCTIONAL_TESTS=false diff --git a/ci/test/00_setup_env_amd64_trusty.sh b/ci/test/00_setup_env_amd64_trusty.sh index 9b32c66a9a3..9d37cdbf5c6 100644 --- a/ci/test/00_setup_env_amd64_trusty.sh +++ b/ci/test/00_setup_env_amd64_trusty.sh @@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8 export HOST=x86_64-unknown-linux-gnu export DOCKER_NAME_TAG=ubuntu:14.04 -export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" +export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.1++-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" export NO_DEPENDS=1 export RUN_FUNCTIONAL_TESTS=false export GOAL="install" diff --git a/ci/test/00_setup_env_amd64_tsan.sh b/ci/test/00_setup_env_amd64_tsan.sh index 6a5ef7b5707..6dec401dd05 100644 --- a/ci/test/00_setup_env_amd64_tsan.sh +++ b/ci/test/00_setup_env_amd64_tsan.sh @@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8 export HOST=x86_64-unknown-linux-gnu export DOCKER_NAME_TAG=ubuntu:16.04 -export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" +export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev" export NO_DEPENDS=1 export GOAL="install" export DEFI_CONFIG="--enable-zmq --disable-wallet CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=thread --disable-hardening --disable-asm CC=clang CXX=clang++" diff --git a/configure.ac b/configure.ac index 9e218cf6e4f..4eeb5202c78 100644 --- a/configure.ac +++ b/configure.ac @@ -302,34 +302,29 @@ if test "x$enable_werror" = "xyes"; then if test "x$CXXFLAG_WERROR" = "x"; then AC_MSG_ERROR("enable-werror set but -Werror is not usable") fi - AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Werror=switch],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=switch"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Werror=thread-safety-analysis],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=thread-safety-analysis"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Werror=thread-safety],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=thread-safety"],,[[$CXXFLAG_WERROR]]) fi # Add these warnings per default AX_CHECK_COMPILE_FLAG([-Wall],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wall"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wextra],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wformat],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wswitch],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wswitch"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wformat-security],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wrange-loop-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wuninitialized],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wuninitialized"],,[[$CXXFLAG_WERROR]]) - -if test "x$CXXFLAGS_overridden" = "xno"; then - AX_CHECK_COMPILE_FLAG([-Wextra],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wextra"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wvla],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wredundant-decls],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"],,[[$CXXFLAG_WERROR]]) - - ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all - ## unknown options if any other warning is produced. Test the -Wfoo case, and - ## set the -Wno-foo case if it works. - AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wself-assign],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) - AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) -fi +AX_CHECK_COMPILE_FLAG([-Wthread-safety],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wthread-safety"],,[[$CXXFLAG_WERROR]]) + +## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all +## unknown options if any other warning is produced. Test the -Wfoo case, and +## set the -Wno-foo case if it works. +AX_CHECK_COMPILE_FLAG([-Wunused-parameter],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-parameter"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wmissing-field-initializers],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-missing-field-initializers"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wself-assign],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-self-assign"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) +AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) enable_sse42=no enable_sse41=no @@ -519,7 +514,7 @@ case $host in AC_MSG_ERROR("windres not found") fi - CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601" + CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -D_WIN32_WINNT=0x0601" LEVELDB_TARGET_FLAGS="-DOS_WINDOWS" if test "x$CXXFLAGS_overridden" = "xno"; then CXXFLAGS="$CXXFLAGS -w" @@ -833,7 +828,7 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ if test "x$use_thread_local" = xyes || { test "x$use_thread_local" = xauto && test "x$use_glibc_compat" = xno; }; then TEMP_LDFLAGS="$LDFLAGS" - LDFLAGS="$TEMP_LDFLAGS $PTHREAD_CFLAGS" + LDFLAGS="$TEMP_LDFLAGS" AC_MSG_CHECKING([for thread_local support]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include @@ -1083,13 +1078,11 @@ if test x$want_boost = xno; then fi AX_BOOST_SYSTEM AX_BOOST_FILESYSTEM -AX_BOOST_THREAD -AX_BOOST_CHRONO 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. m4_pattern_allow(DBOOST_AC_USE_STD_ATOMIC) dnl otherwise it's treated like a macro -BOOST_CPPFLAGS="-DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS -DBOOST_MPL_LIMIT_LIST_SIZE=50 -DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS" +BOOST_CPPFLAGS="-DBOOST_SP_USE_STD_ATOMIC -DBOOST_AC_USE_STD_ATOMIC $BOOST_CPPFLAGS" if test x$use_reduce_exports = xyes; then AC_MSG_CHECKING([for working boost reduced exports]) @@ -1151,7 +1144,7 @@ fi if test x$use_boost = xyes; then -BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB" +BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB" dnl If boost (prior to 1.57) was built without c++11, it emulated scoped enums @@ -1189,57 +1182,6 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ LIBS="$TEMP_LIBS" CPPFLAGS="$TEMP_CPPFLAGS" -dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however -dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if -dnl a working version is available, else fall back to sleep. sleep was removed -dnl after 1.56. -dnl If neither is available, abort. -TEMP_LIBS="$LIBS" -LIBS="$BOOST_LIBS $LIBS" -TEMP_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - ]],[[ - #if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200) - boost::this_thread::sleep_for(boost::chrono::milliseconds(0)); - #else - choke me - #endif - ]])], - [boost_sleep=yes; - AC_DEFINE(HAVE_WORKING_BOOST_SLEEP_FOR, 1, [Define this symbol if boost sleep_for works])], - [boost_sleep=no]) -LIBS="$TEMP_LIBS" -CPPFLAGS="$TEMP_CPPFLAGS" - -if test x$boost_sleep != xyes; then -TEMP_LIBS="$LIBS" -LIBS="$BOOST_LIBS $LIBS" -TEMP_CPPFLAGS="$CPPFLAGS" -CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ - #include - #include - #include - ]],[[ - #if BOOST_VERSION <= 105600 - boost::this_thread::sleep(boost::posix_time::milliseconds(0)); - #else - choke me - #endif - ]])], - [boost_sleep=yes; AC_DEFINE(HAVE_WORKING_BOOST_SLEEP, 1, [Define this symbol if boost sleep works])], - [boost_sleep=no]) -LIBS="$TEMP_LIBS" -CPPFLAGS="$TEMP_CPPFLAGS" -fi - -if test x$boost_sleep != xyes; then - AC_MSG_ERROR(No working boost sleep implementation found.) -fi - fi if test x$use_pkgconfig = xyes; then @@ -1633,6 +1575,6 @@ echo " CFLAGS = $CFLAGS" echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CPPFLAGS" echo " CXX = $CXX" echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CXXFLAGS" -echo " LDFLAGS = $PTHREAD_CFLAGS $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAGS" +echo " LDFLAGS = $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAGS" echo " ARFLAGS = $ARFLAGS" echo diff --git a/depends/Makefile b/depends/Makefile index 9ef38551e53..e143fd22cee 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -1,5 +1,33 @@ .NOTPARALLEL : +# Pattern rule to print variables, e.g. make print-top_srcdir +print-%: + @echo $* = $($*) + +# When invoking a sub-make, keep only the command line variable definitions +# matching the pattern in the filter function. +# +# e.g. invoking: +# $ make A=1 C=1 print-MAKEOVERRIDES print-MAKEFLAGS +# +# with the following in the Makefile: +# MAKEOVERRIDES := $(filter A=% B=%,$(MAKEOVERRIDES)) +# +# will print: +# MAKEOVERRIDES = A=1 +# MAKEFLAGS = -- A=1 +# +# this is because as the GNU make manual says: +# The command line variable definitions really appear in the variable +# MAKEOVERRIDES, and MAKEFLAGS contains a reference to this variable. +# +# and since the GNU make manual also says: +# variables defined on the command line are passed to the sub-make through +# MAKEFLAGS +# +# this means that sub-makes will be invoked as if: +# $(MAKE) A=1 blah blah +MAKEOVERRIDES := $(filter V=%,$(MAKEOVERRIDES)) SOURCES_PATH ?= $(BASEDIR)/sources WORK_PATH = $(BASEDIR)/work BASE_CACHE ?= $(BASEDIR)/built diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk index 144e5f88b78..258619a9d05 100644 --- a/depends/hosts/default.mk +++ b/depends/hosts/default.mk @@ -13,9 +13,18 @@ default_host_OTOOL = $(host_toolchain)otool default_host_NM = $(host_toolchain)nm define add_host_tool_func +ifneq ($(filter $(origin $1),undefined default),) +# Do not consider the well-known var $1 if it is undefined or is taking a value +# that is predefined by "make" (e.g. the make variable "CC" has a predefined +# value of "cc") $(host_os)_$1?=$$(default_host_$1) $(host_arch)_$(host_os)_$1?=$$($(host_os)_$1) $(host_arch)_$(host_os)_$(release_type)_$1?=$$($(host_os)_$1) +else +$(host_os)_$1=$(or $($1),$($(host_os)_$1),$(default_host_$1)) +$(host_arch)_$(host_os)_$1=$(or $($1),$($(host_arch)_$(host_os)_$1),$$($(host_os)_$1)) +$(host_arch)_$(host_os)_$(release_type)_$1=$(or $($1),$($(host_arch)_$(host_os)_$(release_type)_$1),$$($(host_os)_$1)) +endif host_$1=$$($(host_arch)_$(host_os)_$1) endef diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index f983c754ab6..f56346c5005 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -9,6 +9,7 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic +$(package)_cflags+=-Wno-error=implicit-function-declaration $(package)_cxxflags=-std=c++17 $(package)_cppflags_mingw32=-DUNICODE -D_UNICODE endef diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 0e31ff9ceb2..558651cf13d 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -10,45 +10,45 @@ package=boost # 77: fc9f85fc030e233142908241af7a846e60630aa7388de9a5fafb1f3a26840854 # 78: 8681f175d4bdb26c52222665793eef08490d7758529330f98d3b29dd0735bccc -$(package)_version=1_75_0 -$(package)_sha256_hash=953db31e016db7bb207f11432bef7df100516eeb746843fa0486a222e3fd49cb - -$(package)_version_dot=$(subst _,.,$($(package)_version)) -$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version_dot)/source/ -$(package)_file_name=$(package)_$($(package)_version).tar.bz2 +$(package)_version=1_77_0 +$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/ +$(package)_file_name=boost_$($(package)_version).tar.bz2 +$(package)_sha256_hash=fc9f85fc030e233142908241af7a846e60630aa7388de9a5fafb1f3a26840854 +$(package)_dependencies=native_b2 define $(package)_set_vars $(package)_config_opts_release=variant=release $(package)_config_opts_debug=variant=debug $(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam -$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1 -$(package)_config_opts_linux=threadapi=pthread runtime-link=shared -$(package)_config_opts_darwin=--toolset=darwin-4.2.1 runtime-link=shared -$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static -$(package)_config_opts_x86_64_mingw32=address-model=64 -$(package)_config_opts_i686_mingw32=address-model=32 -$(package)_config_opts_i686_linux=address-model=32 architecture=x86 +$(package)_config_opts+=threading=multi link=static -sNO_COMPRESSION=1 +$(package)_config_opts_linux=target-os=linux threadapi=pthread runtime-link=shared +$(package)_config_opts_darwin=target-os=darwin runtime-link=shared +$(package)_config_opts_mingw32=target-os=windows binary-format=pe threadapi=win32 runtime-link=static +$(package)_config_opts_x86_64=architecture=x86 address-model=64 +$(package)_config_opts_i686=architecture=x86 address-model=32 +ifneq (,$(findstring clang,$($(package)_cxx))) +$(package)_toolset_$(host_os)=clang +else $(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,system,thread,test -$(package)_cxxflags=-std=c++17 -fvisibility=hidden +endif +$(package)_config_libraries=filesystem,system,test +$(package)_cxxflags+=-std=c++17 $(package)_cxxflags_linux=-fPIC +$(package)_cxxflags_x86_64_darwin=-fcf-protection=full 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 + echo "using $($(package)_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cflags)\" \"$($(package)_cxxflags)\" \"$($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$($(package)_ar)\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam endef define $(package)_config_cmds - ./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries) + ./bootstrap.sh --without-icu --with-libraries=$($(package)_config_libraries) --with-toolset=$($(package)_toolset_$(host_os)) --with-bjam=b2 endef define $(package)_build_cmds - ./b2 -d2 -j2 -d1 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) stage + b2 -d2 -j2 -d1 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) toolset=$($(package)_toolset_$(host_os)) stage endef define $(package)_stage_cmds - ./b2 -d0 -j4 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) install + b2 -d0 -j4 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) toolset=$($(package)_toolset_$(host_os)) --no-cmake-config install endef diff --git a/depends/packages/native_b2.mk b/depends/packages/native_b2.mk new file mode 100644 index 00000000000..aaa37cdcfa7 --- /dev/null +++ b/depends/packages/native_b2.mk @@ -0,0 +1,20 @@ +package=native_b2 +$(package)_version=$(boost_version) +$(package)_download_path=$(boost_download_path) +$(package)_file_name=$(boost_file_name) +$(package)_sha256_hash=$(boost_sha256_hash) +$(package)_build_subdir=tools/build/src/engine +ifneq (,$(findstring clang,$($(package)_cxx))) +$(package)_toolset_$(host_os)=clang +else +$(package)_toolset_$(host_os)=gcc +endif + +define $(package)_build_cmds + CXX="$($(package)_cxx)" CXXFLAGS="$($(package)_cxxflags)" ./build.sh "$($(package)_toolset_$(host_os))" +endef + +define $(package)_stage_cmds + mkdir -p "$($(package)_staging_prefix_dir)"/bin/ && \ + cp b2 "$($(package)_staging_prefix_dir)"/bin/ +endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index ea003be486c..657e85efda9 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -10,6 +10,8 @@ upnp_packages=miniupnpc darwin_native_packages = native_biplist native_ds_store native_mac_alias +$(host_arch)_$(host_os)_native_packages += native_b2 + ifneq ($(build_os),darwin) darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus endif diff --git a/doc/build-unix.md b/doc/build-unix.md index aaf3a246839..fb8ee8e599b 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -81,7 +81,7 @@ Build requirements: Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: - sudo apt-get install libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev + sudo apt-get install libssl-dev libevent-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev BerkeleyDB is required for the wallet. diff --git a/make.sh b/make.sh index 525a2569b69..cf83131f443 100755 --- a/make.sh +++ b/make.sh @@ -25,7 +25,7 @@ setup_vars() { # shellcheck disable=SC2206 # This intentionally word-splits the array as env arg can only be strings. - # Other options available: x86_64-w64-mingw32 x86_64-apple-darwin11 + # Other options available: x86_64-w64-mingw32 x86_64-apple-darwin18 TARGET=${TARGET:-"${default_target}"} local default_compiler_flags="" diff --git a/src/Makefile.am b/src/Makefile.am index 932c135d9cd..c6901f0bdff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ DIST_SUBDIRS = secp256k1 univalue -AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) +AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS) AM_LIBTOOLFLAGS = --preserve-dup-deps @@ -156,7 +156,21 @@ DEFI_CORE_H = \ masternodes/auctionhistory.h \ masternodes/balances.h \ masternodes/communityaccounttypes.h \ + masternodes/consensus/accounts.h \ + masternodes/consensus/governance.h \ + masternodes/consensus/icxorders.h \ + masternodes/consensus/loans.h \ + masternodes/consensus/masternodes.h \ + masternodes/consensus/oracles.h \ + masternodes/consensus/poolpairs.h \ + masternodes/consensus/proposals.h \ + masternodes/consensus/smartcontracts.h \ + masternodes/consensus/tokens.h \ + masternodes/consensus/txvisitor.h \ + masternodes/consensus/vaults.h \ + masternodes/customtx.h \ masternodes/factory.h \ + masternodes/futureswap.h \ masternodes/govvariables/attributes.h \ masternodes/govvariables/icx_takerfee_per_btc.h \ masternodes/govvariables/loan_daily_reward.h \ @@ -176,6 +190,7 @@ DEFI_CORE_H = \ masternodes/res.h \ masternodes/oracles.h \ masternodes/poolpairs.h \ + masternodes/proposals.h \ masternodes/tokens.h \ masternodes/undo.h \ masternodes/undos.h \ @@ -195,7 +210,6 @@ DEFI_CORE_H = \ node/psbt.h \ node/transaction.h \ noui.h \ - optional.h \ outputtype.h \ policy/feerate.h \ policy/fees.h \ @@ -248,7 +262,6 @@ DEFI_CORE_H = \ util/error.h \ util/fees.h \ util/system.h \ - util/memory.h \ util/moneystr.h \ util/rbf.h \ util/string.h \ @@ -290,7 +303,7 @@ obj/build.h: FORCE "$(abs_top_srcdir)" libdefi_util_a-clientversion.$(OBJEXT): obj/build.h -libdefi_spv_a_CPPFLAGS = $(AM_CPPFLAGS) -Wpointer-arith -fpermissive -I./spv -I./spv/support -I./secp256k1 -I./secp256k1/src -Wno-format-extra-args -lm -lbsd +libdefi_spv_a_CPPFLAGS = $(AM_CPPFLAGS) -Wpointer-arith -fpermissive -I./spv -I./spv/support -I./secp256k1 -I./secp256k1/src -Wno-format-extra-args libdefi_spv_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libdefi_spv_a_SOURCES = \ spv/bcash/BRBCashAddr.cpp \ @@ -365,6 +378,7 @@ libdefi_server_a_SOURCES = \ chain.cpp \ consensus/tx_verify.cpp \ flatfile.cpp \ + flushablestorage.cpp \ httprpc.cpp \ httpserver.cpp \ index/base.cpp \ @@ -377,7 +391,19 @@ libdefi_server_a_SOURCES = \ masternodes/accountshistory.cpp \ masternodes/anchors.cpp \ masternodes/auctionhistory.cpp \ - masternodes/oracles.cpp \ + masternodes/consensus/accounts.cpp \ + masternodes/consensus/governance.cpp \ + masternodes/consensus/icxorders.cpp \ + masternodes/consensus/loans.cpp \ + masternodes/consensus/masternodes.cpp \ + masternodes/consensus/oracles.cpp \ + masternodes/consensus/poolpairs.cpp \ + masternodes/consensus/proposals.cpp \ + masternodes/consensus/smartcontracts.cpp \ + masternodes/consensus/tokens.cpp \ + masternodes/consensus/txvisitor.cpp \ + masternodes/consensus/vaults.cpp \ + masternodes/futureswap.cpp \ masternodes/govvariables/attributes.cpp \ masternodes/govvariables/icx_takerfee_per_btc.cpp \ masternodes/govvariables/loan_daily_reward.cpp \ @@ -394,6 +420,7 @@ libdefi_server_a_SOURCES = \ masternodes/masternodes.cpp \ masternodes/mn_checks.cpp \ masternodes/mn_rpc.cpp \ + masternodes/oracles.cpp \ masternodes/rpc_accounts.cpp \ masternodes/rpc_customtx.cpp \ masternodes/rpc_masternodes.cpp \ @@ -401,11 +428,13 @@ libdefi_server_a_SOURCES = \ masternodes/rpc_loan.cpp \ masternodes/rpc_oracles.cpp \ masternodes/rpc_poolpair.cpp \ + masternodes/rpc_proposals.cpp \ masternodes/rpc_tokens.cpp \ masternodes/rpc_vault.cpp \ - masternodes/tokens.cpp \ masternodes/poolpairs.cpp \ + masternodes/proposals.cpp \ masternodes/skipped_txs.cpp \ + masternodes/tokens.cpp \ masternodes/undos.cpp \ masternodes/vault.cpp \ masternodes/vaulthistory.cpp \ @@ -593,6 +622,7 @@ libdefi_common_a_SOURCES = \ core_write.cpp \ key.cpp \ key_io.cpp \ + masternodes/customtx.cpp \ merkleblock.cpp \ netaddress.cpp \ netbase.cpp \ diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 31107f51c8b..127054c97e7 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -6,10 +6,6 @@ bin_PROGRAMS += bench/bench_defi BENCH_SRCDIR = bench BENCH_BINARY = bench/bench_defi$(EXEEXT) -RAW_BENCH_FILES = \ - bench/data/block413567.raw -GENERATED_BENCH_FILES = $(RAW_BENCH_FILES:.raw=.raw.h) - bench_bench_defi_SOURCES = \ $(RAW_BENCH_FILES) \ bench/bench_defi.cpp \ @@ -18,8 +14,6 @@ bench_bench_defi_SOURCES = \ bench/block_assemble.cpp \ bench/checkblock.cpp \ bench/checkqueue.cpp \ - bench/data.h \ - bench/data.cpp \ bench/duplicate_inputs.cpp \ bench/examples.cpp \ bench/rollingbloom.cpp \ @@ -44,8 +38,6 @@ bench_bench_defi_SOURCES = \ test/util.h \ test/util.cpp -nodist_bench_bench_defi_SOURCES = $(GENERATED_BENCH_FILES) - bench_bench_defi_CPPFLAGS = $(AM_CPPFLAGS) $(DEFI_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_defi_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_defi_LDADD = \ @@ -77,12 +69,10 @@ endif bench_bench_defi_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) bench_bench_defi_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -CLEAN_DEFI_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES) +CLEAN_DEFI_BENCH = bench/*.gcda bench/*.gcno CLEANFILES += $(CLEAN_DEFI_BENCH) -bench/data.cpp: bench/data/block413567.raw.h - defi_bench: $(BENCH_BINARY) bench: $(BENCH_BINARY) FORCE diff --git a/src/addrman.cpp b/src/addrman.cpp index 96252bd93ff..e82e0dfc328 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -5,6 +5,7 @@ #include +#include #include #include @@ -59,7 +60,7 @@ double CAddrInfo::GetChance(int64_t nNow) const fChance *= 0.01; // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. - fChance *= pow(0.66, std::min(nAttempts, 8)); + fChance *= std::pow(0.66, std::min(nAttempts, 8)); return fChance; } diff --git a/src/amount.h b/src/amount.h index c69ed5f8f34..ad40cbe575b 100644 --- a/src/amount.h +++ b/src/amount.h @@ -75,7 +75,7 @@ struct DCT_ID { } }; -static const CAmount COIN = 100000000; +constexpr CAmount COIN = 100000000; //Converts the given value to decimal format string with COIN precision. inline std::string GetDecimaleString(CAmount nValue) @@ -89,21 +89,21 @@ inline std::string GetDecimaleString(CAmount nValue) typedef std::map TAmounts; -inline ResVal SafeAdd(CAmount _a, CAmount _b) { +template +ResVal SafeAdd(T a, T b) { + static_assert(std::is_integral_v, "SafeAdd is implemented to integral types"); + // check limits - if (_a < 0 || _b < 0) { + if (a < 0 || b < 0) { return Res::Err("negative amount"); } - // convert to unsigned, because signed overflow is UB - const uint64_t a = (uint64_t) _a; - const uint64_t b = (uint64_t) _b; - const uint64_t sum = a + b; + constexpr auto max = std::numeric_limits::max(); // check overflow - if ((sum - a) != b || ((uint64_t)std::numeric_limits::max()) < sum) { - return Res::Err("overflow"); + if (max - a < b) { + return Res::Err("integral overflow"); } - return {(CAmount) sum, Res::Ok()}; + return {a + b, Res::Ok()}; } inline CAmount MultiplyAmounts(CAmount a, CAmount b) @@ -130,11 +130,11 @@ struct CTokenAmount { // simple std::pair is less informative return Res::Err("negative amount: %s", GetDecimaleString(amount)); } // add - auto sumRes = SafeAdd(this->nValue, amount); - if (!sumRes.ok) { + auto sumRes = SafeAdd(nValue, amount); + if (!sumRes) { return std::move(sumRes); } - this->nValue = *sumRes.val; + nValue = sumRes; return Res::Ok(); } Res Sub(CAmount amount) { @@ -142,11 +142,11 @@ struct CTokenAmount { // simple std::pair is less informative if (amount < 0) { return Res::Err("negative amount: %s", GetDecimaleString(amount)); } - if (this->nValue < amount) { - return Res::Err("amount %s is less than %s", GetDecimaleString(this->nValue), GetDecimaleString(amount)); + if (nValue < amount) { + return Res::Err("amount %s is less than %s", GetDecimaleString(nValue), GetDecimaleString(amount)); } // sub - this->nValue -= amount; + nValue -= amount; return Res::Ok(); } CAmount SubWithRemainder(CAmount amount) { @@ -155,13 +155,13 @@ struct CTokenAmount { // simple std::pair is less informative Add(-amount); return 0; } - if (this->nValue < amount) { - CAmount remainder = amount - this->nValue; - this->nValue = 0; + if (nValue < amount) { + CAmount remainder = amount - nValue; + nValue = 0; return remainder; } // sub - this->nValue -= amount; + nValue -= amount; return 0; } diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index b290c6b3b09..29687abdef3 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -27,8 +27,7 @@ template base_uint& base_uint::operator<<=(unsigned int shift) { base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; + pn.fill(0); int k = shift / 32; shift = shift % 32; for (int i = 0; i < WIDTH; i++) { @@ -44,8 +43,7 @@ template base_uint& base_uint::operator>>=(unsigned int shift) { base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; + pn.fill(0); int k = shift / 32; shift = shift % 32; for (int i = 0; i < WIDTH; i++) { @@ -180,6 +178,19 @@ std::string base_uint::GetHex() const return b.GetHex(); } +template +std::string base_uint::GetDecimal() const +{ + auto a = *this; + std::string str; + constexpr char dec[] = "0123456789"; + do { + str.insert(str.begin(), dec[(a % 10).GetLow64()]); + a /= 10; + } while (a != 0); + return str; +} + template void base_uint::SetHex(const char* psz) { diff --git a/src/arith_uint256.h b/src/arith_uint256.h index f46d9ec84c4..637f745da35 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -6,6 +6,7 @@ #ifndef DEFI_ARITH_UINT256_H #define DEFI_ARITH_UINT256_H +#include #include #include #include @@ -27,34 +28,24 @@ class base_uint { protected: static constexpr int WIDTH = BITS / 32; - uint32_t pn[WIDTH]; + std::array pn; public: template friend class base_uint; - base_uint() + constexpr base_uint() : pn{} { static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32."); - - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; } - base_uint(const base_uint& b) + constexpr base_uint(const base_uint& b) : pn(b.pn) { static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32."); - - (*this) = b; } - base_uint(uint64_t b) + constexpr base_uint(uint64_t b) : pn{uint32_t(b), uint32_t(b >> 32)} { static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32."); - - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; } template @@ -224,24 +215,32 @@ class base_uint return ret; } + base_uint& operator%=(const base_uint& b) + { + auto div = (*this) / b; + (*this) -= (div * b); + return *this; + } + int CompareTo(const base_uint& b) const; bool EqualTo(uint64_t b) const; - friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } - friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } - friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } - friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } - friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } - friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } - friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } - friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } - friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } - friend inline const base_uint operator*(const base_uint& a, int32_t b) { return base_uint(a) *= b; } - friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } - friend inline const base_uint operator*(const base_uint& a, int64_t b) { return base_uint(a) *= b; } - friend inline const base_uint operator*(const base_uint& a, uint64_t b) { return base_uint(a) *= b; } - friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; } - friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; } + friend inline constexpr base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } + friend inline constexpr base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } + friend inline constexpr base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } + friend inline constexpr base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } + friend inline constexpr base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } + friend inline constexpr base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } + friend inline constexpr base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } + friend inline constexpr base_uint operator%(const base_uint& a, const base_uint& b) { return base_uint(a) %= b; } + friend inline constexpr base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } + friend inline constexpr base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } + friend inline constexpr base_uint operator*(const base_uint& a, int32_t b) { return base_uint(a) *= b; } + friend inline constexpr base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } + friend inline constexpr base_uint operator*(const base_uint& a, int64_t b) { return base_uint(a) *= b; } + friend inline constexpr base_uint operator*(const base_uint& a, uint64_t b) { return base_uint(a) *= b; } + friend inline bool operator==(const base_uint& a, const base_uint& b) { return a.CompareTo(b) == 0; } + friend inline bool operator!=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) != 0; } friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } @@ -250,11 +249,12 @@ class base_uint friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } std::string GetHex() const; + std::string GetDecimal() const; void SetHex(const char* psz); void SetHex(const std::string& str); std::string ToString() const; - unsigned int size() const + constexpr int size() const { return sizeof(pn); } @@ -276,23 +276,21 @@ class base_uint template void Serialize(Stream& s) const { - s.write((char*)pn, sizeof(pn)); + s.write((char*)&pn[0], size()); } template void Unserialize(Stream& s) { - s.read((char*)pn, sizeof(pn)); + s.read((char*)&pn[0], size()); } }; /** 256-bit unsigned big integer. */ class arith_uint256 : public base_uint<256> { public: - arith_uint256() {} + using base_uint<256>::base_uint; arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} - arith_uint256(uint64_t b) : base_uint<256>(b) {} - explicit arith_uint256(const std::string& str) : base_uint<256>(str) {} /** * The "compact" format is a representation of a whole diff --git a/src/bench/bench_defi.cpp b/src/bench/bench_defi.cpp index 8b0de868938..a24efcbf76c 100644 --- a/src/bench/bench_defi.cpp +++ b/src/bench/bench_defi.cpp @@ -33,40 +33,40 @@ static void SetupBenchArgs() int main(int argc, char** argv) { -// SetupBenchArgs(); // TODO: (temp) disable benches -// std::string error; -// if (!gArgs.ParseParameters(argc, argv, error)) { -// tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str()); -// return EXIT_FAILURE; -// } -// -// if (HelpRequested(gArgs)) { -// std::cout << gArgs.GetHelpMessage(); -// -// return EXIT_SUCCESS; -// } -// -// int64_t evaluations = gArgs.GetArg("-evals", DEFAULT_BENCH_EVALUATIONS); -// std::string regex_filter = gArgs.GetArg("-filter", DEFAULT_BENCH_FILTER); -// std::string scaling_str = gArgs.GetArg("-scaling", DEFAULT_BENCH_SCALING); -// bool is_list_only = gArgs.GetBoolArg("-list", false); -// -// double scaling_factor; -// if (!ParseDouble(scaling_str, &scaling_factor)) { -// tfm::format(std::cerr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str()); -// return EXIT_FAILURE; -// } -// -// std::unique_ptr printer = MakeUnique(); -// std::string printer_arg = gArgs.GetArg("-printer", DEFAULT_BENCH_PRINTER); -// if ("plot" == printer_arg) { -// printer.reset(new benchmark::PlotlyPrinter( -// gArgs.GetArg("-plot-plotlyurl", DEFAULT_PLOT_PLOTLYURL), -// gArgs.GetArg("-plot-width", DEFAULT_PLOT_WIDTH), -// gArgs.GetArg("-plot-height", DEFAULT_PLOT_HEIGHT))); -// } -// -// benchmark::BenchRunner::RunAll(*printer, evaluations, scaling_factor, regex_filter, is_list_only); + SetupBenchArgs(); + std::string error; + if (!gArgs.ParseParameters(argc, argv, error)) { + tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str()); + return EXIT_FAILURE; + } + + if (HelpRequested(gArgs)) { + std::cout << gArgs.GetHelpMessage(); + + return EXIT_SUCCESS; + } + + int64_t evaluations = gArgs.GetArg("-evals", DEFAULT_BENCH_EVALUATIONS); + std::string regex_filter = gArgs.GetArg("-filter", DEFAULT_BENCH_FILTER); + std::string scaling_str = gArgs.GetArg("-scaling", DEFAULT_BENCH_SCALING); + bool is_list_only = gArgs.GetBoolArg("-list", false); + + double scaling_factor; + if (!ParseDouble(scaling_str, &scaling_factor)) { + tfm::format(std::cerr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str()); + return EXIT_FAILURE; + } + + std::unique_ptr printer = std::make_unique(); + std::string printer_arg = gArgs.GetArg("-printer", DEFAULT_BENCH_PRINTER); + if ("plot" == printer_arg) { + printer.reset(new benchmark::PlotlyPrinter( + gArgs.GetArg("-plot-plotlyurl", DEFAULT_PLOT_PLOTLYURL), + gArgs.GetArg("-plot-width", DEFAULT_PLOT_WIDTH), + gArgs.GetArg("-plot-height", DEFAULT_PLOT_HEIGHT))); + } + + benchmark::BenchRunner::RunAll(*printer, evaluations, scaling_factor, regex_filter, is_list_only); return EXIT_SUCCESS; } diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index 112245a7ee8..1884be1293a 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -3,11 +3,11 @@ // file LICENSE or http://www.opensource.org/licenses/mit-license.php. #include -#include #include #include #include +#include #include // These are the two major time-sinks which happen after we have fully received @@ -16,35 +16,45 @@ static void DeserializeBlockTest(benchmark::State& state) { - CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); + const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << chainParams->GenesisBlock(); + auto size = stream.size(); + char a = '\0'; stream.write(&a, 1); // Prevent compaction while (state.KeepRunning()) { CBlock block; stream >> block; - bool rewound = stream.Rewind(benchmark::data::block413567.size()); + bool rewound = stream.Rewind(size); assert(rewound); } } static void DeserializeAndCheckBlockTest(benchmark::State& state) { - CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); + const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + + stream << chainParams->GenesisBlock(); + auto size = stream.size(); + char a = '\0'; stream.write(&a, 1); // Prevent compaction - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); - while (state.KeepRunning()) { CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here stream >> block; - bool rewound = stream.Rewind(benchmark::data::block413567.size()); + bool rewound = stream.Rewind(size); assert(rewound); CValidationState validationState; CheckContextState ctxState; - + + LockAssertion lock(cs_main); bool checked = CheckBlock(block, validationState, chainParams->GetConsensus(), ctxState, false, 413567); assert(checked); } diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index 684b45f6545..724d94e0442 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -6,12 +6,10 @@ #include #include #include -#include -#include #include +#include -static const int MIN_CORES = 2; static const size_t BATCHES = 101; static const size_t BATCH_SIZE = 30; static const int PREVECTOR_SIZE = 28; @@ -36,10 +34,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::State& state) void swap(PrevectorJob& x){p.swap(x.p);}; }; CCheckQueue queue {QUEUE_BATCH_SIZE}; - boost::thread_group tg; - for (auto x = 0; x < std::max(MIN_CORES, GetNumCores()); ++x) { - tg.create_thread([&]{queue.Thread();}); - } + queue.StartWorkerThreads(GetNumCores() - 1); while (state.KeepRunning()) { // Make insecure_rand here so that each iteration is identical. FastRandomContext insecure_rand(true); @@ -55,7 +50,6 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::State& state) // it is done explicitly here for clarity control.Wait(); } - tg.interrupt_all(); - tg.join_all(); + queue.StopWorkerThreads(); } BENCHMARK(CCheckQueueSpeedPrevectorJob, 1400); diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 2f8c97c4779..f2e3eab5425 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -16,7 +16,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector(&wallet, MakeTransactionRef(std::move(tx)))); + wtxs.push_back(std::make_unique(&wallet, MakeTransactionRef(std::move(tx)))); } // Simple benchmark for wallet coin selection. Note that it maybe be necessary @@ -70,7 +70,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector CMutableTransaction tx; tx.vout.resize(nInput + 1); tx.vout[nInput].nValue = nValue; - std::unique_ptr wtx = MakeUnique(&testWallet, MakeTransactionRef(std::move(tx))); + std::unique_ptr wtx = std::make_unique(&testWallet, MakeTransactionRef(std::move(tx))); set.emplace_back(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0); wtxn.emplace_back(std::move(wtx)); } diff --git a/src/bench/data.cpp b/src/bench/data.cpp deleted file mode 100644 index 6eb38285e2e..00000000000 --- a/src/bench/data.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2019 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. - -#include - -namespace benchmark { -namespace data { - -#include -const std::vector block413567{block413567_raw, block413567_raw + sizeof(block413567_raw) / sizeof(block413567_raw[0])}; - -} // namespace data -} // namespace benchmark diff --git a/src/bench/data.h b/src/bench/data.h deleted file mode 100644 index 191398f0908..00000000000 --- a/src/bench/data.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2019 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file LICENSE or http://www.opensource.org/licenses/mit-license.php. - -#ifndef DEFI_BENCH_DATA_H -#define DEFI_BENCH_DATA_H - -#include -#include - -namespace benchmark { -namespace data { - -extern const std::vector block413567; - -} // namespace data -} // namespace benchmark - -#endif // DEFI_BENCH_DATA_H diff --git a/src/bench/data/block413567.raw b/src/bench/data/block413567.raw deleted file mode 100644 index 67d2d5d3820..00000000000 Binary files a/src/bench/data/block413567.raw and /dev/null differ diff --git a/src/bench/examples.cpp b/src/bench/examples.cpp index e4d1708aff9..f03eaf41733 100644 --- a/src/bench/examples.cpp +++ b/src/bench/examples.cpp @@ -10,7 +10,7 @@ static void Sleep100ms(benchmark::State& state) { while (state.KeepRunning()) { - MilliSleep(100); + UninterruptibleSleep(std::chrono::milliseconds{100}); } } diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 852906f0104..8eea46282a3 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -3,7 +3,6 @@ // file LICENSE or http://www.opensource.org/licenses/mit-license.php. #include -#include #include #include @@ -13,7 +12,12 @@ #include static void BlockToJsonVerbose(benchmark::State& state) { - CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); + + const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << chainParams->GenesisBlock(); + char a = '\0'; stream.write(&a, 1); // Prevent compaction diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp index a0889b97f31..0cbc9ff5344 100644 --- a/src/bench/wallet_balance.cpp +++ b/src/bench/wallet_balance.cpp @@ -4,11 +4,12 @@ #include #include -#include #include #include #include +#include + static void WalletBalance(benchmark::State& state, const bool set_dirty, const bool add_watchonly, const bool add_mine) { const auto& ADDRESS_WATCHONLY = ADDRESS_BCRT1_UNSPENDABLE; @@ -22,11 +23,11 @@ static void WalletBalance(benchmark::State& state, const bool set_dirty, const b } - const Optional address_mine{add_mine ? Optional{getnewaddress(wallet)} : nullopt}; + const std::optional address_mine{add_mine ? std::optional{getnewaddress(wallet)} : std::nullopt}; if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY); for (int i = 0; i < 100; ++i) { - generatetoaddress(address_mine.get_value_or(ADDRESS_WATCHONLY)); + generatetoaddress(address_mine.value_or(ADDRESS_WATCHONLY)); generatetoaddress(ADDRESS_WATCHONLY); } SyncWithValidationInterfaceQueue(); @@ -39,6 +40,7 @@ static void WalletBalance(benchmark::State& state, const bool set_dirty, const b if (add_mine) assert(bal.m_mine_trusted[DCT_ID{0}] > 0); // tokens `0` if (add_watchonly) assert(bal.m_watchonly_trusted[DCT_ID{0}] > 0); // tokens `0` } + wallet.NotifyUnload(); } static void WalletBalanceDirty(benchmark::State& state) { WalletBalance(state, /* set_dirty */ true, /* add_watchonly */ true, /* add_mine */ true); } diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 306d18d6d0d..6749197b719 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -105,13 +105,12 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c std::vector have_txn(txn_available.size()); { LOCK(pool->cs); - const std::vector >& vTxHashes = pool->vTxHashes; - for (size_t i = 0; i < vTxHashes.size(); i++) { - uint64_t shortid = cmpctblock.GetShortID(vTxHashes[i].first); - std::unordered_map::iterator idit = shorttxids.find(shortid); + for (const auto& vhash : pool->vTxHashes) { + uint64_t shortid = cmpctblock.GetShortID(vhash.first); + auto idit = shorttxids.find(shortid); if (idit != shorttxids.end()) { if (!have_txn[idit->second]) { - txn_available[idit->second] = vTxHashes[i].second->GetSharedTx(); + txn_available[idit->second] = vhash.second->GetSharedTx(); have_txn[idit->second] = true; mempool_count++; } else { diff --git a/src/blockencodings.h b/src/blockencodings.h index dc331f417ce..99c1859642e 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -6,11 +6,14 @@ #define DEFI_BLOCKENCODINGS_H #include +#include #include class CTxMemPool; +extern RecursiveMutex cs_main; + // Dumb helper to handle CTransaction compression at serialize-time struct TransactionCompressor { private: @@ -206,7 +209,7 @@ class PartiallyDownloadedBlock { // extra_txn is a list of extra transactions to look at, in form ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector>& extra_txn); bool IsTxAvailable(size_t index) const; - ReadStatus FillBlock(CBlock& block, const std::vector& vtx_missing, const int height); + ReadStatus FillBlock(CBlock& block, const std::vector& vtx_missing, const int height) EXCLUSIVE_LOCKS_REQUIRED(cs_main); }; #endif // DEFI_BLOCKENCODINGS_H diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f653376d16e..df70163d019 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -13,11 +13,11 @@ #include #include +#include #include #include #include -#include std::vector CChainParams::CreateGenesisMasternodes() { @@ -31,15 +31,15 @@ std::vector CChainParams::CreateGenesisMasternodes() txNew.vin[0].scriptSig = CScript(); // << 486604799 << CScriptNum(4) << std::vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); CTxDestination operatorDest = DecodeDestination(addrs.operatorAddress, *this); - assert(operatorDest.which() == PKHashType || operatorDest.which() == WitV0KeyHashType); + assert(operatorDest.index() == PKHashType || operatorDest.index() == WitV0KeyHashType); CTxDestination ownerDest = DecodeDestination(addrs.ownerAddress, *this); - assert(ownerDest.which() == PKHashType || ownerDest.which() == WitV0KeyHashType); + assert(ownerDest.index() == PKHashType || ownerDest.index() == WitV0KeyHashType); - CKeyID operatorAuthKey = operatorDest.which() == PKHashType ? CKeyID(*boost::get(&operatorDest)) : CKeyID(*boost::get(&operatorDest)) ; + CKeyID operatorAuthKey = operatorDest.index() == PKHashType ? CKeyID(std::get(operatorDest)) : CKeyID(std::get(operatorDest)) ; genesisTeam.insert(operatorAuthKey); CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION); metadata << static_cast(CustomTxType::CreateMasternode) - << static_cast(operatorDest.which()) << operatorAuthKey; + << static_cast(operatorDest.index()) << operatorAuthKey; CScript scriptMeta; scriptMeta << OP_RETURN << ToByteVector(metadata); @@ -129,7 +129,8 @@ class CMainParams : public CChainParams { consensus.FortCanningMuseumHeight = 1430640; consensus.FortCanningParkHeight = 1503143; consensus.FortCanningHillHeight = 1604999; // Feb 7, 2022. - consensus.FortCanningRoadHeight = 1786000; // April 11, 2022. + consensus.FortCanningRoadHeight = 1786000; // April 11, 2022. + consensus.GreatWorldHeight = std::numeric_limits::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -185,6 +186,15 @@ class CMainParams : public CChainParams { consensus.vaultCreationFee = 2 * COIN; + consensus.props.cfp.fee = 10 * COIN; + consensus.props.cfp.majorityThreshold = 5000; // vote pass with over 50% majority + consensus.props.voc.fee = 50 * COIN; + consensus.props.voc.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.brp.fee = 500 * COIN; + consensus.props.brp.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.minVoting = 100; // 1% of the masternodes must vote + consensus.props.votingPeriod = 130000; // tally votes every 130K blocks + consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI of 200 per block (rate normalized to (COIN == 100%)) consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN /10 / 200); // 0.1 DFI of 200 per block @@ -202,6 +212,7 @@ class CMainParams : public CChainParams { consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); /** * The message start string is designed to be unlikely to occur in normal data. @@ -358,6 +369,7 @@ class CTestNetParams : public CChainParams { consensus.FortCanningParkHeight = 828800; consensus.FortCanningHillHeight = 828900; consensus.FortCanningRoadHeight = 893700; + consensus.GreatWorldHeight = std::numeric_limits::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -413,6 +425,15 @@ class CTestNetParams : public CChainParams { consensus.vaultCreationFee = 1 * COIN; + consensus.props.cfp.fee = 10 * COIN; + consensus.props.cfp.majorityThreshold = 5000; // vote pass with over 50% majority + consensus.props.voc.fee = 50 * COIN; + consensus.props.voc.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.brp.fee = 500 * COIN; + consensus.props.brp.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.minVoting = 100; // 1% of the masternodes must vote + consensus.props.votingPeriod = 70000; // tally votes every 70K blocks + consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block @@ -430,6 +451,7 @@ class CTestNetParams : public CChainParams { consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); pchMessageStartPostAMK[0] = pchMessageStart[0] = 0x0b; pchMessageStartPostAMK[1] = pchMessageStart[1] = 0x11; @@ -547,6 +569,7 @@ class CDevNetParams : public CChainParams { consensus.FortCanningParkHeight = std::numeric_limits::max(); consensus.FortCanningHillHeight = std::numeric_limits::max(); consensus.FortCanningRoadHeight = std::numeric_limits::max(); + consensus.GreatWorldHeight = std::numeric_limits::max(); consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks @@ -600,6 +623,15 @@ class CDevNetParams : public CChainParams { consensus.vaultCreationFee = 1 * COIN; + consensus.props.cfp.fee = 1 * COIN; + consensus.props.cfp.majorityThreshold = 5000; // vote pass with over 50% majority + consensus.props.voc.fee = 5 * COIN; + consensus.props.voc.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.brp.fee = 10 * COIN; + consensus.props.brp.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.minVoting = 100; // 1% of the masternodes must vote + consensus.props.votingPeriod = 100; // tally votes every 1K blocks + consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block @@ -617,6 +649,7 @@ class CDevNetParams : public CChainParams { consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); pchMessageStartPostAMK[0] = pchMessageStart[0] = 0x0b; pchMessageStartPostAMK[1] = pchMessageStart[1] = 0x11; @@ -641,16 +674,18 @@ class CDevNetParams : public CChainParams { consensus.foundationShareDFIP1 = 199 * COIN / 10 / 200; // 19.9 DFI @ 200 per block (rate normalized to (COIN == 100%) // now it is for devnet and regtest only, 2 first of genesis MNs acts as foundation members - consensus.foundationMembers.emplace(GetScriptForDestination(DecodeDestination("7M3g9CSERjLdXisE5pv2qryDbURUj9Vpi1", *this))); - consensus.foundationMembers.emplace(GetScriptForDestination(DecodeDestination("7L29itepC13pgho1X2y7mcuf4WjkBi7x2w", *this))); + consensus.foundationMembers.emplace(GetScriptForDestination(DecodeDestination("7AEMWykWPPSFuKrQtgRvTtGp5eTvoDfcFA", *this))); + // cQieU9KNjuUK9jSs7B5tqnByjXtMPEyAJG1YHzRMQus4Fg5Wms9t + consensus.foundationMembers.emplace(GetScriptForDestination(DecodeDestination("77Mdyp5E54JLVAwJwvYK7LSM7vAzb6wiUk", *this))); + // cSjyfiS4stWnk1hqWqZR2e5Rj58gQjPCAfuLGNPHp7ZqZLv4Pft7 consensus.smartContracts.clear(); consensus.smartContracts[SMART_CONTRACT_DFIP_2201] = GetScriptForDestination(CTxDestination(WitnessV0KeyHash(std::vector{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}))); consensus.smartContracts[SMART_CONTRACT_DFIP_2203] = GetScriptForDestination(CTxDestination(WitnessV0KeyHash(std::vector{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}))); // owner base58, operator base58 - vMasternodes.push_back({"7M3g9CSERjLdXisE5pv2qryDbURUj9Vpi1", "7Grgx69MZJ4wDKRx1bBxLqTnU9T3quKW7n"}); - vMasternodes.push_back({"7L29itepC13pgho1X2y7mcuf4WjkBi7x2w", "773MiaEtQK2HAwWj55gyuRiU8tSwowRTTW"}); + vMasternodes.push_back({"7AEMWykWPPSFuKrQtgRvTtGp5eTvoDfcFA", "7AEMWykWPPSFuKrQtgRvTtGp5eTvoDfcFA"}); + vMasternodes.push_back({"77Mdyp5E54JLVAwJwvYK7LSM7vAzb6wiUk", "77Mdyp5E54JLVAwJwvYK7LSM7vAzb6wiUk"}); vMasternodes.push_back({"75Wramp2iARchHedXcn1qRkQtMpSt9Mi3V", "7Ku81yvqbPkxpWjZpZWZZnWydXyzJozZfN"}); vMasternodes.push_back({"7LfqHbyh9dBQDjWB6MxcWvH2PBC5iY4wPa", "75q6ftr3QGfBT3DBu15fVfetP6duAgfhNH"}); @@ -666,8 +701,8 @@ class CDevNetParams : public CChainParams { genesis = CreateGenesisBlock(1585132338, 0x1d00ffff, 1, initdist, CreateGenesisMasternodes()); // old=1296688602 consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x0000099a168f636895a019eacfc1798ec54c593c015cfc5aac1f12817f7ddff7")); - assert(genesis.hashMerkleRoot == uint256S("0x3f327ba2475176bcf8226b10d871f0f992e17ba9e040ff3dbd11d17c1e5914cb")); + assert(consensus.hashGenesisBlock == uint256S("0x2d77a1099b52f23aa96075551907786995c4bad4c86599b1b08790ce49e25c40")); + assert(genesis.hashMerkleRoot == uint256S("0xf9079b6644798cbba8097b52596969b6e26cf03f2916a0b499662731eadef242")); vFixedSeeds.clear(); vSeeds.clear(); @@ -728,6 +763,7 @@ class CRegTestParams : public CChainParams { consensus.FortCanningParkHeight = 10000000; consensus.FortCanningHillHeight = 10000000; consensus.FortCanningRoadHeight = 10000000; + consensus.GreatWorldHeight = 10000000; consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks @@ -779,6 +815,15 @@ class CRegTestParams : public CChainParams { consensus.spv.subsidyIncreaseValue = 5 * COIN; consensus.spv.minConfirmations = 6; + consensus.props.cfp.fee = 1 * COIN; + consensus.props.cfp.majorityThreshold = 5000; // vote pass with over 50% majority + consensus.props.voc.fee = 5 * COIN; + consensus.props.voc.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.brp.fee = 10 * COIN; + consensus.props.brp.majorityThreshold = 6667; // vote pass with over 66.67% majority + consensus.props.minVoting = 100; // 1% of the masternodes must vote + consensus.props.votingPeriod = 70; // tally votes every 70 blocks + consensus.vaultCreationFee = 1 * COIN; consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 10 * COIN / 50); // normalized to (COIN == 100%) // 10 per block @@ -798,6 +843,7 @@ class CRegTestParams : public CChainParams { consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); pchMessageStartPostAMK[0] = pchMessageStart[0] = 0xfa; pchMessageStartPostAMK[1] = pchMessageStart[1] = 0xbf; @@ -911,11 +957,11 @@ class CRegTestParams : public CChainParams { }; /// Check for fork height based flag, validate and set the value to a target var -boost::optional UpdateHeightValidation(const std::string& argName, const std::string& argFlag, int& argTarget) { +std::optional UpdateHeightValidation(const std::string& argName, const std::string& argFlag, int& argTarget) { if (gArgs.IsArgSet(argFlag)) { int64_t height = gArgs.GetArg(argFlag, argTarget); if (height < -1 || height >= std::numeric_limits::max()) { - auto lowerArgName = boost::to_lower_copy(argName); + std::string lowerArgName = ToLower(argFlag); throw std::runtime_error(strprintf( "Activation height %ld for %s is out of valid range. Use -1 to disable %s.", height, argName, lowerArgName)); @@ -940,7 +986,7 @@ void CRegTestParams::UpdateActivationParametersFromArgs() UpdateHeightValidation("Dakota Crescent", "-dakotacrescentheight", consensus.DakotaCrescentHeight); auto eunosHeight = UpdateHeightValidation("Eunos", "-eunosheight", consensus.EunosHeight); if (eunosHeight.has_value()){ - consensus.EunosKampungHeight = static_cast(eunosHeight.get()); + consensus.EunosKampungHeight = static_cast(eunosHeight.value()); } UpdateHeightValidation("Eunos Paya", "-eunospayaheight", consensus.EunosPayaHeight); UpdateHeightValidation("Fort Canning", "-fortcanningheight", consensus.FortCanningHeight); @@ -948,6 +994,7 @@ void CRegTestParams::UpdateActivationParametersFromArgs() UpdateHeightValidation("Fort Canning Park", "-fortcanningparkheight", consensus.FortCanningParkHeight); UpdateHeightValidation("Fort Canning Hill", "-fortcanninghillheight", consensus.FortCanningHillHeight); UpdateHeightValidation("Fort Canning Road", "-fortcanningroadheight", consensus.FortCanningRoadHeight); + UpdateHeightValidation("Great World", "-greatworldheight", consensus.GreatWorldHeight); if (gArgs.GetBoolArg("-simulatemainnet", false)) { consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 95b7836b522..fc2526f43e5 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -7,7 +7,6 @@ #include #include -#include #include @@ -37,13 +36,13 @@ const CBaseChainParams& BaseParams() std::unique_ptr CreateBaseChainParams(const std::string& chain) { if (chain == CBaseChainParams::MAIN) - return MakeUnique("", 8554); + return std::make_unique("", 8554); else if (chain == CBaseChainParams::TESTNET) - return MakeUnique("testnet3", 18554); + return std::make_unique("testnet3", 18554); else if (chain == CBaseChainParams::DEVNET) - return MakeUnique("devnet", 20554); + return std::make_unique("devnet", 20554); else if (chain == CBaseChainParams::REGTEST) - return MakeUnique("regtest", 19554); + return std::make_unique("regtest", 19554); else throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } diff --git a/src/checkqueue.h b/src/checkqueue.h index 4cdc74e565b..19599d556b9 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -6,13 +6,12 @@ #define DEFI_CHECKQUEUE_H #include +#include +#include #include #include -#include -#include - template class CCheckQueueControl; @@ -31,67 +30,69 @@ class CCheckQueue { private: //! Mutex to protect the inner state - boost::mutex mutex; + Mutex m_mutex; //! Worker threads block on this when out of work - boost::condition_variable condWorker; + std::condition_variable m_worker_cv; //! Master thread blocks on this when out of work - boost::condition_variable condMaster; + std::condition_variable m_master_cv; //! The queue of elements to be processed. //! As the order of booleans doesn't matter, it is used as a LIFO (stack) - std::vector queue; + std::vector queue GUARDED_BY(m_mutex); //! The number of workers (including the master) that are idle. - int nIdle; + int nIdle GUARDED_BY(m_mutex){0}; //! The total number of workers (including the master). - int nTotal; + int nTotal GUARDED_BY(m_mutex){0}; //! The temporary evaluation result. - bool fAllOk; + bool fAllOk GUARDED_BY(m_mutex){true}; /** * Number of verifications that haven't completed yet. * This includes elements that are no longer queued, but still in the * worker's own batches. */ - unsigned int nTodo; + unsigned int nTodo GUARDED_BY(m_mutex){0}; //! The maximum number of elements to be processed in one batch - unsigned int nBatchSize; + const unsigned int nBatchSize; + + std::vector m_worker_threads; + bool m_request_stop GUARDED_BY(m_mutex){false}; /** Internal function that does bulk of the verification work. */ - bool Loop(bool fMaster = false) + bool Loop(bool fMaster) { - boost::condition_variable& cond = fMaster ? condMaster : condWorker; + std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv; std::vector vChecks; vChecks.reserve(nBatchSize); unsigned int nNow = 0; bool fOk = true; do { { - boost::unique_lock lock(mutex); + WAIT_LOCK(m_mutex, lock); // first do the clean-up of the previous loop run (allowing us to do it in the same critsect) if (nNow) { fAllOk &= fOk; nTodo -= nNow; if (nTodo == 0 && !fMaster) // We processed the last element; inform the master it can exit and return the result - condMaster.notify_one(); + m_master_cv.notify_one(); } else { // first iteration nTotal++; } // logically, the do loop starts here - while (queue.empty()) { + while (queue.empty() && !m_request_stop) { if (fMaster && nTodo == 0) { nTotal--; bool fRet = fAllOk; // reset the status for new work later - if (fMaster) - fAllOk = true; + fAllOk = true; // return the current status return fRet; } @@ -99,6 +100,10 @@ class CCheckQueue cond.wait(lock); // wait nIdle--; } + if (m_request_stop) { + return false; + } + // Decide how many work units to process now. // * Do not try to do everything at once, but aim for increasingly smaller batches so // all workers finish approximately simultaneously. @@ -125,15 +130,27 @@ class CCheckQueue public: //! Mutex to ensure only one concurrent CCheckQueueControl - boost::mutex ControlMutex; + Mutex m_control_mutex; //! Create a new check queue - explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), nBatchSize(nBatchSizeIn) {} + explicit CCheckQueue(unsigned int nBatchSizeIn) : nBatchSize(nBatchSizeIn) {} - //! Worker thread - void Thread() + //! Create a pool of new worker threads. + void StartWorkerThreads(const int threads_num) { - Loop(); + { + LOCK(m_mutex); + nIdle = 0; + nTotal = 0; + fAllOk = true; + } + assert(m_worker_threads.empty()); + for (int n = 0; n < threads_num; ++n) { + m_worker_threads.emplace_back([this, n]() { + util::ThreadRename(strprintf("scriptch.%i", n)); + Loop(false /* worker thread */); + }); + } } //! Wait until execution finishes, and return whether all evaluations were successful. @@ -145,20 +162,33 @@ class CCheckQueue //! Add a batch of checks to the queue void Add(std::vector& vChecks) { - boost::unique_lock lock(mutex); + LOCK(m_mutex); for (T& check : vChecks) { queue.push_back(T()); check.swap(queue.back()); } nTodo += vChecks.size(); if (vChecks.size() == 1) - condWorker.notify_one(); + m_worker_cv.notify_one(); else if (vChecks.size() > 1) - condWorker.notify_all(); + m_worker_cv.notify_all(); + } + + //! Stop all of the worker threads. + void StopWorkerThreads() + { + WITH_LOCK(m_mutex, m_request_stop = true); + m_worker_cv.notify_all(); + for (std::thread& t : m_worker_threads) { + t.join(); + } + m_worker_threads.clear(); + WITH_LOCK(m_mutex, m_request_stop = false); } ~CCheckQueue() { + assert(m_worker_threads.empty()); } }; @@ -182,7 +212,7 @@ class CCheckQueueControl { // passed queue is supposed to be unused, or nullptr if (pqueue != nullptr) { - ENTER_CRITICAL_SECTION(pqueue->ControlMutex); + ENTER_CRITICAL_SECTION(pqueue->m_control_mutex); } } @@ -206,7 +236,7 @@ class CCheckQueueControl if (!fDone) Wait(); if (pqueue != nullptr) { - LEAVE_CRITICAL_SECTION(pqueue->ControlMutex); + LEAVE_CRITICAL_SECTION(pqueue->m_control_mutex); } } }; diff --git a/src/consensus/params.h b/src/consensus/params.h index 2d047d9bcd3..0e0d45c2e66 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -95,6 +95,7 @@ struct Params { int FortCanningParkHeight; int FortCanningHillHeight; int FortCanningRoadHeight; + int GreatWorldHeight; /** Foundation share after AMK, normalized to COIN = 100% */ CAmount foundationShareDFIP1; @@ -198,6 +199,16 @@ struct Params { CAmount vaultCreationFee; + struct CPropsParams { + struct CPropsSpecs { + CAmount fee; + uint32_t majorityThreshold; + } cfp, brp, voc; + int votingPeriod; + uint32_t minVoting; + }; + CPropsParams props; + std::map nonUtxoBlockSubsidies; std::map newNonUTXOSubsidies; }; diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp index ee03891b96d..472f795decd 100644 --- a/src/consensus/tx_check.cpp +++ b/src/consensus/tx_check.cpp @@ -8,8 +8,10 @@ #include /// @todo refactor it to unify txs!!! (need to restart blockchain) +const std::vector DfTxMarker = {'D', 'f', 'T', 'x'}; const std::vector DfAnchorFinalizeTxMarker = {'D', 'f', 'A', 'f'}; const std::vector DfAnchorFinalizeTxMarkerPlus = {'D', 'f', 'A', 'P'}; +const std::vector DfTokenSplitMarker = {'D', 'f', 'T', 'S'}; bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs) { @@ -49,7 +51,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe if (tx.IsCoinBase()) { std::vector dummy; - if (IsAnchorRewardTx(tx, dummy) || IsAnchorRewardTxPlus(tx, dummy)) + if (IsAnchorRewardTx(tx, dummy) || IsAnchorRewardTxPlus(tx, dummy) || IsTokenSplitTx(tx, dummy)) return true; if (tx.vin[0].scriptSig.size() < 2 || (tx.vin[0].scriptSig.size() > 100)) return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length"); @@ -90,17 +92,13 @@ bool ParseScriptByMarker(CScript const & script, return true; } -bool IsAnchorRewardTx(CTransaction const & tx, std::vector & metadata, bool fortCanning) +bool IsAnchorRewardTx(CTransaction const & tx, std::vector & metadata) { if (!tx.IsCoinBase() || tx.vout.size() != 2 || tx.vout[0].nValue != 0) { return false; } bool hasAdditionalOpcodes{false}; - const auto result = ParseScriptByMarker(tx.vout[0].scriptPubKey, DfAnchorFinalizeTxMarker, metadata, hasAdditionalOpcodes); - if (fortCanning && hasAdditionalOpcodes) { - return false; - } - return result; + return ParseScriptByMarker(tx.vout[0].scriptPubKey, DfAnchorFinalizeTxMarker, metadata, hasAdditionalOpcodes); } bool IsAnchorRewardTxPlus(CTransaction const & tx, std::vector & metadata, bool fortCanning) @@ -115,3 +113,19 @@ bool IsAnchorRewardTxPlus(CTransaction const & tx, std::vector & } return result; } + +bool IsTokenSplitTx(CTransaction const & tx, std::vector & metadata, bool greatWorld) +{ + if (!greatWorld) { + return false; + } + if (!tx.IsCoinBase() || tx.vout.size() != 1 || tx.vout[0].nValue != 0) { + return false; + } + bool hasAdditionalOpcodes{false}; + const auto result = ParseScriptByMarker(tx.vout[0].scriptPubKey, DfTokenSplitMarker, metadata, hasAdditionalOpcodes); + if (hasAdditionalOpcodes) { + return false; + } + return result; +} diff --git a/src/consensus/tx_check.h b/src/consensus/tx_check.h index 3a7d334ef2f..fab1299d197 100644 --- a/src/consensus/tx_check.h +++ b/src/consensus/tx_check.h @@ -14,9 +14,10 @@ #include -/// moved here (!!) due to strange linker errors under mac/win builds +extern const std::vector DfTxMarker; extern const std::vector DfAnchorFinalizeTxMarker; extern const std::vector DfAnchorFinalizeTxMarkerPlus; +extern const std::vector DfTokenSplitMarker; class CScript; class CTransaction; @@ -28,7 +29,8 @@ bool ParseScriptByMarker(CScript const & script, const std::vector & marker, std::vector & metadata, bool& hasAdditionalOpcodes); -bool IsAnchorRewardTx(CTransaction const & tx, std::vector & metadata, bool fortCanning = false); +bool IsAnchorRewardTx(CTransaction const & tx, std::vector & metadata); bool IsAnchorRewardTxPlus(CTransaction const & tx, std::vector & metadata, bool fortCanning = false); +bool IsTokenSplitTx(CTransaction const & tx, std::vector & metadata, bool greatWorld = true); #endif // DEFI_CONSENSUS_TX_CHECK_H diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 21d30380527..a2ae6f911cc 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -161,7 +162,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i return nSigOps; } -bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, const CCustomCSView * mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams) +bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, CCustomCSView& mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams) { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { @@ -169,6 +170,20 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c strprintf("%s: inputs missing/spent", __func__)); } + // check for tokens values + uint256 canSpend; + std::vector dummy; + const auto txType = GuessCustomTxType(tx, dummy); + + if (NotAllowedToFail(txType, nSpendHeight) || (nSpendHeight >= chainparams.GetConsensus().GreatWorldHeight && txType == CustomTxType::UpdateMasternode)) { + CCustomCSView discardCache(mnview); + CFutureSwapView futureSwapView(*pfutureSwapView); + auto res = ApplyCustomTx(discardCache, futureSwapView, inputs, tx, chainparams.GetConsensus(), nSpendHeight, 0, &canSpend); + if (!res.ok && (res.code & CustomTxErrCodes::Fatal) && txType != CustomTxType::UpdateMasternode) { + return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-customtx", res.msg); + } + } + TAmounts nValuesIn; for (unsigned int i = 0; i < tx.vin.size(); ++i) { const COutPoint &prevout = tx.vin[i].prevout; @@ -187,8 +202,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); } /// @todo tokens: later match the range with TotalSupply - - if (prevout.n == 1 && !mnview->CanSpend(prevout.hash, nSpendHeight)) { + if (canSpend != prevout.hash && prevout.n == 1 && !mnview.CanSpend(prevout.hash, nSpendHeight)) { return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-collateral-locked", strprintf("tried to spend locked collateral for %s", prevout.hash.ToString())); /// @todo may be somehow place the height of unlocking? } @@ -215,18 +229,6 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-tokens-in-old-version-tx"); } - // check for tokens values - std::vector dummy; - const auto txType = GuessCustomTxType(tx, dummy); - - if (NotAllowedToFail(txType, nSpendHeight)) { - CCustomCSView discardCache(const_cast(*mnview)); - auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight); - if (!res.ok && (res.code & CustomTxErrCodes::Fatal)) { - return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-customtx", res.msg); - } - } - for (auto const & kv : non_minted_values_out) { DCT_ID const & tokenId = kv.first; diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index 42293d7d114..24cf5a15a05 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -6,6 +6,7 @@ #define DEFI_CONSENSUS_TX_VERIFY_H #include +#include #include #include @@ -17,6 +18,8 @@ class CCustomCSView; class CTransaction; class CValidationState; +extern RecursiveMutex cs_main; + /** Transaction validation functions */ namespace Consensus { @@ -26,7 +29,7 @@ namespace Consensus { * @param[out] txfee Set to the transaction fee if successful. * Preconditions: tx.IsCoinBase() is false. */ -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, const CCustomCSView * mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams); +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, CCustomCSView& mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); } // namespace Consensus /** Auxiliary functions for transaction validation (ideally should not be exposed) */ diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 54e6263cf59..60f6f78b0ff 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -100,8 +100,7 @@ static void SetMaxOpenFiles(leveldb::Options *options) { static leveldb::Options GetOptions(size_t nCacheSize) { leveldb::Options options; - options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); - options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously + options.block_cache = leveldb::NewLRUCache(nCacheSize); options.filter_policy = leveldb::NewBloomFilterPolicy(10); options.compression = leveldb::kNoCompression; options.info_log = new CDefiLevelDBLogger(); diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 8cb4ef56da8..22896a195b8 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -16,6 +16,8 @@ #include #include +#include + static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; @@ -65,16 +67,13 @@ class CDBBatch const CDBWrapper &parent; leveldb::WriteBatch batch; - CDataStream ssKey; - CDataStream ssValue; - size_t size_estimate; public: /** * @param[in] _parent CDBWrapper that this batch is to be submitted to */ - explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { }; + explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), size_estimate(0) {} void Clear() { @@ -85,11 +84,13 @@ class CDBBatch template void Write(const K& key, const V& value) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(ssKey.data(), ssKey.size()); // leveldb::Slice slKey(SliceKey(key)); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE); ssValue << value; ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); @@ -104,13 +105,12 @@ class CDBBatch // - byte[]: value // The formula below assumes the key and value are both less than 16k. size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size(); - ssKey.clear(); - ssValue.clear(); } template void Erase(const K& key) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(ssKey.data(), ssKey.size()); @@ -123,7 +123,6 @@ class CDBBatch // - byte[]: key // The formula below assumes the key is less than 16kB. size_estimate += 2 + (slKey.size() > 127) + slKey.size(); - ssKey.clear(); } size_t SizeEstimate() const { return size_estimate; } @@ -259,7 +258,7 @@ class CDBWrapper CDBWrapper& operator=(const CDBWrapper&) = delete; template - bool Read(const K& key, V& value) const + bool Read(const K& key, V& value, std::optional options = {}) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); @@ -268,7 +267,8 @@ class CDBWrapper // leveldb::Slice slKey(SliceKey(key)); std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + auto& currentOptions = options ? *options : readoptions; + leveldb::Status status = pdb->Get(currentOptions, slKey, &strValue); if (!status.ok()) { if (status.IsNotFound()) return false; @@ -294,7 +294,7 @@ class CDBWrapper } template - bool Exists(const K& key) const + bool Exists(const K& key, std::optional options = {}) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); @@ -303,7 +303,8 @@ class CDBWrapper // leveldb::Slice slKey(SliceKey(key)); std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + auto& currentOptions = options ? *options : readoptions; + leveldb::Status status = pdb->Get(currentOptions, slKey, &strValue); if (!status.ok()) { if (status.IsNotFound()) return false; @@ -338,11 +339,32 @@ class CDBWrapper return WriteBatch(batch, true); } - CDBIterator *NewIterator() + CDBIterator *NewIterator(std::optional options = {}) + { + auto& currentOptions = options ? *options : iteroptions; + return new CDBIterator(*this, pdb->NewIterator(currentOptions)); + } + + const leveldb::Snapshot *GetSnapshot() { - return new CDBIterator(*this, pdb->NewIterator(iteroptions)); + return pdb->GetSnapshot(); } + void ReleaseSnapshot(const leveldb::Snapshot *snapshot) + { + pdb->ReleaseSnapshot(snapshot); + } + + leveldb::ReadOptions GetReadOptions() const + { + return readoptions; + } + + leveldb::ReadOptions GetIterOptions() const + { + return iteroptions; + } + /** * Return true if the database managed by this class contains no entries. */ diff --git a/src/defi-cli.cpp b/src/defi-cli.cpp index 57a8e430419..5e7a40fc8cb 100644 --- a/src/defi-cli.cpp +++ b/src/defi-cli.cpp @@ -483,7 +483,7 @@ static int CommandLineRPC(int argc, char *argv[]) } catch (const CConnectionFailed&) { if (fWait) - MilliSleep(1000); + UninterruptibleSleep(std::chrono::milliseconds{1000}); else throw; } diff --git a/src/defid.cpp b/src/defid.cpp index 356253fbdfb..c6931ebb4d4 100644 --- a/src/defid.cpp +++ b/src/defid.cpp @@ -47,7 +47,7 @@ static void WaitForShutdown() { while (!ShutdownRequested()) { - MilliSleep(200); + UninterruptibleSleep(std::chrono::milliseconds{200}); } Interrupt(); } diff --git a/src/flatfile.cpp b/src/flatfile.cpp index 887ae9999fb..7d5d6308c72 100644 --- a/src/flatfile.cpp +++ b/src/flatfile.cpp @@ -92,6 +92,7 @@ bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize) fclose(file); return error("%s: failed to commit file %d", __func__, pos.nFile); } + DirectoryCommit(m_dir); fclose(file); return true; diff --git a/src/flushablestorage.cpp b/src/flushablestorage.cpp new file mode 100644 index 00000000000..2159e64d4e4 --- /dev/null +++ b/src/flushablestorage.cpp @@ -0,0 +1,412 @@ + +#include + +// doesn't serialize/deserialize vector size +template +struct RawTBytes { + std::reference_wrapper ref; + + template + void Serialize(Stream& os) const { + auto& val = ref.get(); + os.write((char*)val.data(), val.size()); + } + + template + void Unserialize(Stream& is) { + auto& val = ref.get(); + val.resize(is.size()); + is.read((char*)val.data(), is.size()); + } +}; + +template +inline RawTBytes refTBytes(T& val) { + return RawTBytes{val}; +} + +CLevelDBSnapshot::CLevelDBSnapshot(std::shared_ptr db) : db(db) { + snapshot = db->GetSnapshot(); +} + +CLevelDBSnapshot::~CLevelDBSnapshot() { + db->ReleaseSnapshot(snapshot); +} + +CLevelDBSnapshot::operator const leveldb::Snapshot*() const { + return snapshot; +} + +// LevelDB iterator +CStorageLevelDBIterator::CStorageLevelDBIterator(std::shared_ptr db, + std::shared_ptr s) : snapshot(s) { + auto options = db->GetIterOptions(); + options.snapshot = *snapshot; + it.reset(db->NewIterator(options)); +} + +void CStorageLevelDBIterator::Next() { + it->Next(); +} + +void CStorageLevelDBIterator::Prev() { + it->Prev(); +} + +bool CStorageLevelDBIterator::Valid() { + return it->Valid(); +} + +void CStorageLevelDBIterator::Seek(const TBytes& key) { + it->Seek(refTBytes(key)); +} + +TBytes CStorageLevelDBIterator::Key() { + TBytes key; + auto rawKey = refTBytes(key); + return it->GetKey(rawKey) ? key : TBytes{}; +} + +TBytes CStorageLevelDBIterator::Value() { + TBytes value; + auto rawValue = refTBytes(value); + return it->GetValue(rawValue) ? value : TBytes{}; +} + +// Flushable iterator +CFlushableStorageKVIterator::CFlushableStorageKVIterator( + std::unique_ptr&& pIt, const MapKV& map) + : map(map), pIt(std::move(pIt)) { + itState = Invalid; +} + +void CFlushableStorageKVIterator::Next() { + assert(Valid()); + mIt = Advance(mIt, map.end(), std::greater{}, Key()); +} + +void CFlushableStorageKVIterator::Prev() { + assert(Valid()); + auto tmp = mIt; + if (tmp != map.end()) { + ++tmp; + } + auto it = std::reverse_iterator(tmp); + auto end = Advance(it, map.rend(), std::less{}, Key()); + if (end == map.rend()) { + mIt = map.begin(); + } else { + auto offset = mIt == map.end() ? 1 : 0; + std::advance(mIt, -std::distance(it, end) - offset); + } +} + +void CFlushableStorageKVIterator::Seek(const TBytes& key) { + pIt->Seek(key); + mIt = Advance(map.lower_bound(key), map.end(), std::greater{}, {}); +} + +bool CFlushableStorageKVIterator::Valid() { + return itState != Invalid; +} + +TBytes CFlushableStorageKVIterator::Key() { + assert(Valid()); + return itState == Map ? mIt->first : pIt->Key(); +} + +TBytes CFlushableStorageKVIterator::Value() { + assert(Valid()); + return itState == Map ? *mIt->second : pIt->Value(); +} + +template +TIterator CFlushableStorageKVIterator::Advance(TIterator it, TIterator end, Compare comp, TBytes prevKey) { + + while (it != end || pIt->Valid()) { + while (it != end && (!pIt->Valid() || !comp(it->first, pIt->Key()))) { + if (prevKey.empty() || comp(it->first, prevKey)) { + if (it->second) { + itState = Map; + return it; + } else { + prevKey = it->first; + } + } + ++it; + } + if (pIt->Valid()) { + if (prevKey.empty() || comp(pIt->Key(), prevKey)) { + itState = Parent; + return it; + } + if constexpr (std::is_same_v) { + pIt->Next(); + } else { + pIt->Prev(); + } + } + } + itState = Invalid; + return it; +} + +// iterator interface +void CStorageKVIterator::Next() { + std::visit([](auto& it) { it.Next(); }, iterators); +} + +void CStorageKVIterator::Prev() { + std::visit([](auto& it) { it.Prev(); }, iterators); +} + +void CStorageKVIterator::Seek(const TBytes& key) { + std::visit([&](auto& it) { it.Seek(key); }, iterators); +} + +TBytes CStorageKVIterator::Key() { + return std::visit([](auto& it) { return it.Key(); }, iterators); +} + +TBytes CStorageKVIterator::Value() { + return std::visit([](auto& it) { return it.Value(); }, iterators); +} + +bool CStorageKVIterator::Valid() { + return std::visit([](auto& it) { return it.Valid(); }, iterators); +} + +// LevelDB storage +CStorageLevelDB::CStorageLevelDB(const fs::path& dbName, + std::size_t cacheSize, + bool fMemory, bool fWipe) + : db(std::make_shared(dbName, cacheSize, fMemory, fWipe)) + , batch(std::make_shared(*db)) + , snapshot(std::make_shared(db)) {} + +bool CStorageLevelDB::Erase(const TBytes& key) { + batch->Erase(refTBytes(key)); + return true; +} + +bool CStorageLevelDB::Exists(const TBytes& key) const { + auto snapshotEx = snapshot; + auto options = db->GetReadOptions(); + options.snapshot = *snapshotEx; + return db->Exists(refTBytes(key), options); +} + +bool CStorageLevelDB::Read(const TBytes& key, TBytes& value) const { + auto rawVal = refTBytes(value); + auto snapshotEx = snapshot; + auto options = db->GetReadOptions(); + options.snapshot = *snapshotEx; + return db->Read(refTBytes(key), rawVal, options); +} + +bool CStorageLevelDB::Write(const TBytes& key, const TBytes& value) { + batch->Write(refTBytes(key), refTBytes(value)); + return true; +} + +bool CStorageLevelDB::Flush(bool sync) { + auto result = db->WriteBatch(*batch, sync); + batch->Clear(); + snapshot = std::make_shared(db); + return result; +} + +void CStorageLevelDB::Discard() { + batch->Clear(); +} + +size_t CStorageLevelDB::SizeEstimate() const { + return batch->SizeEstimate(); +} + +CStorageKVIterator CStorageLevelDB::NewIterator() const { + return CStorageLevelDBIterator{db, snapshot}; +} + +void CStorageLevelDB::Compact(const TBytes& begin, const TBytes& end) { + db->CompactRange(refTBytes(begin), refTBytes(end)); +} + +bool CStorageLevelDB::IsEmpty() const { + return db->IsEmpty(); +} + +// Flushable storage +CFlushableStorageKV::CFlushableStorageKV(std::shared_ptr db) : db(db) {} + +bool CFlushableStorageKV::Exists(const TBytes& key) const { + auto it = changed.find(key); + if (it != changed.end()) { + return bool(it->second); + } + return db->Exists(key); +} + +bool CFlushableStorageKV::Write(const TBytes& key, const TBytes& value) { + changed[key] = value; + return true; +} + +bool CFlushableStorageKV::Erase(const TBytes& key) { + changed[key] = {}; + return true; +} + +bool CFlushableStorageKV::Read(const TBytes& key, TBytes& value) const { + auto it = changed.find(key); + if (it == changed.end()) { + return db->Read(key, value); + } else if (it->second) { + value = it->second.value(); + return true; + } else { + return false; + } +} + +bool CFlushableStorageKV::Flush(bool) { + for (const auto& it : changed) { + if (!it.second) { + db->Erase(it.first); + } else { + db->Write(it.first, it.second.value()); + } + } + changed.clear(); + return true; +} + +void CFlushableStorageKV::Discard() { + changed.clear(); +} + +size_t CFlushableStorageKV::SizeEstimate() const { + return memusage::DynamicUsage(changed); +} + +CStorageKVIterator CFlushableStorageKV::NewIterator() const { + auto it = std::make_unique(db->NewIterator()); + return CFlushableStorageKVIterator{std::move(it), changed}; +} + +void CFlushableStorageKV::SetStorage(std::shared_ptr db) { + this->db = db; +} + +const MapKV& CFlushableStorageKV::GetRaw() const { + return changed; +} + +void CFlushableStorageKV::Compact(const TBytes& begin, const TBytes& end) { + if (changed.key_comp()(begin, end)) { + auto first = changed.find(begin); + if (first != changed.end()) { + changed.erase(first, changed.upper_bound(end)); + } + } +} + +bool CFlushableStorageKV::IsEmpty() const { + return changed.empty(); +} + +// Storage interface +bool CStorageKV::Erase(const TBytes& key) { + return std::visit([&](auto& db) { return db.Erase(key); }, dbs); +} + +bool CStorageKV::Exists(const TBytes& key) const { + return std::visit([&](auto& db) { return db.Exists(key); }, dbs); +} + +bool CStorageKV::Read(const TBytes& key, TBytes& value) const { + return std::visit([&](auto& db) { return db.Read(key, value); }, dbs); +} + +bool CStorageKV::Write(const TBytes& key, const TBytes& value) { + return std::visit([&](auto& db) { return db.Write(key, value); }, dbs); +} + +CStorageKVIterator CStorageKV::NewIterator() const { + return std::visit([](auto& db) { return db.NewIterator(); }, dbs); +} + +size_t CStorageKV::SizeEstimate() const { + return std::visit([](auto& db) { return db.SizeEstimate(); }, dbs); +} + +bool CStorageKV::Flush(bool sync) { + return std::visit([sync](auto& db) { return db.Flush(sync); }, dbs); +} + +void CStorageKV::Discard() { + std::visit([](auto& db) { db.Discard(); }, dbs); +} + +void CStorageKV::Compact(const TBytes& begin, const TBytes& end) { + std::visit([&](auto& db) { db.Compact(begin, end); }, dbs); +} + +bool CStorageKV::IsEmpty() const { + return std::visit([](auto& db) { return db.IsEmpty(); }, dbs); +} + +CStorageLevelDB* CStorageKV::GetStorageLevelDB() { + return std::get_if(&dbs); +} + +CFlushableStorageKV* CStorageKV::GetFlushableStorage() { + return std::get_if(&dbs); +} + +// Storage abstract translator +CStorageView::CStorageView(std::shared_ptr db) : db(db) {} + +void CStorageView::Discard() { + db->Discard(); +} + +CStorageKV& CStorageView::GetStorage() { + return *db; +} + +bool CStorageView::IsEmpty() const { + return db->IsEmpty(); +} + +size_t CStorageView::SizeEstimate() const { + return db->SizeEstimate(); +} + +bool CStorageView::Flush(bool sync) { + return db->Flush(sync); +} + +void CStorageView::Compact(const TBytes& begin, const TBytes& end) { + db->Compact(begin, end); +} + +static std::shared_ptr CloneLevelDB(std::shared_ptr db) { + if (auto ldb = db->GetStorageLevelDB()) { + return std::make_shared(*ldb); + } + return db; +} + +void CStorageView::SetBackend(CStorageView& backend) { + if (auto flushable = db->GetFlushableStorage()) { + flushable->SetStorage(CloneLevelDB(backend.db)); + } else { + db = backend.Clone(); + } +} + +std::shared_ptr CStorageView::Clone() { + auto clone = CloneLevelDB(db); + return std::make_shared(CFlushableStorageKV{clone}); +} diff --git a/src/flushablestorage.h b/src/flushablestorage.h index c9a9ffcea17..18fd8259038 100644 --- a/src/flushablestorage.h +++ b/src/flushablestorage.h @@ -6,15 +6,17 @@ #define DEFI_FLUSHABLESTORAGE_H #include -#include -#include -#include #include +#include -#include +#include +#include +#include +#include +#include using TBytes = std::vector; -using MapKV = std::map>; +using MapKV = std::map>; template static TBytes DbTypeToBytes(const T& value) { @@ -31,312 +33,185 @@ static bool BytesToDbType(const TBytes& bytes, T& value) { stream >> value; // assert(stream.size() == 0); // will fail with partial key matching } - catch (std::ios_base::failure&) { + catch (const std::ios_base::failure&) { return false; } return true; } -// Key-Value storage iterator interface -class CStorageKVIterator { -public: - virtual ~CStorageKVIterator() = default; - virtual void Seek(const TBytes& key) = 0; - virtual void Next() = 0; - virtual void Prev() = 0; - virtual bool Valid() = 0; - virtual TBytes Key() = 0; - virtual TBytes Value() = 0; -}; - // Represents an empty iterator -class CStorageKVEmptyIterator : public CStorageKVIterator { +class CStorageKVEmptyIterator { public: - ~CStorageKVEmptyIterator() override = default; - void Seek(const TBytes&) override {} - void Next() override {} - void Prev() override {} - bool Valid() override { return false; } - TBytes Key() override { return {}; } - TBytes Value() override { return {}; } + void Next() {} + void Prev() {} + void Seek(const TBytes&) {} + TBytes Key() { return {}; } + TBytes Value() { return {}; } + bool Valid() { return false; } }; -// Key-Value storage interface -class CStorageKV { +class CLevelDBSnapshot { public: - virtual ~CStorageKV() = default; - virtual bool Exists(const TBytes& key) const = 0; - virtual bool Write(const TBytes& key, const TBytes& value) = 0; - virtual bool Erase(const TBytes& key) = 0; - virtual bool Read(const TBytes& key, TBytes& value) const = 0; - virtual std::unique_ptr NewIterator() = 0; - virtual size_t SizeEstimate() const = 0; - virtual void Discard() = 0; - virtual bool Flush() = 0; -}; - -// doesn't serialize/deserialize vector size -template -struct RawTBytes { - std::reference_wrapper ref; - - template - void Serialize(Stream& os) const { - auto& val = ref.get(); - os.write((char*)val.data(), val.size()); - } - - template - void Unserialize(Stream& is) { - auto& val = ref.get(); - val.resize(is.size()); - is.read((char*)val.data(), is.size()); - } + explicit CLevelDBSnapshot(std::shared_ptr db); + ~CLevelDBSnapshot(); + operator const leveldb::Snapshot*() const; +private: + std::shared_ptr db; + const leveldb::Snapshot* snapshot; }; -template -inline RawTBytes refTBytes(T& val) { - return RawTBytes{val}; -} - // LevelDB glue layer Iterator -class CStorageLevelDBIterator : public CStorageKVIterator { +class CStorageLevelDBIterator { public: - explicit CStorageLevelDBIterator(std::unique_ptr&& it) : it{std::move(it)} { } + CStorageLevelDBIterator(CStorageLevelDBIterator&&) = default; CStorageLevelDBIterator(const CStorageLevelDBIterator&) = delete; - ~CStorageLevelDBIterator() override = default; - - void Seek(const TBytes& key) override { - it->Seek(refTBytes(key)); // lower_bound in fact - } - void Next() override { - it->Next(); - } - void Prev() override { - it->Prev(); - } - bool Valid() override { - return it->Valid(); - } - TBytes Key() override { - TBytes key; - auto rawKey = refTBytes(key); - return it->GetKey(rawKey) ? key : TBytes{}; - } - TBytes Value() override { - TBytes value; - auto rawValue = refTBytes(value); - return it->GetValue(rawValue) ? value : TBytes{}; - } -private: - std::unique_ptr it; -}; - -// LevelDB glue layer storage -class CStorageLevelDB : public CStorageKV { -public: - explicit CStorageLevelDB(const fs::path& dbName, std::size_t cacheSize, bool fMemory = false, bool fWipe = false) - : db{dbName, cacheSize, fMemory, fWipe}, batch(db) {} - ~CStorageLevelDB() override = default; + CStorageLevelDBIterator(std::shared_ptr db, std::shared_ptr s); - bool Exists(const TBytes& key) const override { - return db.Exists(refTBytes(key)); - } - bool Write(const TBytes& key, const TBytes& value) override { - batch.Write(refTBytes(key), refTBytes(value)); - return true; - } - bool Erase(const TBytes& key) override { - batch.Erase(refTBytes(key)); - return true; - } - bool Read(const TBytes& key, TBytes& value) const override { - auto rawVal = refTBytes(value); - return db.Read(refTBytes(key), rawVal); - } - bool Flush() override { // Commit batch - auto result = db.WriteBatch(batch); - batch.Clear(); - return result; - } - void Discard() override { - batch.Clear(); - } - size_t SizeEstimate() const override { - return batch.SizeEstimate(); - } - std::unique_ptr NewIterator() override { - return MakeUnique(std::unique_ptr(db.NewIterator())); - } - void Compact(const TBytes& begin, const TBytes& end) { - db.CompactRange(refTBytes(begin), refTBytes(end)); - } - bool IsEmpty() { - return db.IsEmpty(); - } + void Next(); + void Prev(); + bool Valid(); + TBytes Key(); + TBytes Value(); + void Seek(const TBytes& key); private: - CDBWrapper db; - CDBBatch batch; + std::unique_ptr it; + std::shared_ptr snapshot; }; -// Flashable storage +class CStorageKVIterator; // Flushable Key-Value Storage Iterator -class CFlushableStorageKVIterator : public CStorageKVIterator { +class CFlushableStorageKVIterator { public: - explicit CFlushableStorageKVIterator(std::unique_ptr&& pIt, MapKV& map) : map(map), pIt(std::move(pIt)) { - itState = Invalid; - } + CFlushableStorageKVIterator(CFlushableStorageKVIterator&&) = default; CFlushableStorageKVIterator(const CFlushableStorageKVIterator&) = delete; - ~CFlushableStorageKVIterator() override = default; + CFlushableStorageKVIterator(std::unique_ptr&& pIt, const MapKV& map); + + void Next(); + void Prev(); + bool Valid(); + TBytes Key(); + TBytes Value(); + void Seek(const TBytes& key); - void Seek(const TBytes& key) override { - pIt->Seek(key); - mIt = Advance(map.lower_bound(key), map.end(), std::greater{}, {}); - } - void Next() override { - assert(Valid()); - mIt = Advance(mIt, map.end(), std::greater{}, Key()); - } - void Prev() override { - assert(Valid()); - auto tmp = mIt; - if (tmp != map.end()) { - ++tmp; - } - auto it = std::reverse_iterator(tmp); - auto end = Advance(it, map.rend(), std::less{}, Key()); - if (end == map.rend()) { - mIt = map.begin(); - } else { - auto offset = mIt == map.end() ? 1 : 0; - std::advance(mIt, -std::distance(it, end) - offset); - } - } - bool Valid() override { - return itState != Invalid; - } - TBytes Key() override { - assert(Valid()); - return itState == Map ? mIt->first : pIt->Key(); - } - TBytes Value() override { - assert(Valid()); - return itState == Map ? *mIt->second : pIt->Value(); - } private: template - TIterator Advance(TIterator it, TIterator end, Compare comp, TBytes prevKey) { - - while (it != end || pIt->Valid()) { - while (it != end && (!pIt->Valid() || !comp(it->first, pIt->Key()))) { - if (prevKey.empty() || comp(it->first, prevKey)) { - if (it->second) { - itState = Map; - return it; - } else { - prevKey = it->first; - } - } - ++it; - } - if (pIt->Valid()) { - if (prevKey.empty() || comp(pIt->Key(), prevKey)) { - itState = Parent; - return it; - } - NextParent(it); - } - } - itState = Invalid; - return it; - } - void NextParent(MapKV::const_iterator&) { - pIt->Next(); - } - void NextParent(std::reverse_iterator&) { - pIt->Prev(); - } + TIterator Advance(TIterator it, TIterator end, Compare comp, TBytes prevKey); + const MapKV& map; MapKV::const_iterator mIt; std::unique_ptr pIt; enum IteratorState { Invalid, Map, Parent } itState; }; -// Flushable Key-Value Storage -class CFlushableStorageKV : public CStorageKV { +class CStorageKVIterator { public: - explicit CFlushableStorageKV(CStorageKV& db_) : db(db_) {} - CFlushableStorageKV(const CFlushableStorageKV&) = delete; - ~CFlushableStorageKV() override = default; - - bool Exists(const TBytes& key) const override { - auto it = changed.find(key); - if (it != changed.end()) { - return bool(it->second); - } - return db.Exists(key); - } - bool Write(const TBytes& key, const TBytes& value) override { - changed[key] = value; - return true; - } - bool Erase(const TBytes& key) override { - changed[key] = {}; - return true; - } - bool Read(const TBytes& key, TBytes& value) const override { - auto it = changed.find(key); - if (it == changed.end()) { - return db.Read(key, value); - } else if (it->second) { - value = it->second.get(); - return true; - } else { - return false; - } - } - bool Flush() override { - for (const auto& it : changed) { - if (!it.second) { - if (!db.Erase(it.first)) { - return false; - } - } else if (!db.Write(it.first, it.second.get())) { - return false; - } - } - changed.clear(); - return true; - } - void Discard() override { - changed.clear(); - } - size_t SizeEstimate() const override { - return memusage::DynamicUsage(changed); - } - std::unique_ptr NewIterator() override { - return MakeUnique(db.NewIterator(), changed); - } + template + CStorageKVIterator(T&& t) : iterators(std::forward(t)) {} + CStorageKVIterator(CStorageKVIterator&&) = default; + CStorageKVIterator(const CStorageKVIterator&) = delete; - MapKV& GetRaw() { - return changed; - } + void Next(); + void Prev(); + bool Valid(); + TBytes Key(); + TBytes Value(); + void Seek(const TBytes& key); + +private: + std::variant iterators; +}; + +// LevelDB glue layer storage +class CStorageLevelDB { +public: + CStorageLevelDB(const fs::path& dbName, std::size_t cacheSize, + bool fMemory = false, bool fWipe = false); + + bool Erase(const TBytes& key); + bool Exists(const TBytes& key) const; + bool Read(const TBytes& key, TBytes& value) const; + bool Write(const TBytes& key, const TBytes& value); + void Discard(); + bool IsEmpty() const; + bool Flush(bool sync); + size_t SizeEstimate() const; + CStorageKVIterator NewIterator() const; + void Compact(const TBytes& begin, const TBytes& end); private: - CStorageKV& db; + std::shared_ptr db; + std::shared_ptr batch; + std::shared_ptr snapshot; +}; + +class CStorageKV; + +// Flushable Key-Value Storage +class CFlushableStorageKV { +public: + explicit CFlushableStorageKV(std::shared_ptr db); + + bool Erase(const TBytes& key); + bool Exists(const TBytes& key) const; + bool Read(const TBytes& key, TBytes& value) const; + bool Write(const TBytes& key, const TBytes& value); + void Discard(); + bool IsEmpty() const; + bool Flush(bool sync); + const MapKV& GetRaw() const; + size_t SizeEstimate() const; + CStorageKVIterator NewIterator() const; + void SetStorage(std::shared_ptr db); + void Compact(const TBytes& begin, const TBytes& end); + +private: + std::shared_ptr db; MapKV changed; }; +// Key-Value storage interface +class CStorageKV { +public: + template + CStorageKV(T&& db) : dbs(std::forward(db)) {} + + bool Erase(const TBytes& key); + bool Exists(const TBytes& key) const; + bool Read(const TBytes& key, TBytes& value) const; + bool Write(const TBytes& key, const TBytes& value); + void Discard(); + bool IsEmpty() const; + bool Flush(bool sync); + size_t SizeEstimate() const; + CStorageKVIterator NewIterator() const; + void Compact(const TBytes& begin, const TBytes& end); + CStorageLevelDB* GetStorageLevelDB(); + CFlushableStorageKV* GetFlushableStorage(); + +private: + std::variant dbs; +}; + template class CLazySerialize { - Optional value; - std::unique_ptr& it; + std::optional value; + std::function lazy; public: - CLazySerialize(const CLazySerialize&) = default; - explicit CLazySerialize(std::unique_ptr& it) : it(it) {} + CLazySerialize(CLazySerialize&&) = default; + CLazySerialize(const CLazySerialize&) = delete; + explicit CLazySerialize(CStorageKVIterator& it) { + lazy = [&]() { + T value{}; + BytesToDbType(it.Value(), value); + return value; + }; + } + explicit CLazySerialize(std::function func) : lazy(func) {} operator T() & { return get(); @@ -346,10 +221,7 @@ class CLazySerialize { return std::move(*value); } const T& get() { - if (!value) { - value = T{}; - BytesToDbType(it->Value(), *value); - } + !value && (value = lazy()); return *value; } }; @@ -357,15 +229,18 @@ class CLazySerialize { template class CStorageIteratorWrapper { bool valid = false; + CStorageKVIterator it; std::pair key; - std::unique_ptr it; void UpdateValidity() { - valid = it->Valid() && BytesToDbType(it->Key(), key) && key.first == By::prefix(); + valid = it.Valid() && BytesToDbType(it.Key(), key) && key.first == By::prefix(); } - struct Resolver { - std::unique_ptr& it; + class CResolver { + CStorageKVIterator& it; + + public: + CResolver(CStorageKVIterator& it) : it(it) {} template inline operator CLazySerialize() { @@ -383,14 +258,9 @@ class CStorageIteratorWrapper { public: CStorageIteratorWrapper(CStorageIteratorWrapper&&) = default; - CStorageIteratorWrapper(std::unique_ptr it) : it(std::move(it)) {} + CStorageIteratorWrapper(const CStorageIteratorWrapper&) = delete; + explicit CStorageIteratorWrapper(CStorageKVIterator it) : it(std::move(it)) {} - CStorageIteratorWrapper& operator=(CStorageIteratorWrapper&& other) { - valid = other.valid; - it = std::move(other.it); - key = std::move(other.key); - return *this; - } bool Valid() { return valid; } @@ -398,37 +268,37 @@ class CStorageIteratorWrapper { assert(Valid()); return key.second; } - Resolver Value() { + CResolver Value() { assert(Valid()); - return Resolver{it}; + return CResolver{it}; } void Next() { assert(Valid()); - it->Next(); + it.Next(); UpdateValidity(); } void Prev() { assert(Valid()); - it->Prev(); + it.Prev(); UpdateValidity(); } void Seek(const KeyType& newKey) { key = std::make_pair(By::prefix(), newKey); - it->Seek(DbTypeToBytes(key)); + it.Seek(DbTypeToBytes(key)); UpdateValidity(); } template bool Value(T& value) { assert(Valid()); - return BytesToDbType(it->Value(), value); + return BytesToDbType(it.Value(), value); } }; // Creates an iterator to single level key value storage template -CStorageIteratorWrapper NewKVIterator(const KeyType& key, MapKV& map) { - auto emptyParent = MakeUnique(); - auto flushableIterator = MakeUnique(std::move(emptyParent), map); +CStorageIteratorWrapper NewKVIterator(const KeyType& key, const MapKV& map) { + auto emptyParent = std::make_unique(CStorageKVEmptyIterator{}); + CStorageKVIterator flushableIterator = CFlushableStorageKVIterator{std::move(emptyParent), map}; CStorageIteratorWrapper it{std::move(flushableIterator)}; it.Seek(key); return it; @@ -437,12 +307,14 @@ CStorageIteratorWrapper NewKVIterator(const KeyType& key, MapKV& ma class CStorageView { public: CStorageView() = default; - CStorageView(CStorageKV * st) : storage(st) {} + CStorageView(CStorageView&&) = default; + CStorageView(const CStorageView&) = delete; + CStorageView(CStorageView& o) : db(o.Clone()) {} virtual ~CStorageView() = default; template bool Exists(const KeyType& key) const { - return DB().Exists(DbTypeToBytes(key)); + return db->Exists(DbTypeToBytes(key)); } template bool ExistsBy(const KeyType& key) const { @@ -453,7 +325,7 @@ class CStorageView { bool Write(const KeyType& key, const ValueType& value) { auto vKey = DbTypeToBytes(key); auto vValue = DbTypeToBytes(value); - return DB().Write(vKey, vValue); + return db->Write(vKey, vValue); } template bool WriteBy(const KeyType& key, const ValueType& value) { @@ -463,7 +335,7 @@ class CStorageView { template bool Erase(const KeyType& key) { auto vKey = DbTypeToBytes(key); - return DB().Exists(vKey) && DB().Erase(vKey); + return db->Exists(vKey) && db->Erase(vKey); } template bool EraseBy(const KeyType& key) { @@ -474,7 +346,7 @@ class CStorageView { bool Read(const KeyType& key, ValueType& value) const { auto vKey = DbTypeToBytes(key); TBytes vValue; - return DB().Read(vKey, vValue) && BytesToDbType(vValue, value); + return db->Read(vKey, vValue) && BytesToDbType(vValue, value); } template bool ReadBy(const KeyType& key, ValueType& value) const { @@ -482,38 +354,51 @@ class CStorageView { } // second type of 'ReadBy' (may be 'GetBy'?) template - boost::optional ReadBy(KeyType const & id) const { - ResultType result; + std::optional ReadBy(KeyType const & id) const { + ResultType result{}; if (ReadBy(id, result)) - return {result}; + return result; return {}; } + + template + void Compact(const KeyType& begin, const KeyType& end) { + db->Compact(DbTypeToBytes(begin), DbTypeToBytes(end)); + } + template + void CompactBy(const KeyType& begin, const KeyType& end) { + Compact(std::make_pair(By::prefix(), begin), std::make_pair(By::prefix(), end)); + } + template CStorageIteratorWrapper LowerBound(KeyType const & key) { - CStorageIteratorWrapper it{DB().NewIterator()}; + CStorageIteratorWrapper it{db->NewIterator()}; it.Seek(key); return it; } template void ForEach(std::function)> callback, KeyType const & start = {}) { for(auto it = LowerBound(start); it.Valid(); it.Next()) { - boost::this_thread::interruption_point(); - if (!callback(it.Key(), it.Value())) { break; } } } - bool Flush() { return DB().Flush(); } - void Discard() { DB().Discard(); } - size_t SizeEstimate() const { return DB().SizeEstimate(); } + void Discard(); + bool IsEmpty() const; + CStorageKV& GetStorage(); + size_t SizeEstimate() const; + virtual bool Flush(bool sync = false); + void Compact(const TBytes& begin, const TBytes& end); protected: - CStorageKV & DB() { return *storage.get(); } - CStorageKV const & DB() const { return *storage.get(); } + CStorageView(std::shared_ptr db); + void SetBackend(CStorageView& backend); + private: - std::unique_ptr storage; + std::shared_ptr Clone(); + std::shared_ptr db; }; #endif // DEFI_FLUSHABLESTORAGE_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 48d1d08d672..611f8a19824 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -80,8 +80,9 @@ static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const Uni else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND; - std::string strReply = JSONRPCReply(NullUniValue, objError, id); + auto strReply = JSONRPCReplyObj(NullUniValue, objError, id).write(); + strReply += '\n'; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(nStatus, strReply); } @@ -198,7 +199,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) /* Deter brute-forcing If this results in a DoS the user really shouldn't have their RPC port exposed. */ - MilliSleep(250); + UninterruptibleSleep(std::chrono::milliseconds{250}); req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); req->WriteReply(HTTP_UNAUTHORIZED); @@ -219,17 +220,16 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) if (valRequest.isObject()) { jreq.parse(valRequest); - UniValue result = tableRPC.execute(jreq); - // Send reply - strReply = JSONRPCReply(result, NullUniValue, jreq.id); + strReply = JSONRPCReplyObj(tableRPC.execute(jreq), NullUniValue, jreq.id).write(); // array of requests } else if (valRequest.isArray()) - strReply = JSONRPCExecBatch(jreq, valRequest.get_array()); + strReply = JSONRPCExecBatch(jreq, valRequest).write(); else throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); + strReply += '\n'; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strReply); @@ -281,7 +281,7 @@ bool StartHTTPRPC() } struct event_base* eventBase = EventBase(); assert(eventBase); - httpRPCTimerInterface = MakeUnique(eventBase); + httpRPCTimerInterface = std::make_unique(eventBase); RPCSetTimerInterface(httpRPCTimerInterface.get()); if (statsRPC.isActive()) statsRPC.load(); return true; diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index f45cd06e418..849bbb51591 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -107,8 +107,8 @@ BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type, fs::create_directories(path); m_name = filter_name + " block filter index"; - m_db = MakeUnique(path / "db", n_cache_size, f_memory, f_wipe); - m_filter_fileseq = MakeUnique(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE); + m_db = std::make_unique(path / "db", n_cache_size, f_memory, f_wipe); + m_filter_fileseq = std::make_unique(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE); } bool BlockFilterIndex::Init() diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index cca08fd0f92..0e46109d555 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -9,8 +9,6 @@ #include #include -#include - constexpr char DB_BEST_BLOCK = 'B'; constexpr char DB_TXINDEX = 't'; constexpr char DB_TXINDEX_BLOCK = 'T'; @@ -152,7 +150,6 @@ bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& bool interrupted = false; std::unique_ptr cursor(block_tree_db.NewIterator()); for (cursor->Seek(begin_key); cursor->Valid(); cursor->Next()) { - boost::this_thread::interruption_point(); if (ShutdownRequested()) { interrupted = true; break; @@ -225,7 +222,7 @@ bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& } TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe) - : m_db(MakeUnique(n_cache_size, f_memory, f_wipe)) + : m_db(std::make_unique(n_cache_size, f_memory, f_wipe)) {} TxIndex::~TxIndex() {} diff --git a/src/init.cpp b/src/init.cpp index 102c84818b4..bbdab575d80 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -22,11 +21,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -73,10 +72,7 @@ #include #endif -#include #include -#include -#include #if ENABLE_ZMQ #include @@ -159,7 +155,7 @@ NODISCARD static bool CreatePidFile() static std::unique_ptr globalVerifyHandle; -static boost::thread_group threadGroup; +std::vector threadGroup; static CScheduler scheduler; void Interrupt() @@ -218,9 +214,12 @@ void Shutdown(InitInterfaces& interfaces) StopTorControl(); // After everything has been shut down, but before things get flushed, stop the - // CScheduler/checkqueue threadGroup - threadGroup.interrupt_all(); - threadGroup.join_all(); + // CScheduler/checkqueue threaGroup + scheduler.stop(); + for (auto& thread : threadGroup) { + if (thread.joinable()) thread.join(); + } + StopScriptCheckWorkerThreads(); // After the threads that potentially access these pointers have been stopped, // destruct and reset all to nullptr. @@ -279,7 +278,6 @@ void Shutdown(InitInterfaces& interfaces) panchorAwaitingConfirms.reset(); panchorauths.reset(); pcustomcsview.reset(); - pcustomcsDB.reset(); pblocktree.reset(); } for (const auto& client : interfaces.chain_clients) { @@ -477,6 +475,7 @@ void SetupServerArgs() gArgs.AddArg("-fortcanningparkheight", "Fort Canning Park fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-fortcanninghillheight", "Fort Canning Hill fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-fortcanningroadheight", "Fort Canning Road fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); + gArgs.AddArg("-greatworldheight", "Great World fork activation height (regtest only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); gArgs.AddArg("-jellyfish_regtest", "Configure the regtest network for jellyfish testing", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); gArgs.AddArg("-simulatemainnet", "Configure the regtest network to mainnet target timespan and spacing ", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); #ifdef USE_UPNP @@ -730,6 +729,10 @@ static void ThreadImport(std::vector vImportFiles) break; // This error is logged in OpenBlockFile LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile); LoadExternalBlockFile(chainparams, file, &pos); + if (ShutdownRequested()) { + LogPrintf("Shutdown requested. Exit %s\n", __func__); + return; + } nFile++; } pblocktree->WriteReindexing(false); @@ -747,6 +750,10 @@ static void ThreadImport(std::vector vImportFiles) fs::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old"; LogPrintf("Importing bootstrap.dat...\n"); LoadExternalBlockFile(chainparams, file); + if (ShutdownRequested()) { + LogPrintf("Shutdown requested. Exit %s\n", __func__); + return; + } RenameOver(pathBootstrap, pathBootstrapOld); } else { LogPrintf("Warning: Could not open bootstrap file %s\n", pathBootstrap.string()); @@ -1117,15 +1124,6 @@ bool AppInitParameterInteraction() incrementalRelayFee = CFeeRate(n); } - // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency - nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); - if (nScriptCheckThreads <= 0) - nScriptCheckThreads += GetNumCores(); - if (nScriptCheckThreads <= 1) - nScriptCheckThreads = 0; - else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) - nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; - // block pruning; get the amount of disk space (in MiB) to allot for block & undo files int64_t nPruneArg = gArgs.GetArg("-prune", 0); if (nPruneArg < 0) { @@ -1266,7 +1264,7 @@ bool AppInitLockDataDirectory() void SetupAnchorSPVDatabases(bool resync) { // Close and open database panchors.reset(); - panchors = MakeUnique(nDefaultDbCache << 20, false, gArgs.GetBoolArg("-spv", true) && resync); + panchors = std::make_unique(nDefaultDbCache << 20, false, gArgs.GetBoolArg("-spv", true) && resync); // load anchors after spv due to spv (and spv height) not set before (no last height yet) if (gArgs.GetBoolArg("-spv", true)) { @@ -1275,15 +1273,73 @@ void SetupAnchorSPVDatabases(bool resync) { // Open database based on network if (Params().NetworkIDString() == "regtest") { - spv::pspv = MakeUnique(); + spv::pspv = std::make_unique(); } else if (Params().NetworkIDString() == "test" || Params().NetworkIDString() == "devnet") { - spv::pspv = MakeUnique(false, nMinDbCache << 20, false, resync); + spv::pspv = std::make_unique(false, nMinDbCache << 20, false, resync); } else { - spv::pspv = MakeUnique(true, nMinDbCache << 20, false, resync); + spv::pspv = std::make_unique(true, nMinDbCache << 20, false, resync); } } } +void MigrateDBs() +{ + auto it = pundosView->LowerBound(UndoSourceKey{}); + if (it.Valid()) { + return; + } + + LogPrintf("Migrating future swap and undo entries, might take a while...\n"); + auto time = GetTimeMillis(); + + // Migrate Undos + std::vector> undos; + pcustomcsview->ForEachUndo([&](const UndoKey& key, const CUndo& undo){ + undos.emplace_back(key, undo); + pundosView->SetUndo({{key.height, key.txid}, UndoSource::CustomView}, undo); + return true; + }); + + for (const auto& [key, undo] : undos) { + pcustomcsview->DelUndo(key); + } + + if (!undos.empty()) { + pcustomcsview->Flush(); + pcustomcsview->CompactBy(undos.begin()->first, undos.rbegin()->first); + pcustomcsview->Flush(true); + } + + // Migrate FutureSwaps + std::multimap> keyMap; + pcustomcsview->ForEachFuturesUserValues([&](const CFuturesUserKey& key, const CFuturesUserValue& swap){ + keyMap.emplace(key.height, std::make_pair(key, swap)); + return true; + }); + + if (!keyMap.empty()) { + auto futureView(*pfutureSwapView); + + for (auto heightIt = keyMap.begin(); heightIt != keyMap.end();) { + auto [start, end] = keyMap.equal_range(heightIt->first); + for (auto valueIt{start}; valueIt != end; ++valueIt) { + pcustomcsview->EraseFuturesUserValues(valueIt->second.first); + futureView.StoreFuturesUserValues(valueIt->second.first, valueIt->second.second); + } + static const auto txIdAllOne = uint256S(std::string(64, '1')); + pundosView->AddUndo(UndoSource::FutureView, *pfutureSwapView, futureView, txIdAllOne, heightIt->first); + futureView.Flush(); + heightIt = end; + } + + pundosView->Flush(); + pfutureSwapView->Flush(); + } + + LogPrintf("Migrating future swap and undo data finished.\n"); + LogPrint(BCLog::BENCH, " - Migrating future swap and undo data takes: %dms\n", GetTimeMillis() - time); +} + bool AppInitMain(InitInterfaces& interfaces) { const CChainParams& chainparams = Params(); @@ -1335,15 +1391,27 @@ bool AppInitMain(InitInterfaces& interfaces) InitSignatureCache(); InitScriptExecutionCache(); - LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); - if (nScriptCheckThreads) { - for (int i=0; i= 1) { + g_parallel_script_checks = true; + StartScriptCheckWorkerThreads(script_threads); } // Start the lightweight task scheduler thread - CScheduler::Function serviceLoop = std::bind(&CScheduler::serviceQueue, &scheduler); - threadGroup.create_thread(std::bind(&TraceThread, "scheduler", serviceLoop)); + scheduler.m_service_thread = std::thread([&] { TraceThread("scheduler", [&] { scheduler.serviceQueue(); }); }); GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); GetMainSignals().RegisterWithMempoolSignals(mempool); @@ -1392,7 +1460,7 @@ bool AppInitMain(InitInterfaces& interfaces) // need to reindex later. assert(!g_banman); - g_banman = MakeUnique(GetDataDir() / "banlist.dat", &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); + g_banman = std::make_unique(GetDataDir() / "banlist.dat", &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); assert(!g_connman); g_connman = std::unique_ptr(new CConnman(GetRand(std::numeric_limits::max()), GetRand(std::numeric_limits::max()))); @@ -1508,7 +1576,8 @@ bool AppInitMain(InitInterfaces& interfaces) int64_t nTotalCache = (gArgs.GetArg("-dbcache", nDefaultDbCache) << 20); nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache - auto nCustomCacheSize = nTotalCache; // used for customs + auto nCustomMinCacheSize = nMinDbCache << 20; + auto nCustomDefaultCacheSize = std::max(nTotalCache / 2, nCustomMinCacheSize); int64_t nBlockTreeDBCache = std::min(nTotalCache / 8, nMaxBlockDBCache << 20); nTotalCache -= nBlockTreeDBCache; int64_t nTxIndexCache = std::min(nTotalCache / 8, gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0); @@ -1551,7 +1620,7 @@ bool AppInitMain(InitInterfaces& interfaces) try { LOCK(cs_main); // This statement makes ::ChainstateActive() usable. - g_chainstate = MakeUnique(); + g_chainstate = std::make_unique(); UnloadBlockIndex(); // new CBlockTreeDB tries to delete the existing file, which @@ -1615,10 +1684,9 @@ bool AppInitMain(InitInterfaces& interfaces) "", CClientUIInterface::MSG_ERROR); }); - pcustomcsDB.reset(); - pcustomcsDB = MakeUnique(GetDataDir() / "enhancedcs", nCustomCacheSize, false, fReset || fReindexChainState); + auto pcustomcsDB = std::make_shared(CStorageLevelDB(GetDataDir() / "enhancedcs", 2 * nCustomDefaultCacheSize, false, fReset || fReindexChainState)); pcustomcsview.reset(); - pcustomcsview = MakeUnique(*pcustomcsDB.get()); + pcustomcsview = std::make_unique(pcustomcsDB); if (!fReset && !fReindexChainState) { if (!pcustomcsDB->IsEmpty() && pcustomcsview->GetDbVersion() != CCustomCSView::DbVersion) { strLoadError = _("Account database is unsuitable").translated; @@ -1632,18 +1700,33 @@ bool AppInitMain(InitInterfaces& interfaces) // make account history db paccountHistoryDB.reset(); if (gArgs.GetBoolArg("-acindex", DEFAULT_ACINDEX)) { - paccountHistoryDB = MakeUnique(GetDataDir() / "history", nCustomCacheSize, false, fReset || fReindexChainState); + paccountHistoryDB = std::make_unique(GetDataDir() / "history", 2 * nCustomDefaultCacheSize, false, fReset || fReindexChainState); + paccountHistoryDB->CreateMultiIndexIfNeeded(); } pburnHistoryDB.reset(); - pburnHistoryDB = MakeUnique(GetDataDir() / "burn", nCustomCacheSize, false, fReset || fReindexChainState); + pburnHistoryDB = std::make_unique(GetDataDir() / "burn", nCustomMinCacheSize, false, fReset || fReindexChainState); + pburnHistoryDB->CreateMultiIndexIfNeeded(); // Create vault history DB pvaultHistoryDB.reset(); if (gArgs.GetBoolArg("-vaultindex", DEFAULT_VAULTINDEX)) { - pvaultHistoryDB = MakeUnique(GetDataDir() / "vault", nCustomCacheSize, false, fReset || fReindexChainState); + pvaultHistoryDB = std::make_unique(GetDataDir() / "vault", nCustomMinCacheSize, false, fReset || fReindexChainState); } + // Create Future Swap DB + auto pfutureSwapDB = std::make_shared(CStorageLevelDB(GetDataDir() / "futureswap", nCustomMinCacheSize, false, fReset || fReindexChainState)); + pfutureSwapView.reset(); + pfutureSwapView = std::make_unique(pfutureSwapDB); + + // Create Future Swap DB + auto pundosDB = std::make_shared(CStorageLevelDB(GetDataDir() / "undos", nCustomMinCacheSize, false, fReset || fReindexChainState)); + pundosView.reset(); + pundosView = std::make_unique(pundosDB); + + // Migrate FutureSwaps and Undos to their own new DBs. + MigrateDBs(); + // If necessary, upgrade from older database format. // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate if (!::ChainstateActive().CoinsDB().Upgrade()) { @@ -1652,7 +1735,7 @@ bool AppInitMain(InitInterfaces& interfaces) } // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate - if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB(), pcustomcsview.get())) { + if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB(), pcustomcsview.get(), pfutureSwapView.get(), pundosView.get())) { strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated; break; } @@ -1759,7 +1842,7 @@ bool AppInitMain(InitInterfaces& interfaces) // ********************************************************* Step 8: start indexers if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - g_txindex = MakeUnique(nTxIndexCache, false, fReindex); + g_txindex = std::make_unique(nTxIndexCache, false, fReindex); g_txindex->Start(); } @@ -1781,9 +1864,9 @@ bool AppInitMain(InitInterfaces& interfaces) LOCK(cs_main); panchorauths.reset(); - panchorauths = MakeUnique(); + panchorauths = std::make_unique(); panchorAwaitingConfirms.reset(); - panchorAwaitingConfirms = MakeUnique(); + panchorAwaitingConfirms = std::make_unique(); SetupAnchorSPVDatabases(gArgs.GetBoolArg("-spv_resync", fReindex || fReindexChainState)); // Check if DB version changed @@ -1836,7 +1919,7 @@ bool AppInitMain(InitInterfaces& interfaces) // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. // No locking, as this happens before any background thread is started. boost::signals2::connection block_notify_genesis_wait_connection; - if (::ChainActive().Tip() == nullptr) { + if (WITH_LOCK(cs_main, return !::ChainActive().Tip())) { block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait); } else { fHaveGenesis = true; @@ -1852,7 +1935,7 @@ bool AppInitMain(InitInterfaces& interfaces) vImportFiles.push_back(strFile); } - threadGroup.create_thread(std::bind(&ThreadImport, vImportFiles)); + threadGroup.emplace_back(ThreadImport, vImportFiles); // Wait for genesis block to be processed { @@ -1991,8 +2074,8 @@ bool AppInitMain(InitInterfaces& interfaces) auto& coinbaseScript = stakerParams.coinbaseScript; CTxDestination destination = DecodeDestination(op); - operatorId = destination.which() == PKHashType ? CKeyID(*boost::get(&destination)) : - destination.which() == WitV0KeyHashType ? CKeyID(*boost::get(&destination)) : CKeyID(); + operatorId = destination.index() == PKHashType ? CKeyID(std::get(destination)) : + destination.index() == WitV0KeyHashType ? CKeyID(std::get(destination)) : CKeyID(); if (operatorId.IsNull()) { LogPrintf("Error: wrong masternode_operator address (%s)\n", op); @@ -2059,13 +2142,11 @@ bool AppInitMain(InitInterfaces& interfaces) } // Mint proof-of-stake blocks in background - threadGroup.create_thread( - std::bind(TraceThread>, "CoinStaker", [=]() { - // Run ThreadStaker - pos::ThreadStaker threadStaker; - threadStaker(std::move(stakersParams), std::move(chainparams)); - } - )); + threadGroup.emplace_back(TraceThread>, "CoinStaker", [=]() { + // Run ThreadStaker + pos::ThreadStaker threadStaker; + threadStaker(stakersParams, chainparams); + }); } if (!gArgs.GetBoolArg("-rpcstats", DEFAULT_RPC_STATS)) statsRPC.setActive(false); diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index e688629cfa9..df592b7f620 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -41,76 +41,71 @@ namespace { class LockImpl : public Chain::Lock { - CCriticalSection& m_mutex; - public: - LockImpl(CCriticalSection& mutex) : m_mutex(mutex) - { - } - Optional getHeight() override + std::optional getHeight() override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); int height = ::ChainActive().Height(); if (height >= 0) { return height; } - return nullopt; + return std::nullopt; } - Optional getBlockHeight(const uint256& hash) override + std::optional getBlockHeight(const uint256& hash) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); CBlockIndex* block = LookupBlockIndex(hash); if (block && ::ChainActive().Contains(block)) { return block->nHeight; } - return nullopt; + return std::nullopt; } int getBlockDepth(const uint256& hash) override { - const Optional tip_height = getHeight(); - const Optional height = getBlockHeight(hash); + const std::optional tip_height = getHeight(); + const std::optional height = getBlockHeight(hash); return tip_height && height ? *tip_height - *height + 1 : 0; } uint256 getBlockHash(int height) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockHash(); } int64_t getBlockTime(int height) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockTime(); } int64_t getBlockMedianTimePast(int height) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetMedianTimePast(); } bool haveBlockOnDisk(int height) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); CBlockIndex* block = ::ChainActive()[height]; return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; } - Optional findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override + std::optional findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height); if (block) { if (hash) *hash = block->GetBlockHash(); return block->nHeight; } - return nullopt; + return std::nullopt; } - Optional findPruned(int start_height, Optional stop_height) override + std::optional findPruned(int start_height, std::optional stop_height) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); if (::fPruneMode) { CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip(); while (block && block->nHeight >= start_height) { @@ -120,11 +115,11 @@ class LockImpl : public Chain::Lock block = block->pprev; } } - return nullopt; + return std::nullopt; } - Optional findFork(const uint256& hash, Optional* height) override + std::optional findFork(const uint256& hash, std::optional* height) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); const CBlockIndex* block = LookupBlockIndex(hash); const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr; if (height) { @@ -137,29 +132,29 @@ class LockImpl : public Chain::Lock if (fork) { return fork->nHeight; } - return nullopt; + return std::nullopt; } CBlockLocator getTipLocator() override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); return ::ChainActive().GetLocator(); } - Optional findLocatorFork(const CBlockLocator& locator) override + std::optional findLocatorFork(const CBlockLocator& locator) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) { return fork->nHeight; } - return nullopt; + return std::nullopt; } bool checkFinalTx(const CTransaction& tx) override { - LockAssertion lock(m_mutex); + LockAssertion lock(::cs_main); return CheckFinalTx(tx); } CCriticalSection& mutex() override { - return m_mutex; + return ::cs_main; } }; @@ -250,7 +245,7 @@ class ChainImpl : public Chain public: std::unique_ptr lock() override { - return MakeUnique(::cs_main); + return std::make_unique(); } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { @@ -280,12 +275,12 @@ class ChainImpl : public Chain return pcustomcsview->CanSpend(nodeId, height); } - boost::optional mnExists(const uint256 & nodeId) const override + std::optional mnExists(const uint256 & nodeId) const override { LOCK(cs_main); return pcustomcsview->GetMasternode(nodeId); } - boost::optional existTokenGuessId(const std::string & str, DCT_ID & id) const override + std::optional existTokenGuessId(const std::string & str, DCT_ID & id) const override { LOCK(cs_main); return pcustomcsview->GetTokenGuessId(str, id); @@ -365,7 +360,7 @@ class ChainImpl : public Chain } std::unique_ptr handleNotifications(Notifications& notifications) override { - return MakeUnique(*this, notifications); + return std::make_unique(*this, notifications); } void waitForNotificationsIfNewBlocksConnected(const uint256& old_tip) override { @@ -379,7 +374,7 @@ class ChainImpl : public Chain } std::unique_ptr handleRpc(const CRPCCommand& command) override { - return MakeUnique(command); + return std::make_unique(command); } bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); } void rpcRunLater(const std::string& name, std::function fn, int64_t seconds) override @@ -397,6 +392,6 @@ class ChainImpl : public Chain }; } // namespace -std::unique_ptr MakeChain() { return MakeUnique(); } +std::unique_ptr MakeChain() { return std::make_unique(); } } // namespace interfaces diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 55a9b6f96b8..143c35d2cc3 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -5,11 +5,12 @@ #ifndef DEFI_INTERFACES_CHAIN_H #define DEFI_INTERFACES_CHAIN_H -#include // For Optional and nullopt #include // For CTransactionRef #include +#include #include +#include #include #include #include @@ -71,12 +72,12 @@ class Chain //! Get current chain height, not including genesis block (returns 0 if //! chain only contains genesis block, nullopt if chain does not contain //! any blocks). - virtual Optional getHeight() = 0; + virtual std::optional getHeight() = 0; //! Get block height above genesis block. Returns 0 for genesis block, //! 1 for following block, and so on. Returns nullopt for a block not //! included in the current chain. - virtual Optional getBlockHeight(const uint256& hash) = 0; + virtual std::optional getBlockHeight(const uint256& hash) = 0; //! Get block depth. Returns 1 for chain tip, 2 for preceding block, and //! so on. Returns 0 for a block not included in the current chain. @@ -101,11 +102,11 @@ class Chain //! given height, or nullopt if there is no block with a high enough //! timestamp and height. Also return the block hash as an optional output parameter //! (to avoid the cost of a second lookup in case this information is needed.) - virtual Optional findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) = 0; + virtual std::optional findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) = 0; //! Return height of last block in the specified range which is pruned, or //! nullopt if no block in the range is pruned. Range is inclusive. - virtual Optional findPruned(int start_height = 0, Optional stop_height = nullopt) = 0; + virtual std::optional findPruned(int start_height = 0, std::optional stop_height = std::nullopt) = 0; //! Return height of the specified block if it is on the chain, otherwise //! return the height of the highest block on chain that's an ancestor @@ -113,7 +114,7 @@ class Chain //! Also return the height of the specified block as an optional output //! parameter (to avoid the cost of a second hash lookup in case this //! information is desired). - virtual Optional findFork(const uint256& hash, Optional* height) = 0; + virtual std::optional findFork(const uint256& hash, std::optional* height) = 0; //! Get locator for the current chain tip. virtual CBlockLocator getTipLocator() = 0; @@ -121,7 +122,7 @@ class Chain //! Return height of the highest block on chain in common with the locator, //! which will either be the original block used to create the locator, //! or one of its ancestors. - virtual Optional findLocatorFork(const CBlockLocator& locator) = 0; + virtual std::optional findLocatorFork(const CBlockLocator& locator) = 0; //! Check if transaction will be final given chain height current time. virtual bool checkFinalTx(const CTransaction& tx) = 0; @@ -151,8 +152,8 @@ class Chain virtual void findCoins(std::map& coins) = 0; virtual bool mnCanSpend(const uint256 & nodeId, int height) const = 0; - virtual boost::optional mnExists(const uint256 & nodeId) const = 0; - virtual boost::optional existTokenGuessId(const std::string & str, DCT_ID & id) const = 0; + virtual std::optional mnExists(const uint256 & nodeId) const = 0; + virtual std::optional existTokenGuessId(const std::string & str, DCT_ID & id) const = 0; //! Estimate fraction of total transactions verified if blocks up to //! the specified block hash are verified. diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp index 0262ec712f9..eb3d257328e 100644 --- a/src/interfaces/handler.cpp +++ b/src/interfaces/handler.cpp @@ -4,7 +4,6 @@ #include -#include #include #include @@ -26,7 +25,7 @@ class HandlerImpl : public Handler std::unique_ptr MakeHandler(boost::signals2::connection connection) { - return MakeUnique(std::move(connection)); + return std::make_unique(std::move(connection)); } } // namespace interfaces diff --git a/src/key_io.cpp b/src/key_io.cpp index 126d92d9da0..29e53785543 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -5,19 +5,13 @@ #include #include #include -#include