From 3c5ac14b01a58390fd0f4c4d8f4ce3969ffaa018 Mon Sep 17 00:00:00 2001 From: Reuben Yap Date: Thu, 18 Jan 2024 00:12:44 +0800 Subject: [PATCH 01/17] Update README.md Update wording to Spark and added MAGIC donate option. --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b23ff681e6..1304e41610 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,13 @@ [![GitHub commits-per-month](https://img.shields.io/github/commit-activity/m/firoorg/firo)](https://github.com/firoorg/firo/graphs/code-frequency) [![GitHub last-commit](https://img.shields.io/github/last-commit/firoorg/firo)](https://github.com/firoorg/firo/commits/master) -[Firo](https://firo.org) formerly known as Zcoin, is a privacy focused cryptocurrency that utilizes zero-knowledge proofs which allows users to destroy coins and then redeem them later for brand new ones with no transaction history. +[Firo](https://firo.org) formerly known as Zcoin, is a privacy focused cryptocurrency that utilizes the [Lelantus Spark protocol](https://eprint.iacr.org/2021/1173) which supports high anonymity sets without requiring trusted setup and relying on standard cryptographic assumptions. -Our research created the [Lelantus privacy protocol](https://eprint.iacr.org/2019/373) which supports high anonymity sets without requiring trusted setup and relying only on standard cryptographic assumptions. The Lelantus cryptographic library was audited by [Trail of Bits](https://github.com/trailofbits/publications/blob/master/reviews/zcoin-lelantus-summary.pdf) and funded by Firo's CCS. Lelantus' cryptography was also audited by [ABDK Consulting](https://www.abdk.consulting/). +The Lelantus Spark cryptographic library and implementation was audited by [HashCloak](https://firo.org/about/research/papers/lelantus_spark_code_audit_report.pdf). The Lelantus Spark cryptography paper has undergone two separate audits by [HashCloak](https://firo.org/about/research/papers/Lelantus_Spark_Audit_Report.pdf) and [Daniel (Linfeng) Zhao](https://firo.org/about/research/papers/LinfengSparkAudit.pdf). Firo also utilises [Dandelion++](https://arxiv.org/abs/1805.11060) to obscure the originating IP of transactions without relying on any external services such as Tor/i2P. -Firo uses FiroPoW (a ProgPoW variant) as its Proof-of-Work GPU focused algorithm which is FPGA/ASIC resistant. - -# How Firo’s Privacy Technology Compares to the Competition - -![A comparison chart of Firo’s solutions with other leading privacy technologies can be found below](https://firo.org/guide/assets/privacy-technology-comparison/comparison-table-firo-updated.png) -read more https://firo.org/guide/privacy-technology-comparison.html +Firo uses a hybrid PoW and LLMQ Chainlocks system combining fair distribution of supply with protection against 51% attacks and quick finality of blocks and transactions. FiroPOW (a ProgPOW variant) is used as its Proof-of-Work algorithm which targets GPUs and is FPGA/ASIC resistant. # Running with Docker @@ -202,6 +197,8 @@ This project exists thanks to all the people who contribute. Would you like to h Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/firo/contribute)] +You can also donate to the [MAGIC Firo Fund](https://magicgrants.org/funds/firo/) which allows some US entities to claim a charitable deduction. + ## Individuals From f3fe49c4ce201332b83b10c13974b3adc6bc7416 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:12:12 +0400 Subject: [PATCH 02/17] Exchange address index (#1392) --- src/addresstype.h | 1 + src/base58.cpp | 4 ++++ src/rpc/misc.cpp | 2 +- src/txdb.cpp | 3 +++ src/txmempool.cpp | 15 +++++++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/addresstype.h b/src/addresstype.h index 155508a131..9b0083f7c4 100644 --- a/src/addresstype.h +++ b/src/addresstype.h @@ -17,6 +17,7 @@ enum struct AddressType , sparkMint = 11 , sparksMint = 12 , sparkSpend = 13 + , payToExchangeAddress = 14 }; namespace zerocoin { namespace utils { diff --git a/src/base58.cpp b/src/base58.cpp index 005eed6d35..7044503063 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -297,6 +297,10 @@ bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, AddressType & type) const memcpy(&hashBytes, &vchData[0], 20); type = AddressType::payToPubKeyHash; return true; + } else if (vchVersion == Params().Base58Prefix(CChainParams::EXCHANGE_PUBKEY_ADDRESS)) { + memcpy(&hashBytes, &vchData[0], 20); + type = AddressType::payToExchangeAddress; + return true; } else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) { memcpy(&hashBytes, &vchData[0], 20); type = AddressType::payToScriptHash; diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index f10aba2e66..bafb94b712 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -566,7 +566,7 @@ bool getAddressFromIndex(AddressType const & type, const uint160 &hash, std::str { if (type == AddressType::payToScriptHash) { address = CBitcoinAddress(CScriptID(hash)).ToString(); - } else if (type == AddressType::payToPubKeyHash) { + } else if (type == AddressType::payToPubKeyHash || type == AddressType::payToExchangeAddress) { address = CBitcoinAddress(CKeyID(hash)).ToString(); } else { return false; diff --git a/src/txdb.cpp b/src/txdb.cpp index 32066e7328..f3bb39f43a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -504,6 +504,9 @@ std::pair classifyAddress(txnouttype type, std::vector(addresses.front().begin(), addresses.front().end())); + } else if(type == TX_EXCHANGEADDRESS) { + result.first = AddressType::payToExchangeAddress; + result.second = uint160(std::vector(addresses.front().begin(), addresses.front().end())); } return result; } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a21edd2f3f..2d3c92cc07 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -677,6 +677,12 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); mapAddress.insert(std::make_pair(key, delta)); inserted.push_back(key); + } else if (prevout.scriptPubKey.IsPayToExchangeAddress()) { + std::vector hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23); + CMempoolAddressDeltaKey key(AddressType::payToExchangeAddress, uint160(hashBytes), txhash, j, 1); + CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); + mapAddress.insert(std::make_pair(key, delta)); + inserted.push_back(key); } } @@ -693,6 +699,12 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC CMempoolAddressDeltaKey key(AddressType::payToPubKeyHash, uint160(hashBytes), txhash, k, 0); mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); inserted.push_back(key); + } else if (out.scriptPubKey.IsPayToExchangeAddress()) { + std::vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); + std::pair ret; + CMempoolAddressDeltaKey key(AddressType::payToExchangeAddress, uint160(hashBytes), txhash, k, 0); + mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue))); + inserted.push_back(key); } } @@ -753,6 +765,9 @@ void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCac } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { addressHash = uint160(std::vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); addressType = AddressType::payToPubKeyHash; + } else if (prevout.scriptPubKey.IsPayToExchangeAddress()) { + addressHash = uint160(std::vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); + addressType = AddressType::payToExchangeAddress; } else { addressHash.SetNull(); addressType = AddressType::unknown; From 21395405e737b08a8b9b29d9969eded8860df3e6 Mon Sep 17 00:00:00 2001 From: Aaron Feickert <66188213+AaronFeickert@users.noreply.github.com> Date: Sat, 20 Jan 2024 09:55:17 -0600 Subject: [PATCH 03/17] Update binding hash function signature (#1396) * Update binding hash function signature * Add binding hash comment --- src/libspark/spend_transaction.cpp | 10 +++++++++- src/libspark/spend_transaction.h | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libspark/spend_transaction.cpp b/src/libspark/spend_transaction.cpp index b2d3561e79..69eda151d9 100644 --- a/src/libspark/spend_transaction.cpp +++ b/src/libspark/spend_transaction.cpp @@ -178,7 +178,9 @@ SpendTransaction::SpendTransaction( Scalar mu = hash_bind( hash_bind_inner( this->cover_set_representations, + this->S1, this->C1, + this->T, this->grootle_proofs, this->balance_proof, this->range_proof @@ -293,9 +295,11 @@ bool SpendTransaction::verify( // Compute the binding hash Scalar mu = hash_bind( - tx.hash_bind_inner( + hash_bind_inner( tx.cover_set_representations, + tx.S1, tx.C1, + tx.T, tx.grootle_proofs, tx.balance_proof, tx.range_proof @@ -405,9 +409,13 @@ bool SpendTransaction::verify( // Hash function H_bind_inner // This function pre-hashes auxiliary data that makes things easier for a limited signer who cannot process the data directly // Its value is then used as part of the binding hash, which a limited signer can verify as part of the signing process +// +// Note that transparent components of the transaction are bound into `cover_set_representation`, so they don't appear separately. std::vector SpendTransaction::hash_bind_inner( const std::unordered_map>& cover_set_representations, + const std::vector& S1, const std::vector& C1, + const std::vector& T, const std::vector& grootle_proofs, const SchnorrProof& balance_proof, const BPPlusProof& range_proof diff --git a/src/libspark/spend_transaction.h b/src/libspark/spend_transaction.h index 6b2803da5a..5dce27d137 100644 --- a/src/libspark/spend_transaction.h +++ b/src/libspark/spend_transaction.h @@ -60,9 +60,11 @@ class SpendTransaction { static bool verify(const Params* params, const std::vector& transactions, const std::unordered_map>& cover_sets); static bool verify(const SpendTransaction& transaction, const std::unordered_map>& cover_sets); - std::vector hash_bind_inner( + static std::vector hash_bind_inner( const std::unordered_map>& cover_set_representations, + const std::vector& S1, const std::vector& C1, + const std::vector& T, const std::vector& grootle_proofs, const SchnorrProof& balance_proof, const BPPlusProof& range_proof From 2347fb11b06c98634b8c86ac9d25eecdcb8c6295 Mon Sep 17 00:00:00 2001 From: psolstice Date: Wed, 24 Jan 2024 14:08:20 +0100 Subject: [PATCH 04/17] MacOS Sonoma compilation fix (#1393) * Fix for recent macOS compilation * Restored accidentally removed alternative package download path --- depends/builders/darwin.mk | 7 + depends/builders/default.mk | 5 +- depends/funcs.mk | 106 +++++----- depends/packages/boost.mk | 9 +- depends/packages/libxcb.mk | 34 +-- depends/packages/libxcb_util.mk | 32 +++ depends/packages/libxcb_util_image.mk | 31 +++ depends/packages/libxcb_util_keysyms.mk | 31 +++ depends/packages/libxcb_util_render.mk | 31 +++ depends/packages/libxcb_util_wm.mk | 31 +++ depends/packages/native_comparisontool.mk | 21 -- depends/packages/openssl.mk | 2 +- depends/packages/packages.mk | 4 +- depends/packages/qt.mk | 126 +++++++----- depends/packages/xcb_proto.mk | 16 +- .../patches/libxcb/remove_pthread_stubs.patch | 12 ++ depends/patches/qt/dont_hardcode_x86_64.patch | 123 ----------- depends/patches/qt/duplicate_lcqpafonts.patch | 104 ++++++++++ .../qt/fast_fixed_dtoa_no_optimize.patch | 20 ++ depends/patches/qt/fix-macos-linker.patch | 55 +++++ .../patches/qt/fix_android_jni_static.patch | 2 +- depends/patches/qt/fix_android_pch.patch | 10 - depends/patches/qt/fix_lib_paths.patch | 193 ------------------ depends/patches/qt/fix_limits_header.patch | 44 ---- depends/patches/qt/fix_montery_include.patch | 21 -- depends/patches/qt/fix_no_printer.patch | 19 -- depends/patches/qt/fix_qt_pkgconfig.patch | 14 +- depends/patches/qt/guix_cross_lib_path.patch | 17 ++ depends/patches/qt/mac-qmake.conf | 4 +- depends/patches/qt/memory_resource.patch | 49 +++++ depends/patches/qt/no-xlib.patch | 19 +- depends/patches/qt/no_sdk_version_check.patch | 20 -- .../qt/qtbase-moc-ignore-gcc-macro.patch | 2 +- .../patches/qt/rcc_hardcode_timestamp.patch | 24 +++ .../patches/qt/support_new_android_ndks.patch | 122 ----------- depends/patches/qt/use_android_ndk23.patch | 13 ++ depends/patches/qt/windows_lto.patch | 31 +++ src/qt/addressbookpage.cpp | 2 +- src/qt/bitcoin.cpp | 5 +- src/qt/bitcoingui.cpp | 6 +- src/qt/coincontroldialog.cpp | 2 +- src/qt/lelantuscoincontroldialog.cpp | 2 +- src/qt/optionsdialog.cpp | 2 +- src/qt/paymentserver.cpp | 2 +- src/qt/peertablemodel.cpp | 4 +- src/qt/platformstyle.cpp | 3 +- src/qt/receivecoinsdialog.cpp | 2 +- src/qt/sendcoinsdialog.cpp | 4 +- src/qt/splashscreen.cpp | 2 +- src/qt/trafficgraphwidget.cpp | 4 +- src/qt/transactiondesc.cpp | 2 +- src/qt/transactiontablemodel.cpp | 2 +- src/qt/utilitydialog.cpp | 2 +- src/qt/walletmodel.cpp | 12 +- src/qt/walletmodeltransaction.cpp | 2 +- src/sync.cpp | 10 + 56 files changed, 700 insertions(+), 774 deletions(-) create mode 100644 depends/packages/libxcb_util.mk create mode 100644 depends/packages/libxcb_util_image.mk create mode 100644 depends/packages/libxcb_util_keysyms.mk create mode 100644 depends/packages/libxcb_util_render.mk create mode 100644 depends/packages/libxcb_util_wm.mk delete mode 100644 depends/packages/native_comparisontool.mk create mode 100644 depends/patches/libxcb/remove_pthread_stubs.patch delete mode 100644 depends/patches/qt/dont_hardcode_x86_64.patch create mode 100644 depends/patches/qt/duplicate_lcqpafonts.patch create mode 100644 depends/patches/qt/fast_fixed_dtoa_no_optimize.patch create mode 100644 depends/patches/qt/fix-macos-linker.patch delete mode 100644 depends/patches/qt/fix_android_pch.patch delete mode 100644 depends/patches/qt/fix_lib_paths.patch delete mode 100644 depends/patches/qt/fix_limits_header.patch delete mode 100644 depends/patches/qt/fix_montery_include.patch delete mode 100644 depends/patches/qt/fix_no_printer.patch create mode 100644 depends/patches/qt/guix_cross_lib_path.patch create mode 100644 depends/patches/qt/memory_resource.patch delete mode 100644 depends/patches/qt/no_sdk_version_check.patch create mode 100644 depends/patches/qt/rcc_hardcode_timestamp.patch delete mode 100644 depends/patches/qt/support_new_android_ndks.patch create mode 100644 depends/patches/qt/use_android_ndk23.patch create mode 100644 depends/patches/qt/windows_lto.patch diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index 001c928424..8ed82b276d 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -6,6 +6,7 @@ build_darwin_STRIP:=$(shell xcrun -f strip) build_darwin_OTOOL:=$(shell xcrun -f otool) build_darwin_NM:=$(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +build_darwin_DSYMUTIL:=$(shell xcrun -f dsymutil) build_darwin_SHA256SUM=shasum -a 256 build_darwin_DOWNLOAD=curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o @@ -19,5 +20,11 @@ darwin_LIBTOOL:=$(shell xcrun -f libtool) darwin_OTOOL:=$(shell xcrun -f otool) darwin_NM:=$(shell xcrun -f nm) darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +darwin_DSYMUTIL:=$(shell xcrun -f dsymutil) darwin_native_binutils= darwin_native_toolchain= + +x86_64_darwin_CFLAGS += -arch x86_64 +x86_64_darwin_CXXFLAGS += -arch x86_64 +aarch64_darwin_CFLAGS += -arch arm64 +aarch64_darwin_CXXFLAGS += -arch arm64 diff --git a/depends/builders/default.mk b/depends/builders/default.mk index f097db65d6..cc6dec66c2 100644 --- a/depends/builders/default.mk +++ b/depends/builders/default.mk @@ -1,18 +1,17 @@ default_build_CC = gcc default_build_CXX = g++ default_build_AR = ar +default_build_TAR = tar default_build_RANLIB = ranlib default_build_STRIP = strip default_build_NM = nm -default_build_OTOOL = otool -default_build_INSTALL_NAME_TOOL = install_name_tool define add_build_tool_func build_$(build_os)_$1 ?= $$(default_build_$1) build_$(build_arch)_$(build_os)_$1 ?= $$(build_$(build_os)_$1) build_$1=$$(build_$(build_arch)_$(build_os)_$1) endef -$(foreach var,CC CXX AR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL,$(eval $(call add_build_tool_func,$(var)))) +$(foreach var,CC CXX AR TAR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL DSYMUTIL,$(eval $(call add_build_tool_func,$(var)))) define add_build_flags_func build_$(build_arch)_$(build_os)_$1 += $(build_$(build_os)_$1) build_$1=$$(build_$(build_arch)_$(build_os)_$1) diff --git a/depends/funcs.mk b/depends/funcs.mk index 24585240c5..1dd3fd6923 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -38,7 +38,7 @@ define fetch_file ( test -f $$($(1)_source_dir)/$(4) || \ ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)) || \ - $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH_ALTERNATIVE),$(3),$(4),$(5)))) + $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH_ALTERNATIVE),$(3),$(4),$(5)))) endef define int_get_build_recipe_hash @@ -68,6 +68,7 @@ $(1)_cached_checksum:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_bui $(1)_patch_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)/.patches-$($(1)_build_id) $(1)_prefixbin:=$($($(1)_type)_prefix)/bin/ $(1)_cached:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz +$(1)_build_log:=$(BASEDIR)/$(1)-$($(1)_version)-$($(1)_build_id).log $(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources) #stamps @@ -76,7 +77,7 @@ $(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted $(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed $(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned $(1)_built=$$($(1)_build_dir)/.stamp_built -$(1)_configured=$$($(1)_build_dir)/.stamp_configured +$(1)_configured=$(host_prefix)/.$(1)_stamp_configured $(1)_staged=$$($(1)_staging_dir)/.stamp_staged $(1)_postprocessed=$$($(1)_staging_prefix_dir)/.stamp_postprocessed $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) @@ -85,11 +86,11 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) #default commands # The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior $(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) -$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --no-same-owner --strip-components=1 -xf $$($(1)_source) -$(1)_preprocess_cmds ?= -$(1)_build_cmds ?= -$(1)_config_cmds ?= -$(1)_stage_cmds ?= +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_TAR) --no-same-owner --strip-components=1 -xf $$($(1)_source) +$(1)_preprocess_cmds ?= true +$(1)_build_cmds ?= true +$(1)_config_cmds ?= true +$(1)_stage_cmds ?= true $(1)_set_vars ?= @@ -137,6 +138,7 @@ $(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$( $(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig +$(1)_config_env+=PKG_CONFIG_SYSROOT_DIR=/ $(1)_config_env+=CMAKE_MODULE_PATH=$($($(1)_type)_prefix)/lib/cmake $(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH) $(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH) @@ -175,7 +177,7 @@ $(1)_cmake=env CC="$$($(1)_cc)" \ CXX="$$($(1)_cxx)" \ CXXFLAGS="$$($(1)_cppflags) $$($(1)_cxxflags)" \ LDFLAGS="$$($(1)_ldflags)" \ - cmake -DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" + cmake -DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" $$($(1)_config_opts) ifeq ($($(1)_type),build) $(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH="$$($($(1)_type)_prefix)/lib" else @@ -188,54 +190,61 @@ endif endef define int_add_cmds +ifneq ($(LOG),) +$(1)_logging = >>$$($(1)_build_log) 2>&1 || { if test -f $$($(1)_build_log); then cat $$($(1)_build_log); fi; exit 1; } +endif + $($(1)_fetched): - $(AT)mkdir -p $$(@D) $(SOURCES_PATH) - $(AT)rm -f $$@ - $(AT)touch $$@ - $(AT)cd $$(@D); $(call $(1)_fetch_cmds,$(1)) - $(AT)cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);) - $(AT)touch $$@ + mkdir -p $$(@D) $(SOURCES_PATH) + rm -f $$@ + touch $$@ + cd $$(@D); $($(1)_fetch_cmds) + cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);) + touch $$@ $($(1)_extracted): | $($(1)_fetched) - $(AT)echo Extracting $(1)... - $(AT)mkdir -p $$(@D) - $(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1)) - $(AT)touch $$@ + echo Extracting $(1)... + mkdir -p $$(@D) + cd $$(@D); $($(1)_extract_cmds) + touch $$@ $($(1)_preprocessed): | $($(1)_extracted) - $(AT)echo Preprocessing $(1)... - $(AT)mkdir -p $$(@D) $($(1)_patch_dir) - $(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) - $(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1)) - $(AT)touch $$@ + echo Preprocessing $(1)... + mkdir -p $$(@D) $($(1)_patch_dir) + $(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) + { cd $$(@D); $($(1)_preprocess_cmds); } $$($(1)_logging) + touch $$@ $($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed) - $(AT)echo Configuring $(1)... - $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar --no-same-owner -xf $($(package)_cached); ) - $(AT)mkdir -p $$(@D) - $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) - $(AT)touch $$@ + echo Configuring $(1)... + rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), $(build_TAR) --no-same-owner -xf $($(package)_cached); ) + mkdir -p $$($(1)_build_dir) + +{ cd $$($(1)_build_dir); export $($(1)_config_env); $($(1)_config_cmds); } $$($(1)_logging) + touch $$@ $($(1)_built): | $($(1)_configured) - $(AT)echo Building $(1)... - $(AT)mkdir -p $$(@D) - $(AT)+cd $$(@D); $($(1)_build_env) $(call $(1)_build_cmds, $(1)) - $(AT)touch $$@ + echo Building $(1)... + mkdir -p $$(@D) + +{ cd $$(@D); export $($(1)_build_env); $($(1)_build_cmds); } $$($(1)_logging) + touch $$@ $($(1)_staged): | $($(1)_built) - $(AT)echo Staging $(1)... - $(AT)mkdir -p $($(1)_staging_dir)/$(host_prefix) - $(AT)cd $($(1)_build_dir); $($(1)_stage_env) $(call $(1)_stage_cmds, $(1)) - $(AT)rm -rf $($(1)_extract_dir) - $(AT)touch $$@ + echo Staging $(1)... + mkdir -p $($(1)_staging_dir)/$(host_prefix) + +{ cd $($(1)_build_dir); export $($(1)_stage_env); $($(1)_stage_cmds); } $$($(1)_logging) + rm -rf $($(1)_extract_dir) + touch $$@ $($(1)_postprocessed): | $($(1)_staged) - $(AT)echo Postprocessing $(1)... - $(AT)cd $($(1)_staging_prefix_dir); $(call $(1)_postprocess_cmds) - $(AT)touch $$@ + echo Postprocessing $(1)... + cd $($(1)_staging_prefix_dir); $($(1)_postprocess_cmds) + touch $$@ $($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed) - $(AT)echo Caching $(1)... - $(AT)cd $$($(1)_staging_dir)/$(host_prefix); find . | sort | tar --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T - - $(AT)mkdir -p $$(@D) - $(AT)rm -rf $$(@D) && mkdir -p $$(@D) - $(AT)mv $$($(1)_staging_dir)/$$(@F) $$(@) - $(AT)rm -rf $($(1)_staging_dir) + echo Caching $(1)... + cd $$($(1)_staging_dir)/$(host_prefix); \ + find . ! -name '.stamp_postprocessed' -print0 | TZ=UTC xargs -0r touch -h -m -t 200001011200; \ + find . ! -name '.stamp_postprocessed' | LC_ALL=C sort | $(build_TAR) --numeric-owner --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T - + mkdir -p $$(@D) + rm -rf $$(@D) && mkdir -p $$(@D) + mv $$($(1)_staging_dir)/$$(@F) $$(@) + rm -rf $($(1)_staging_dir) + if test -f $($(1)_build_log); then mv $($(1)_build_log) $$(@D); fi $($(1)_cached_checksum): $($(1)_cached) - $(AT)cd $$(@D); $(build_SHA256SUM) $$( $$(@) + cd $$(@D); $(build_SHA256SUM) $$( $$(@) .PHONY: $(1) $(1): | $($(1)_cached_checksum) @@ -265,7 +274,8 @@ $(foreach package,$(packages),$(eval $(package)_type=$(host_arch)_$(host_os))) $(foreach package,$(all_packages),$(eval $(call int_vars,$(package)))) #include package files -$(foreach package,$(all_packages),$(eval include packages/$(package).mk)) +$(foreach native_package,$(native_packages),$(eval include packages/$(native_package).mk)) +$(foreach package,$(packages),$(eval include packages/$(package).mk)) #compute a hash of all files that comprise this package's build recipe $(foreach package,$(all_packages),$(eval $(call int_get_build_recipe_hash,$(package)))) diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 0a0208e2c3..859ac1af28 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_77_0 -$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$(subst _,.,$($(package)_version))/source/ -$(package)_file_name=boost_$($(package)_version).tar.bz2 -$(package)_sha256_hash=fc9f85fc030e233142908241af7a846e60630aa7388de9a5fafb1f3a26840854 +$(package)_version=1.81.0 +$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/ +$(package)_file_name=boost_$(subst .,_,$($(package)_version)).tar.bz2 +$(package)_sha256_hash=71feeed900fbccca04a3b4f2f84a7c217186f28a940ed8b7ed4725986baf99fa $(package)_dependencies=native_b2 define $(package)_set_vars @@ -44,3 +44,4 @@ endef define $(package)_stage_cmds 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/libxcb.mk b/depends/packages/libxcb.mk index 28f2bd6f25..036eaf6560 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -1,25 +1,31 @@ package=libxcb -$(package)_version=1.10 -$(package)_download_path=http://xcb.freedesktop.org/dist -$(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5 -$(package)_dependencies=xcb_proto libXau xproto +$(package)_version=1.14 +$(package)_download_path=https://xcb.freedesktop.org/dist +$(package)_file_name=$(package)-$($(package)_version).tar.xz +$(package)_sha256_hash=a55ed6db98d43469801262d81dc2572ed124edc3db31059d4e9916eb9f844c34 +$(package)_dependencies=xcb_proto libXau +$(package)_patches = remove_pthread_stubs.patch define $(package)_set_vars -$(package)_config_opts=--disable-static +$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen --without-launchd +$(package)_config_opts += --disable-dependency-tracking --enable-option-checking +# Disable unneeded extensions. +# More info is available from: https://doc.qt.io/qt-5.15/linux-requirements.html +$(package)_config_opts += --disable-composite --disable-damage --disable-dpms +$(package)_config_opts += --disable-dri2 --disable-dri3 --disable-glx +$(package)_config_opts += --disable-present --disable-record --disable-resource +$(package)_config_opts += --disable-screensaver --disable-xevie --disable-xfree86-dri +$(package)_config_opts += --disable-xinput --disable-xprint --disable-selinux +$(package)_config_opts += --disable-xtest --disable-xv --disable-xvmc endef define $(package)_preprocess_cmds - sed "s/pthread-stubs//" -i configure + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux && \ + patch -p1 -i $($(package)_patch_dir)/remove_pthread_stubs.patch endef -# Don't install xcb headers to the default path in order to work around a qt -# build issue: https://bugreports.qt.io/browse/QTBUG-34748 -# When using qt's internal libxcb, it may end up finding the real headers in -# depends staging. Use a non-default path to avoid that. - define $(package)_config_cmds - $($(package)_autoconf) --includedir=$(host_prefix)/include/xcb-shared + $($(package)_autoconf) endef define $(package)_build_cmds @@ -31,5 +37,5 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds - rm -rf share/man share/doc + rm -rf share lib/*.la endef diff --git a/depends/packages/libxcb_util.mk b/depends/packages/libxcb_util.mk new file mode 100644 index 0000000000..6f1b9cd7c6 --- /dev/null +++ b/depends/packages/libxcb_util.mk @@ -0,0 +1,32 @@ +package=libxcb_util +$(package)_version=0.4.0 +$(package)_download_path=https://xcb.freedesktop.org/dist +$(package)_file_name=xcb-util-$($(package)_version).tar.bz2 +$(package)_sha256_hash=46e49469cb3b594af1d33176cd7565def2be3fa8be4371d62271fabb5eae50e9 +$(package)_dependencies=libxcb + +define $(package)_set_vars +$(package)_config_opts = --disable-shared --disable-devel-docs --without-doxygen +$(package)_config_opts += --disable-dependency-tracking --enable-option-checking +$(package)_config_opts += --with-pic +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf share/man share/doc lib/*.la +endef diff --git a/depends/packages/libxcb_util_image.mk b/depends/packages/libxcb_util_image.mk new file mode 100644 index 0000000000..d12d67e8e8 --- /dev/null +++ b/depends/packages/libxcb_util_image.mk @@ -0,0 +1,31 @@ +package=libxcb_util_image +$(package)_version=0.4.0 +$(package)_download_path=https://xcb.freedesktop.org/dist +$(package)_file_name=xcb-util-image-$($(package)_version).tar.bz2 +$(package)_sha256_hash=2db96a37d78831d643538dd1b595d7d712e04bdccf8896a5e18ce0f398ea2ffc +$(package)_dependencies=libxcb libxcb_util + +define $(package)_set_vars +$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen +$(package)_config_opts+= --disable-dependency-tracking --enable-option-checking +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf share/man share/doc lib/*.la +endef diff --git a/depends/packages/libxcb_util_keysyms.mk b/depends/packages/libxcb_util_keysyms.mk new file mode 100644 index 0000000000..d4f72dedbe --- /dev/null +++ b/depends/packages/libxcb_util_keysyms.mk @@ -0,0 +1,31 @@ +package=libxcb_util_keysyms +$(package)_version=0.4.0 +$(package)_download_path=https://xcb.freedesktop.org/dist +$(package)_file_name=xcb-util-keysyms-$($(package)_version).tar.bz2 +$(package)_sha256_hash=0ef8490ff1dede52b7de533158547f8b454b241aa3e4dcca369507f66f216dd9 +$(package)_dependencies=libxcb xproto + +define $(package)_set_vars +$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen +$(package)_config_opts += --disable-dependency-tracking --enable-option-checking +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf share/man share/doc lib/*.la +endef diff --git a/depends/packages/libxcb_util_render.mk b/depends/packages/libxcb_util_render.mk new file mode 100644 index 0000000000..28f1fb073c --- /dev/null +++ b/depends/packages/libxcb_util_render.mk @@ -0,0 +1,31 @@ +package=libxcb_util_render +$(package)_version=0.3.9 +$(package)_download_path=https://xcb.freedesktop.org/dist +$(package)_file_name=xcb-util-renderutil-$($(package)_version).tar.bz2 +$(package)_sha256_hash=c6e97e48fb1286d6394dddb1c1732f00227c70bd1bedb7d1acabefdd340bea5b +$(package)_dependencies=libxcb + +define $(package)_set_vars +$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen +$(package)_config_opts += --disable-dependency-tracking --enable-option-checking +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf share/man share/doc lib/*.la +endef diff --git a/depends/packages/libxcb_util_wm.mk b/depends/packages/libxcb_util_wm.mk new file mode 100644 index 0000000000..3b905ba4ec --- /dev/null +++ b/depends/packages/libxcb_util_wm.mk @@ -0,0 +1,31 @@ +package=libxcb_util_wm +$(package)_version=0.4.1 +$(package)_download_path=https://xcb.freedesktop.org/dist +$(package)_file_name=xcb-util-wm-$($(package)_version).tar.bz2 +$(package)_sha256_hash=28bf8179640eaa89276d2b0f1ce4285103d136be6c98262b6151aaee1d3c2a3f +$(package)_dependencies=libxcb + +define $(package)_set_vars +$(package)_config_opts=--disable-static --disable-devel-docs --without-doxygen +$(package)_config_opts += --disable-dependency-tracking --enable-option-checking +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf share/man share/doc lib/*.la +endef diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk deleted file mode 100644 index e0ae0cec70..0000000000 --- a/depends/packages/native_comparisontool.mk +++ /dev/null @@ -1,21 +0,0 @@ -package=native_comparisontool -$(package)_version=8c6666f -$(package)_download_path=https://github.com/theuni/bitcoind-comparisontool/raw/master -$(package)_file_name=pull-tests-$($(package)_version).jar -$(package)_sha256_hash=a865332b3827abcde684ab79f5f43c083b0b6a4c97ff5508c79f29fee24f11cd -$(package)_install_dirname=BitcoindComparisonTool_jar -$(package)_install_filename=BitcoindComparisonTool.jar - -define $(package)_extract_cmds -endef - -define $(package)_configure_cmds -endef - -define $(package)_build_cmds -endef - -define $(package)_stage_cmds - mkdir -p $($(package)_staging_prefix_dir)/share/$($(package)_install_dirname) && \ - cp $($(package)_source) $($(package)_staging_prefix_dir)/share/$($(package)_install_dirname)/$($(package)_install_filename) -endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 8380c98879..46414f5740 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -34,7 +34,7 @@ $(package)_config_opts+=no-weak-ssl-ciphers $(package)_config_opts+=no-whirlpool $(package)_config_opts+=no-zlib $(package)_config_opts+=no-zlib-dynamic -$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) +#$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) $(package)_config_opts_linux=-fPIC -Wa,--noexecstack $(package)_config_opts_x86_64_linux=linux-x86_64 $(package)_config_opts_i686_linux=linux-generic32 diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 81d7a618bb..574bf3b276 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,9 +1,9 @@ packages:=boost openssl libevent gmp zlib backtrace tor bls-dash darwin_packages:=zeromq linux_packages:=zeromq -native_packages := native_ccache native_comparisontool native_cmake +native_packages := native_ccache native_cmake -qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon +qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm qt_darwin_packages=qt qt_mingw32_packages=qt diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 7aa579e1da..039d15bcb8 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -1,44 +1,54 @@ -PACKAGE=qt -$(package)_version=5.12.11 -$(package)_download_path=https://download.qt.io/official_releases/qt/5.12/$($(package)_version)/submodules -$(package)_suffix=everywhere-src-$($(package)_version).tar.xz +package=qt +$(package)_version=5.15.11 +$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules +$(package)_suffix=everywhere-opensource-src-$($(package)_version).tar.xz $(package)_file_name=qtbase-$($(package)_suffix) -$(package)_sha256_hash=1c1b4e33137ca77881074c140d54c3c9747e845a31338cfe8680f171f0bc3a39 +$(package)_sha256_hash=425ad301acd91ca66c10c0dabee0704e2d0cd2801a6b670115800cbb95f84846 $(package)_dependencies=zlib -$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon +$(package)_linux_dependencies=freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm $(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_linguist_tools = lrelease lupdate lconvert -$(package)_patches = qt.pro qttools_src.pro -$(package)_patches += fix_qt_pkgconfig.patch mac-qmake.conf fix_no_printer.patch no-xlib.patch -$(package)_patches += support_new_android_ndks.patch fix_android_jni_static.patch dont_hardcode_pwd.patch -$(package)_patches += dont_hardcode_x86_64.patch no_sdk_version_check.patch -$(package)_patches+= fix_lib_paths.patch fix_android_pch.patch -$(package)_patches+= qtbase-moc-ignore-gcc-macro.patch fix_limits_header.patch -$(package)_patches+= fix_montery_include.patch +$(package)_patches = qt.pro +$(package)_patches += qttools_src.pro +$(package)_patches += mac-qmake.conf +$(package)_patches += fix_qt_pkgconfig.patch +$(package)_patches += no-xlib.patch +$(package)_patches += fix_android_jni_static.patch +$(package)_patches += dont_hardcode_pwd.patch +$(package)_patches += qtbase-moc-ignore-gcc-macro.patch +$(package)_patches += use_android_ndk23.patch +$(package)_patches += rcc_hardcode_timestamp.patch +$(package)_patches += duplicate_lcqpafonts.patch +$(package)_patches += fast_fixed_dtoa_no_optimize.patch +$(package)_patches += guix_cross_lib_path.patch +$(package)_patches += fix-macos-linker.patch +$(package)_patches += memory_resource.patch +$(package)_patches += windows_lto.patch $(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) -$(package)_qttranslations_sha256_hash=577b0668a777eb2b451c61e8d026d79285371597ce9df06b6dee6c814164b7c3 +$(package)_qttranslations_sha256_hash=a31785948c640b7c66d9fe2db4993728ca07f64e41c560b3625ad191b276ff20 $(package)_qttools_file_name=qttools-$($(package)_suffix) -$(package)_qttools_sha256_hash=98b2aaca230458f65996f3534fd471d2ffd038dd58ac997c0589c06dc2385b4f +$(package)_qttools_sha256_hash=7cd847ae6ff09416df617136eadcaf0eb98e3bc9b89979219a3ea8111fb8d339 $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) define $(package)_set_vars +$(package)_config_env = QT_MAC_SDK_NO_VERSION_CHECK=1 $(package)_config_opts_release = -release $(package)_config_opts_release += -silent $(package)_config_opts_debug = -debug $(package)_config_opts_debug += -optimized-tools $(package)_config_opts += -bindir $(build_prefix)/bin -$(package)_config_opts += -c++std c++1z +$(package)_config_opts += -c++std c++17 $(package)_config_opts += -confirm-license $(package)_config_opts += -hostprefix $(build_prefix) $(package)_config_opts += -no-compile-examples $(package)_config_opts += -no-cups $(package)_config_opts += -no-egl $(package)_config_opts += -no-eglfs -$(package)_config_opts += -no-freetype +$(package)_config_opts += -no-evdev $(package)_config_opts += -no-gif $(package)_config_opts += -no-glib $(package)_config_opts += -no-icu @@ -104,6 +114,7 @@ $(package)_config_opts += -no-feature-sqlmodel $(package)_config_opts += -no-feature-statemachine $(package)_config_opts += -no-feature-syntaxhighlighter $(package)_config_opts += -no-feature-textbrowser +$(package)_config_opts += -no-feature-textmarkdownwriter $(package)_config_opts += -no-feature-textodfwriter $(package)_config_opts += -no-feature-topleveldomain $(package)_config_opts += -no-feature-undocommand @@ -117,6 +128,7 @@ $(package)_config_opts_darwin = -no-dbus $(package)_config_opts_darwin += -no-opengl $(package)_config_opts_darwin += -pch $(package)_config_opts_darwin += -no-feature-corewlan +$(package)_config_opts_darwin += -no-freetype $(package)_config_opts_darwin += QMAKE_MACOSX_DEPLOYMENT_TARGET=$(OSX_MIN_VERSION) ifneq ($(build_os),darwin) @@ -133,7 +145,7 @@ $(package)_config_opts_aarch64_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS $(package)_config_opts_x86_64_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS=x86_64 endif -$(package)_config_opts_linux = -qt-xcb +$(package)_config_opts_linux = -xcb $(package)_config_opts_linux += -no-xcb-xlib $(package)_config_opts_linux += -no-feature-xlib $(package)_config_opts_linux += -system-freetype @@ -141,32 +153,40 @@ $(package)_config_opts_linux += -fontconfig $(package)_config_opts_linux += -no-opengl $(package)_config_opts_linux += -no-feature-vulkan $(package)_config_opts_linux += -dbus-runtime -$(package)_config_opts_arm_linux += -platform linux-g++ -xplatform bitcoin-linux-g++ -$(package)_config_opts_i686_linux = -xplatform linux-g++-32 -$(package)_config_opts_x86_64_linux = -xplatform linux-g++-64 -$(package)_config_opts_aarch64_linux = -xplatform linux-aarch64-gnu-g++ -$(package)_config_opts_powerpc64_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ -$(package)_config_opts_powerpc64le_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ -$(package)_config_opts_riscv64_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ -$(package)_config_opts_s390x_linux = -platform linux-g++ -xplatform bitcoin-linux-g++ +ifneq ($(LTO),) +$(package)_config_opts_linux += -ltcg +endif + +ifneq (,$(findstring clang,$($(package)_cxx))) + ifneq (,$(findstring -stdlib=libc++,$($(package)_cxx))) + $(package)_config_opts_linux += -platform linux-clang-libc++ -xplatform linux-clang-libc++ + else + $(package)_config_opts_linux += -platform linux-clang -xplatform linux-clang + endif +else + $(package)_config_opts_linux += -platform linux-g++ -xplatform bitcoin-linux-g++ +endif $(package)_config_opts_mingw32 = -no-opengl $(package)_config_opts_mingw32 += -no-dbus +$(package)_config_opts_mingw32 += -no-freetype $(package)_config_opts_mingw32 += -xplatform win32-g++ $(package)_config_opts_mingw32 += "QMAKE_CFLAGS = '$($(package)_cflags) $($(package)_cppflags)'" -$(package)_config_opts_mingw32 += "QMAKE_CXXFLAGS = '$($(package)_cflags) $($(package)_cppflags)'" +$(package)_config_opts_mingw32 += "QMAKE_CXX = '$($(package)_cxx)'" +$(package)_config_opts_mingw32 += "QMAKE_CXXFLAGS = '$($(package)_cxxflags) $($(package)_cppflags)'" $(package)_config_opts_mingw32 += "QMAKE_LFLAGS = '$($(package)_ldflags)'" +$(package)_config_opts_mingw32 += "QMAKE_LIB = '$($(package)_ar) rc'" $(package)_config_opts_mingw32 += -device-option CROSS_COMPILE="$(host)-" $(package)_config_opts_mingw32 += -pch +ifneq ($(LTO),) +$(package)_config_opts_mingw32 += -ltcg +endif $(package)_config_opts_android = -xplatform android-clang $(package)_config_opts_android += -android-sdk $(ANDROID_SDK) $(package)_config_opts_android += -android-ndk $(ANDROID_NDK) $(package)_config_opts_android += -android-ndk-platform android-$(ANDROID_API_LEVEL) -$(package)_config_opts_android += -device-option CROSS_COMPILE="$(host)-" $(package)_config_opts_android += -egl -$(package)_config_opts_android += -qpa xcb -$(package)_config_opts_android += -no-eglfs $(package)_config_opts_android += -no-dbus $(package)_config_opts_android += -opengl es2 $(package)_config_opts_android += -qt-freetype @@ -179,7 +199,6 @@ $(package)_config_opts_android += -no-feature-vulkan $(package)_config_opts_aarch64_android += -android-arch arm64-v8a $(package)_config_opts_armv7a_android += -android-arch armeabi-v7a $(package)_config_opts_x86_64_android += -android-arch x86_64 -$(package)_config_opts_i686_android += -android-arch i686 endef define $(package)_fetch_cmds @@ -195,11 +214,11 @@ define $(package)_extract_cmds echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir qtbase && \ - tar --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \ + $(build_TAR) --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \ mkdir qttranslations && \ - tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ + $(build_TAR) --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ mkdir qttools && \ - tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools + $(build_TAR) --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools endef # Preprocessing steps work as follows: @@ -209,50 +228,45 @@ endef # 2. Create a macOS-Clang-Linux mkspec using our mac-qmake.conf. # # 3. After making a copy of the mkspec for the linux-arm-gnueabi host, named -# bitcoin-linux-g++, replace instances of linux-arm-gnueabi with $(host). This -# way we can generically support hosts like riscv64-linux-gnu, which Qt doesn't -# ship a mkspec for. See it's usage in config_opts_* above. +# bitcoin-linux-g++, replace tool names with $($($(package)_type)_TOOL). # # 4. Put our C, CXX and LD FLAGS into gcc-base.conf. Only used for non-host builds. # -# 5. Do similar for the win32-g++ mkspec. -# -# 6. In clang.conf, swap out clang & clang++, for our compiler + flags. See #17466. -# -# 7. Adjust a regex in toolchain.prf, to accommodate Guix's usage of -# CROSS_LIBRARY_PATH. See #15277. +# 5. In clang.conf, swap out clang & clang++, for our compiler + flags. See #17466. define $(package)_preprocess_cmds cp $($(package)_patch_dir)/qt.pro qt.pro && \ cp $($(package)_patch_dir)/qttools_src.pro qttools/src/src.pro && \ + patch -p1 -i $($(package)_patch_dir)/fix-macos-linker.patch && \ patch -p1 -i $($(package)_patch_dir)/dont_hardcode_pwd.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \ - patch -p1 -i $($(package)_patch_dir)/support_new_android_ndks.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_android_jni_static.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_android_pch.patch && \ patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \ - patch -p1 -i $($(package)_patch_dir)/dont_hardcode_x86_64.patch && \ - patch -p1 -i $($(package)_patch_dir)/no_sdk_version_check.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_lib_paths.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase-moc-ignore-gcc-macro.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_limits_header.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_montery_include.patch && \ + patch -p1 -i $($(package)_patch_dir)/use_android_ndk23.patch && \ + patch -p1 -i $($(package)_patch_dir)/memory_resource.patch && \ + patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch && \ + patch -p1 -i $($(package)_patch_dir)/duplicate_lcqpafonts.patch && \ + patch -p1 -i $($(package)_patch_dir)/fast_fixed_dtoa_no_optimize.patch && \ + patch -p1 -i $($(package)_patch_dir)/guix_cross_lib_path.patch && \ + patch -p1 -i $($(package)_patch_dir)/windows_lto.patch && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \ - sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + sed -i.old "s|arm-linux-gnueabi-gcc|$($($(package)_type)_CC)|" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + sed -i.old "s|arm-linux-gnueabi-g++|$($($(package)_type)_CXX)|" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + sed -i.old "s|arm-linux-gnueabi-ar|$($($(package)_type)_AR)|" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + sed -i.old "s|arm-linux-gnueabi-objcopy|$($($(package)_type)_OBJCOPY)|" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + sed -i.old "s|arm-linux-gnueabi-nm|$($($(package)_type)_NM)|" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ + sed -i.old "s|arm-linux-gnueabi-strip|$($($(package)_type)_STRIP)|" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \ echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ sed -i.old "s|QMAKE_CC = \$$$$\$$$${CROSS_COMPILE}clang|QMAKE_CC = $($(package)_cc)|" qtbase/mkspecs/common/clang.conf && \ - sed -i.old "s|QMAKE_CXX = \$$$$\$$$${CROSS_COMPILE}clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf && \ - sed -i.old "s/LIBRARY_PATH/(CROSS_)?\0/g" qtbase/mkspecs/features/toolchain.prf + sed -i.old "s|QMAKE_CXX = \$$$$\$$$${CROSS_COMPILE}clang++|QMAKE_CXX = $($(package)_cxx)|" qtbase/mkspecs/common/clang.conf endef define $(package)_config_cmds - export PKG_CONFIG_SYSROOT_DIR=/ && \ - export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ cd qtbase && \ ./configure -top-level $($(package)_config_opts) endef diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk index 0c7c958d62..6e1c5a10a8 100644 --- a/depends/packages/xcb_proto.mk +++ b/depends/packages/xcb_proto.mk @@ -1,13 +1,8 @@ package=xcb_proto -$(package)_version=1.10 -$(package)_download_path=http://xcb.freedesktop.org/dist -$(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 -$(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05 - -define $(package)_set_vars - $(package)_config_opts=--disable-shared - $(package)_config_opts_linux=--with-pic -endef +$(package)_version=1.15.2 +$(package)_download_path=https://xorg.freedesktop.org/archive/individual/proto +$(package)_file_name=xcb-proto-$($(package)_version).tar.xz +$(package)_sha256_hash=7072beb1f680a2fe3f9e535b797c146d22528990c72f63ddb49d2f350a3653ed define $(package)_config_cmds $($(package)_autoconf) @@ -22,6 +17,5 @@ define $(package)_stage_cmds endef define $(package)_postprocess_cmds - find -name "*.pyc" -delete && \ - find -name "*.pyo" -delete + rm -rf lib/python*/site-packages/xcbgen/__pycache__ endef diff --git a/depends/patches/libxcb/remove_pthread_stubs.patch b/depends/patches/libxcb/remove_pthread_stubs.patch new file mode 100644 index 0000000000..1f32dea527 --- /dev/null +++ b/depends/patches/libxcb/remove_pthread_stubs.patch @@ -0,0 +1,12 @@ +Remove uneeded pthread-stubs dependency +--- a/configure ++++ b/configure +@@ -19695,7 +19695,7 @@ fi + NEEDED="xau >= 0.99.2" + case $host_os in + linux*) ;; +- *) NEEDED="$NEEDED pthread-stubs" ;; ++ *) NEEDED="$NEEDED" ;; + esac + + pkg_failed=no diff --git a/depends/patches/qt/dont_hardcode_x86_64.patch b/depends/patches/qt/dont_hardcode_x86_64.patch deleted file mode 100644 index 0e1ca6acda..0000000000 --- a/depends/patches/qt/dont_hardcode_x86_64.patch +++ /dev/null @@ -1,123 +0,0 @@ -macOS: Don't hard-code x86_64 as the architecture when using qmake - -Upstream commit: - - Qt 6.1: 9082cc8e8d5a6441dabe5e7a95bc0cd9085b95fe - -For other Qt branches see -https://codereview.qt-project.org/q/I70db7e4c27f0d3da5d0af33cb491d72c312d3fa8 - - ---- old/qtbase/configure.json -+++ new/qtbase/configure.json -@@ -208,11 +208,18 @@ - - "testTypeDependencies": { - "linkerSupportsFlag": [ "use_gold_linker" ], -- "verifySpec": [ "shared", "use_gold_linker", "compiler-flags", "qmakeargs", "commit" ], -+ "verifySpec": [ -+ "shared", -+ "use_gold_linker", -+ "compiler-flags", "qmakeargs", -+ "simulator_and_device", -+ "thread", -+ "commit" ], - "compile": [ "verifyspec" ], - "detectPkgConfig": [ "cross_compile", "machineTuple" ], - "library": [ "pkg-config", "compiler-flags" ], -- "getPkgConfigVariable": [ "pkg-config" ] -+ "getPkgConfigVariable": [ "pkg-config" ], -+ "architecture" : [ "verifyspec" ] - }, - - "testTypeAliases": { -@@ -653,7 +660,7 @@ - }, - "architecture": { - "label": "Architecture", -- "output": [ "architecture" ] -+ "output": [ "architecture", "commitConfig" ] - }, - "pkg-config": { - "label": "Using pkg-config", -diff --git a/configure.pri b/configure.pri -index 33c90a8c2f..71767e29d6 100644 - ---- old/qtbase/configure.pri -+++ new/qtbase/configure.pri -@@ -642,6 +642,13 @@ defineTest(qtConfOutput_commitOptions) { - write_file($$QT_BUILD_TREE/mkspecs/qdevice.pri, $${currentConfig}.output.devicePro)|error() - } - -+# Output is written after configuring each Qt module, -+# but some tests within a module might depend on the -+# configuration output of previous tests. -+defineTest(qtConfOutput_commitConfig) { -+ qtConfProcessOutput() -+} -+ - # type (empty or 'host'), option name, default value - defineTest(processQtPath) { - out_var = config.rel_input.$${2} -diff --git a/mkspecs/common/macx.conf b/mkspecs/common/macx.conf -index 7d4a406134..de96c12fc9 100644 - ---- old/qtbase/mkspecs/common/macx.conf -+++ new/qtbase/mkspecs/common/macx.conf -@@ -6,7 +6,6 @@ QMAKE_PLATFORM += macos osx macx - QMAKE_MAC_SDK = macosx - - QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12 --QMAKE_APPLE_DEVICE_ARCHS = x86_64 - - QT_MAC_SDK_VERSION_MIN = 10.13 - QT_MAC_SDK_VERSION_MAX = 11.0 -diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/default_post.prf -index d052808c14..0a89effe87 100644 - ---- old/qtbase/mkspecs/features/mac/default_post.prf -+++ new/qtbase/mkspecs/features/mac/default_post.prf -@@ -89,6 +89,11 @@ app_extension_api_only { - QMAKE_LFLAGS += $$QMAKE_CFLAGS_APPLICATION_EXTENSION - } - -+# Non-universal builds do not set QMAKE_APPLE_DEVICE_ARCHS, -+# so we pick it up from what the arch test resolved instead. -+isEmpty(QMAKE_APPLE_DEVICE_ARCHS): \ -+ QMAKE_APPLE_DEVICE_ARCHS = $$QT_ARCH -+ - macx-xcode { - qmake_pkginfo_typeinfo.name = QMAKE_PKGINFO_TYPEINFO - !isEmpty(QMAKE_PKGINFO_TYPEINFO): \ -@@ -144,9 +149,6 @@ macx-xcode { - simulator: VALID_SIMULATOR_ARCHS = $$QMAKE_APPLE_SIMULATOR_ARCHS - VALID_ARCHS = $$VALID_DEVICE_ARCHS $$VALID_SIMULATOR_ARCHS - -- isEmpty(VALID_ARCHS): \ -- error("QMAKE_APPLE_DEVICE_ARCHS or QMAKE_APPLE_SIMULATOR_ARCHS must contain at least one architecture") -- - single_arch: VALID_ARCHS = $$first(VALID_ARCHS) - - ACTIVE_ARCHS = $(filter $(EXPORT_VALID_ARCHS), $(ARCHS)) -diff --git a/mkspecs/features/toolchain.prf b/mkspecs/features/toolchain.prf -index 5003679bd0..c7c080cb07 100644 - ---- old/qtbase/mkspecs/features/toolchain.prf -+++ new/qtbase/mkspecs/features/toolchain.prf -@@ -182,9 +182,14 @@ isEmpty($${target_prefix}.INCDIRS) { - # UIKit simulator platforms will see the device SDK's sysroot in - # QMAKE_DEFAULT_*DIRS, because they're handled in a single build pass. - darwin { -- # Clang doesn't pick up the architecture from the sysroot, and will -- # default to the host architecture, so we need to manually set it. -- cxx_flags += -arch $$QMAKE_APPLE_DEVICE_ARCHS -+ uikit { -+ # Clang doesn't automatically pick up the architecture, just because -+ # we're passing the iOS sysroot below, and we will end up building the -+ # test for the host architecture, resulting in linker errors when -+ # linking against the iOS libraries. We work around this by passing -+ # the architecture explicitly. -+ cxx_flags += -arch $$first(QMAKE_APPLE_DEVICE_ARCHS) -+ } - - uikit:macx-xcode: \ - cxx_flags += -isysroot $$sdk_path_device.value diff --git a/depends/patches/qt/duplicate_lcqpafonts.patch b/depends/patches/qt/duplicate_lcqpafonts.patch new file mode 100644 index 0000000000..c460b51dcf --- /dev/null +++ b/depends/patches/qt/duplicate_lcqpafonts.patch @@ -0,0 +1,104 @@ +QtGui: Fix duplication of logging category lcQpaFonts + +Move it to qplatformfontdatabase.h. + +Upstream commit: + - Qt 6.0: ab01885e48873fb2ad71841a3f1627fe4d9cd835 + +--- a/qtbase/src/gui/text/qplatformfontdatabase.cpp ++++ b/qtbase/src/gui/text/qplatformfontdatabase.cpp +@@ -52,6 +52,8 @@ + + QT_BEGIN_NAMESPACE + ++Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") ++ + void qt_registerFont(const QString &familyname, const QString &stylename, + const QString &foundryname, int weight, + QFont::Style style, int stretch, bool antialiased, + +--- a/qtbase/src/gui/text/qplatformfontdatabase.h ++++ b/qtbase/src/gui/text/qplatformfontdatabase.h +@@ -50,6 +50,7 @@ + // + + #include ++#include + #include + #include + #include +@@ -62,6 +63,7 @@ + + QT_BEGIN_NAMESPACE + ++Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) + + class QWritingSystemsPrivate; + + +--- a/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm ++++ b/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +@@ -86,8 +86,6 @@ + + QT_BEGIN_NAMESPACE + +-Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") +- + static float SYNTHETIC_ITALIC_SKEW = std::tan(14.f * std::acos(0.f) / 90.f); + + bool QCoreTextFontEngine::ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length) + +--- a/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h ++++ b/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +@@ -64,8 +64,6 @@ + + QT_BEGIN_NAMESPACE + +-Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) +- + class QCoreTextFontEngine : public QFontEngine + { + Q_GADGET + +--- a/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp ++++ b/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +@@ -68,8 +68,6 @@ + + QT_BEGIN_NAMESPACE + +-Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") +- + #ifndef QT_NO_DIRECTWRITE + // ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711) + + +--- a/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h ++++ b/qtbase/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +@@ -63,8 +63,6 @@ + + QT_BEGIN_NAMESPACE + +-Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) +- + class QWindowsFontEngineData + { + Q_DISABLE_COPY_MOVE(QWindowsFontEngineData) + +--- a/qtbase/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp ++++ b/qtbase/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +@@ -40,6 +40,7 @@ + #include "qgenericunixthemes_p.h" + + #include "qpa/qplatformtheme_p.h" ++#include "qpa/qplatformfontdatabase.h" + + #include + #include +@@ -76,7 +77,6 @@ + QT_BEGIN_NAMESPACE + + Q_DECLARE_LOGGING_CATEGORY(qLcTray) +-Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") + + ResourceHelper::ResourceHelper() + { diff --git a/depends/patches/qt/fast_fixed_dtoa_no_optimize.patch b/depends/patches/qt/fast_fixed_dtoa_no_optimize.patch new file mode 100644 index 0000000000..d4d6539f56 --- /dev/null +++ b/depends/patches/qt/fast_fixed_dtoa_no_optimize.patch @@ -0,0 +1,20 @@ +Modify the optimisation flags for FastFixedDtoa. +This fixes a non-determinism issue in the asm produced for +this function when cross-compiling on x86_64 and aarch64 for +the arm-linux-gnueabihf HOST. + +--- a/qtbase/src/3rdparty/double-conversion/fixed-dtoa.h ++++ b/qtbase/src/3rdparty/double-conversion/fixed-dtoa.h +@@ -48,9 +48,12 @@ namespace double_conversion { + // + // This method only works for some parameters. If it can't handle the input it + // returns false. The output is null-terminated when the function succeeds. ++#pragma GCC push_options ++#pragma GCC optimize ("-O1") + bool FastFixedDtoa(double v, int fractional_count, + Vector buffer, int* length, int* decimal_point); + ++#pragma GCC pop_options + } // namespace double_conversion + + #endif // DOUBLE_CONVERSION_FIXED_DTOA_H_ diff --git a/depends/patches/qt/fix-macos-linker.patch b/depends/patches/qt/fix-macos-linker.patch new file mode 100644 index 0000000000..e439685656 --- /dev/null +++ b/depends/patches/qt/fix-macos-linker.patch @@ -0,0 +1,55 @@ +qmake: Don't error out if QMAKE_DEFAULT_LIBDIRS is empty on macOS + +The new linker in Xcode 15 doesn't provide any default linker or +framework paths when requested via -v, but still seems to use the +default paths documented in the ld man page. + +We trust that linker will do the right thing, even if we don't +know of its default linker paths. + +We also need to opt out of the default fallback logic to +set the libdirs to /lib and /usr/lib. + +This may result in UnixMakefileGenerator::findLibraries finding +different libraries than expected, if additional paths are +passed with -L, which will then take precedence for qmake, +even if the linker itself will use the library from the +SDK's default paths. This should hopefully not be an issue +in practice, as we don't turn -lFoo into absolute paths in +qmake, so the only risk is that we're picking up the wrong +prl files and adding additional dependencies that the lib +in the SDK doesn't have. + +Upstream commits: + - Qt 5.15.16: Not yet publicly available. + - Qt dev: cdf64b0e47115cc473e1afd1472b4b09e130b2a5 + +For other Qt branches see +https://codereview.qt-project.org/q/I2347b26e2df0828471373b0e15b8c9089274c65d + +--- old/qtbase/mkspecs/features/toolchain.prf ++++ new/qtbase/mkspecs/features/toolchain.prf +@@ -288,9 +288,12 @@ isEmpty($${target_prefix}.INCDIRS) { + } + } + } +- isEmpty(QMAKE_DEFAULT_LIBDIRS)|isEmpty(QMAKE_DEFAULT_INCDIRS): \ ++ isEmpty(QMAKE_DEFAULT_INCDIRS): \ + !integrity: \ +- error("failed to parse default search paths from compiler output") ++ error("failed to parse default include paths from compiler output") ++ isEmpty(QMAKE_DEFAULT_LIBDIRS): \ ++ !integrity:!darwin: \ ++ error("failed to parse default library paths from compiler output") + QMAKE_DEFAULT_LIBDIRS = $$unique(QMAKE_DEFAULT_LIBDIRS) + } else: ghs { + cmd = $$QMAKE_CXX $$QMAKE_CXXFLAGS -$${LITERAL_HASH} -o /tmp/fake_output /tmp/fake_input.cpp +@@ -412,7 +415,7 @@ isEmpty($${target_prefix}.INCDIRS) { + QMAKE_DEFAULT_INCDIRS = $$split(INCLUDE, $$QMAKE_DIRLIST_SEP) + } + +- unix:if(!cross_compile|host_build) { ++ unix:!darwin:if(!cross_compile|host_build) { + isEmpty(QMAKE_DEFAULT_INCDIRS): QMAKE_DEFAULT_INCDIRS = /usr/include /usr/local/include + isEmpty(QMAKE_DEFAULT_LIBDIRS): QMAKE_DEFAULT_LIBDIRS = /lib /usr/lib + } diff --git a/depends/patches/qt/fix_android_jni_static.patch b/depends/patches/qt/fix_android_jni_static.patch index a186aeb8f6..89c96026fb 100644 --- a/depends/patches/qt/fix_android_jni_static.patch +++ b/depends/patches/qt/fix_android_jni_static.patch @@ -1,6 +1,6 @@ --- old/qtbase/src/plugins/platforms/android/androidjnimain.cpp +++ new/qtbase/src/plugins/platforms/android/androidjnimain.cpp -@@ -898,6 +898,14 @@ +@@ -979,6 +979,14 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } diff --git a/depends/patches/qt/fix_android_pch.patch b/depends/patches/qt/fix_android_pch.patch deleted file mode 100644 index 195e1c5e59..0000000000 --- a/depends/patches/qt/fix_android_pch.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- old/qtbase/mkspecs/common/android-base-head.conf -+++ new/qtbase/mkspecs/common/android-base-head.conf -@@ -72,6 +72,6 @@ CROSS_COMPILE = $$NDK_TOOLCHAIN_PATH/bin/$$NDK_TOOLS_PREFIX- - QMAKE_PCH_OUTPUT_EXT = .gch - - QMAKE_CFLAGS_PRECOMPILE = -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} --QMAKE_CFLAGS_USE_PRECOMPILE = -include ${QMAKE_PCH_OUTPUT_BASE} -+QMAKE_CFLAGS_USE_PRECOMPILE = -include-pch ${QMAKE_PCH_OUTPUT} - QMAKE_CXXFLAGS_PRECOMPILE = -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} - QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE diff --git a/depends/patches/qt/fix_lib_paths.patch b/depends/patches/qt/fix_lib_paths.patch deleted file mode 100644 index d1a15373f4..0000000000 --- a/depends/patches/qt/fix_lib_paths.patch +++ /dev/null @@ -1,193 +0,0 @@ ---- old/qtbase/mkspecs/common/mac.conf -+++ new/qtbase/mkspecs/common/mac.conf -@@ -14,7 +14,6 @@ - - QMAKE_RESOURCE = /Developer/Tools/Rez - QMAKE_EXTENSION_SHLIB = dylib --QMAKE_EXTENSIONS_AUX_SHLIB = tbd - QMAKE_LIBDIR = - - # sdk.prf will prefix the proper SDK sysroot - ---- old/qtbase/mkspecs/features/qmake_use.prf -+++ new/qtbase/mkspecs/features/qmake_use.prf -@@ -22,6 +22,8 @@ - !defined(QMAKE_LIBS_$$nu, var): \ - error("Library '$$lower($$replace(nu, _, -))' is not defined.") - -+ QMAKE_LIBDIR += $$eval(QMAKE_LIBDIR_$$nu) -+ - debug: \ - LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu) - else: \ - ---- old/qtbase/mkspecs/features/qt_configure.prf -+++ new/qtbase/mkspecs/features/qt_configure.prf -@@ -526,98 +526,23 @@ - return($$sysrootified) - } - --# libs-var, libs, in-paths, out-paths-var -+# libs-var, libs, in-paths - defineTest(qtConfResolveLibs) { -- ret = true -- paths = $$3 -- out = -- copy = false -- for (l, 2) { -- $$copy { -- copy = false -- out += $$l -- } else: equals(l, "-s") { -- # em++ flag to link libraries from emscripten-ports; passed on literally. -- copy = true -- out += $$l -- } else: contains(l, "^-L.*") { -- lp = $$replace(l, "^-L", ) -- gcc: lp = $$qtGccSysrootifiedPath($$lp) -- !exists($$lp/.) { -- qtLog("Library path $$val_escape(lp) is invalid.") -- ret = false -- } else { -- paths += $$lp -- } -- } else: contains(l, "^-l.*") { -- lib = $$replace(l, "^-l", ) -- lcan = -- integrity:contains(lib, "^.*\\.a") { -- # INTEGRITY compiler searches for exact filename -- # if -l argument has .a suffix -- lcan += $${lib} -- } else: contains(lib, "^:.*") { -- # Use exact filename when -l:filename syntax is used. -- lib ~= s/^:// -- lcan += $${lib} -- } else: unix { -- # Under UNIX, we look for actual shared libraries, in addition -- # to static ones. -- shexts = $$QMAKE_EXTENSION_SHLIB $$QMAKE_EXTENSIONS_AUX_SHLIB -- for (ext, shexts) { -- lcan += $${QMAKE_PREFIX_SHLIB}$${lib}.$${ext} -- } -- lcan += \ -- $${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB} -- } else { -- # Under Windows, we look only for static libraries, as even for DLLs -- # one actually links against a static import library. -- mingw { -- lcan += \ -- # MinGW supports UNIX-style library naming in addition to -- # the MSVC style. -- lib$${lib}.dll.a lib$${lib}.a \ -- # Fun fact: prefix-less libraries are also supported. -- $${lib}.dll.a $${lib}.a -- } -- lcan += $${lib}.lib -- } -- l = $$qtConfFindInPathList($$lcan, $$paths $$EXTRA_LIBDIR $$QMAKE_DEFAULT_LIBDIRS) -- isEmpty(l) { -- qtLog("None of [$$val_escape(lcan)] found in [$$val_escape(paths)] and global paths.") -- ret = false -- } else { -- out += $$l -- } -- } else { -- out += $$l -- } -- } -- $$1 = $$out -+ for (path, 3): \ -+ pre_lflags += -L$$path -+ $$1 = $$pre_lflags $$2 - export($$1) -- !isEmpty(4) { -- $$4 = $$paths -- export($$4) -- } -- return($$ret) --} -- --# source-var --defineTest(qtConfResolveAllLibs) { -- ret = true -- !qtConfResolveLibs($${1}.libs, $$eval($${1}.libs), , $${1}.libdirs): \ -- ret = false -- for (b, $${1}.builds._KEYS_): \ -- !qtConfResolveLibs($${1}.builds.$${b}, $$eval($${1}.builds.$${b}), $$eval($${1}.libdirs), ): \ -- ret = false -- return($$ret) -+ return(true) - } - - # libs-var, in-paths, libs - defineTest(qtConfResolvePathLibs) { - ret = true -- gcc: 2 = $$qtGccSysrootifiedPaths($$2) -- for (libdir, 2) { -+ gcc: \ -+ local_paths = $$qtGccSysrootifiedPaths($$2) -+ else: \ -+ local_paths = $$2 -+ for (libdir, local_paths) { - !exists($$libdir/.) { - qtLog("Library path $$val_escape(libdir) is invalid.") - ret = false -@@ -667,8 +592,11 @@ - # includes-var, in-paths, test-object-var - defineTest(qtConfResolvePathIncs) { - ret = true -- gcc: 2 = $$qtGccSysrootifiedPaths($$2) -- for (incdir, 2) { -+ gcc: \ -+ local_paths = $$qtGccSysrootifiedPaths($$2) -+ else: \ -+ local_paths = $$2 -+ for (incdir, local_paths) { - !exists($$incdir/.) { - qtLog("Include path $$val_escape(incdir) is invalid.") - ret = false -@@ -727,6 +655,7 @@ - vars += $$eval(config.commandline.rev_assignments.$${iv}) - defined(config.input.$${iv}, var) { - eval($${1}.builds.$${b} = $$eval(config.input.$${iv})) -+ export($${1}.builds.$${b}) - $${1}.builds._KEYS_ *= $${b} - any = true - } else { -@@ -741,11 +670,14 @@ - export($${1}.builds._KEYS_) - # we also reset the generic libs, to avoid surprises. - $${1}.libs = -+ export($${1}.libs) - } - - # direct libs. overwrites inline libs. -- defined(config.input.$${input}.libs, var): \ -+ defined(config.input.$${input}.libs, var) { - eval($${1}.libs = $$eval(config.input.$${input}.libs)) -+ export($${1}.libs) -+ } - - includes = $$eval(config.input.$${input}.incdir) - -@@ -754,6 +686,7 @@ - !isEmpty(prefix) { - includes += $$prefix/include - $${1}.libs = -L$$prefix/lib $$eval($${1}.libs) -+ export($${1}.libs) - } - - libdir = $$eval(config.input.$${input}.libdir) -@@ -762,11 +695,9 @@ - for (ld, libdir): \ - libs += -L$$ld - $${1}.libs = $$libs $$eval($${1}.libs) -+ export($${1}.libs) - } - -- !qtConfResolveAllLibs($$1): \ -- return(false) -- - !qtConfResolvePathIncs($${1}.includedir, $$includes, $$2): \ - return(false) - diff --git a/depends/patches/qt/fix_limits_header.patch b/depends/patches/qt/fix_limits_header.patch deleted file mode 100644 index e4313770e5..0000000000 --- a/depends/patches/qt/fix_limits_header.patch +++ /dev/null @@ -1,44 +0,0 @@ -Fix compiling with GCC 11 - -See: https://bugreports.qt.io/browse/QTBUG-90395. - -Upstream commits: - - Qt 5.15 -- unavailable as open source - - Qt 6.0: b2af6332ea37e45ab230a7a5d2d278f86d961b83 - - Qt 6.1: 9c56d4da2ff631a8c1c30475bd792f6c86bda53c - ---- old/qtbase/src/corelib/global/qendian.h -+++ new/qtbase/src/corelib/global/qendian.h -@@ -44,6 +44,8 @@ - #include - #include - -+#include -+ - // include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems - #include - #include - ---- old/qtbase/src/corelib/tools/qbytearraymatcher.h -+++ new/qtbase/src/corelib/tools/qbytearraymatcher.h -@@ -42,6 +42,8 @@ - - #include - -+#include -+ - QT_BEGIN_NAMESPACE - - - ---- old/qtbase/src/tools/moc/generator.cpp -+++ new/qtbase/src/tools/moc/generator.cpp -@@ -40,6 +40,8 @@ - #include - #include - -+#include -+ - #include - #include - diff --git a/depends/patches/qt/fix_montery_include.patch b/depends/patches/qt/fix_montery_include.patch deleted file mode 100644 index 38b700addf..0000000000 --- a/depends/patches/qt/fix_montery_include.patch +++ /dev/null @@ -1,21 +0,0 @@ -From dece6f5840463ae2ddf927d65eb1b3680e34a547 -From: Øystein Heskestad -Date: Wed, 27 Oct 2021 13:07:46 +0200 -Subject: [PATCH] Add missing macOS header file that was indirectly included before - -See: https://bugreports.qt.io/browse/QTBUG-97855 - -Upstream Commits: - - Qt 6.2: c884bf138a21dd7320e35cef34d24e22e74d7ce0 - -diff --git a/qtbase/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h b/qtbase/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h -index e070ba97..07c75b04 100644 ---- a/qtbase/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h -+++ b/qtbase/src/plugins/platforms/cocoa/qiosurfacegraphicsbuffer.h -@@ -40,6 +40,7 @@ - #ifndef QIOSURFACEGRAPHICSBUFFER_H - #define QIOSURFACEGRAPHICSBUFFER_H - -+#include - #include - #include diff --git a/depends/patches/qt/fix_no_printer.patch b/depends/patches/qt/fix_no_printer.patch deleted file mode 100644 index 1372356138..0000000000 --- a/depends/patches/qt/fix_no_printer.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h -+++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h -@@ -52,6 +52,7 @@ - // - - #include -+#include - - #ifndef QT_NO_PRINTER - ---- x/qtbase/src/plugins/plugins.pro -+++ y/qtbase/src/plugins/plugins.pro -@@ -9,6 +9,3 @@ qtHaveModule(gui) { - !android:qtConfig(library): SUBDIRS *= generic - } - qtHaveModule(widgets): SUBDIRS += styles -- --!winrt:qtHaveModule(printsupport): \ -- SUBDIRS += printsupport diff --git a/depends/patches/qt/fix_qt_pkgconfig.patch b/depends/patches/qt/fix_qt_pkgconfig.patch index a5de2b4b9e..73f4d89f73 100644 --- a/depends/patches/qt/fix_qt_pkgconfig.patch +++ b/depends/patches/qt/fix_qt_pkgconfig.patch @@ -4,20 +4,8 @@ load(qt_targets) # this builds on top of qt_common --!internal_module:if(unix|mingw) { +-!internal_module:if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) { +if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) { CONFIG += create_pc QMAKE_PKGCONFIG_DESTDIR = pkgconfig host_build: \ -@@ -284,9 +284,9 @@ load(qt_targets) - QMAKE_PKGCONFIG_CFLAGS = -D$$MODULE_DEFINE -I${includedir}/$$MODULE_INCNAME - } - QMAKE_PKGCONFIG_NAME = $$replace(TARGET, ^Qt, "Qt$$QT_MAJOR_VERSION ") -- QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION) -+ QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION)$$qtPlatformTargetSuffix() - for(i, MODULE_DEPENDS): \ -- QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0)) -+ QMAKE_PKGCONFIG_REQUIRES += $$replace(QT.$${i}.name, ^Qt, Qt$$section(QT.$${i}.VERSION, ., 0, 0))$$qtPlatformTargetSuffix() - isEmpty(QMAKE_PKGCONFIG_DESCRIPTION): \ - QMAKE_PKGCONFIG_DESCRIPTION = $$replace(TARGET, ^Qt, "Qt ") module - !isEmpty(lib_replace0.match) { diff --git a/depends/patches/qt/guix_cross_lib_path.patch b/depends/patches/qt/guix_cross_lib_path.patch new file mode 100644 index 0000000000..7911dc21d7 --- /dev/null +++ b/depends/patches/qt/guix_cross_lib_path.patch @@ -0,0 +1,17 @@ +Facilitate guix building with CROSS_LIBRARY_PATH + +See discussion in https://github.com/bitcoin/bitcoin/pull/15277. + +--- a/qtbase/mkspecs/features/toolchain.prf ++++ b/qtbase/mkspecs/features/toolchain.prf +@@ -236,8 +236,8 @@ isEmpty($${target_prefix}.INCDIRS) { + add_libraries = false + for (line, output) { + line ~= s/^[ \\t]*// # remove leading spaces +- contains(line, "LIBRARY_PATH=.*") { +- line ~= s/^LIBRARY_PATH=// # remove leading LIBRARY_PATH= ++ contains(line, "(CROSS_)?LIBRARY_PATH=.*") { ++ line ~= s/^(CROSS_)?LIBRARY_PATH=// # remove leading (CROSS_)?LIBRARY_PATH= + equals(QMAKE_HOST.os, Windows): \ + paths = $$split(line, ;) + else: \ diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt/mac-qmake.conf index e4bfaa1463..cb94bf07b4 100644 --- a/depends/patches/qt/mac-qmake.conf +++ b/depends/patches/qt/mac-qmake.conf @@ -15,10 +15,8 @@ QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION} QMAKE_MAC_SDK.macosx.PlatformPath = /phony !host_build: QMAKE_CFLAGS += -target $${MAC_TARGET} !host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS -!host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS +!host_build: QMAKE_CXXFLAGS += -target $${MAC_TARGET} !host_build: QMAKE_LFLAGS += -target $${MAC_TARGET} QMAKE_AR = $${CROSS_COMPILE}ar cq QMAKE_RANLIB=$${CROSS_COMPILE}ranlib -QMAKE_LIBTOOL=$${CROSS_COMPILE}libtool -QMAKE_INSTALL_NAME_TOOL=$${CROSS_COMPILE}install_name_tool load(qt_config) diff --git a/depends/patches/qt/memory_resource.patch b/depends/patches/qt/memory_resource.patch new file mode 100644 index 0000000000..650c328528 --- /dev/null +++ b/depends/patches/qt/memory_resource.patch @@ -0,0 +1,49 @@ +Fix unusable memory_resource on macos + +See https://bugreports.qt.io/browse/QTBUG-117484 +and https://bugreports.qt.io/browse/QTBUG-114316 + +--- a/qtbase/src/corelib/tools/qduplicatetracker_p.h ++++ b/qtbase/src/corelib/tools/qduplicatetracker_p.h +@@ -52,7 +52,7 @@ + + #include + +-#if QT_HAS_INCLUDE() && __cplusplus > 201402L ++#ifdef __cpp_lib_memory_resource + # include + # include + #else + +--- a/qtbase/src/corelib/global/qcompilerdetection.h ++++ b/qtbase/src/corelib/global/qcompilerdetection.h +@@ -1050,16 +1050,22 @@ + # endif // !_HAS_CONSTEXPR + # endif // !__GLIBCXX__ && !_LIBCPP_VERSION + # endif // Q_OS_QNX +-# if (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) && defined(__GNUC_LIBSTD__) \ +- && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) ++# if (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) ++# if defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) + // Apple has not updated libstdc++ since 2007, which means it does not have + // or std::move. Let's disable these features +-# undef Q_COMPILER_INITIALIZER_LISTS +-# undef Q_COMPILER_RVALUE_REFS +-# undef Q_COMPILER_REF_QUALIFIERS ++# undef Q_COMPILER_INITIALIZER_LISTS ++# undef Q_COMPILER_RVALUE_REFS ++# undef Q_COMPILER_REF_QUALIFIERS + // Also disable , since it's clearly not there +-# undef Q_COMPILER_ATOMICS +-# endif ++# undef Q_COMPILER_ATOMICS ++# endif ++# if defined(__cpp_lib_memory_resource) \ ++ && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000) \ ++ || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 170000)) ++# undef __cpp_lib_memory_resource // Only supported on macOS 14 and iOS 17 ++# endif ++# endif // (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) + # if defined(Q_CC_CLANG) && defined(Q_CC_INTEL) && Q_CC_INTEL >= 1500 + // ICC 15.x and 16.0 have their own implementation of std::atomic, which is activated when in Clang mode + // (probably because libc++'s on OS X failed to compile), but they're missing some diff --git a/depends/patches/qt/no-xlib.patch b/depends/patches/qt/no-xlib.patch index f4a6f09ee4..0f7965d2ea 100644 --- a/depends/patches/qt/no-xlib.patch +++ b/depends/patches/qt/no-xlib.patch @@ -4,12 +4,7 @@ Date: Thu, 18 Jul 2019 17:22:05 -0400 Subject: [PATCH] Wrap xlib related code blocks in #if's They are not necessary to compile QT. ---- - qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp | 8 ++++++++ - 1 file changed, 8 insertions(+) -diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp -index 7c62c2e2b3..c05c6c0a07 100644 --- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -49,7 +49,9 @@ @@ -38,7 +33,7 @@ index 7c62c2e2b3..c05c6c0a07 100644 xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) { -@@ -556,7 +560,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape) +@@ -558,7 +562,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape) xcb_cursor_t QXcbCursor::createFontCursor(int cshape) { xcb_connection_t *conn = xcb_connection(); @@ -47,17 +42,16 @@ index 7c62c2e2b3..c05c6c0a07 100644 +#endif xcb_cursor_t cursor = XCB_NONE; - // Try Xcursor first -@@ -585,7 +591,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) - + #if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) +@@ -590,6 +596,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) // Non-standard X11 cursors are created from bitmaps cursor = createNonStandardCursor(cshape); -- + +#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library) // Create a glpyh cursor if everything else failed if (!cursor && cursorId) { cursor = xcb_generate_id(conn); -@@ -593,6 +599,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) +@@ -597,6 +604,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) cursorId, cursorId + 1, 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); } @@ -65,6 +59,3 @@ index 7c62c2e2b3..c05c6c0a07 100644 if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) { const char *name = cursorNames[cshape].front(); --- -2.22.0 - diff --git a/depends/patches/qt/no_sdk_version_check.patch b/depends/patches/qt/no_sdk_version_check.patch deleted file mode 100644 index b16635b572..0000000000 --- a/depends/patches/qt/no_sdk_version_check.patch +++ /dev/null @@ -1,20 +0,0 @@ -commit f5eb142cd04be2bc4ca610ed3b5b7e8ce3520ee3 -Author: fanquake -Date: Tue Jan 5 16:08:49 2021 +0800 - - Don't invoke macOS SDK version checking - - This tries to use xcrun which is not available when cross-compiling. - -diff --git a/qtbase/mkspecs/features/mac/default_post.prf b/qtbase/mkspecs/features/mac/default_post.prf -index 92a9112bca6..447e186eb26 100644 ---- a/qtbase/mkspecs/features/mac/default_post.prf -+++ b/qtbase/mkspecs/features/mac/default_post.prf -@@ -8,7 +8,6 @@ contains(TEMPLATE, .*app) { - !macx-xcode:if(isEmpty(BUILDS)|build_pass) { - # Detect changes to the platform SDK - QMAKE_EXTRA_VARIABLES += QMAKE_MAC_SDK QMAKE_MAC_SDK_VERSION QMAKE_XCODE_DEVELOPER_PATH -- QMAKE_EXTRA_INCLUDES += $$shell_quote($$PWD/sdk.mk) - } - - # Detect incompatible SDK versions diff --git a/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch b/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch index 0358bea6e9..f0c14a9400 100644 --- a/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch +++ b/depends/patches/qt/qtbase-moc-ignore-gcc-macro.patch @@ -7,7 +7,7 @@ Upstream report: https://bugreports.qt.io/browse/QTBUG-83160 diff --git a/qtbase/src/tools/moc/main.cpp b/qtbase/src/tools/moc/main.cpp --- a/qtbase/src/tools/moc/main.cpp +++ b/qtbase/src/tools/moc/main.cpp -@@ -188,6 +188,7 @@ int runMoc(int argc, char **argv) +@@ -238,6 +238,7 @@ int runMoc(int argc, char **argv) dummyVariadicFunctionMacro.arguments += Symbol(0, PP_IDENTIFIER, "__VA_ARGS__"); pp.macros["__attribute__"] = dummyVariadicFunctionMacro; pp.macros["__declspec"] = dummyVariadicFunctionMacro; diff --git a/depends/patches/qt/rcc_hardcode_timestamp.patch b/depends/patches/qt/rcc_hardcode_timestamp.patch new file mode 100644 index 0000000000..03f3897975 --- /dev/null +++ b/depends/patches/qt/rcc_hardcode_timestamp.patch @@ -0,0 +1,24 @@ +Hardcode last modified timestamp in Qt RCC + +This change allows the already built qt package to be reused even with +the SOURCE_DATE_EPOCH variable set, e.g., for Guix builds. + + +--- old/qtbase/src/tools/rcc/rcc.cpp ++++ new/qtbase/src/tools/rcc/rcc.cpp +@@ -227,14 +227,7 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) + + if (lib.formatVersion() >= 2) { + // last modified time stamp +- const QDateTime lastModified = m_fileInfo.lastModified(); +- quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0); +- static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong(); +- if (sourceDate != 0) +- lastmod = sourceDate; +- static const quint64 sourceDate2 = 1000 * qgetenv("SOURCE_DATE_EPOCH").toULongLong(); +- if (sourceDate2 != 0) +- lastmod = sourceDate2; ++ quint64 lastmod = quint64(1); + lib.writeNumber8(lastmod); + if (text || pass1) + lib.writeChar('\n'); diff --git a/depends/patches/qt/support_new_android_ndks.patch b/depends/patches/qt/support_new_android_ndks.patch deleted file mode 100644 index 85c8ae2132..0000000000 --- a/depends/patches/qt/support_new_android_ndks.patch +++ /dev/null @@ -1,122 +0,0 @@ -Follow Google's BuildSystemMaintainers doc to support future NDK releases. - -Upstream commit: - - Qt 5.14: 9b14950ff600a4ce5a8698b67ab38907c50417f1 - ---- old/qtbase/mkspecs/android-clang/qmake.conf -+++ new/qtbase/mkspecs/android-clang/qmake.conf -@@ -14,43 +14,29 @@ - QMAKE_CC = $$NDK_LLVM_PATH/bin/clang - QMAKE_CXX = $$NDK_LLVM_PATH/bin/clang++ - -+# Follow https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md -+ - equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ -- QMAKE_CFLAGS += -target armv7-none-linux-androideabi --else: equals(ANDROID_TARGET_ARCH, armeabi): \ -- QMAKE_CFLAGS += -target armv5te-none-linux-androideabi -+ QMAKE_CFLAGS = -target armv7a-linux-androideabi$$replace(ANDROID_PLATFORM, "android-", "") - else: equals(ANDROID_TARGET_ARCH, arm64-v8a): \ -- QMAKE_CFLAGS += -target aarch64-none-linux-android -+ QMAKE_CFLAGS = -target aarch64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") - else: equals(ANDROID_TARGET_ARCH, x86): \ -- QMAKE_CFLAGS += -target i686-none-linux-android -mstackrealign -+ QMAKE_CFLAGS = -target i686-linux-android$$replace(ANDROID_PLATFORM, "android-", "") -mstackrealign - else: equals(ANDROID_TARGET_ARCH, x86_64): \ -- QMAKE_CFLAGS += -target x86_64-none-linux-android --else: equals(ANDROID_TARGET_ARCH, mips): \ -- QMAKE_CFLAGS += -target mipsel-none-linux-android --else: equals(ANDROID_TARGET_ARCH, mips64): \ -- QMAKE_CFLAGS += -target mips64el-none-linux-android -- --QMAKE_CFLAGS += -gcc-toolchain $$NDK_TOOLCHAIN_PATH -fno-limit-debug-info -- --QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --equals(ANDROID_TARGET_ARCH, armeabi-v7a): QMAKE_LINK += -Wl,--exclude-libs,libunwind.a -- --QMAKE_CFLAGS += -DANDROID_HAS_WSTRING --sysroot=$$NDK_ROOT/sysroot \ -- -isystem $$NDK_ROOT/sysroot/usr/include/$$NDK_TOOLS_PREFIX \ -- -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++/include \ -- -isystem $$NDK_ROOT/sources/android/support/include \ -- -isystem $$NDK_ROOT/sources/cxx-stl/llvm-libc++abi/include -+ QMAKE_CFLAGS = -target x86_64-linux-android$$replace(ANDROID_PLATFORM, "android-", "") - --ANDROID_SOURCES_CXX_STL_LIBDIR = $$NDK_ROOT/sources/cxx-stl/llvm-libc++/libs/$$ANDROID_TARGET_ARCH -+QMAKE_CFLAGS += -fno-limit-debug-info - --ANDROID_STDCPP_PATH = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++_shared.so -+QMAKE_LINK = $$QMAKE_CXX $$QMAKE_CFLAGS - --ANDROID_USE_LLVM = true -+ANDROID_STDCPP_PATH = $$NDK_LLVM_PATH/sysroot/usr/lib/$$NDK_TOOLS_PREFIX/libc++_shared.so - --exists($$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so): \ -- ANDROID_CXX_STL_LIBS = -lc++ --else: \ -- ANDROID_CXX_STL_LIBS = $$ANDROID_SOURCES_CXX_STL_LIBDIR/libc++.so.$$replace(ANDROID_PLATFORM, "android-", "") -+ANDROID_USE_LLVM = true - --QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz -+QMAKE_CFLAGS_OPTIMIZE_SIZE = -Oz -+QMAKE_LIBDIR_POST = -+QMAKE_LFLAGS = -+QMAKE_LIBS_PRIVATE = -+ANDROID_CXX_STL_LIBS = - - include(../common/android-base-tail.conf) - ---- old/qtbase/mkspecs/common/android-base-head.conf -+++ new/qtbase/mkspecs/common/android-base-head.conf -@@ -64,7 +58,6 @@ - } - - CONFIG += $$ANDROID_PLATFORM --QMAKE_CFLAGS = -D__ANDROID_API__=$$replace(ANDROID_PLATFORM, "android-", "") - - ANDROID_PLATFORM_ROOT_PATH = $$NDK_ROOT/platforms/$$ANDROID_PLATFORM/arch-$$ANDROID_ARCHITECTURE/ - ---- old/qtbase/mkspecs/common/android-base-tail.conf -+++ new/qtbase/mkspecs/common/android-base-tail.conf -@@ -6,22 +6,17 @@ - QMAKE_CFLAGS += -fstack-protector-strong -DANDROID - - equals(ANDROID_TARGET_ARCH, armeabi-v7a): \ -- QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-builtin-memmove -+ QMAKE_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp - else: equals(ANDROID_TARGET_ARCH, armeabi): \ -- QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float -fno-builtin-memmove --# -fno-builtin-memmove is used to workaround https://code.google.com/p/android/issues/detail?id=81692 -+ QMAKE_CFLAGS += -march=armv5te -mtune=xscale -msoft-float - - QMAKE_CFLAGS_WARN_ON = -Wall -W - QMAKE_CFLAGS_WARN_OFF = - equals(ANDROID_TARGET_ARCH, armeabi-v7a) | equals(ANDROID_TARGET_ARCH, armeabi) { - CONFIG += optimize_size - QMAKE_CFLAGS_DEBUG = -g -marm -O0 -- equals(ANDROID_TARGET_ARCH, armeabi):if(equals(NDK_TOOLCHAIN_VERSION, 4.8)|equals(NDK_TOOLCHAIN_VERSION, 4.9)) { -- DEFINES += QT_OS_ANDROID_GCC_48_WORKAROUND -- } else { -- QMAKE_CFLAGS_RELEASE += -mthumb -- QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb -- } -+ QMAKE_CFLAGS_RELEASE += -mthumb -+ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -mthumb - } - - QMAKE_CFLAGS_SHLIB = -fPIC -@@ -61,15 +56,12 @@ - QMAKE_RANLIB = $${CROSS_COMPILE}ranlib - - QMAKE_INCDIR_POST = --QMAKE_LIBDIR_POST = $$ANDROID_SOURCES_CXX_STL_LIBDIR - QMAKE_INCDIR_X11 = - QMAKE_LIBDIR_X11 = - QMAKE_INCDIR_OPENGL = - QMAKE_LIBDIR_OPENGL = - - QMAKE_LINK_SHLIB = $$QMAKE_LINK --QMAKE_LFLAGS = --sysroot=$$ANDROID_PLATFORM_ROOT_PATH --equals(ANDROID_TARGET_ARCH, x86_64) QMAKE_LFLAGS += -L$$ANDROID_PLATFORM_ROOT_PATH/usr/lib64 - QMAKE_LFLAGS_APP = -Wl,--no-undefined -Wl,-z,noexecstack -shared - QMAKE_LFLAGS_SHLIB = -Wl,--no-undefined -Wl,-z,noexecstack -shared - QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB diff --git a/depends/patches/qt/use_android_ndk23.patch b/depends/patches/qt/use_android_ndk23.patch new file mode 100644 index 0000000000..f22367d527 --- /dev/null +++ b/depends/patches/qt/use_android_ndk23.patch @@ -0,0 +1,13 @@ +Use Android NDK r23 LTS + +--- old/qtbase/mkspecs/features/android/default_pre.prf ++++ new/qtbase/mkspecs/features/android/default_pre.prf +@@ -76,7 +76,7 @@ else: equals(QT_ARCH, x86_64): CROSS_COMPILE = $$NDK_LLVM_PATH/bin/x86_64-linux- + else: equals(QT_ARCH, arm64-v8a): CROSS_COMPILE = $$NDK_LLVM_PATH/bin/aarch64-linux-android- + else: CROSS_COMPILE = $$NDK_LLVM_PATH/bin/arm-linux-androideabi- + +-QMAKE_RANLIB = $${CROSS_COMPILE}ranlib ++QMAKE_RANLIB = $$NDK_LLVM_PATH/bin/llvm-ranlib + QMAKE_LINK_SHLIB = $$QMAKE_LINK + QMAKE_LFLAGS = + diff --git a/depends/patches/qt/windows_lto.patch b/depends/patches/qt/windows_lto.patch new file mode 100644 index 0000000000..ea379a60f1 --- /dev/null +++ b/depends/patches/qt/windows_lto.patch @@ -0,0 +1,31 @@ +Qt (for Windows) fails to build under LTO, due to multiple definition issues, i.e + +multiple definition of `QAccessibleLineEdit::~QAccessibleLineEdit()'; + +Possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94156. + +diff --git a/qtbase/src/widgets/accessible/simplewidgets.cpp b/qtbase/src/widgets/accessible/simplewidgets.cpp +index 107fd729fe..0e61878f39 100644 +--- a/qtbase/src/widgets/accessible/simplewidgets.cpp ++++ b/qtbase/src/widgets/accessible/simplewidgets.cpp +@@ -109,6 +109,8 @@ QString qt_accHotKey(const QString &text); + \ingroup accessibility + */ + ++QAccessibleLineEdit::~QAccessibleLineEdit(){}; ++ + /*! + Creates a QAccessibleButton object for \a w. + */ +diff --git a/qtbase/src/widgets/accessible/simplewidgets_p.h b/qtbase/src/widgets/accessible/simplewidgets_p.h +index 73572e3059..658da86143 100644 +--- a/qtbase/src/widgets/accessible/simplewidgets_p.h ++++ b/qtbase/src/widgets/accessible/simplewidgets_p.h +@@ -155,6 +155,7 @@ class QAccessibleLineEdit : public QAccessibleWidget, public QAccessibleTextInte + public: + explicit QAccessibleLineEdit(QWidget *o, const QString &name = QString()); + ++ ~QAccessibleLineEdit(); + QString text(QAccessible::Text t) const override; + void setText(QAccessible::Text t, const QString &text) override; + QAccessible::State state() const override; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index bd08df359d..f8588235ce 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -319,7 +319,7 @@ void AddressBookPage::done(int retval) // Figure out which address was selected, and return it QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); - Q_FOREACH (const QModelIndex& index, indexes) { + for (const QModelIndex& index : indexes) { QVariant address = table->model()->data(index); returnValue = address.toString(); } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 5c6aab1d01..65f7ffd8e9 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -580,7 +581,7 @@ bool BitcoinApplication::migrateSettings(const QString &oldOrganizationName, con QSettings oldSettings(oldOrganizationName, oldApplicationName); QList keys = oldSettings.allKeys(); if (!keys.empty()) { - Q_FOREACH(const QString &key, keys) { + for (const QString &key : keys) { newSettings.setValue(key, oldSettings.value(key)); } newSettings.sync(); @@ -657,7 +658,7 @@ void BitcoinApplication::migrateToFiro() } else if (doNotShowAgain) { // create file to block migration in the future - boost::filesystem::ofstream(dontMigrateFilePath).flush(); + std::ofstream(dontMigrateFilePath.string()).flush(); } } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3b0cb09ab0..b1ac1c059c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1191,7 +1191,7 @@ void BitcoinGUI::dropEvent(QDropEvent *event) { if(event->mimeData()->hasUrls()) { - Q_FOREACH(const QUrl &uri, event->mimeData()->urls()) + for (const QUrl &uri : event->mimeData()->urls()) { Q_EMIT receivedURI(uri.toString()); } @@ -1439,7 +1439,7 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *pl QList units = BitcoinUnits::availableUnits(); int max_width = 0; const QFontMetrics fm(font()); - Q_FOREACH (const BitcoinUnits::Unit unit, units) + for (const BitcoinUnits::Unit unit : units) { max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit))); } @@ -1457,7 +1457,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) void UnitDisplayStatusBarControl::createContextMenu() { menu = new QMenu(this); - Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) + for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this); menuAction->setData(QVariant(u)); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 332774e688..2963acd958 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -426,7 +426,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog, bool a CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; - Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts) + for (const CAmount &amount : CoinControlDialog::payAmounts) { nPayAmount += amount; diff --git a/src/qt/lelantuscoincontroldialog.cpp b/src/qt/lelantuscoincontroldialog.cpp index 930268ca39..6837cf8f04 100644 --- a/src/qt/lelantuscoincontroldialog.cpp +++ b/src/qt/lelantuscoincontroldialog.cpp @@ -43,7 +43,7 @@ void CoinControlStorage::updateLabels(WalletModel *model, QDialog* dialog) CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; - Q_FOREACH(const CAmount &amount, payAmounts) + for (const CAmount &amount : payAmounts) { nPayAmount += amount; diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 6b94d1cc7a..6017558d4f 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -84,7 +84,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME))); ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); - Q_FOREACH(const QString &langStr, translations.entryList()) + for (const QString &langStr : translations.entryList()) { QLocale locale(langStr); diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 1e95277093..9bbd3e465b 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -117,7 +117,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) bool PaymentServer::ipcSendCommandLine() { bool fResult = false; - Q_FOREACH (const QString& r, savedPaymentRequests) + for (const QString& r : savedPaymentRequests) { QLocalSocket* socket = new QLocalSocket(); socket->connectToServer(ipcServerName(), QIODevice::WriteOnly); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 088be1a150..35fe0bc16a 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -62,7 +62,7 @@ class PeerTablePriv #if QT_VERSION >= 0x040700 cachedNodeStats.reserve(vstats.size()); #endif - Q_FOREACH (const CNodeStats& nodestats, vstats) + for (const CNodeStats& nodestats : vstats) { CNodeCombinedStats stats; stats.nodeStateStats.nMisbehavior = 0; @@ -91,7 +91,7 @@ class PeerTablePriv // build index map mapNodeRows.clear(); int row = 0; - Q_FOREACH (const CNodeCombinedStats& stats, cachedNodeStats) + for (const CNodeCombinedStats& stats : cachedNodeStats) mapNodeRows.insert(std::pair(stats.nodeStats.nodeid, row++)); } diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index dc8084b256..f098d9b3a6 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -62,8 +62,7 @@ void MakeLockColorImage(QImage& img, const QColor& colorbase) QIcon ColorizeIcon(const QIcon& ico, const QColor& colorbase) { QIcon new_ico; - QSize sz; - Q_FOREACH(sz, ico.availableSizes()) + for (QSize sz : ico.availableSizes()) { QImage img(ico.pixmap(sz).toImage()); MakeSingleColorImage(img, colorbase); diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 87a95bf84e..963a11f4dd 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -222,7 +222,7 @@ void ReceiveCoinsDialog::on_showRequestButton_clicked() return; QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows(); - Q_FOREACH (const QModelIndex& index, selection) { + for (const QModelIndex& index : selection) { on_recentRequestsView_doubleClicked(index); } } diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 1bfe3e3c27..baa5412e11 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -434,7 +434,7 @@ void SendCoinsDialog::on_sendButton_clicked() formatted.append(recipientElement); } } else { - Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients()) + for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients()) { // generate bold amount string QString amount = "" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount); @@ -499,7 +499,7 @@ void SendCoinsDialog::on_sendButton_clicked() } QStringList alternativeUnits; - Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) + for (BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) { if(u != model->getOptionsModel()->getDisplayUnit()) alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount)); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 8f0276f063..16a6ae820f 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -235,7 +235,7 @@ void SplashScreen::unsubscribeFromCoreSignals() uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); #ifdef ENABLE_WALLET - Q_FOREACH(CWallet* const & pwallet, connectedWallets) { + for (CWallet* const & pwallet : connectedWallets) { pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); } #endif diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 78e4fc4d99..796112d5f0 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -141,10 +141,10 @@ void TrafficGraphWidget::updateRates() } float tmax = 0.0f; - Q_FOREACH(float f, vSamplesIn) { + for (float f : vSamplesIn) { if(f > tmax) tmax = f; } - Q_FOREACH(float f, vSamplesOut) { + for (float f : vSamplesOut) { if(f > tmax) tmax = f; } fMax = tmax; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 899f438b2c..a13eb7e347 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -312,7 +312,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "" + tr("Output index") + ": " + QString::number(rec->getOutputIndex()) + "
"; // Message from normal firo:URI (firo:123...?message=example) - Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm) + for (const PAIRTYPE(std::string, std::string)& r : wtx.vOrderForm) if (r.first == "Message") strHTML += "
" + tr("Message") + ":
" + GUIUtil::HtmlEscape(r.second, true) + "
"; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 4ef5fe269f..d65f7577f7 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -146,7 +146,7 @@ class TransactionTablePriv { parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1); int insert_idx = lowerIndex; - Q_FOREACH(const TransactionRecord &rec, toInsert) + for (const TransactionRecord &rec : toInsert) { cachedWallet.insert(insert_idx, rec); insert_idx += 1; diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 0f468a65fe..27cdb40da8 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -102,7 +102,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : QTextCharFormat bold; bold.setFontWeight(QFont::Bold); - Q_FOREACH (const QString &line, coreOptions.split("\n")) { + for (const QString &line : coreOptions.split("\n")) { if (line.startsWith(" -")) { cursor.currentTable()->appendRows(1); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 6db696c214..5230375437 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -288,7 +288,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact int nAddresses = 0; // Pre-check input data for validity - Q_FOREACH(const SendCoinsRecipient &rcp, recipients) + for (const SendCoinsRecipient &rcp : recipients) { if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; @@ -379,7 +379,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareJoinSplitTransaction( int nAddresses = 0; // Pre-check input data for validity - Q_FOREACH(const SendCoinsRecipient &rcp, recipients) + for (const SendCoinsRecipient &rcp : recipients) { if (rcp.fSubtractFeeFromAmount) fSubtractFeeFromAmount = true; @@ -564,7 +564,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); - Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) + for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { if (!rcp.message.isEmpty()) // Message from normal firo:URI (firo:123...?message=example) newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); @@ -582,7 +582,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran // Add addresses / update labels that we've sent to to the address book, // and emit coinsSent signal for each recipient - Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) + for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { { std::string strAddress = rcp.address.toStdString(); @@ -619,7 +619,7 @@ WalletModel::SendCoinsReturn WalletModel::sendPrivateCoins(WalletModelTransactio LOCK2(cs_main, wallet->cs_wallet); CWalletTx *newTx = transaction.getTransaction(); - Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) + for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { if (!rcp.message.isEmpty()) // Message from normal firo:URI (firo:123...?message=example) newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); @@ -639,7 +639,7 @@ WalletModel::SendCoinsReturn WalletModel::sendPrivateCoins(WalletModelTransactio // Add addresses / update labels that we've sent to to the address book, // and emit coinsSent signal for each recipient - Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients()) + for (const SendCoinsRecipient &rcp : transaction.getRecipients()) { { std::string strAddress = rcp.address.toStdString(); diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 855e721f59..c9109b9a12 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -83,7 +83,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet) CAmount WalletModelTransaction::getTotalTransactionAmount() { CAmount totalTransactionAmount = 0; - Q_FOREACH(const SendCoinsRecipient &rcp, recipients) + for (const SendCoinsRecipient &rcp : recipients) { totalTransactionAmount += rcp.amount; } diff --git a/src/sync.cpp b/src/sync.cpp index 41785c0caa..a7450a013b 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -4,6 +4,16 @@ #include "sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "util.h" #include "utilstrencodings.h" From 6d2b76c19e613eead7f89737a9bba9d60824eb8b Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:08:49 +0400 Subject: [PATCH 05/17] Fix bug creating large spark spend tx (#1399) --- src/spark/sparkwallet.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/spark/sparkwallet.cpp b/src/spark/sparkwallet.cpp index 69502c8c18..822aafdaff 100644 --- a/src/spark/sparkwallet.cpp +++ b/src/spark/sparkwallet.cpp @@ -1525,9 +1525,6 @@ CWalletTx CSparkWallet::CreateSparkSpendTransaction( i++; } - // check fee - wtxNew.SetTx(MakeTransactionRef(std::move(tx))); - if (GetTransactionWeight(tx) >= MAX_NEW_TX_WEIGHT) { throw std::runtime_error(_("Transaction too large")); } @@ -1546,6 +1543,8 @@ CWalletTx CSparkWallet::CreateSparkSpendTransaction( throw std::invalid_argument(_("Not enough fee estimated")); } + wtxNew.SetTx(MakeTransactionRef(std::move(tx))); + result.push_back(wtxNew); } } From 91959a32393a7740b2616d3ff49608075dd016c1 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:09:11 +0400 Subject: [PATCH 06/17] Removed checks slowing down spark (#1400) --- src/libspark/grootle.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/libspark/grootle.cpp b/src/libspark/grootle.cpp index 7fd11135e2..26c8085641 100644 --- a/src/libspark/grootle.cpp +++ b/src/libspark/grootle.cpp @@ -413,16 +413,6 @@ bool Grootle::verify( return false; } - // Check for zero inputs - for (std::size_t t = 0; t < S1.size(); t++) { - for (std::size_t i = 0; i < S.size(); i++) { - if (S[i] == S1[t] || V[i] == V1[t]) { - LogPrintf("Invalid offset commitment"); - return false; - } - } - } - // Check proof semantics for (std::size_t t = 0; t < M; t++) { GrootleProof proof = proofs[t]; From c1c464db0e4f2aca97ad92d32ab34fe76bc01114 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:09:31 +0400 Subject: [PATCH 07/17] Non-HD wallets crash fix (#1401) --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cd599b771c..fababfae30 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1948,7 +1948,7 @@ bool CWallet::IsMine(const CTransaction& tx) const { if (tx.IsSparkTransaction()) { if (!sparkWallet) - false; + return false; std::vector serialContext = spark::getSerialContext(tx); for (const auto& txout : tx.vout) { if (txout.scriptPubKey.IsSparkMint() || txout.scriptPubKey.IsSparkSMint()) { From 295774821b274397b0acf1b0bfa613a8add11f74 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Thu, 25 Jan 2024 20:16:12 +0400 Subject: [PATCH 08/17] getsparkcoinaddr rpc added (#1397) * getsparkcoinaddr rpc added * Fix crashing ui bug * Bug fixed --- src/qt/walletmodel.cpp | 9 ++++---- src/wallet/rpcwallet.cpp | 45 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 5230375437..e6908f973d 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1547,18 +1547,19 @@ WalletModel::SendCoinsReturn WalletModel::mintSparkCoins(std::vectorCommitTransaction(wtxAndFee[i].first, *reservekey++, g_connman.get(), state)) + return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason())); + Q_FOREACH(const SendCoinsRecipient &rcp, transactions[i].getRecipients()) { // CWalletTx* newTx = transactions[i].getTransaction(); if (!rcp.message.isEmpty()) // Message from normal firo:URI (firo:123...?message=example) wtxAndFee[i].first.vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); - if (!wallet->CommitTransaction(wtxAndFee[i].first, *reservekey++, g_connman.get(), state)) - return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(state.GetRejectReason())); - + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << *wtxAndFee[i].first.tx; transaction_array.append(&(ssTx[0]), ssTx.size()); - + { std::string strAddress = rcp.address.toStdString(); std::string strLabel = rcp.label.toStdString(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 45d90dc4b5..3357bbac11 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3937,7 +3937,7 @@ UniValue identifysparkcoins(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "identifysparkcoin \"txHash\"\n" + "identifysparkcoins \"txHash\"\n" "Identifies coins in transaction, and adds into wallet if yours"); EnsureSparkWalletIsAvailable(); @@ -3968,6 +3968,48 @@ UniValue identifysparkcoins(const JSONRPCRequest& request) return results; } +UniValue getsparkcoinaddr(const JSONRPCRequest& request) +{ + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() != 1) + throw std::runtime_error( + "getsparkcoinaddr \"txHash\"\n" + "Returns all spark outputs to you, address memo and amount for each"); + + EnsureSparkWalletIsAvailable(); + + uint256 txHash; + txHash.SetHex(request.params[0].get_str()); + + CTransactionRef tx; + uint256 hashBlock; + GetTransaction(txHash, tx, Params().GetConsensus(), hashBlock); + + UniValue results(UniValue::VARR);; + assert(pwallet != NULL); + + std::unordered_map coins = pwallet->sparkWallet->getMintMap(); + unsigned char network = spark::GetNetworkType(); + + for (const auto& coin : coins) + { + if (txHash == coin.second.txid) { + spark::Address address = pwallet->sparkWallet->getAddress(coin.second.i); + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("address", address.encode(network))); + entry.push_back(Pair("memo", SanitizeString(coin.second.memo))); + entry.push_back(Pair("amount", ValueFromAmount(coin.second.v))); + results.push_back(entry); + } + } + + return results; +} + UniValue mint(const JSONRPCRequest& request) { CWallet * const pwallet = GetWalletForJSONRPCRequest(request); @@ -5720,6 +5762,7 @@ static const CRPCCommand commands[] = { "wallet", "spendspark", &spendspark, false }, { "wallet", "lelantustospark", &lelantustospark, false }, { "wallet", "identifysparkcoins", &identifysparkcoins, false }, + { "wallet", "getsparkcoinaddr", &getsparkcoinaddr, false }, //bip47 From 28dbfb395750d1532e59a2b01017af2289802a78 Mon Sep 17 00:00:00 2001 From: psolstice Date: Thu, 25 Jan 2024 17:16:47 +0100 Subject: [PATCH 09/17] Spork for managing Spark functionality (#1398) * Introduce sporks "spark" and "sparktransparentlimit" * Added spark and sparktransparentlimit to allowed spork features * Added test for spark spork * Fixes for spark limit block template creation * Fixed test instability * Additional cleanup in tests --- src/evo/spork.cpp | 32 ++++- src/evo/spork.h | 2 + src/miner.cpp | 63 +++++---- src/miner.h | 5 + src/rpc/rpcevo.cpp | 4 +- src/test/evospork_tests.cpp | 251 ++++++++++++++++++++++++++++++++++++ src/test/test_bitcoin.cpp | 8 +- 7 files changed, 335 insertions(+), 30 deletions(-) diff --git a/src/evo/spork.cpp b/src/evo/spork.cpp index 16ebde591f..9a0ccfb400 100644 --- a/src/evo/spork.cpp +++ b/src/evo/spork.cpp @@ -65,6 +65,18 @@ static bool IsTransactionAllowed(const CTransaction &tx, const ActiveSporkMap &s } } } + else if (tx.IsSparkTransaction()) { + if (sporkMap.count(CSporkAction::featureSpark) > 0) + return state.DoS(100, false, REJECT_CONFLICT, "txn-spark-disabled", false, "Spark transactions are disabled at the moment"); + + if (tx.IsSparkSpend()) { + const auto &limitSpork = sporkMap.find(CSporkAction::featureSparkTransparentLimit); + if (limitSpork != sporkMap.cend()) { + if (spark::GetSpendTransparentAmount(tx) > (CAmount)limitSpork->second.second) + return state.DoS(100, false, REJECT_CONFLICT, "txn-spark-disabled", false, "Spark transaction is over the transparent limit"); + } + } + } return true; } @@ -176,8 +188,24 @@ bool CSporkManager::IsBlockAllowed(const CBlock &block, const CBlockIndex *pinde totalTransparentOutput += lelantus::GetSpendTransparentAmount(*tx); } - return totalTransparentOutput <= CAmount(limit) ? true : - state.DoS(100, false, REJECT_CONFLICT, "txn-lelantus-disabled", false, "Block is over the transparent output limit because of existing spork"); + if (totalTransparentOutput > CAmount(limit)) + return state.DoS(100, false, REJECT_CONFLICT, "txn-lelantus-disabled", false, "Block is over the transparent output limit because of existing spork"); + } + + if (pindex->activeDisablingSporks.count(CSporkAction::featureSparkTransparentLimit) > 0) { + // limit total transparent output of lelantus joinsplit + int64_t limit = pindex->activeDisablingSporks.at(CSporkAction::featureSparkTransparentLimit).second; + CAmount totalTransparentOutput = 0; + + for (const auto &tx: block.vtx) { + if (!tx->IsSparkSpend()) + continue; + + totalTransparentOutput += spark::GetSpendTransparentAmount(*tx); + } + + if (totalTransparentOutput > CAmount(limit)) + return state.DoS(100, false, REJECT_CONFLICT, "txn-spark-disabled", false, "Block is over the transparent output limit because of existing spork"); } return true; diff --git a/src/evo/spork.h b/src/evo/spork.h index 4087513813..4b4d67fc67 100644 --- a/src/evo/spork.h +++ b/src/evo/spork.h @@ -17,6 +17,8 @@ struct CSporkAction static constexpr const char *featureLelantusTransparentLimit = "lelantustransparentlimit"; static constexpr const char *featureChainlocks = "chainlocks"; static constexpr const char *featureInstantSend = "instantsend"; + static constexpr const char *featureSpark = "spark"; + static constexpr const char *featureSparkTransparentLimit = "sparktransparentlimit"; enum ActionType { sporkDisable = 1, diff --git a/src/miner.cpp b/src/miner.cpp index fee39aaff0..492cb3477b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1003,34 +1003,49 @@ void BlockAssembler::FillBlackListForBlockTemplate() { // Now if we have limit on lelantus transparent outputs scan mempool and drop all the transactions exceeding the limit if (sporkMap.count(CSporkAction::featureLelantusTransparentLimit) > 0) { - CAmount limit = sporkMap[CSporkAction::featureLelantusTransparentLimit].second; + BlacklistTxsExceedingLimit(sporkMap[CSporkAction::featureLelantusTransparentLimit].second, + [](const CTransaction &tx)->bool { return tx.IsLelantusJoinSplit(); }, + [](const CTransaction &tx)->CAmount { return lelantus::GetSpendTransparentAmount(tx); }); + } - std::vector joinSplitTxs; - for (CTxMemPool::txiter mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { - if (txBlackList.count(mi) == 0 && mi->GetTx().IsLelantusJoinSplit()) - joinSplitTxs.push_back(mi); - } + // Same for spark spends + if (sporkMap.count(CSporkAction::featureSparkTransparentLimit) > 0) { + BlacklistTxsExceedingLimit(sporkMap[CSporkAction::featureSparkTransparentLimit].second, + [](const CTransaction &tx)->bool { return tx.IsSparkSpend(); }, + [](const CTransaction &tx)->CAmount { return spark::GetSpendTransparentAmount(tx); }); + } +} - // sort join splits in order of their transparent outputs so large txs won't block smaller ones - // from getting into the mempool - std::sort(joinSplitTxs.begin(), joinSplitTxs.end(), - [](CTxMemPool::txiter a, CTxMemPool::txiter b) -> bool { - return lelantus::GetSpendTransparentAmount(a->GetTx()) < lelantus::GetSpendTransparentAmount(b->GetTx()); - }); - - CAmount transparentAmount = 0; - std::vector::const_iterator it; - for (it = joinSplitTxs.cbegin(); it != joinSplitTxs.cend(); ++it) { - CAmount output = lelantus::GetSpendTransparentAmount((*it)->GetTx()); - if (transparentAmount + output > limit) - break; - transparentAmount += output; - } +void BlockAssembler::BlacklistTxsExceedingLimit(CAmount limit, + std::function txTypeFilter, + std::function txAmount) { + + std::vector txList; + for (CTxMemPool::txiter mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { + if (txBlackList.count(mi) == 0 && txTypeFilter(mi->GetTx())) + txList.push_back(mi); + } - // found all the joinsplit transaction fitting in the limit, blacklist the rest - while (it != joinSplitTxs.cend()) - mempool.CalculateDescendants(*it++, txBlackList); + // sort transactions in order of their transparent outputs so large txs won't block smaller ones + // from getting into the mempool + std::sort(txList.begin(), txList.end(), + [=](CTxMemPool::txiter a, CTxMemPool::txiter b) -> bool { + return txAmount(a->GetTx()) < txAmount(b->GetTx()); + }); + + CAmount transparentAmount = 0; + std::vector::const_iterator it; + for (it = txList.cbegin(); it != txList.cend(); ++it) { + CAmount output = txAmount((*it)->GetTx()); + if (transparentAmount + output > limit) + break; + transparentAmount += output; } + + // found all the private transaction fitting in the limit, blacklist the rest + while (it != txList.cend()) + mempool.CalculateDescendants(*it++, txBlackList); + } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/miner.h b/src/miner.h index b6348ab94e..cd55d640eb 100644 --- a/src/miner.h +++ b/src/miner.h @@ -232,6 +232,11 @@ class BlockAssembler /** Fill txBlackList set */ void FillBlackListForBlockTemplate(); + + /** Ensure spark/lelantus txs don't exceed specific limit */ + void BlacklistTxsExceedingLimit(CAmount limit, + std::function txTypeFilter, + std::function txAmount); }; /** Modify the extranonce in a block */ diff --git a/src/rpc/rpcevo.cpp b/src/rpc/rpcevo.cpp index 14cd7d9dcb..6037b4835f 100644 --- a/src/rpc/rpcevo.cpp +++ b/src/rpc/rpcevo.cpp @@ -1405,7 +1405,9 @@ UniValue spork(const JSONRPCRequest& request) CSporkAction::featureLelantus, CSporkAction::featureChainlocks, CSporkAction::featureInstantSend, - CSporkAction::featureLelantusTransparentLimit + CSporkAction::featureLelantusTransparentLimit, + CSporkAction::featureSpark, + CSporkAction::featureSparkTransparentLimit }; for (const CSporkAction &action: sporkTx.actions) { diff --git a/src/test/evospork_tests.cpp b/src/test/evospork_tests.cpp index 775a1ae581..fb01ac97bc 100644 --- a/src/test/evospork_tests.cpp +++ b/src/test/evospork_tests.cpp @@ -432,4 +432,255 @@ BOOST_AUTO_TEST_CASE(startstopblock) } +BOOST_AUTO_TEST_SUITE_END() + +// Extend spork stop block to 2000 +struct SparkSporkTestingSetup : public SparkTestingSetup +{ + Consensus::Params &mutableParams; + Consensus::Params originalParams; + + SparkSporkTestingSetup() : SparkTestingSetup(), mutableParams(const_cast(Params().GetConsensus())) + { + spark::CSparkState::GetState()->Reset(); + mempool.clear(); + originalParams = mutableParams; + mutableParams.nEvoSporkStopBlock = 2000; + } + + ~SparkSporkTestingSetup() { + mutableParams = originalParams; + spark::CSparkState::GetState()->Reset(); + mempool.clear(); + } + +}; + +BOOST_FIXTURE_TEST_SUITE(evospork_spark_tests, SparkSporkTestingSetup) + +BOOST_AUTO_TEST_CASE(general) +{ + int prevHeight; + pwalletMain->SetBroadcastTransactions(true); + + for (int n=chainActive.Height(); n<1000; n++) + GenerateBlock({}); + + auto utxos = BuildSimpleUtxoMap(coinbaseTxns); + CMutableTransaction sporkTx1 = CreateSporkTx(utxos, coinbaseKey, { + {CSporkAction::sporkDisable, CSporkAction::featureSpark, 0, 1075} + }); + CMutableTransaction sporkTx2 = CreateSporkTx(utxos, coinbaseKey, { + {CSporkAction::sporkDisable, CSporkAction::featureSpark, 0, 1085} + }); + CMutableTransaction sporkTx3 = CreateSporkTx(utxos, coinbaseKey, { + {CSporkAction::sporkEnable, CSporkAction::featureSpark, 0, 0} + }); + + prevHeight = chainActive.Height(); + GenerateBlock({sporkTx1}); + // spork should be accepted + BOOST_ASSERT(chainActive.Height() == prevHeight+1); + + std::vector sparkMints; + GenerateMints({1*COIN, 2*COIN}, sparkMints); + + prevHeight = chainActive.Height(); + GenerateBlock(sparkMints); + // can't accept spark tx after spark + BOOST_ASSERT(chainActive.Height() == prevHeight); + + // wait until the spork expires + for (int n=chainActive.Height(); n<1075; n++) + GenerateBlock({}); + prevHeight = chainActive.Height(); + GenerateBlock({sparkMints[0]}); + BOOST_ASSERT(chainActive.Height() == prevHeight+1); + + // another disabling spork + GenerateBlock({sporkTx2}); + // ensure lelantus is disabled + prevHeight = chainActive.Height(); + GenerateBlock({sparkMints[1]}); + BOOST_ASSERT(chainActive.Height() == prevHeight); + + // block with enabling spork + GenerateBlock({sporkTx3}); + // ensure lelantus is enabled now + prevHeight = chainActive.Height(); + GenerateBlock({sparkMints[1]}); + BOOST_ASSERT(chainActive.Height() == prevHeight+1); +} + +BOOST_AUTO_TEST_CASE(mempool) +{ + int prevHeight; + pwalletMain->SetBroadcastTransactions(true); + + for (int n=chainActive.Height(); n<1000; n++) + GenerateBlock({}); + + auto utxos = BuildSimpleUtxoMap(coinbaseTxns); + CMutableTransaction sporkTx1 = CreateSporkTx(utxos, coinbaseKey, { + {CSporkAction::sporkDisable, CSporkAction::featureSpark, 0, 1075} + }); + CMutableTransaction sporkTx2 = CreateSporkTx(utxos, coinbaseKey, { + {CSporkAction::sporkDisable, CSporkAction::featureSpark, 0, 1085} + }); + + std::vector sparkMints; + GenerateMints({1*COIN, 2*COIN}, sparkMints); + ::mempool.removeRecursive(sparkMints[0]); + ::mempool.removeRecursive(sparkMints[1]); + + CBlock blockWithSparkMint = CreateBlock({sparkMints[0]}, coinbaseKey); + + // put one mint into the mempool + CommitToMempool(sparkMints[0]); + BOOST_ASSERT(::mempool.size() == 1); + + // push spork to mempool + CommitToMempool(sporkTx1); + // spork should be in the mempool, spark mint should be pushed out of it + BOOST_ASSERT(::mempool.size() == 1); + BOOST_ASSERT(::mempool.exists(sporkTx1.GetHash()) && !::mempool.exists(sparkMints[0].GetHash())); + + // another spark tx shouldn't get to the mempool + CommitToMempool(sparkMints[1]); + BOOST_ASSERT(::mempool.size() == 1); + + // but should be accepted in block + prevHeight = chainActive.Height(); + ProcessNewBlock(Params(), std::make_shared(blockWithSparkMint), true, nullptr); + BOOST_ASSERT(chainActive.Height() == prevHeight+1); + + // mine spork into the block + CreateAndProcessBlock({sporkTx1}, coinbaseKey); + // mempool should clear + BOOST_ASSERT(::mempool.size() == 0); + + // because there is active spork at the tip spark mint shouldn't get into the mempool + BOOST_ASSERT(!CommitToMempool(sparkMints[1])); + + for (int n=chainActive.Height(); n<1075; n++) + CreateAndProcessBlock({}, coinbaseKey); + + // spork expired, should accept now + BOOST_ASSERT(CommitToMempool(sparkMints[1])); + // try and generate a block with second spork without it ever entering the mempool + CreateAndProcessBlock({sporkTx2}, coinbaseKey); + // now we have a mint in the mempool and active spork. Verify that miner correctly blocks the mint + // from being mined + fAllowMempoolTxsInCreateBlock = true; + CBlock block = CreateBlock({}, coinbaseKey); + for (CTransactionRef tx: block.vtx) { + BOOST_ASSERT(!tx->IsSparkTransaction()); + } + BOOST_ASSERT(::mempool.exists(sparkMints[1].GetHash())); + prevHeight = chainActive.Height(); + ProcessNewBlock(Params(), std::make_shared(block), true, nullptr); + BOOST_CHECK_EQUAL(chainActive.Height(), prevHeight+1); +} + +BOOST_AUTO_TEST_CASE(limit) +{ + int prevHeight; + pwalletMain->SetBroadcastTransactions(true); + + for (int n=chainActive.Height(); n<1000; n++) + GenerateBlock({}); + + auto utxos = BuildSimpleUtxoMap(coinbaseTxns); + CMutableTransaction sporkTx1 = CreateSporkTx(utxos, coinbaseKey, { + {CSporkAction::sporkLimit, CSporkAction::featureSparkTransparentLimit, 100*COIN, 1050} + }); + + auto params = spark::Params::get_default(); + + BOOST_ASSERT(pwalletMain->sparkWallet); + spark::Address address = pwalletMain->sparkWallet->generateNewAddress(); + + std::vector sparkMints; + for (int i=0; i<10; i++) { + std::vector> wtxAndFee; + std::vector mints{{address, 50*COIN, ""}}; + std::string error = pwalletMain->MintAndStoreSpark(mints, wtxAndFee, false); + BOOST_ASSERT(error.empty()); + for (auto &w: wtxAndFee) + sparkMints.emplace_back(*w.first.tx); + } + + GenerateBlock(sparkMints); + + for (int i=0; i<10; i++) + GenerateBlock({}); + + CAmount fee = 0; + CWalletTx spendWalletTx = pwalletMain->SpendAndStoreSpark({{script, 120*COIN, false, ""}}, {}, fee); + + CMutableTransaction spendTx = *spendWalletTx.tx; + + ::mempool.removeRecursive(spendWalletTx); + + auto sparkSpend = spark::ParseSparkSpend(spendTx); + std::vector lTags = sparkSpend.getUsedLTags(); + + // generate two smaller spark spend txs + CWalletTx smallSparkWalletTxs[2] = { + pwalletMain->SpendAndStoreSpark({{script, 70*COIN, false, ""}}, {}, fee), + pwalletMain->SpendAndStoreSpark({{script, 70*COIN, false, ""}}, {}, fee), + }; + + CMutableTransaction smallSparkTxs[2] = {*smallSparkWalletTxs[0].tx, *smallSparkWalletTxs[1].tx}; + + CommitToMempool(sporkTx1); + BOOST_ASSERT(::mempool.size() == 3); // two small spark spends and spork + + fAllowMempoolTxsInCreateBlock = true; + CBlock block = CreateBlock({}, script); + // should only have one spark spend transaction in the block + int nSparkSpends = 0; + for (CTransactionRef ptx: block.vtx) { + if (ptx->IsSparkSpend()) + nSparkSpends++; + } + BOOST_ASSERT(nSparkSpends == 1); + prevHeight = chainActive.Height(); + ProcessNewBlock(Params(), std::make_shared(block), true, nullptr); + BOOST_ASSERT(chainActive.Height() == prevHeight+1); + // one spark spend should be left at the mempool + BOOST_ASSERT(::mempool.size() == 1); + + // mine remaining spark spend into the block + prevHeight = chainActive.Height(); + GenerateBlock({}); + BOOST_ASSERT(chainActive.Height() == prevHeight+1); + BOOST_ASSERT(::mempool.size() == 0); + fAllowMempoolTxsInCreateBlock = false; + + // large spark spend tx is out of range, should fail now + BOOST_ASSERT(!CommitToMempool(spendTx)); + // should fail in block as well + prevHeight = chainActive.Height(); + GenerateBlock({spendTx}); + BOOST_ASSERT(chainActive.Height() == prevHeight); + + // skip to 1050 (spork expiration block) + for (int n=chainActive.Height(); n<1050; n++) + GenerateBlock({}); + + // should be accepted into the mempool + BOOST_ASSERT(CommitToMempool(spendTx)); + // and be mined into the block + prevHeight = chainActive.Height(); + GenerateBlock({spendTx}); + BOOST_ASSERT(chainActive.Height() == prevHeight+1); + // mempool should be clear + BOOST_ASSERT(::mempool.size() == 0); + // lTags should go into the state + spark::CSparkState *sparkState = spark::CSparkState::GetState(); + for (const GroupElement &lTag : lTags) + BOOST_ASSERT(sparkState->IsUsedLTag(lTag)); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 72ed006b2b..870d1be3ae 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -186,10 +186,12 @@ CBlock TestChain100Setup::CreateBlock(const std::vector& tx } // Replace mempool-selected txns with just coinbase plus passed-in txns: - if (!fAllowMempoolTxsInCreateBlock) + if (!fAllowMempoolTxsInCreateBlock) { block.vtx.resize(1); - // Re-add quorum commitments - block.vtx.insert(block.vtx.end(), llmqCommitments.begin(), llmqCommitments.end()); + // Re-add quorum commitments + block.vtx.insert(block.vtx.end(), llmqCommitments.begin(), llmqCommitments.end()); + } + BOOST_FOREACH(const CMutableTransaction& tx, txns) block.vtx.push_back(MakeTransactionRef(tx)); From 807db781b7238d09870ba393eec4db8f19668ef0 Mon Sep 17 00:00:00 2001 From: justanwar <42809091+justanwar@users.noreply.github.com> Date: Fri, 26 Jan 2024 00:44:49 +0800 Subject: [PATCH 10/17] Bump version to v0.14.13.2 (#1404) --- configure.ac | 2 +- src/clientversion.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 10300cf4a7..f6243d1b43 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 14) define(_CLIENT_VERSION_REVISION, 13) -define(_CLIENT_VERSION_BUILD, 1) +define(_CLIENT_VERSION_BUILD, 2) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) diff --git a/src/clientversion.h b/src/clientversion.h index d71a0b7e5e..6f9956da0d 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,7 +17,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 14 #define CLIENT_VERSION_REVISION 13 -#define CLIENT_VERSION_BUILD 1 +#define CLIENT_VERSION_BUILD 2 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true From 07c6e125035bf4100d0248991e6515196c0ee022 Mon Sep 17 00:00:00 2001 From: psolstice Date: Sun, 28 Jan 2024 20:24:34 +0100 Subject: [PATCH 11/17] Allow validateaddress to print hdkeypath for exchange addresses (#1405) --- src/base58.cpp | 11 +++++++++++ src/base58.h | 1 + src/rpc/misc.cpp | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/base58.cpp b/src/base58.cpp index 7044503063..47fc8e12c2 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -320,6 +320,17 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const return true; } +bool CBitcoinAddress::GetKeyIDExt(CKeyID& keyID) const +{ + if (!IsValid() || !(vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || + vchVersion == Params().Base58Prefix(CChainParams::EXCHANGE_PUBKEY_ADDRESS))) + return false; + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; +} + bool CBitcoinAddress::IsScript() const { return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); diff --git a/src/base58.h b/src/base58.h index 1ea609ae40..4f2789c0c1 100644 --- a/src/base58.h +++ b/src/base58.h @@ -127,6 +127,7 @@ class CBitcoinAddress : public CBase58Data { CTxDestination Get() const; bool GetIndexKey(uint160& hashBytes, AddressType & type) const; bool GetKeyID(CKeyID &keyID) const; + bool GetKeyIDExt(CKeyID &keyID) const; // same as GetKeyID() but also works in case of exchange address bool IsScript() const; }; diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index bafb94b712..c7142df306 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -233,7 +233,7 @@ UniValue validateaddress(const JSONRPCRequest& request) CKeyID keyID; if (pwallet) { const auto& meta = pwallet->mapKeyMetadata; - auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end(); + auto it = address.GetKeyIDExt(keyID) ? meta.find(keyID) : meta.end(); if (it == meta.end()) { it = meta.find(CScriptID(scriptPubKey)); } From 285a58e3edc28648bee300c252608d2da62cf41b Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:25:02 +0400 Subject: [PATCH 12/17] Disable spark tx creation when spork is active (#1406) --- src/spark/sparkwallet.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/spark/sparkwallet.cpp b/src/spark/sparkwallet.cpp index 822aafdaff..4c767b4fe5 100644 --- a/src/spark/sparkwallet.cpp +++ b/src/spark/sparkwallet.cpp @@ -1153,6 +1153,14 @@ bool CSparkWallet::CreateSparkMintTransactions( nIn++; } + { + CValidationState state; + if (!mempool.IsTransactionAllowed(*wtx.tx, state)) { + strFailReason = _("Signing transaction failed"); + return false; + } + } + wtx.SetTx(MakeTransactionRef(std::move(tx))); wtxAndFee.push_back(std::make_pair(wtx, nFeeRet)); @@ -1548,7 +1556,13 @@ CWalletTx CSparkWallet::CreateSparkSpendTransaction( result.push_back(wtxNew); } } - + { + CValidationState state; + for (CWalletTx& wtx : result) { + if (!mempool.IsTransactionAllowed(*wtx.tx, state)) + throw std::invalid_argument(_("Spark transactions are disabled at the moment")); + } + } if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { // Lastly, ensure this tx will pass the mempool's chain limits size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); From 53c05264ca4e959e312b6a3274e12a4ab15c4e36 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:25:26 +0400 Subject: [PATCH 13/17] validateaddress rpc for spark addresses (#1407) --- src/rpc/misc.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index c7142df306..d1b0eeef45 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -210,8 +210,26 @@ UniValue validateaddress(const JSONRPCRequest& request) CBitcoinAddress address(request.params[0].get_str()); bool isValid = address.IsValid(); + bool isvalidSpark = false; + const spark::Params* params = spark::Params::get_default(); + unsigned char network = spark::GetNetworkType(); + spark::Address sAddress(params); + + if (!isValid) { + try { + unsigned char coinNetwork = sAddress.decode(request.params[0].get_str()); + isvalidSpark = coinNetwork == network; + } catch (const std::exception &) { + isvalidSpark = false; + } + } + UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("isvalid", isValid)); + if (isvalidSpark) + ret.push_back(Pair("isvalidSpark", isvalidSpark)); + else + ret.push_back(Pair("isvalid", isValid)); + if (isValid) { CTxDestination dest = address.Get(); @@ -245,6 +263,18 @@ UniValue validateaddress(const JSONRPCRequest& request) } } } +#endif + } else if (isvalidSpark) { + std::string currentAddress = sAddress.encode(network); + ret.push_back(Pair("address", currentAddress)); + +#ifdef ENABLE_WALLET + bool ismine = false; + if (pwallet && pwallet->sparkWallet) { + ismine = pwallet->sparkWallet->isAddressMine(currentAddress); + } + + ret.push_back(Pair("ismine", ismine)); #endif } return ret; From ff35368db375e4499eff7ab22ed89f97415e6a3e Mon Sep 17 00:00:00 2001 From: ErC Date: Wed, 7 Feb 2024 05:53:27 +0100 Subject: [PATCH 14/17] add files needed for flatpak (#1409) --- contrib/debian/bitcoin-qt.desktop | 13 ------------- contrib/debian/firo-qt.desktop | 9 +++++++++ contrib/debian/qt-screenshot.jpg | Bin 0 -> 79207 bytes 3 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 contrib/debian/bitcoin-qt.desktop create mode 100644 contrib/debian/firo-qt.desktop create mode 100644 contrib/debian/qt-screenshot.jpg diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop deleted file mode 100644 index 593d7584ab..0000000000 --- a/contrib/debian/bitcoin-qt.desktop +++ /dev/null @@ -1,13 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Name=Bitcoin Core -Comment=Connect to the Bitcoin P2P Network -Comment[de]=Verbinde mit dem Bitcoin peer-to-peer Netzwerk -Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair -Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi -Exec=bitcoin-qt %u -Terminal=false -Type=Application -Icon=bitcoin128 -MimeType=x-scheme-handler/bitcoin; -Categories=Office;Finance; diff --git a/contrib/debian/firo-qt.desktop b/contrib/debian/firo-qt.desktop new file mode 100644 index 0000000000..0d610ac4c3 --- /dev/null +++ b/contrib/debian/firo-qt.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Firo +Comment=Connect to Firo +Exec=firo-qt %u +Terminal=false +Type=Application +Icon=/app/share/icons/hicolor/scalable/apps/org.firo.firo-qt.svg +Categories=Office;Finance; diff --git a/contrib/debian/qt-screenshot.jpg b/contrib/debian/qt-screenshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..135ff4acba87472a6a120f9313f0323c202524dc GIT binary patch literal 79207 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 NN7K0em%~3x{{`~fcE Date: Thu, 8 Feb 2024 02:58:58 +0400 Subject: [PATCH 15/17] Fix sync issue on mac (#1410) --- src/libspark/spend_transaction.cpp | 4 ++-- src/libspark/spend_transaction.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libspark/spend_transaction.cpp b/src/libspark/spend_transaction.cpp index 69eda151d9..d98dc67a15 100644 --- a/src/libspark/spend_transaction.cpp +++ b/src/libspark/spend_transaction.cpp @@ -412,7 +412,7 @@ bool SpendTransaction::verify( // // Note that transparent components of the transaction are bound into `cover_set_representation`, so they don't appear separately. std::vector SpendTransaction::hash_bind_inner( - const std::unordered_map>& cover_set_representations, + const std::map>& cover_set_representations, const std::vector& S1, const std::vector& C1, const std::vector& T, @@ -459,4 +459,4 @@ const std::map& SpendTransaction::getBlockHashes() { return set_id_blockHash; } -} +} \ No newline at end of file diff --git a/src/libspark/spend_transaction.h b/src/libspark/spend_transaction.h index 5dce27d137..24da12bea2 100644 --- a/src/libspark/spend_transaction.h +++ b/src/libspark/spend_transaction.h @@ -61,7 +61,7 @@ class SpendTransaction { static bool verify(const SpendTransaction& transaction, const std::unordered_map>& cover_sets); static std::vector hash_bind_inner( - const std::unordered_map>& cover_set_representations, + const std::map>& cover_set_representations, const std::vector& S1, const std::vector& C1, const std::vector& T, @@ -113,7 +113,7 @@ class SpendTransaction { const Params* params; // We need to construct and pass this data before running verification std::unordered_map cover_set_sizes; - std::unordered_map> cover_set_representations; + std::map> cover_set_representations; std::vector out_coins; // All this data we need to serialize From 0f9d27dfef6f27f5c4d97a060c0954846d3ea547 Mon Sep 17 00:00:00 2001 From: levonpetrosyan93 <45027856+levonpetrosyan93@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:39:01 +0400 Subject: [PATCH 16/17] Tx size estimation fixed on Send dialog (#1411) --- src/qt/sendcoinsdialog.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index baa5412e11..8880bf0af7 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -461,14 +461,17 @@ void SendCoinsDialog::on_sendButton_clicked() } QString questionString = tr("Are you sure you want to send?"); questionString.append("

%1"); + double txSize; if ((fAnonymousMode == false) && (recipients.size() == sparkAddressCount) && spark::IsSparkAllowed()) { for (auto &transaction : transactions) { txFee += transaction.getTransactionFee(); mintSparkAmount += transaction.getTotalTransactionAmount(); + txSize += (double)transaction.getTransactionSize(); } } else { - txFee= currentTransaction.getTransactionFee(); + txFee = currentTransaction.getTransactionFee(); + txSize = (double)currentTransaction.getTransactionSize(); } if(txFee > 0) @@ -480,7 +483,7 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append(tr("added as transaction fee")); // append transaction size - questionString.append(" (" + QString::number((double)currentTransaction.getTransactionSize() / 1000) + " kB)"); + questionString.append(" (" + QString::number(txSize / 1000) + " kB)"); } // add total amount in all subdivision units From 1d433ffadee349bf01fdd43508e3478677c6c53d Mon Sep 17 00:00:00 2001 From: firstcryptoman Date: Fri, 16 Feb 2024 19:42:53 +0400 Subject: [PATCH 17/17] Build error fix --- depends/packages/qt.mk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 322e9f52fb..86109aef18 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -16,7 +16,7 @@ $(package)_patches += no-xlib.patch $(package)_patches += fix_android_jni_static.patch $(package)_patches += dont_hardcode_pwd.patch $(package)_patches += qtbase-moc-ignore-gcc-macro.patch -$(package)_patches += use_android_ndk23.patch fix_sonoma_qmake.patch +$(package)_patches += use_android_ndk23.patch $(package)_patches += rcc_hardcode_timestamp.patch $(package)_patches += duplicate_lcqpafonts.patch $(package)_patches += fast_fixed_dtoa_no_optimize.patch @@ -249,7 +249,6 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fast_fixed_dtoa_no_optimize.patch && \ patch -p1 -i $($(package)_patch_dir)/guix_cross_lib_path.patch && \ patch -p1 -i $($(package)_patch_dir)/windows_lto.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix_sonoma_qmake.patch && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ @@ -268,6 +267,8 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds + export PKG_CONFIG_SYSROOT_DIR=/ && \ + export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ cd qtbase && \ ./configure -top-level $($(package)_config_opts) endef @@ -285,4 +286,4 @@ endef define $(package)_postprocess_cmds rm -rf native/mkspecs/ native/lib/ lib/cmake/ && \ rm -f lib/lib*.la -endef +endef \ No newline at end of file