diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a217d9dd43..9012a44ea0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: workflow_dispatch: inputs: upload_tag: - description: "If set, upload artifacts to this existing release tag (e.g. 1.12.2.0)" + description: "If set, upload artifacts to this existing release tag (e.g. 1.12.3.0)" required: false default: "" @@ -62,6 +62,38 @@ jobs: strip src/wojakcoind src/wojakcoin-cli src/wojakcoin-tx || true strip src/qt/wojakcoin-qt || true + - name: Smoke test daemon (regtest) + run: | + DATA="$PWD/smoke-data" + mkdir -p "$DATA" + CLI="./src/wojakcoin-cli -regtest -datadir=$DATA -rpcuser=ci -rpcpassword=ci -rpcport=28499" + ./src/wojakcoind -regtest -datadir="$DATA" -listen=0 -server \ + -rpcuser=ci -rpcpassword=ci -rpcport=28499 -printtoconsole > wojakcoind-smoke.log 2>&1 & + DPID=$! + ready=0 + for i in $(seq 1 60); do + if $CLI getblockcount >/dev/null 2>&1; then ready=1; break; fi + if ! kill -0 "$DPID" 2>/dev/null; then break; fi + sleep 1 + done + if [ "$ready" != 1 ]; then + echo "::error::wojakcoind did not become ready on $(uname -m)" + tail -n 200 wojakcoind-smoke.log || true + sudo dmesg | tail -n 40 || true + if kill -0 "$DPID" 2>/dev/null; then + sudo apt-get install -y gdb >/dev/null 2>&1 || true + sudo gdb -p "$DPID" -batch -ex 'thread apply all bt' || true + kill -9 "$DPID" || true + fi + exit 1 + fi + ADDR="$($CLI getnewaddress)" + $CLI generatetoaddress 5 "$ADDR" + test "$($CLI getblockcount)" = "5" + $CLI stop + wait "$DPID" || true + echo "smoke test OK on $(uname -m)" + - name: Stage artifacts run: | mkdir -p dist @@ -148,6 +180,41 @@ jobs: make -j${JOBS} strip src/wojakcoind src/wojakcoin-cli src/wojakcoin-tx + # Runs on the native arm64 runner — same environment class as arm64 + # Docker hosts (Apple Silicon, Graviton). Catches aarch64-only startup + # failures that a QEMU-emulated build/check cannot see. + - name: Smoke test daemon (regtest) + run: | + DATA="$PWD/smoke-data" + mkdir -p "$DATA" + CLI="./src/wojakcoin-cli -regtest -datadir=$DATA -rpcuser=ci -rpcpassword=ci -rpcport=28499" + ./src/wojakcoind -regtest -datadir="$DATA" -listen=0 -server \ + -rpcuser=ci -rpcpassword=ci -rpcport=28499 -printtoconsole > wojakcoind-smoke.log 2>&1 & + DPID=$! + ready=0 + for i in $(seq 1 60); do + if $CLI getblockcount >/dev/null 2>&1; then ready=1; break; fi + if ! kill -0 "$DPID" 2>/dev/null; then break; fi + sleep 1 + done + if [ "$ready" != 1 ]; then + echo "::error::wojakcoind did not become ready on $(uname -m)" + tail -n 200 wojakcoind-smoke.log || true + sudo dmesg | tail -n 40 || true + if kill -0 "$DPID" 2>/dev/null; then + sudo apt-get install -y gdb >/dev/null 2>&1 || true + sudo gdb -p "$DPID" -batch -ex 'thread apply all bt' || true + kill -9 "$DPID" || true + fi + exit 1 + fi + ADDR="$($CLI getnewaddress)" + $CLI generatetoaddress 5 "$ADDR" + test "$($CLI getblockcount)" = "5" + $CLI stop + wait "$DPID" || true + echo "smoke test OK on $(uname -m)" + - name: Stage artifacts (aarch64 names) run: | mkdir -p dist diff --git a/configure.ac b/configure.ac index 4ee1a7efc2..e320975cdf 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MINOR, 12) -define(_CLIENT_VERSION_REVISION, 2) +define(_CLIENT_VERSION_REVISION, 3) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2016) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index e46b16b8a2..b7128ca9f2 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,41 +1,43 @@ package=boost -$(package)_version=1_59_0 -$(package)_download_path=https://archives.boost.io/release/1.59.0/source +$(package)_version=1_70_0 +$(package)_download_path=https://archives.boost.io/release/1.70.0/source $(package)_file_name=$(package)_$($(package)_version).tar.bz2 -$(package)_sha256_hash=727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca +$(package)_sha256_hash=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 +$(package)_patches=fix_pthread_stack_min_glibc234.patch 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_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_mingw32=address-model=64 $(package)_config_opts_i686_mingw32=address-model=32 $(package)_config_opts_i686_linux=address-model=32 architecture=x86 $(package)_toolset_$(host_os)=gcc +$(package)_toolset_darwin=clang $(package)_archiver_$(host_os)=$($(package)_ar) -$(package)_toolset_darwin=darwin $(package)_archiver_darwin=$($(package)_libtool) $(package)_config_libraries=chrono,filesystem,program_options,system,thread,test -$(package)_cxxflags=-fvisibility=hidden +$(package)_cxxflags=-std=c++11 -fvisibility=hidden $(package)_cxxflags_linux=-fPIC endef define $(package)_preprocess_cmds - echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam + patch -p1 < $($(package)_patch_dir)/fix_pthread_stack_min_glibc234.patch && \ + echo "using $($(package)_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$($(package)_archiver_$(host_os))\" \"$(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)) 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)) install endef diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index 2e9be1e98c..b80ac2acdd 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -1,16 +1,11 @@ package=libevent -$(package)_version=2.0.22 -$(package)_download_path=https://github.com/libevent/libevent/releases/download/release-2.0.22-stable -$(package)_file_name=$(package)-$($(package)_version)-stable.tar.gz -$(package)_sha256_hash=71c2c49f0adadacfdbe6332a372c38cf9c8b7895bb73dabeaa53cdcc1d4e1fa3 -$(package)_patches=reuseaddr.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/reuseaddr.patch -endef +$(package)_version=2.1.12-stable +$(package)_download_path=https://github.com/libevent/libevent/releases/download/release-$($(package)_version) +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb define $(package)_set_vars - $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress + $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples $(package)_config_opts_release=--disable-debug-mode $(package)_config_opts_linux=--with-pic endef diff --git a/depends/patches/boost/fix_pthread_stack_min_glibc234.patch b/depends/patches/boost/fix_pthread_stack_min_glibc234.patch new file mode 100644 index 0000000000..f081c7a9a4 --- /dev/null +++ b/depends/patches/boost/fix_pthread_stack_min_glibc234.patch @@ -0,0 +1,16 @@ +Fix boost.thread build with glibc >= 2.34, where PTHREAD_STACK_MIN is +defined as sysconf(_SC_THREAD_STACK_MIN) and can no longer be used in +preprocessor arithmetic. Backport of upstream boostorg/thread commit +74ff2db959c5fa75bec770c41ed2951a740fe936 (shipped in boost 1.78). + +--- a/boost/thread/pthread/thread_data.hpp ++++ b/boost/thread/pthread/thread_data.hpp +@@ -57,7 +57,7 @@ + #else + std::size_t page_size = ::sysconf( _SC_PAGESIZE); + #endif +-#if PTHREAD_STACK_MIN > 0 ++#ifdef PTHREAD_STACK_MIN + if (size 1.70, fixing the aarch64 startup crash +- depends: update libevent 2.0.22 -> 2.1.12-stable +- ci: smoke-boot the built daemon on regtest in both Linux release jobs, so + aarch64 startup failures fail the release instead of shipping + +Credits +======= + +Thanks to the Bitcoin Computer team for the integration testing and the +detailed report in bitcoin-computer/monorepo#456. diff --git a/docker/README.md b/docker/README.md index bbd397671d..98a19636b4 100644 --- a/docker/README.md +++ b/docker/README.md @@ -7,7 +7,7 @@ The official multi-platform Docker image is maintained in a separate repo: Hub: **https://hub.docker.com/r/reallyshadydev/wojakcoin-core** ```bash -docker pull reallyshadydev/wojakcoin-core:1.12.2.0 +docker pull reallyshadydev/wojakcoin-core:1.12.3.0 # or docker pull reallyshadydev/wojakcoin-core:latest ``` diff --git a/src/clientversion.h b/src/clientversion.h index dba466ba95..df735f9e83 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -16,7 +16,7 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 1 #define CLIENT_VERSION_MINOR 12 -#define CLIENT_VERSION_REVISION 2 +#define CLIENT_VERSION_REVISION 3 #define CLIENT_VERSION_BUILD 0 //! Set to true for release, false for prerelease or test build diff --git a/src/init.cpp b/src/init.cpp index a65965681c..e5de9eca90 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -486,7 +486,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Node relay options:")); if (showDebug) strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard())); - strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); + strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); diff --git a/src/main.cpp b/src/main.cpp index b8ae73f73f..f2123dedc1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1173,8 +1173,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // sigops, making it impossible to mine. Since the coinbase transaction // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than - // merely non-standard transaction. - if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp)) + // merely non-standard transaction. Sigop density below that limit is + // no longer grounds for rejection: -bytespersigop is applied as a + // fee-based policy via CTxMemPoolEntry::GetTxSize(), matching the + // bytespersigop implementation introduced in Bitcoin Core 0.13. + if (nSigOps > MAX_STANDARD_TX_SIGOPS) return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, strprintf("%d", nSigOps)); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 0471580237..3594fddf88 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -31,6 +31,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "setgenerate", 0 }, { "setgenerate", 1 }, { "generate", 0 }, + { "generatetoaddress", 0 }, { "getnetworkhashps", 0 }, { "getnetworkhashps", 1 }, { "sendtoaddress", 1 }, diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 97e342d848..7d4bf49bc2 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" +#include "base58.h" #include "chain.h" #include "chainparams.h" #include "consensus/consensus.h" @@ -112,40 +113,11 @@ UniValue getgenerate(const UniValue& params, bool fHelp) return GetBoolArg("-gen", DEFAULT_GENERATE); } -UniValue generate(const UniValue& params, bool fHelp) +static UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nGenerate, bool keepScript) { - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "generate numblocks\n" - "\nMine blocks immediately (before the RPC call returns)\n" - "\nNote: this function can only be used on the regtest network\n" - "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" - "\nResult\n" - "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" - "\nGenerate 11 blocks\n" - + HelpExampleCli("generate", "11") - ); - - if (!Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); - int nHeightStart = 0; int nHeightEnd = 0; int nHeight = 0; - int nGenerate = params[0].get_int(); - - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - // If the keypool is exhausted, no script is returned at all. Catch this. - if (!coinbaseScript) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - //throw an error if no script was provided - if (coinbaseScript->reserveScript.empty()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); { // Don't keep cs_main locked LOCK(cs_main); @@ -177,11 +149,81 @@ UniValue generate(const UniValue& params, bool fHelp) blockHashes.push_back(pblock->GetHash().GetHex()); //mark script as important because it was used at least for one coinbase output - coinbaseScript->KeepScript(); + if (keepScript) + { + coinbaseScript->KeepScript(); + } } return blockHashes; } +UniValue generate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "generate numblocks\n" + "\nMine blocks immediately (before the RPC call returns)\n" + "\nNote: this function can only be used on the regtest network\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") + ); + + if (!Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); + + int nGenerate = params[0].get_int(); + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + // If the keypool is exhausted, no script is returned at all. Catch this. + if (!coinbaseScript) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + //throw an error if no script was provided + if (coinbaseScript->reserveScript.empty()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); + + return generateBlocks(coinbaseScript, nGenerate, true); +} + +UniValue generatetoaddress(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 2) + throw runtime_error( + "generatetoaddress numblocks address\n" + "\nMine blocks immediately to a specified address (before the RPC call returns)\n" + "\nNote: this function can only be used on the regtest network\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "2. address (string, required) The address to send the newly generated coins to.\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks to myaddress\n" + + HelpExampleCli("generatetoaddress", "11 \"myaddress\"") + ); + + if (!Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); + + int nGenerate = params[0].get_int(); + + CBitcoinAddress address(params[1].get_str()); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); + + boost::shared_ptr coinbaseScript(new CReserveScript()); + coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); + + return generateBlocks(coinbaseScript, nGenerate, false); +} + UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 22cc56286b..9a42a81a16 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -304,6 +304,7 @@ static const CRPCCommand vRPCCommands[] = { "generating", "getgenerate", &getgenerate, true }, { "generating", "setgenerate", &setgenerate, true }, { "generating", "generate", &generate, true }, + { "generating", "generatetoaddress", &generatetoaddress, true }, /* Raw transactions */ { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index babf7c8d2e..8b7c12cf9b 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -186,6 +186,7 @@ extern UniValue importwallet(const UniValue& params, bool fHelp); extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp extern UniValue setgenerate(const UniValue& params, bool fHelp); extern UniValue generate(const UniValue& params, bool fHelp); +extern UniValue generatetoaddress(const UniValue& params, bool fHelp); // in rpcmining.cpp extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); extern UniValue getmininginfo(const UniValue& params, bool fHelp); extern UniValue prioritisetransaction(const UniValue& params, bool fHelp); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5f814749b7..6989076dc4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -32,7 +32,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, nUsageSize = RecursiveDynamicUsage(tx); nCountWithDescendants = 1; - nSizeWithDescendants = nTxSize; + nSizeWithDescendants = GetTxSize(); nModFeesWithDescendants = nFee; CAmount nValueIn = tx.GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); @@ -309,10 +309,15 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove) void CTxMemPoolEntry::SetDirty() { nCountWithDescendants = 0; - nSizeWithDescendants = nTxSize; + nSizeWithDescendants = GetTxSize(); nModFeesWithDescendants = GetModifiedFee(); } +size_t CTxMemPoolEntry::GetTxSize() const +{ + return std::max(nTxSize, (size_t)sigOpCount * nBytesPerSigOp); +} + void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount) { if (!IsDirty()) { diff --git a/src/txmempool.h b/src/txmempool.h index c7bc73a096..6d549d34c9 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -111,7 +111,10 @@ class CTxMemPoolEntry */ double GetPriority(unsigned int currentHeight) const; const CAmount& GetFee() const { return nFee; } - size_t GetTxSize() const { return nTxSize; } + // Virtual size for fee and mempool accounting: sigop-dense transactions + // are treated as if they were -bytespersigop bytes per sigop, so density + // raises the required fee instead of being rejected outright. + size_t GetTxSize() const; int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return entryHeight; } bool WasClearAtEntry() const { return hadNoDependencies; }