From 5216e951c79b2d0820b222ea79f699c650f725c5 Mon Sep 17 00:00:00 2001 From: reallyshadydev Date: Mon, 3 Aug 2026 15:39:32 -0700 Subject: [PATCH 1/7] policy: apply -bytespersigop as fee-based policy instead of rejection Backport of Bitcoin Core 0.13's bytespersigop implementation (bitcoin/bitcoin#7081). Sigop-dense transactions below the absolute MAX_STANDARD_TX_SIGOPS cap are no longer rejected from the mempool; instead CTxMemPoolEntry::GetTxSize() returns a virtual size of max(real size, sigops * bytespersigop), so density raises the required fee for relay and mining priority. This lets Bitcoin Computer transactions (many bare OP_CHECKMULTISIG sigops in small scripts) relay with default node settings; operators and miners no longer need bytespersigop=0 in wojakcoin.conf. Policy-only change: block validity (MAX_BLOCK_SIGOPS in ConnectBlock) is untouched, so upgraded and non-upgraded nodes remain in consensus. --- src/init.cpp | 2 +- src/main.cpp | 7 +++++-- src/txmempool.cpp | 9 +++++++-- src/txmempool.h | 5 ++++- 4 files changed, 17 insertions(+), 6 deletions(-) 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/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; } From 50bb968e4e67c5bea55247b2ec763631cff0ac7e Mon Sep 17 00:00:00 2001 From: reallyshadydev Date: Mon, 3 Aug 2026 15:39:40 -0700 Subject: [PATCH 2/7] rpc: add generatetoaddress (regtest) Backport of the generatetoaddress RPC from Bitcoin Core 0.13: mine blocks directly to a supplied address without needing wallet keypool state. The existing generate RPC is refactored onto a shared generateBlocks() helper, unchanged in behavior. Lets the Bitcoin Computer test suite (which calls generateToAddress on regtest) run against WojakCore unmodified. --- src/rpcclient.cpp | 1 + src/rpcmining.cpp | 104 ++++++++++++++++++++++++++++++++-------------- src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + 4 files changed, 76 insertions(+), 31 deletions(-) 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); From f87bea08261f149cdb63dd3b5beba5dadb71fff1 Mon Sep 17 00:00:00 2001 From: reallyshadydev Date: Mon, 3 Aug 2026 16:16:50 -0700 Subject: [PATCH 3/7] depends: update boost 1.59 -> 1.70, fixing aarch64 startup SIGSEGV The linux-aarch64 release binaries crash with SIGSEGV immediately after logging 'scheduler thread start', so arm64 Docker containers loop under restart: always. Reported by the Bitcoin Computer team in bitcoin-computer/monorepo#456. Reproduced natively on Apple Silicon (linux/arm64 container, no emulation). An unstripped CI-replica build shows the scheduler thread faulting on the first boost::function invocation in the process: pthread_mutex_lock is reached from CScheduler::serviceQueue() with a garbage this pointer produced by the boost::bind member-function dispatch. Boost 1.59 (2015) headers are miscompiled by the gcc 11 toolchain on the ubuntu-22.04-arm runner; the same binary runs under linux/amd64 emulation, and Bitcoin Core's own aarch64 releases only ever paired boost 1.59 with gcc 5/6 era toolchains. Adopt Bitcoin Core v0.21's boost.mk (1.70.0), adapted for this tree: - download from archives.boost.io (bintray is gone) - wojakcore's library set (chrono, filesystem, program_options, system, thread, test) - backport boostorg/thread commit 74ff2db9 (shipped in 1.78) so boost.thread builds against glibc >= 2.34, where PTHREAD_STACK_MIN is no longer a preprocessor constant Verified on native linux/arm64 (ubuntu-22.04 + depends replica of the CI job): the identical build that crashed with exit 139 now reaches RPC readiness and mines regtest blocks via generatetoaddress. --- depends/packages/boost.mk | 26 ++++++++++--------- .../fix_pthread_stack_min_glibc234.patch | 16 ++++++++++++ 2 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 depends/patches/boost/fix_pthread_stack_min_glibc234.patch 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/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 Date: Mon, 3 Aug 2026 16:16:50 -0700 Subject: [PATCH 4/7] depends: update libevent 2.0.22 -> 2.1.12-stable Modernizes the other 2014-era network dependency alongside the boost update: 2.1.12 is the libevent Bitcoin Core shipped for years, httpserver.cpp already carries >=2.1 version guards, and this tree builds and runs against libevent 2.1.13 on macOS arm64. The 2.0.22 reuseaddr patch is upstream in 2.1.x and is dropped. (Initially investigated as the cause of the aarch64 startup crash; the actual cause was boost 1.59 - see the preceding commit. A native linux/arm64 depends build with libevent 2.1.12 alone still crashed, and with the boost update it runs.) --- depends/packages/libevent.mk | 15 +++++---------- depends/patches/libevent/reuseaddr.patch | 21 --------------------- 2 files changed, 5 insertions(+), 31 deletions(-) delete mode 100644 depends/patches/libevent/reuseaddr.patch 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/libevent/reuseaddr.patch b/depends/patches/libevent/reuseaddr.patch deleted file mode 100644 index 58695c11f5..0000000000 --- a/depends/patches/libevent/reuseaddr.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- old/evutil.c 2015-08-28 19:26:23.488765923 -0400 -+++ new/evutil.c 2015-08-28 19:27:41.392767019 -0400 -@@ -321,15 +321,16 @@ - int - evutil_make_listen_socket_reuseable(evutil_socket_t sock) - { --#ifndef WIN32 - int one = 1; -+#ifndef WIN32 - /* REUSEADDR on Unix means, "don't hang on to this address after the - * listener is closed." On Windows, though, it means "don't keep other - * processes from binding to this address while we're using it. */ - return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, - (ev_socklen_t)sizeof(one)); - #else -- return 0; -+ return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &one, -+ (ev_socklen_t)sizeof(one)); - #endif - } - From 4d044a5cd4fc0274cf6700266dc124e0162ae082 Mon Sep 17 00:00:00 2001 From: reallyshadydev Date: Mon, 3 Aug 2026 16:16:50 -0700 Subject: [PATCH 5/7] ci: smoke-boot the built daemon on regtest for both Linux jobs Start wojakcoind on regtest after the build, wait for RPC readiness, mine 5 blocks via generatetoaddress, and stop cleanly. On the linux-arm64 job this runs on the native arm64 runner - the same environment class as arm64 Docker hosts - so aarch64-only startup failures (like the boost 1.59 SIGSEGV fixed in this branch) fail the release instead of shipping. On timeout the step dumps the daemon log, dmesg, and full gdb thread backtraces. --- .github/workflows/release.yml | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a217d9dd43..efd240d518 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 From 830355f4ea587c4da6e6d7451e4474699612285c Mon Sep 17 00:00:00 2001 From: reallyshadydev Date: Mon, 3 Aug 2026 16:33:18 -0700 Subject: [PATCH 6/7] build: bump version to 1.12.3.0 First release carrying the Bitcoin Computer integration changes and the aarch64 startup fix (boost 1.70). --- configure.ac | 2 +- src/clientversion.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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 From dd919b49d6ec5b25f4ea55541288ba4025de735d Mon Sep 17 00:00:00 2001 From: reallyshadydev Date: Mon, 3 Aug 2026 16:46:37 -0700 Subject: [PATCH 7/7] doc: add 1.12.3.0 release notes, refresh version references Documents the aarch64 startup fix, the bytespersigop policy change, and generatetoaddress. Points the docker pull example and the release workflow's tag example at 1.12.3.0. --- .github/workflows/release.yml | 2 +- doc/release-notes/release-notes-1.12.3.0.md | 72 +++++++++++++++++++++ docker/README.md | 2 +- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 doc/release-notes/release-notes-1.12.3.0.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index efd240d518..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: "" diff --git a/doc/release-notes/release-notes-1.12.3.0.md b/doc/release-notes/release-notes-1.12.3.0.md new file mode 100644 index 0000000000..8595c4b96f --- /dev/null +++ b/doc/release-notes/release-notes-1.12.3.0.md @@ -0,0 +1,72 @@ +WojakCore version 1.12.3.0 +========================== + +Notable changes +=============== + +Fix daemon crash on startup on aarch64 (arm64) +---------------------------------------------- + +The Linux aarch64 binaries crashed with `SIGSEGV` immediately after logging +`scheduler thread start`, so arm64 Docker hosts (Apple Silicon, Graviton) never +reached a usable node and containers restarted in a loop. + +The cause was the depends build of Boost 1.59 (2015), whose `boost::bind` / +`boost::function` headers are miscompiled by modern GCC on aarch64: the +scheduler thread dispatched its first `boost::function` call with a corrupt +`this` pointer. Depends now builds Boost 1.70, and libevent is updated from +2.0.22 to 2.1.12-stable alongside it. + +Operators running arm64 no longer need the `platform: linux/amd64` emulation +workaround in `docker-compose.yml`. + +`bytespersigop` no longer rejects sigop-dense transactions +---------------------------------------------------------- + +Transactions below the `MAX_STANDARD_TX_SIGOPS` limit (16,000) are no longer +rejected for sigop *density*. Following Bitcoin Core 0.13, `-bytespersigop` +is now a fee-based policy: a transaction's virtual size for relay and mining +is `max(actual size, sigops * bytespersigop)`, so dense scripts pay more fee +instead of being dropped. + +Bitcoin Computer transactions now relay with default settings. Node operators +and mining pools no longer need `bytespersigop=0` in `wojakcoin.conf`. + +This is a policy (standardness) change only. Block validity, including +`MAX_BLOCK_SIGOPS`, is unchanged, so upgraded and non-upgraded nodes stay in +consensus. + +New RPC: `generatetoaddress` +--------------------------- + +`generatetoaddress numblocks address` mines blocks directly to a given address +on regtest, without requiring wallet keypool state. Backported from Bitcoin +Core 0.13; `generate` is unchanged. + +1.12.3.0 change log +=================== + +Policy +------ + +- Apply `-bytespersigop` as a fee-based policy instead of rejecting + sigop-dense transactions + +RPC +--- + +- Add `generatetoaddress` (regtest) + +Build system +------------ + +- depends: update Boost 1.59 -> 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 ```