aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml30
-rw-r--r--build_msvc/libsecp256k1_config.h2
-rwxr-xr-xci/test/00_setup_env_native_asan.sh2
-rwxr-xr-xci/test/00_setup_env_native_tsan.sh2
-rwxr-xr-xci/test/05_before_script.sh24
-rw-r--r--configure.ac32
-rwxr-xr-xcontrib/devtools/security-check.py18
-rwxr-xr-xcontrib/devtools/symbol-check.py36
-rwxr-xr-xcontrib/devtools/test-security-check.py12
-rwxr-xr-xcontrib/devtools/test-symbol-check.py2
-rwxr-xr-xcontrib/guix/libexec/build.sh5
-rwxr-xr-xcontrib/install_db4.sh8
-rwxr-xr-xcontrib/macdeploy/gen-sdk2
-rw-r--r--contrib/tracing/README.md59
-rwxr-xr-xcontrib/tracing/log_utxocache_flush.py107
-rwxr-xr-xcontrib/tracing/log_utxos.bt86
-rw-r--r--depends/README.md22
-rw-r--r--depends/config.site.in1
-rw-r--r--depends/hosts/android.mk7
-rw-r--r--depends/packages.md4
-rw-r--r--depends/packages/boost.mk1
-rw-r--r--depends/packages/qt.mk11
-rw-r--r--depends/patches/qt/dont_hardcode_x86_64.patch123
-rw-r--r--depends/patches/qt/fix_montery_include.patch21
-rw-r--r--depends/patches/qt/mac-qmake.conf1
-rw-r--r--depends/patches/qt/no_sdk_version_check.patch20
-rw-r--r--doc/build-android.md17
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/developer-notes.md6
-rw-r--r--doc/release-notes-16807.md6
-rw-r--r--doc/release-notes.md4
-rw-r--r--doc/tracing.md49
-rw-r--r--src/Makefile.am14
-rw-r--r--src/Makefile.test.include22
-rw-r--r--src/banman.h2
-rw-r--r--src/bech32.cpp451
-rw-r--r--src/bech32.h4
-rw-r--r--src/bench/ccoins_caching.cpp2
-rw-r--r--src/bench/coin_selection.cpp2
-rw-r--r--src/bench/rpc_mempool.cpp2
-rw-r--r--src/bitcoin-cli.cpp29
-rw-r--r--src/chain.cpp3
-rw-r--r--src/checkqueue.h22
-rw-r--r--src/coins.cpp19
-rw-r--r--src/consensus/amount.h2
-rw-r--r--src/dbwrapper.cpp4
-rw-r--r--src/fs.h45
-rw-r--r--src/httprpc.h2
-rw-r--r--src/i2p.h2
-rw-r--r--src/init.cpp14
-rw-r--r--src/interfaces/chain.h3
-rw-r--r--src/interfaces/node.h4
-rw-r--r--src/interfaces/wallet.h5
-rw-r--r--src/key.cpp4
-rw-r--r--src/key.h4
-rw-r--r--src/key_io.cpp43
-rw-r--r--src/key_io.h2
-rw-r--r--src/net.cpp354
-rw-r--r--src/net.h120
-rw-r--r--src/net_processing.cpp7
-rw-r--r--src/netaddress.h6
-rw-r--r--src/node/interfaces.cpp17
-rw-r--r--src/node/miner.cpp (renamed from src/miner.cpp)3
-rw-r--r--src/node/miner.h (renamed from src/miner.h)10
-rw-r--r--src/node/minisketchwrapper.cpp (renamed from src/minisketchwrapper.cpp)2
-rw-r--r--src/node/minisketchwrapper.h (renamed from src/minisketchwrapper.h)7
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/policy.cpp11
-rw-r--r--src/policy/policy.h3
-rw-r--r--src/psbt.cpp10
-rw-r--r--src/psbt.h2
-rw-r--r--src/pubkey.h6
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/forms/openuridialog.ui21
-rw-r--r--src/qt/forms/optionsdialog.ui4
-rw-r--r--src/qt/openuridialog.cpp23
-rw-r--r--src/qt/openuridialog.h9
-rw-r--r--src/qt/psbtoperationsdialog.cpp4
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/qt/test/test_main.cpp2
-rw-r--r--src/randomenv.h2
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp4
-rw-r--r--src/rpc/misc.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/scheduler.h2
-rw-r--r--src/script/descriptor.cpp1
-rw-r--r--src/script/interpreter.cpp2
-rw-r--r--src/script/interpreter.h1
-rw-r--r--src/script/sign.cpp15
-rw-r--r--src/script/sign.h4
-rw-r--r--src/script/signingprovider.cpp14
-rw-r--r--src/shutdown.h2
-rw-r--r--src/span.h35
-rw-r--r--src/streams.h12
-rw-r--r--src/test/base64_tests.cpp10
-rw-r--r--src/test/bech32_tests.cpp55
-rw-r--r--src/test/blockfilter_index_tests.cpp2
-rw-r--r--src/test/data/bip341_wallet_vectors.json452
-rw-r--r--src/test/denialofservice_tests.cpp24
-rw-r--r--src/test/fuzz/coins_view.cpp3
-rw-r--r--src/test/fuzz/minisketch.cpp64
-rw-r--r--src/test/fuzz/transaction.cpp3
-rw-r--r--src/test/fuzz/tx_pool.cpp4
-rw-r--r--src/test/key_tests.cpp4
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/minisketch_tests.cpp2
-rw-r--r--src/test/script_p2sh_tests.cpp6
-rw-r--r--src/test/script_standard_tests.cpp46
-rw-r--r--src/test/script_tests.cpp76
-rw-r--r--src/test/scriptnum10.h2
-rw-r--r--src/test/streams_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/test/txpackage_tests.cpp16
-rw-r--r--src/test/util/mining.cpp2
-rw-r--r--src/test/util/net.h10
-rw-r--r--src/test/util/setup_common.cpp2
-rw-r--r--src/test/util/setup_common.h2
-rw-r--r--src/test/util_tests.cpp71
-rw-r--r--src/test/validation_block_tests.cpp4
-rw-r--r--src/threadinterrupt.h2
-rw-r--r--src/torcontrol.cpp18
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/util/overloaded.h22
-rw-r--r--src/util/readwritefile.h2
-rw-r--r--src/util/strencodings.cpp51
-rw-r--r--src/util/strencodings.h34
-rw-r--r--src/util/string.h2
-rw-r--r--src/util/syscall_sandbox.cpp3
-rw-r--r--src/util/trace.h2
-rw-r--r--src/validation.cpp12
-rw-r--r--src/wallet/context.h2
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp6
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.h2
-rw-r--r--src/wallet/init.cpp4
-rw-r--r--src/wallet/interfaces.cpp5
-rw-r--r--src/wallet/ismine.h8
-rw-r--r--src/wallet/rpc/signmessage.cpp68
-rw-r--r--src/wallet/rpcdump.cpp16
-rw-r--r--src/wallet/rpcwallet.cpp83
-rw-r--r--src/wallet/rpcwallet.h4
-rw-r--r--src/wallet/scriptpubkeyman.cpp26
-rw-r--r--src/wallet/scriptpubkeyman.h13
-rw-r--r--src/wallet/test/coinselector_tests.cpp2
-rw-r--r--src/wallet/test/fuzz/notifications.cpp3
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp4
-rw-r--r--src/wallet/test/wallet_tests.cpp28
-rw-r--r--src/wallet/test/wallet_transaction_tests.cpp24
-rw-r--r--src/wallet/transaction.cpp2
-rw-r--r--src/wallet/transaction.h180
-rw-r--r--src/wallet/wallet.cpp169
-rw-r--r--src/wallet/wallet.h15
-rw-r--r--src/wallet/walletdb.cpp2
-rw-r--r--src/wallet/wallettool.cpp2
-rw-r--r--src/warnings.h2
-rw-r--r--src/zmq/zmqrpc.h2
-rwxr-xr-xtest/functional/combine_logs.py2
-rw-r--r--test/functional/data/invalid_txs.py2
-rwxr-xr-xtest/functional/example_test.py2
-rwxr-xr-xtest/functional/feature_abortnode.py2
-rwxr-xr-xtest/functional/feature_anchors.py10
-rwxr-xr-xtest/functional/feature_asmap.py2
-rwxr-xr-xtest/functional/feature_assumevalid.py7
-rwxr-xr-xtest/functional/feature_backwards_compatibility.py6
-rwxr-xr-xtest/functional/feature_bind_extra.py2
-rwxr-xr-xtest/functional/feature_bip68_sequence.py6
-rwxr-xr-xtest/functional/feature_block.py7
-rwxr-xr-xtest/functional/feature_blockfilterindex_prune.py4
-rwxr-xr-xtest/functional/feature_blocksdir.py2
-rwxr-xr-xtest/functional/feature_cltv.py10
-rwxr-xr-xtest/functional/feature_coinstatsindex.py6
-rwxr-xr-xtest/functional/feature_config_args.py2
-rwxr-xr-xtest/functional/feature_csv_activation.py7
-rwxr-xr-xtest/functional/feature_dbcrash.py2
-rwxr-xr-xtest/functional/feature_dersig.py9
-rwxr-xr-xtest/functional/feature_fee_estimation.py7
-rwxr-xr-xtest/functional/feature_filelock.py2
-rwxr-xr-xtest/functional/feature_help.py2
-rwxr-xr-xtest/functional/feature_includeconf.py2
-rwxr-xr-xtest/functional/feature_loadblock.py2
-rwxr-xr-xtest/functional/feature_logging.py2
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py2
-rwxr-xr-xtest/functional/feature_minchainwork.py2
-rwxr-xr-xtest/functional/feature_notifications.py3
-rwxr-xr-xtest/functional/feature_nulldummy.py32
-rwxr-xr-xtest/functional/feature_presegwit_node_upgrade.py2
-rwxr-xr-xtest/functional/feature_proxy.py2
-rwxr-xr-xtest/functional/feature_pruning.py2
-rwxr-xr-xtest/functional/feature_rbf.py2
-rwxr-xr-xtest/functional/feature_reindex.py2
-rwxr-xr-xtest/functional/feature_segwit.py7
-rwxr-xr-xtest/functional/feature_settings.py2
-rwxr-xr-xtest/functional/feature_signet.py2
-rwxr-xr-xtest/functional/feature_taproot.py342
-rwxr-xr-xtest/functional/feature_versionbits_warning.py5
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py2
-rwxr-xr-xtest/functional/interface_http.py2
-rwxr-xr-xtest/functional/interface_rest.py9
-rwxr-xr-xtest/functional/interface_rpc.py2
-rwxr-xr-xtest/functional/interface_zmq.py15
-rwxr-xr-xtest/functional/mempool_accept.py2
-rwxr-xr-xtest/functional/mempool_compatibility.py2
-rwxr-xr-xtest/functional/mempool_expiry.py2
-rwxr-xr-xtest/functional/mempool_limit.py2
-rwxr-xr-xtest/functional/mempool_package_onemore.py2
-rwxr-xr-xtest/functional/mempool_packages.py5
-rwxr-xr-xtest/functional/mempool_persist.py2
-rwxr-xr-xtest/functional/mempool_reorg.py2
-rwxr-xr-xtest/functional/mempool_resurrect.py2
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py2
-rwxr-xr-xtest/functional/mempool_unbroadcast.py2
-rwxr-xr-xtest/functional/mempool_updatefromblock.py2
-rwxr-xr-xtest/functional/mining_basic.py2
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py3
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py2
-rwxr-xr-xtest/functional/mocks/signer.py6
-rwxr-xr-xtest/functional/p2p_add_connections.py8
-rwxr-xr-xtest/functional/p2p_addr_relay.py2
-rwxr-xr-xtest/functional/p2p_addrv2_relay.py2
-rwxr-xr-xtest/functional/p2p_blockfilters.py3
-rwxr-xr-xtest/functional/p2p_blocksonly.py2
-rwxr-xr-xtest/functional/p2p_compactblocks.py2
-rwxr-xr-xtest/functional/p2p_compactblocks_hb.py2
-rwxr-xr-xtest/functional/p2p_dos_header_tree.py2
-rwxr-xr-xtest/functional/p2p_eviction.py2
-rwxr-xr-xtest/functional/p2p_feefilter.py2
-rwxr-xr-xtest/functional/p2p_filter.py2
-rwxr-xr-xtest/functional/p2p_fingerprint.py2
-rwxr-xr-xtest/functional/p2p_ibd_txrelay.py55
-rwxr-xr-xtest/functional/p2p_invalid_block.py37
-rwxr-xr-xtest/functional/p2p_invalid_locator.py2
-rwxr-xr-xtest/functional/p2p_invalid_messages.py2
-rwxr-xr-xtest/functional/p2p_invalid_tx.py2
-rwxr-xr-xtest/functional/p2p_leak.py2
-rwxr-xr-xtest/functional/p2p_leak_tx.py2
-rwxr-xr-xtest/functional/p2p_message_capture.py2
-rwxr-xr-xtest/functional/p2p_node_network_limited.py5
-rwxr-xr-xtest/functional/p2p_permissions.py3
-rwxr-xr-xtest/functional/p2p_ping.py2
-rwxr-xr-xtest/functional/p2p_segwit.py10
-rwxr-xr-xtest/functional/p2p_sendheaders.py4
-rwxr-xr-xtest/functional/p2p_tx_download.py2
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py7
-rwxr-xr-xtest/functional/rpc_blockchain.py2
-rwxr-xr-xtest/functional/rpc_createmultisig.py4
-rwxr-xr-xtest/functional/rpc_decodescript.py67
-rwxr-xr-xtest/functional/rpc_deprecated.py2
-rwxr-xr-xtest/functional/rpc_dumptxoutset.py2
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py39
-rwxr-xr-xtest/functional/rpc_generateblock.py36
-rwxr-xr-xtest/functional/rpc_getblockfilter.py2
-rwxr-xr-xtest/functional/rpc_getblockstats.py3
-rwxr-xr-xtest/functional/rpc_getchaintips.py2
-rwxr-xr-xtest/functional/rpc_help.py2
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py101
-rwxr-xr-xtest/functional/rpc_invalidateblock.py2
-rwxr-xr-xtest/functional/rpc_misc.py2
-rwxr-xr-xtest/functional/rpc_net.py3
-rwxr-xr-xtest/functional/rpc_preciousblock.py2
-rwxr-xr-xtest/functional/rpc_psbt.py16
-rwxr-xr-xtest/functional/rpc_rawtransaction.py14
-rwxr-xr-xtest/functional/rpc_scantxoutset.py2
-rwxr-xr-xtest/functional/rpc_setban.py2
-rwxr-xr-xtest/functional/rpc_signer.py2
-rwxr-xr-xtest/functional/rpc_signmessagewithprivkey.py2
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py3
-rwxr-xr-xtest/functional/rpc_txoutproof.py4
-rwxr-xr-xtest/functional/rpc_uptime.py2
-rw-r--r--test/functional/test_framework/address.py2
-rw-r--r--test/functional/test_framework/bdb.py2
-rw-r--r--test/functional/test_framework/blocktools.py2
-rw-r--r--test/functional/test_framework/coverage.py2
-rw-r--r--test/functional/test_framework/key.py20
-rwxr-xr-xtest/functional/test_framework/messages.py2
-rw-r--r--test/functional/test_framework/netutil.py2
-rwxr-xr-xtest/functional/test_framework/p2p.py4
-rw-r--r--test/functional/test_framework/script.py86
-rwxr-xr-xtest/functional/test_framework/script_util.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py8
-rwxr-xr-xtest/functional/test_framework/test_node.py2
-rw-r--r--test/functional/test_framework/util.py9
-rw-r--r--test/functional/test_framework/wallet.py2
-rwxr-xr-xtest/functional/test_framework/wallet_util.py2
-rwxr-xr-xtest/functional/test_runner.py5
-rwxr-xr-xtest/functional/tool_wallet.py9
-rwxr-xr-xtest/functional/wallet_abandonconflict.py3
-rwxr-xr-xtest/functional/wallet_address_types.py46
-rwxr-xr-xtest/functional/wallet_avoidreuse.py12
-rwxr-xr-xtest/functional/wallet_backup.py8
-rwxr-xr-xtest/functional/wallet_balance.py8
-rwxr-xr-xtest/functional/wallet_basic.py3
-rwxr-xr-xtest/functional/wallet_bumpfee.py12
-rwxr-xr-xtest/functional/wallet_coinbase_category.py2
-rwxr-xr-xtest/functional/wallet_create_tx.py2
-rwxr-xr-xtest/functional/wallet_createwallet.py4
-rwxr-xr-xtest/functional/wallet_descriptor.py8
-rwxr-xr-xtest/functional/wallet_disable.py2
-rwxr-xr-xtest/functional/wallet_dump.py2
-rwxr-xr-xtest/functional/wallet_fallbackfee.py2
-rwxr-xr-xtest/functional/wallet_groups.py25
-rwxr-xr-xtest/functional/wallet_hd.py6
-rwxr-xr-xtest/functional/wallet_import_rescan.py3
-rwxr-xr-xtest/functional/wallet_importdescriptors.py10
-rwxr-xr-xtest/functional/wallet_importmulti.py2
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py4
-rwxr-xr-xtest/functional/wallet_keypool.py10
-rwxr-xr-xtest/functional/wallet_keypool_topup.py3
-rwxr-xr-xtest/functional/wallet_labels.py2
-rwxr-xr-xtest/functional/wallet_listdescriptors.py6
-rwxr-xr-xtest/functional/wallet_listreceivedby.py7
-rwxr-xr-xtest/functional/wallet_listsinceblock.py4
-rwxr-xr-xtest/functional/wallet_listtransactions.py3
-rwxr-xr-xtest/functional/wallet_multisig_descriptor_psbt.py3
-rwxr-xr-xtest/functional/wallet_multiwallet.py2
-rwxr-xr-xtest/functional/wallet_orphanedreward.py3
-rwxr-xr-xtest/functional/wallet_reorgsrestore.py3
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py2
-rwxr-xr-xtest/functional/wallet_send.py5
-rwxr-xr-xtest/functional/wallet_signer.py3
-rwxr-xr-xtest/functional/wallet_signmessagewithaddress.py2
-rwxr-xr-xtest/functional/wallet_taproot.py24
-rwxr-xr-xtest/functional/wallet_transactiontime_rescan.py2
-rwxr-xr-xtest/functional/wallet_txn_clone.py3
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py3
-rwxr-xr-xtest/functional/wallet_upgradewallet.py2
-rwxr-xr-xtest/functional/wallet_watchonly.py2
-rwxr-xr-xtest/fuzz/test_runner.py2
-rwxr-xr-xtest/get_previous_releases.py2
-rwxr-xr-xtest/lint/commit-script-check.sh2
-rwxr-xr-xtest/lint/extended-lint-cppcheck.sh2
-rwxr-xr-xtest/lint/lint-circular-dependencies.sh2
-rwxr-xr-xtest/lint/lint-include-guards.sh2
-rwxr-xr-xtest/lint/lint-includes.sh2
-rwxr-xr-xtest/lint/lint-locale-dependence.sh5
-rwxr-xr-xtest/lint/lint-logs.sh2
-rwxr-xr-xtest/lint/lint-python.sh2
-rwxr-xr-xtest/lint/lint-shell.sh2
-rwxr-xr-xtest/lint/lint-spelling.sh2
-rwxr-xr-xtest/lint/lint-whitespace.sh2
-rw-r--r--test/sanitizer_suppressions/ubsan3
341 files changed, 3848 insertions, 1533 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index ed65510293..460906817e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -51,10 +51,6 @@ global_task_template: &GLOBAL_TASK_TEMPLATE
<< : *BASE_TEMPLATE
<< : *MAIN_TEMPLATE
-depends_sdk_cache_template: &DEPENDS_SDK_CACHE_TEMPLATE
- depends_sdk_cache:
- folder: "depends/sdk-sources"
-
compute_credits_template: &CREDITS_TEMPLATE
# https://cirrus-ci.org/pricing/#compute-credits
# Only use credits for pull requests to the main repo
@@ -208,10 +204,10 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_qt5.sh"
task:
- name: '[depends, sanitizers: thread (TSan), no gui] [hirsute]'
+ name: '[TSan, depends, no gui] [jammy]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:hirsute
+ image: ubuntu:jammy
cpu: 6 # Increase CPU and Memory to avoid timeout
memory: 24G
env:
@@ -220,7 +216,7 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_tsan.sh"
task:
- name: '[depends, sanitizers: memory (MSan)] [focal]'
+ name: '[MSan, depends] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
image: ubuntu:focal
@@ -229,16 +225,16 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_msan.sh"
task:
- name: '[no depends, sanitizers: address/leak (ASan + LSan) + undefined (UBSan) + integer] [hirsute]'
+ name: '[ASan + LSan + UBSan + integer, no depends] [jammy]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:hirsute
+ image: ubuntu:jammy
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
task:
- name: '[no depends, sanitizers: fuzzer,address,undefined,integer] [focal]'
+ name: '[fuzzer,address,undefined,integer, no depends] [focal]'
only_if: $CIRRUS_BRANCH == $CIRRUS_DEFAULT_BRANCH || $CIRRUS_BASE_BRANCH == $CIRRUS_DEFAULT_BRANCH
<< : *GLOBAL_TASK_TEMPLATE
container:
@@ -273,18 +269,22 @@ task:
task:
name: 'macOS 10.15 [gui, no tests] [focal]'
- << : *DEPENDS_SDK_CACHE_TEMPLATE
- << : *GLOBAL_TASK_TEMPLATE
+ << : *BASE_TEMPLATE
+ macos_sdk_cache:
+ folder: "depends/SDKs/$MACOS_SDK"
+ fingerprint_key: "$MACOS_SDK"
+ << : *MAIN_TEMPLATE
container:
image: ubuntu:focal
env:
+ MACOS_SDK: "Xcode-12.1-12A7403-extracted-SDK-with-libcxx-headers"
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
FILE_ENV: "./ci/test/00_setup_env_mac.sh"
task:
name: 'macOS 11 native [gui] [no depends]'
brew_install_script:
- - brew install boost libevent berkeley-db4 qt@5 miniupnpc libnatpmp ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt
+ - brew install boost libevent berkeley-db@4 qt@5 miniupnpc libnatpmp ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt
<< : *GLOBAL_TASK_TEMPLATE
osx_instance:
# Use latest image, but hardcode version to avoid silent upgrades (and breaks)
@@ -297,8 +297,10 @@ task:
task:
name: 'ARM64 Android APK [focal]'
- << : *DEPENDS_SDK_CACHE_TEMPLATE
<< : *BASE_TEMPLATE
+ android_sdk_cache:
+ folder: "depends/SDKs/android"
+ fingerprint_key: "ANDROID_API_LEVEL=28 ANDROID_BUILD_TOOLS_VERSION=28.0.3 ANDROID_NDK_VERSION=22.1.7171670"
depends_sources_cache:
folder: "depends/sources"
fingerprint_script: git rev-list -1 HEAD ./depends
diff --git a/build_msvc/libsecp256k1_config.h b/build_msvc/libsecp256k1_config.h
index 5978b9a0d9..57f2f144ff 100644
--- a/build_msvc/libsecp256k1_config.h
+++ b/build_msvc/libsecp256k1_config.h
@@ -29,4 +29,4 @@
#define ECMULT_GEN_PREC_BITS 4
#define ECMULT_WINDOW_SIZE 15
-#endif /* BITCOIN_LIBSECP256K1_CONFIG_H */
+#endif // BITCOIN_LIBSECP256K1_CONFIG_H
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index ab185b6e71..947c4b2891 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -8,7 +8,7 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_asan
export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libboost-system-dev libboost-filesystem-dev libboost-test-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
-export DOCKER_NAME_TAG=ubuntu:hirsute
+export DOCKER_NAME_TAG=ubuntu:22.04
export NO_DEPENDS=1
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index a5082bdaab..5d0880ff4a 100755
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_tsan
-export DOCKER_NAME_TAG=ubuntu:hirsute
+export DOCKER_NAME_TAG=ubuntu:22.04
export PACKAGES="clang llvm libc++abi-dev libc++-dev python3-zmq"
export DEP_OPTS="CC=clang CXX='clang++ -stdlib=libc++'"
export GOAL="install"
diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh
index 702b84d152..d8c23bd26b 100755
--- a/ci/test/05_before_script.sh
+++ b/ci/test/05_before_script.sh
@@ -15,17 +15,22 @@ fi
DOCKER_EXEC mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources"
-OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers.tar.gz"
-OSX_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${OSX_SDK_BASENAME}"
+OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers"
-if [ -n "$XCODE_VERSION" ] && [ ! -f "$OSX_SDK_PATH" ]; then
- DOCKER_EXEC curl --location --fail "${SDK_URL}/${OSX_SDK_BASENAME}" -o "$OSX_SDK_PATH"
+if [ -n "$XCODE_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${OSX_SDK_BASENAME}" ]; then
+ OSX_SDK_FILENAME="${OSX_SDK_BASENAME}.tar.gz"
+ OSX_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${OSX_SDK_FILENAME}"
+ if [ ! -f "$OSX_SDK_PATH" ]; then
+ DOCKER_EXEC curl --location --fail "${SDK_URL}/${OSX_SDK_FILENAME}" -o "$OSX_SDK_PATH"
+ fi
+ DOCKER_EXEC tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH"
fi
-if [ -n "$ANDROID_TOOLS_URL" ]; then
- ANDROID_TOOLS_PATH=$DEPENDS_DIR/sdk-sources/android-tools.zip
-
- DOCKER_EXEC curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH"
+if [ -n "$ANDROID_HOME" ] && [ ! -d "$ANDROID_HOME" ]; then
+ ANDROID_TOOLS_PATH=${DEPENDS_DIR}/sdk-sources/android-tools.zip
+ if [ ! -f "$ANDROID_TOOLS_PATH" ]; then
+ DOCKER_EXEC curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH"
+ fi
DOCKER_EXEC mkdir -p "${ANDROID_HOME}/cmdline-tools"
DOCKER_EXEC unzip -o "$ANDROID_TOOLS_PATH" -d "${ANDROID_HOME}/cmdline-tools"
DOCKER_EXEC "yes | ${ANDROID_HOME}/cmdline-tools/tools/bin/sdkmanager --install \"build-tools;${ANDROID_BUILD_TOOLS_VERSION}\" \"platform-tools\" \"platforms;android-${ANDROID_API_LEVEL}\" \"ndk;${ANDROID_NDK_VERSION}\""
@@ -38,9 +43,6 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
DOCKER_EXEC "contrib/install_db4.sh \$(pwd) --enable-umrw CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
fi
-if [ -n "$XCODE_VERSION" ] && [ -f "$OSX_SDK_PATH" ]; then
- DOCKER_EXEC tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH"
-fi
if [[ $HOST = *-mingw32 ]]; then
DOCKER_EXEC update-alternatives --set "${HOST}-g++" \$\(which "${HOST}-g++-posix"\)
fi
diff --git a/configure.ac b/configure.ac
index 2c6e762d6d..77f45e2133 100644
--- a/configure.ac
+++ b/configure.ac
@@ -323,6 +323,11 @@ AC_ARG_ENABLE([external-signer],
[use_external_signer=$enableval],
[use_external_signer=yes])
+AC_ARG_ENABLE([lto],
+ [AS_HELP_STRING([--enable-lto],[build using LTO (default is no)])],
+ [enable_lto=$enableval],
+ [enable_lto=no])
+
AC_LANG_PUSH([C++])
dnl Check for a flag to turn compiler warnings into errors. This is helpful for checks which may
@@ -370,6 +375,11 @@ if test "x$enable_debug" = xyes; then
AX_CHECK_COMPILE_FLAG([-ftrapv], [DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -ftrapv"], [], [$CXXFLAG_WERROR])
fi
+if test "x$enable_lto" = "xyes"; then
+ AX_CHECK_COMPILE_FLAG([-flto], [LTO_CXXFLAGS="$LTO_CXXFLAGS -flto"], [AC_MSG_ERROR([compile failed with -flto])], [$CXXFLAG_WERROR])
+ AX_CHECK_LINK_FLAG([-flto], [LTO_LDFLAGS="$LTO_LDFLAGS -flto"], [AC_MSG_ERROR([link failed with -flto])], [$CXXFLAG_WERROR])
+fi
+
if test x$use_sanitizers != x; then
dnl First check if the compiler accepts flags. If an incompatible pair like
dnl -fsanitize=address,thread is used here, this check will fail. This will also
@@ -581,7 +591,7 @@ CXXFLAGS="$TEMP_CXXFLAGS"
fi
-CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
+CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO"
AC_ARG_WITH([utils],
[AS_HELP_STRING([--with-utils],
@@ -683,8 +693,8 @@ case $host in
dnl It's safe to add these paths even if the functionality is disabled by
dnl the user (--without-wallet or --without-gui for example).
- if test "x$use_bdb" != xno && $BREW list --versions berkeley-db4 >/dev/null && test "x$BDB_CFLAGS" = "x" && test "x$BDB_LIBS" = "x"; then
- bdb_prefix=$($BREW --prefix berkeley-db4 2>/dev/null)
+ if test "x$use_bdb" != xno && $BREW list --versions berkeley-db@4 >/dev/null && test "x$BDB_CFLAGS" = "x" && test "x$BDB_LIBS" = "x"; then
+ bdb_prefix=$($BREW --prefix berkeley-db@4 2>/dev/null)
dnl This must precede the call to BITCOIN_FIND_BDB48 below.
BDB_CFLAGS="-I$bdb_prefix/include"
BDB_LIBS="-L$bdb_prefix/lib -ldb_cxx-4.8"
@@ -694,8 +704,8 @@ case $host in
export PKG_CONFIG_PATH="$($BREW --prefix sqlite3 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
- if $BREW list --versions qt5 >/dev/null; then
- export PKG_CONFIG_PATH="$($BREW --prefix qt5 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH"
+ if $BREW list --versions qt@5 >/dev/null; then
+ export PKG_CONFIG_PATH="$($BREW --prefix qt@5 2>/dev/null)/lib/pkgconfig:$PKG_CONFIG_PATH"
fi
case $host in
@@ -1044,9 +1054,6 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
[AC_MSG_RESULT([no])]
)
-dnl thread_local is currently disabled when building with glibc back compat.
-dnl Our minimum supported glibc is 2.17, however support for thread_local
-dnl did not arrive in glibc until 2.18.
if test "x$use_thread_local" = xyes || test "x$use_thread_local" = xauto; then
TEMP_LDFLAGS="$LDFLAGS"
LDFLAGS="$TEMP_LDFLAGS $PTHREAD_CFLAGS"
@@ -1826,6 +1833,8 @@ AC_SUBST(GPROF_LDFLAGS)
AC_SUBST(HARDENED_CXXFLAGS)
AC_SUBST(HARDENED_CPPFLAGS)
AC_SUBST(HARDENED_LDFLAGS)
+AC_SUBST(LTO_CXXFLAGS)
+AC_SUBST(LTO_LDFLAGS)
AC_SUBST(PIC_FLAGS)
AC_SUBST(PIE_FLAGS)
AC_SUBST(SANITIZER_CXXFLAGS)
@@ -1926,7 +1935,7 @@ if test x$bitcoin_enable_qt != xno; then
echo " with qr = $use_qr"
fi
echo " with zmq = $use_zmq"
-if test x$enable_fuzz == xno; then
+if test x$enable_fuzz = xno; then
echo " with test = $use_tests"
else
echo " with test = not building test_bitcoin because fuzzing is enabled"
@@ -1941,6 +1950,7 @@ echo " sanitizers = $use_sanitizers"
echo " debug enabled = $enable_debug"
echo " gprof enabled = $enable_gprof"
echo " werror = $enable_werror"
+echo " LTO = $enable_lto"
echo
echo " target os = $TARGET_OS"
echo " build os = $build_os"
@@ -1949,7 +1959,7 @@ echo " CC = $CC"
echo " CFLAGS = $PTHREAD_CFLAGS $CFLAGS"
echo " CPPFLAGS = $DEBUG_CPPFLAGS $HARDENED_CPPFLAGS $CPPFLAGS"
echo " CXX = $CXX"
-echo " CXXFLAGS = $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CXXFLAGS"
-echo " LDFLAGS = $PTHREAD_LIBS $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAGS"
+echo " CXXFLAGS = $LTO_CXXFLAGS $DEBUG_CXXFLAGS $HARDENED_CXXFLAGS $WARN_CXXFLAGS $NOWARN_CXXFLAGS $ERROR_CXXFLAGS $GPROF_CXXFLAGS $CXXFLAGS"
+echo " LDFLAGS = $LTO_LDFLAGS $PTHREAD_LIBS $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAGS"
echo " ARFLAGS = $ARFLAGS"
echo
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index ef421aebb1..677557b8fa 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -121,6 +121,21 @@ def check_PE_RELOC_SECTION(binary) -> bool:
'''Check for a reloc section. This is required for functional ASLR.'''
return binary.has_relocations
+def check_PE_control_flow(binary) -> bool:
+ '''
+ Check for control flow instrumentation
+ '''
+ main = binary.get_symbol('main').value
+
+ section_addr = binary.section_from_rva(main).virtual_address
+ virtual_address = binary.optional_header.imagebase + section_addr + main
+
+ content = binary.get_content_from_virtual_address(virtual_address, 4, lief.Binary.VA_TYPES.VA)
+
+ if content == [243, 15, 30, 250]: # endbr64
+ return True
+ return False
+
def check_MACHO_NOUNDEFS(binary) -> bool:
'''
Check for no undefined references.
@@ -177,7 +192,8 @@ CHECKS = {
('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
('NX', check_NX),
- ('RELOC_SECTION', check_PE_RELOC_SECTION)
+ ('RELOC_SECTION', check_PE_RELOC_SECTION),
+ ('CONTROL_FLOW', check_PE_control_flow),
],
'MACHO': [
('PIE', check_PIE),
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 136a9b70c1..15d4e729ac 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -19,35 +19,31 @@ import lief #type:ignore
# https://github.com/lief-project/LIEF/pull/562
LIEF_ELF_ARCH_RISCV = lief.ELF.ARCH(243)
-# Debian 8 (Jessie) EOL: 2020. https://wiki.debian.org/DebianReleases#Production_Releases
+# Debian 9 (Stretch) EOL: 2022. https://wiki.debian.org/DebianReleases#Production_Releases
#
-# - g++ version 4.9.2 (https://packages.debian.org/search?suite=jessie&arch=any&searchon=names&keywords=g%2B%2B)
-# - libc version 2.19 (https://packages.debian.org/search?suite=jessie&arch=any&searchon=names&keywords=libc6)
+# - g++ version 6.3.0 (https://packages.debian.org/search?suite=stretch&arch=any&searchon=names&keywords=g%2B%2B)
+# - libc version 2.24 (https://packages.debian.org/search?suite=stretch&arch=any&searchon=names&keywords=libc6)
#
-# Ubuntu 16.04 (Xenial) EOL: 2024. https://wiki.ubuntu.com/Releases
+# Ubuntu 16.04 (Xenial) EOL: 2026. https://wiki.ubuntu.com/Releases
#
-# - g++ version 5.3.1 (https://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=xenial&section=all)
-# - libc version 2.23.0 (https://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=xenial&section=all)
+# - g++ version 5.3.1
+# - libc version 2.23
#
-# CentOS 7 EOL: 2024. https://wiki.centos.org/FAQ/General
+# CentOS Stream 8 EOL: 2024. https://wiki.centos.org/About/Product
#
-# - g++ version 4.8.5 (http://mirror.centos.org/centos/7/os/x86_64/Packages/)
-# - libc version 2.17 (http://mirror.centos.org/centos/7/os/x86_64/Packages/)
-#
-# Taking the minimum of these as our target.
-#
-# According to GNU ABI document (https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to:
-# GCC 4.8.5: GCC_4.8.0
-# (glibc) GLIBC_2_17
+# - g++ version 8.5.0 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
+# - libc version 2.28 (http://mirror.centos.org/centos/8-stream/AppStream/x86_64/os/Packages/)
#
+# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html for more info.
+
MAX_VERSIONS = {
'GCC': (4,8,0),
'GLIBC': {
- lief.ELF.ARCH.i386: (2,17),
- lief.ELF.ARCH.x86_64: (2,17),
- lief.ELF.ARCH.ARM: (2,17),
- lief.ELF.ARCH.AARCH64:(2,17),
- lief.ELF.ARCH.PPC64: (2,17),
+ lief.ELF.ARCH.i386: (2,18),
+ lief.ELF.ARCH.x86_64: (2,18),
+ lief.ELF.ARCH.ARM: (2,18),
+ lief.ELF.ARCH.AARCH64:(2,18),
+ lief.ELF.ARCH.PPC64: (2,18),
LIEF_ELF_ARCH_RISCV: (2,27),
},
'LIBATOMIC': (1,0),
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index 0af7cdf5e6..01df863ac0 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -70,16 +70,18 @@ class TestSecurityChecks(unittest.TestCase):
write_testcode(source)
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--disable-reloc-section','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va','-no-pie','-fno-PIE']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION'))
+ (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA NX RELOC_SECTION CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--disable-reloc-section','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va','-no-pie','-fno-PIE']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION'))
+ (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA RELOC_SECTION CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va','-no-pie','-fno-PIE']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA'))
+ (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--no-dynamicbase','-Wl,--no-high-entropy-va','-pie','-fPIE']),
- (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA')) # -pie -fPIE does nothing unless --dynamicbase is also supplied
+ (1, executable+': failed PIE DYNAMIC_BASE HIGH_ENTROPY_VA CONTROL_FLOW')) # -pie -fPIE does nothing unless --dynamicbase is also supplied
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--no-high-entropy-va','-pie','-fPIE']),
- (1, executable+': failed HIGH_ENTROPY_VA'))
+ (1, executable+': failed HIGH_ENTROPY_VA CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE']),
+ (1, executable+': failed CONTROL_FLOW'))
+ self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--enable-reloc-section','-Wl,--dynamicbase','-Wl,--high-entropy-va','-pie','-fPIE', '-fcf-protection=full']),
(0, ''))
clean_files(source, executable)
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index 5246375fe3..d699e85026 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -44,7 +44,7 @@ class TestSymbolChecks(unittest.TestCase):
self.skipTest("test not available for RISC-V")
# nextup was introduced in GLIBC 2.24, so is newer than our supported
- # glibc (2.17), and available in our release build environment (2.24).
+ # glibc (2.18), and available in our release build environment (2.24).
with open(source, 'w', encoding="utf8") as f:
f.write('''
#define _GNU_SOURCE
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index e009f97c60..596d0ca1fb 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -238,9 +238,6 @@ mkdir -p "$OUTDIR"
# CONFIGFLAGS
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests --disable-fuzz-binary"
-case "$HOST" in
- *linux*) CONFIGFLAGS+=" --disable-threadlocal" ;;
-esac
# CFLAGS
HOST_CFLAGS="-O2 -g"
@@ -263,7 +260,7 @@ case "$HOST" in
*mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;;
esac
-# Using --no-tls-get-addr-optimize retains compatibility with glibc 2.17, by
+# Using --no-tls-get-addr-optimize retains compatibility with glibc 2.18, by
# avoiding a PowerPC64 optimisation available in glibc 2.22 and later.
# https://sourceware.org/binutils/docs-2.35/ld/PowerPC64-ELF64.html
case "$HOST" in
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
index 36a4ea08f6..81c88a2ae7 100755
--- a/contrib/install_db4.sh
+++ b/contrib/install_db4.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -62,6 +62,12 @@ http_get() {
sha256_check "${3}" "${2}"
}
+# Ensure the commands we use exist on the system
+if ! check_exists patch; then
+ echo "Command-line tool 'patch' not found. Install patch and try again."
+ exit 1
+fi
+
mkdir -p "${BDB_PREFIX}"
http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}"
tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX"
diff --git a/contrib/macdeploy/gen-sdk b/contrib/macdeploy/gen-sdk
index 457d8f5e64..ebef1d2db0 100755
--- a/contrib/macdeploy/gen-sdk
+++ b/contrib/macdeploy/gen-sdk
@@ -81,7 +81,7 @@ def run():
print("Creating output .tar.gz file...")
with out_sdktgz_path.open("wb") as fp:
- with gzip.GzipFile(fileobj=fp, compresslevel=9, mtime=0) as gzf:
+ with gzip.GzipFile(fileobj=fp, mode='wb', compresslevel=9, mtime=0) as gzf:
with tarfile.open(mode="w", fileobj=gzf) as tarfp:
print("Adding MacOSX SDK {} files...".format(sdk_version))
tarfp_add_with_base_change(tarfp, sdk_dir, out_name)
diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md
index 1f93474fa0..b71ce2f34b 100644
--- a/contrib/tracing/README.md
+++ b/contrib/tracing/README.md
@@ -234,3 +234,62 @@ Histogram of block connection times in milliseconds (ms).
[16, 32) 9 | |
[32, 64) 4 | |
```
+
+### log_utxocache_flush.py
+
+A BCC Python script to log the cache and index flushes. Based on the
+`utxocache:flush` tracepoint.
+
+```bash
+$ python3 contrib/tracing/log_utxocache_flush.py ./src/bitcoind
+```
+
+```
+Logging utxocache flushes. Ctrl-C to end...
+Duration (µs) Mode Coins Count Memory Usage Prune Full Flush
+0 PERIODIC 28484 3929.87 kB False False
+1 PERIODIC 28485 3930.00 kB False False
+0 PERIODIC 28489 3930.51 kB False False
+1 PERIODIC 28490 3930.64 kB False False
+0 PERIODIC 28491 3930.77 kB False False
+0 PERIODIC 28491 3930.77 kB False False
+0 PERIODIC 28496 3931.41 kB False False
+1 PERIODIC 28496 3931.41 kB False False
+0 PERIODIC 28497 3931.54 kB False False
+1 PERIODIC 28497 3931.54 kB False False
+1 PERIODIC 28499 3931.79 kB False False
+.
+.
+.
+53788 ALWAYS 30076 4136.27 kB False False
+7463 ALWAYS 0 245.84 kB False False
+```
+
+### log_utxos.bt
+
+A `bpftrace` script to log information about the coins that are added, spent, or
+uncached from the UTXO set. Based on the `utxocache:add`, `utxocache:spend` and
+`utxocache:uncache` tracepoints.
+
+```bash
+$ bpftrace contrib/tracing/log_utxos.bt
+```
+
+It should produce an output similar to the following.
+
+```bash
+Attaching 4 probes...
+OP Outpoint Value Height Coinbase
+Added 6ba9ad857e1ef2eb2a2c94f06813c414c7ab273e3d6bd7ad64e000315a887e7c:1 10000 2094512 No
+Spent fa7dc4db56637a151f6649d8f26732956d1c5424c82aae400a83d02b2cc2c87b:0 182264897 2094512 No
+Added eeb2f099b1af6a2a12e6ddd2eeb16fc5968582241d7f08ba202d28b60ac264c7:0 10000 2094512 No
+Added eeb2f099b1af6a2a12e6ddd2eeb16fc5968582241d7f08ba202d28b60ac264c7:1 182254756 2094512 No
+Added a0c7f4ec9cccef2d89672a624a4e6c8237a17572efdd4679eea9e9ee70d2db04:0 10072679 2094513 Yes
+Spent 25e0df5cc1aeb1b78e6056bf403e5e8b7e41f138060ca0a50a50134df0549a5e:2 540 2094508 No
+Spent 42f383c04e09c26a2378272ec33aa0c1bf4883ca5ab739e8b7e06be5a5787d61:1 3848399 2007724 No
+Added f85e3b4b89270863a389395cc9a4123e417ab19384cef96533c6649abd6b0561:0 3788399 2094513 No
+Added f85e3b4b89270863a389395cc9a4123e417ab19384cef96533c6649abd6b0561:2 540 2094513 No
+Spent a05880b8c77971ed0b9f73062c7c4cdb0ff3856ab14cbf8bc481ed571cd34b83:1 5591281046 2094511 No
+Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:0 5589696005 2094513 No
+Added eb689865f7d957938978d6207918748f74e6aa074f47874724327089445b0960:1 1565556 2094513 No
+```
diff --git a/contrib/tracing/log_utxocache_flush.py b/contrib/tracing/log_utxocache_flush.py
new file mode 100755
index 0000000000..df27dc193a
--- /dev/null
+++ b/contrib/tracing/log_utxocache_flush.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+
+import sys
+import ctypes
+from bcc import BPF, USDT
+
+"""Example logging Bitcoin Core utxo set cache flushes utilizing
+ the utxocache:flush tracepoint."""
+
+# USAGE: ./contrib/tracing/log_utxocache_flush.py path/to/bitcoind
+
+# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
+# a sandboxed Linux kernel VM.
+program = """
+# include <uapi/linux/ptrace.h>
+struct data_t
+{
+ u64 duration;
+ u32 mode;
+ u64 coins_count;
+ u64 coins_mem_usage;
+ bool is_flush_prune;
+ bool is_full_flush;
+};
+
+// BPF perf buffer to push the data to user space.
+BPF_PERF_OUTPUT(flush);
+
+int trace_flush(struct pt_regs *ctx) {
+ struct data_t data = {};
+ bpf_usdt_readarg(1, ctx, &data.duration);
+ bpf_usdt_readarg(2, ctx, &data.mode);
+ bpf_usdt_readarg(3, ctx, &data.coins_count);
+ bpf_usdt_readarg(4, ctx, &data.coins_mem_usage);
+ bpf_usdt_readarg(5, ctx, &data.is_flush_prune);
+ bpf_usdt_readarg(5, ctx, &data.is_full_flush);
+ flush.perf_submit(ctx, &data, sizeof(data));
+ return 0;
+}
+"""
+
+FLUSH_MODES = [
+ 'NONE',
+ 'IF_NEEDED',
+ 'PERIODIC',
+ 'ALWAYS'
+]
+
+
+class Data(ctypes.Structure):
+ # define output data structure corresponding to struct data_t
+ _fields_ = [
+ ("duration", ctypes.c_uint64),
+ ("mode", ctypes.c_uint32),
+ ("coins_count", ctypes.c_uint64),
+ ("coins_mem_usage", ctypes.c_uint64),
+ ("is_flush_prune", ctypes.c_bool),
+ ("is_full_flush", ctypes.c_bool)
+ ]
+
+
+def print_event(event):
+ print("%-15d %-10s %-15d %-15s %-8s %-8s" % (
+ event.duration,
+ FLUSH_MODES[event.mode],
+ event.coins_count,
+ "%.2f kB" % (event.coins_mem_usage/1000),
+ event.is_flush_prune,
+ event.is_full_flush
+ ))
+
+
+def main(bitcoind_path):
+ bitcoind_with_usdts = USDT(path=str(bitcoind_path))
+
+ # attaching the trace functions defined in the BPF program
+ # to the tracepoints
+ bitcoind_with_usdts.enable_probe(
+ probe="flush", fn_name="trace_flush")
+ b = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])
+
+ def handle_flush(_, data, size):
+ """ Coins Flush handler.
+ Called each time coin caches and indexes are flushed."""
+ event = ctypes.cast(data, ctypes.POINTER(Data)).contents
+ print_event(event)
+
+ b["flush"].open_perf_buffer(handle_flush)
+ print("Logging utxocache flushes. Ctrl-C to end...")
+ print("%-15s %-10s %-15s %-15s %-8s %-8s" % ("Duration (µs)", "Mode",
+ "Coins Count", "Memory Usage",
+ "Prune", "Full Flush"))
+
+ while True:
+ try:
+ b.perf_buffer_poll()
+ except KeyboardInterrupt:
+ exit(0)
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("USAGE: ", sys.argv[0], "path/to/bitcoind")
+ exit(1)
+
+ path = sys.argv[1]
+ main(path)
diff --git a/contrib/tracing/log_utxos.bt b/contrib/tracing/log_utxos.bt
new file mode 100755
index 0000000000..0d47f3d62b
--- /dev/null
+++ b/contrib/tracing/log_utxos.bt
@@ -0,0 +1,86 @@
+#!/usr/bin/env bpftrace
+
+/*
+
+ USAGE:
+
+ bpftrace contrib/tracing/log_utxos.bt
+
+ This script requires a 'bitcoind' binary compiled with eBPF support and the
+ 'utxochache' tracepoints. By default, it's assumed that 'bitcoind' is
+ located in './src/bitcoind'. This can be modified in the script below.
+
+ NOTE: requires bpftrace v0.12.0 or above.
+*/
+
+BEGIN
+{
+ printf("%-7s %-71s %16s %7s %8s\n",
+ "OP", "Outpoint", "Value", "Height", "Coinbase");
+}
+
+/*
+ Attaches to the 'utxocache:add' tracepoint and prints additions to the UTXO set cache.
+*/
+usdt:./src/bitcoind:utxocache:add
+{
+ $txid = arg0;
+ $index = (uint32)arg1;
+ $height = (uint32)arg2;
+ $value = (int64)arg3;
+ $isCoinbase = arg4;
+
+ printf("Added ");
+ $p = $txid + 31;
+ unroll(32) {
+ $b = *(uint8*)$p;
+ printf("%02x", $b);
+ $p-=1;
+ }
+
+ printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" ));
+}
+
+/*
+ Attaches to the 'utxocache:spent' tracepoint and prints spents from the UTXO set cache.
+*/
+usdt:./src/bitcoind:utxocache:spent
+{
+ $txid = arg0;
+ $index = (uint32)arg1;
+ $height = (uint32)arg2;
+ $value = (int64)arg3;
+ $isCoinbase = arg4;
+
+ printf("Spent ");
+ $p = $txid + 31;
+ unroll(32) {
+ $b = *(uint8*)$p;
+ printf("%02x", $b);
+ $p-=1;
+ }
+
+ printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" ));
+}
+
+/*
+ Attaches to the 'utxocache:uncache' tracepoint and uncache UTXOs from the UTXO set cache.
+*/
+usdt:./src/bitcoind:utxocache:uncache
+{
+ $txid = arg0;
+ $index = (uint32)arg1;
+ $height = (uint32)arg2;
+ $value = (int64)arg3;
+ $isCoinbase = arg4;
+
+ printf("Uncache ");
+ $p = $txid + 31;
+ unroll(32) {
+ $b = *(uint8*)$p;
+ printf("%02x", $b);
+ $p-=1;
+ }
+
+ printf(":%-6d %16ld %7d %s\n", $index, $value, $height, ($isCoinbase ? "Yes" : "No" ));
+}
diff --git a/depends/README.md b/depends/README.md
index 15c82cddf2..5c00807473 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -41,7 +41,7 @@ Common `host-platform-triplet`s for cross compilation are:
- `i686-linux-android` for Android x86 32 bit
- `x86_64-linux-android` for Android x86 64 bit
-The paths are automatically configured and no other options are needed unless targeting [Android](#Android).
+The paths are automatically configured and no other options are needed unless targeting [Android](../doc/build-android.md).
### Install the required dependencies: Ubuntu & Debian
@@ -87,14 +87,6 @@ For linux S390X cross compilation:
sudo apt-get install g++-s390x-linux-gnu binutils-s390x-linux-gnu
-### Install the required dependencies: M1-based macOS
-
-To be able to build the `qt` package, ensure that Rosetta 2 is installed:
-
-```
-softwareupdate --install-rosetta
-```
-
### Dependency Options
The following can be set when running make: `make FOO=bar`
@@ -133,18 +125,6 @@ options will be passed to bitcoin's configure. In this case, `--disable-wallet`.
download-linux: run 'make download-linux' to fetch all sources needed for linux builds
-### Android
-
-Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level).
-In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) and `ANDROID_TOOLCHAIN_BIN` (path to toolchain binaries depending on the platform the build is being performed on) need to be set.
-
-API levels from 24 to 29 have been tested to work.
-
-If the build includes Qt, environment variables `ANDROID_SDK` and `ANDROID_NDK` need to be set as well but can otherwise be omitted.
-This is an example command for a default build with no disabled dependencies:
-
- ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin
-
### Other documentation
- [description.md](description.md): General description of the depends system
diff --git a/depends/config.site.in b/depends/config.site.in
index 5cf107f19b..87d0011b1c 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -72,7 +72,6 @@ fi
if test "@host_os@" = darwin; then
BREW=no
- PORT=no
fi
PATH="${depends_prefix}/native/bin:${PATH}"
diff --git a/depends/hosts/android.mk b/depends/hosts/android.mk
index eabd84bbbe..fcc1c4f5c3 100644
--- a/depends/hosts/android.mk
+++ b/depends/hosts/android.mk
@@ -1,12 +1,11 @@
ifeq ($(HOST),armv7a-linux-android)
-android_AR=$(ANDROID_TOOLCHAIN_BIN)/arm-linux-androideabi-ar
android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)eabi$(ANDROID_API_LEVEL)-clang++
android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)eabi$(ANDROID_API_LEVEL)-clang
-android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/arm-linux-androideabi-ranlib
else
-android_AR=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ar
android_CXX=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang++
android_CC=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)$(ANDROID_API_LEVEL)-clang
-android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ranlib
endif
+android_AR=$(ANDROID_TOOLCHAIN_BIN)/llvm-ar
+android_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/llvm-ranlib
+
android_cmake_system=Android
diff --git a/depends/packages.md b/depends/packages.md
index 7ed20ea129..4158b46d28 100644
--- a/depends/packages.md
+++ b/depends/packages.md
@@ -178,8 +178,8 @@ not sufficient to just say `libprimary`.
For us, it's much easier to just link a static `libsecondary` into a shared
`libprimary`. Especially because in our case, we are linking against a dummy
`libprimary` anyway that we'll throw away. We don't care if the end-user has a
-static or dynamic `libseconday`, that's not our concern. With a static
-`libseconday`, when we need to link `libprimary` into our executable, there's no
+static or dynamic `libsecondary`, that's not our concern. With a static
+`libsecondary`, when we need to link `libprimary` into our executable, there's no
dependency chain to worry about as `libprimary` has all the symbols.
## Build targets:
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index ab29742b55..5fe2b2bbb8 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -27,6 +27,7 @@ $(package)_cxxflags+=-std=c++17
$(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_android=-fPIC
$(package)_cxxflags_x86_64_darwin=-fcf-protection=full
+$(package)_cxxflags_mingw32=-fcf-protection=full
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index 12e0494ad4..ea110b1653 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -10,9 +10,10 @@ $(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+= no_sdk_version_check.patch
+$(package)_patches += dont_hardcode_x86_64.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)_qttranslations_file_name=qttranslations-$($(package)_suffix)
$(package)_qttranslations_sha256_hash=577b0668a777eb2b451c61e8d026d79285371597ce9df06b6dee6c814164b7c3
@@ -127,8 +128,10 @@ $(package)_config_opts_darwin += -device-option MAC_TARGET=$(host)
$(package)_config_opts_darwin += -device-option XCODE_VERSION=$(XCODE_VERSION)
endif
-# for macOS on Apple Silicon (ARM) see https://bugreports.qt.io/browse/QTBUG-85279
+ifneq ($(build_arch),$(host_arch))
$(package)_config_opts_aarch64_darwin += -device-option QMAKE_APPLE_DEVICE_ARCHS=arm64
+$(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 += -no-xcb-xlib
@@ -228,10 +231,11 @@ define $(package)_preprocess_cmds
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)/no_sdk_version_check.patch && \
+ patch -p1 -i $($(package)_patch_dir)/dont_hardcode_x86_64.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 && \
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 && \
@@ -248,6 +252,7 @@ endef
define $(package)_config_cmds
export PKG_CONFIG_SYSROOT_DIR=/ && \
export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
+ export QT_MAC_SDK_NO_VERSION_CHECK=1 && \
cd qtbase && \
./configure -top-level $($(package)_config_opts)
endef
diff --git a/depends/patches/qt/dont_hardcode_x86_64.patch b/depends/patches/qt/dont_hardcode_x86_64.patch
new file mode 100644
index 0000000000..0e1ca6acda
--- /dev/null
+++ b/depends/patches/qt/dont_hardcode_x86_64.patch
@@ -0,0 +1,123 @@
+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/fix_montery_include.patch b/depends/patches/qt/fix_montery_include.patch
new file mode 100644
index 0000000000..38b700addf
--- /dev/null
+++ b/depends/patches/qt/fix_montery_include.patch
@@ -0,0 +1,21 @@
+From dece6f5840463ae2ddf927d65eb1b3680e34a547
+From: Øystein Heskestad <oystein.heskestad@qt.io>
+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 <CoreGraphics/CGColorSpace.h>
+ #include <qpa/qplatformgraphicsbuffer.h>
+ #include <private/qcore_mac_p.h>
diff --git a/depends/patches/qt/mac-qmake.conf b/depends/patches/qt/mac-qmake.conf
index 190ab7a160..e4bfaa1463 100644
--- a/depends/patches/qt/mac-qmake.conf
+++ b/depends/patches/qt/mac-qmake.conf
@@ -13,7 +13,6 @@ QMAKE_MAC_SDK.macosx.Path = $${MAC_SDK_PATH}
QMAKE_MAC_SDK.macosx.platform_name = macosx
QMAKE_MAC_SDK.macosx.SDKVersion = $${MAC_SDK_VERSION}
QMAKE_MAC_SDK.macosx.PlatformPath = /phony
-QMAKE_APPLE_DEVICE_ARCHS=x86_64
!host_build: QMAKE_CFLAGS += -target $${MAC_TARGET}
!host_build: QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_CFLAGS
!host_build: QMAKE_CXXFLAGS += $$QMAKE_CFLAGS
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 <fanquake@gmail.com>
-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/doc/build-android.md b/doc/build-android.md
index 7a8a9e6a65..6d25e72fde 100644
--- a/doc/build-android.md
+++ b/doc/build-android.md
@@ -3,9 +3,22 @@ ANDROID BUILD NOTES
This guide describes how to build and package the `bitcoin-qt` GUI for Android on Linux and macOS.
-## Preparation
-You will need to get the Android NDK and build dependencies for Android as described in [depends/README.md](../depends/README.md).
+## Dependencies
+
+Before proceeding with an Android build one needs to get the [Android SDK](https://developer.android.com/studio) and use the "SDK Manager" tool to download the NDK and one or more "Platform packages" (these are Android versions and have a corresponding API level).
+
+The minimum supported Android NDK version is [r21](https://github.com/android/ndk/wiki/Changelog-r21).
+
+In order to build `ANDROID_API_LEVEL` (API level corresponding to the Android version targeted, e.g. Android 9.0 Pie is 28 and its "Platform package" needs to be available) and `ANDROID_TOOLCHAIN_BIN` (path to toolchain binaries depending on the platform the build is being performed on) need to be set.
+
+API levels from 24 to 29 have been tested to work.
+
+If the build includes Qt, environment variables `ANDROID_SDK` and `ANDROID_NDK` need to be set as well but can otherwise be omitted.
+This is an example command for a default build with no disabled dependencies:
+
+ ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin
+
## Building and packaging
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 0c1fd6ba98..6ccb53f6b3 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -12,7 +12,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| fontconfig | [2.12.1](https://www.freedesktop.org/software/fontconfig/release/) | | No | Yes | |
| FreeType | [2.7.1](https://download.savannah.gnu.org/releases/freetype) | | No | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) (Android only) |
| GCC | | [8.1](https://gcc.gnu.org/) (C++17 & std::filesystem support) | | | |
-| glibc | | [2.17](https://www.gnu.org/software/libc/) | | | | |
+| glibc | | [2.18](https://www.gnu.org/software/libc/) | | | | |
| HarfBuzz-NG | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
| libevent | [2.1.12-stable](https://github.com/libevent/libevent/releases) | [2.0.21](https://github.com/bitcoin/bitcoin/pull/18676) | No | | |
| libnatpmp | git commit [4536032...](https://github.com/miniupnp/libnatpmp/tree/4536032ae32268a45c073a4d5e91bbab4534773a) | | No | | |
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 7ff1d36442..1888897856 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -1254,6 +1254,12 @@ A few guidelines for introducing and reviewing new RPC interfaces:
- *Rationale*: User-facing consistency.
+- Use `fs::path::u8string()` and `fs::u8path()` functions when converting path
+ to JSON strings, not `fs::PathToString` and `fs::PathFromString`
+
+ - *Rationale*: JSON strings are Unicode strings, not byte strings, and
+ RFC8259 requires JSON to be encoded as UTF-8.
+
Internal interface guidelines
-----------------------------
diff --git a/doc/release-notes-16807.md b/doc/release-notes-16807.md
new file mode 100644
index 0000000000..5027550a99
--- /dev/null
+++ b/doc/release-notes-16807.md
@@ -0,0 +1,6 @@
+Updated RPCs
+------------
+
+- The `validateaddress` RPC now optionally returns an `error_locations` array, with the indices of
+invalid characters in the address. For example, this will return the locations of up to two Bech32
+errors. \ No newline at end of file
diff --git a/doc/release-notes.md b/doc/release-notes.md
index b460cd3eb2..4483dee1dd 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -127,6 +127,10 @@ Updated settings
mean `-persistmempool=1`. Passing `-persistmempool=0`, `-persistmempool=1`
and `-nopersistmempool` is unaffected. (#23061)
+- `-maxuploadtarget` now allows human readable byte units [k|K|m|M|g|G|t|T].
+ E.g. `-maxuploadtarget=500g`. No whitespace, +- or fractions allowed.
+ Default is `M` if no suffix provided. (#23249)
+
Tools and Utilities
-------------------
diff --git a/doc/tracing.md b/doc/tracing.md
index 57104c43a0..5b9ba09c2f 100644
--- a/doc/tracing.md
+++ b/doc/tracing.md
@@ -108,6 +108,55 @@ Arguments passed:
5. SigOps in the Block (excluding coinbase SigOps) `uint64`
6. Time it took to connect the Block in microseconds (µs) as `uint64`
+### Context `utxocache`
+
+#### Tracepoint `utxocache:flush`
+
+Is called *after* the caches and indexes are flushed depending on the mode
+`CChainState::FlushStateToDisk` is called with.
+
+Arguments passed:
+1. Duration in microseconds as `int64`
+2. Flush state mode as `uint32`. It's an enumerator class with values `0`
+ (`NONE`), `1` (`IF_NEEDED`), `2` (`PERIODIC`), `3` (`ALWAYS`)
+3. Number of coins flushed as `uint64`
+4. Memory usage in bytes as `uint64`
+5. If the flush was pruned as `bool`
+6. If it was full flush as `bool`
+
+#### Tracepoint `utxocache:add`
+
+It is called when a new coin is added to the UTXO cache.
+
+Arguments passed:
+1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
+2. Output index as `uint32`
+3. Block height the coin was added to the UTXO-set as `uint32`
+4. Value of the coin as `int64`
+5. If the coin is a coinbase as `bool`
+
+#### Tracepoint `utxocache:spent`
+
+It is called when a coin is spent from the UTXO cache.
+
+Arguments passed:
+1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
+2. Output index as `uint32`
+3. Block height the coin was spent, as `uint32`
+4. Value of the coin as `int64`
+5. If the coin is a coinbase as `bool`
+
+#### Tracepoint `utxocache:uncache`
+
+It is called when the UTXO with the given outpoint is removed from the cache.
+
+Arguments passed:
+1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
+2. Output index as `uint32`
+3. Block height the coin was uncached, as `uint32`
+4. Value of the coin as `int64`
+. If the coin is a coinbase as `bool`
+
## Adding tracepoints to Bitcoin Core
To add a new tracepoint, `#include <util/trace.h>` in the compilation unit where
diff --git a/src/Makefile.am b/src/Makefile.am
index 6cfd5a9050..6846eb9693 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,8 +8,8 @@ print-%: FORCE
DIST_SUBDIRS = secp256k1
-AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
-AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS)
+AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) $(LTO_LDFLAGS)
+AM_CXXFLAGS = $(DEBUG_CXXFLAGS) $(HARDENED_CXXFLAGS) $(WARN_CXXFLAGS) $(NOWARN_CXXFLAGS) $(ERROR_CXXFLAGS) $(GPROF_CXXFLAGS) $(SANITIZER_CXXFLAGS) $(LTO_CXXFLAGS)
AM_CPPFLAGS = $(DEBUG_CPPFLAGS) $(HARDENED_CPPFLAGS)
AM_LIBTOOLFLAGS = --preserve-dup-deps
PTHREAD_FLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
@@ -166,8 +166,6 @@ BITCOIN_CORE_H = \
mapport.h \
memusage.h \
merkleblock.h \
- miner.h \
- minisketchwrapper.h \
net.h \
net_permissions.h \
net_processing.h \
@@ -179,6 +177,8 @@ BITCOIN_CORE_H = \
node/coin.h \
node/coinstats.h \
node/context.h \
+ node/miner.h \
+ node/minisketchwrapper.h \
node/psbt.h \
node/transaction.h \
node/ui_interface.h \
@@ -246,6 +246,7 @@ BITCOIN_CORE_H = \
util/macros.h \
util/message.h \
util/moneystr.h \
+ util/overloaded.h \
util/rbf.h \
util/readwritefile.h \
util/serfloat.h \
@@ -334,8 +335,6 @@ libbitcoin_server_a_SOURCES = \
index/txindex.cpp \
init.cpp \
mapport.cpp \
- miner.cpp \
- minisketchwrapper.cpp \
net.cpp \
net_processing.cpp \
node/blockstorage.cpp \
@@ -343,6 +342,8 @@ libbitcoin_server_a_SOURCES = \
node/coinstats.cpp \
node/context.cpp \
node/interfaces.cpp \
+ node/miner.cpp \
+ node/minisketchwrapper.cpp \
node/psbt.cpp \
node/transaction.cpp \
node/ui_interface.cpp \
@@ -408,6 +409,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/interfaces.cpp \
wallet/load.cpp \
wallet/receive.cpp \
+ wallet/rpc/signmessage.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/scriptpubkeyman.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index da4b85665f..06d195aaaf 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -16,6 +16,7 @@ FUZZ_BINARY=test/fuzz/fuzz$(EXEEXT)
JSON_TEST_FILES = \
test/data/script_tests.json \
+ test/data/bip341_wallet_vectors.json \
test/data/base58_encode_decode.json \
test/data/blockfilters.json \
test/data/key_io_valid.json \
@@ -50,6 +51,7 @@ FUZZ_SUITE_LD_COMMON = \
$(BOOST_LIBS) \
$(LIBMEMENV) \
$(LIBSECP256K1) \
+ $(MINISKETCH_LIBS) \
$(EVENT_LIBS) \
$(EVENT_PTHREADS_LIBS)
@@ -63,11 +65,10 @@ endif
# test_bitcoin binary #
BITCOIN_TESTS =\
- test/arith_uint256_tests.cpp \
- test/scriptnum10.h \
test/addrman_tests.cpp \
- test/amount_tests.cpp \
test/allocator_tests.cpp \
+ test/amount_tests.cpp \
+ test/arith_uint256_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
@@ -75,8 +76,8 @@ BITCOIN_TESTS =\
test/bip32_tests.cpp \
test/blockchain_tests.cpp \
test/blockencodings_tests.cpp \
- test/blockfilter_tests.cpp \
test/blockfilter_index_tests.cpp \
+ test/blockfilter_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
@@ -86,6 +87,7 @@ BITCOIN_TESTS =\
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/cuckoocache_tests.cpp \
+ test/dbwrapper_tests.cpp \
test/denialofservice_tests.cpp \
test/descriptor_tests.cpp \
test/flatfile_tests.cpp \
@@ -97,13 +99,11 @@ BITCOIN_TESTS =\
test/key_io_tests.cpp \
test/key_tests.cpp \
test/logging_tests.cpp \
- test/dbwrapper_tests.cpp \
- test/validation_tests.cpp \
test/mempool_tests.cpp \
test/merkle_tests.cpp \
test/merkleblock_tests.cpp \
- test/minisketch_tests.cpp \
test/miner_tests.cpp \
+ test/minisketch_tests.cpp \
test/multisig_tests.cpp \
test/net_peer_eviction_tests.cpp \
test/net_tests.cpp \
@@ -123,6 +123,7 @@ BITCOIN_TESTS =\
test/script_parse_tests.cpp \
test/script_standard_tests.cpp \
test/script_tests.cpp \
+ test/scriptnum10.h \
test/scriptnum_tests.cpp \
test/serfloat_tests.cpp \
test/serialize_tests.cpp \
@@ -134,21 +135,22 @@ BITCOIN_TESTS =\
test/streams_tests.cpp \
test/sync_tests.cpp \
test/system_tests.cpp \
- test/util_threadnames_tests.cpp \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/txindex_tests.cpp \
- test/txrequest_tests.cpp \
test/txpackage_tests.cpp \
+ test/txrequest_tests.cpp \
test/txvalidation_tests.cpp \
test/txvalidationcache_tests.cpp \
test/uint256_tests.cpp \
test/util_tests.cpp \
+ test/util_threadnames_tests.cpp \
test/validation_block_tests.cpp \
test/validation_chainstate_tests.cpp \
test/validation_chainstatemanager_tests.cpp \
test/validation_flush_tests.cpp \
+ test/validation_tests.cpp \
test/validationinterface_tests.cpp \
test/versionbits_tests.cpp
@@ -159,6 +161,7 @@ BITCOIN_TESTS += \
wallet/test/wallet_tests.cpp \
wallet/test/walletdb_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
+ wallet/test/wallet_transaction_tests.cpp \
wallet/test/coinselector_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
@@ -258,6 +261,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/locale.cpp \
test/fuzz/merkleblock.cpp \
test/fuzz/message.cpp \
+ test/fuzz/minisketch.cpp \
test/fuzz/muhash.cpp \
test/fuzz/multiplication_overflow.cpp \
test/fuzz/net.cpp \
diff --git a/src/banman.h b/src/banman.h
index f495dab49d..6cb6304744 100644
--- a/src/banman.h
+++ b/src/banman.h
@@ -95,4 +95,4 @@ private:
CRollingBloomFilter m_discouraged GUARDED_BY(m_cs_banned) {50000, 0.000001};
};
-#endif
+#endif // BITCOIN_BANMAN_H
diff --git a/src/bech32.cpp b/src/bech32.cpp
index 9da2488ef2..ea44480a6c 100644
--- a/src/bech32.cpp
+++ b/src/bech32.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2017, 2021 Pieter Wuille
+// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -30,6 +31,183 @@ const int8_t CHARSET_REV[128] = {
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
+// We work with the finite field GF(1024) defined as a degree 2 extension of the base field GF(32)
+// The defining polynomial of the extension is x^2 + 9x + 23
+// Let (e) be a primitive element of GF(1024), that is, a generator of the field.
+// Every non-zero element of the field can then be represented as (e)^k for some power k.
+// The array GF1024_EXP contains all these powers of (e) - GF1024_EXP[k] = (e)^k in GF(1024).
+// Conversely, GF1024_LOG contains the discrete logarithms of these powers, so
+// GF1024_LOG[GF1024_EXP[k]] == k
+// Each element v of GF(1024) is encoded as a 10 bit integer in the following way:
+// v = v1 || v0 where v0, v1 are 5-bit integers (elements of GF(32)).
+//
+// The element (e) is encoded as 9 || 15. Given (v), we compute (e)*(v) by multiplying in the following way:
+// v0' = 27*v1 + 15*v0
+// v1' = 6*v1 + 9*v0
+// e*v = v1' || v0'
+//
+// The following sage code can be used to reproduce both _EXP and _LOG arrays
+// GF1024_LOG = [-1] + [0] * 1023
+// GF1024_EXP = [1] * 1024
+// v = 1
+// for i in range(1, 1023):
+// v0 = v & 31
+// v1 = v >> 5
+// v0n = F.fetch_int(27)*F.fetch_int(v1) + F.fetch_int(15)*F.fetch_int(v0)
+// v1n = F.fetch_int(6)*F.fetch_int(v1) + F.fetch_int(9)*F.fetch_int(v0)
+// v = v1n.integer_representation() << 5 | v0n.integer_representation()
+// GF1024_EXP[i] = v
+// GF1024_LOG[v] = i
+
+const int16_t GF1024_EXP[] = {
+ 1, 303, 635, 446, 997, 640, 121, 142, 959, 420, 350, 438, 166, 39, 543,
+ 335, 831, 691, 117, 632, 719, 97, 107, 374, 558, 797, 54, 150, 858, 877,
+ 724, 1013, 294, 23, 354, 61, 164, 633, 992, 538, 469, 659, 174, 868, 184,
+ 809, 766, 563, 866, 851, 257, 520, 45, 770, 535, 524, 408, 213, 436, 760,
+ 472, 330, 933, 799, 616, 361, 15, 391, 756, 814, 58, 608, 554, 680, 993,
+ 821, 942, 813, 843, 484, 193, 935, 321, 919, 572, 741, 423, 559, 562,
+ 589, 296, 191, 493, 685, 891, 665, 435, 60, 395, 2, 606, 511, 853, 746,
+ 32, 219, 284, 631, 840, 661, 837, 332, 78, 311, 670, 887, 111, 195, 505,
+ 190, 194, 214, 709, 380, 819, 69, 261, 957, 1018, 161, 739, 588, 7, 708,
+ 83, 328, 507, 736, 317, 899, 47, 348, 1000, 345, 882, 245, 367, 996, 943,
+ 514, 304, 90, 804, 295, 312, 793, 387, 833, 249, 921, 660, 618, 823, 496,
+ 722, 30, 782, 225, 892, 93, 480, 372, 112, 738, 867, 636, 890, 950, 968,
+ 386, 622, 642, 551, 369, 234, 846, 382, 365, 442, 592, 343, 986, 122,
+ 1023, 59, 847, 81, 790, 4, 437, 983, 931, 244, 64, 415, 529, 487, 944,
+ 35, 938, 664, 156, 583, 53, 999, 222, 390, 987, 341, 388, 389, 170, 721,
+ 879, 138, 522, 627, 765, 322, 230, 440, 14, 168, 143, 656, 991, 224, 595,
+ 550, 94, 657, 752, 667, 1005, 451, 734, 744, 638, 292, 585, 157, 872,
+ 590, 601, 827, 774, 930, 475, 571, 33, 500, 871, 969, 173, 21, 828, 450,
+ 1009, 147, 960, 705, 201, 228, 998, 497, 1021, 613, 688, 772, 508, 36,
+ 366, 715, 468, 956, 725, 730, 861, 425, 647, 701, 221, 759, 95, 958, 139,
+ 805, 8, 835, 679, 614, 449, 128, 791, 299, 974, 617, 70, 628, 57, 273,
+ 430, 67, 750, 405, 780, 703, 643, 776, 778, 340, 171, 1022, 276, 308,
+ 495, 243, 644, 460, 857, 28, 336, 286, 41, 695, 448, 431, 364, 149, 43,
+ 233, 63, 762, 902, 181, 240, 501, 584, 434, 275, 1008, 444, 443, 895,
+ 812, 612, 927, 383, 66, 961, 1006, 690, 346, 3, 881, 900, 747, 271, 672,
+ 162, 402, 456, 748, 971, 755, 490, 105, 808, 977, 72, 732, 182, 897, 625,
+ 163, 189, 947, 850, 46, 115, 403, 231, 151, 629, 278, 874, 16, 934, 110,
+ 492, 898, 256, 807, 598, 700, 498, 140, 481, 91, 523, 860, 134, 252, 771,
+ 824, 119, 38, 816, 820, 641, 342, 757, 513, 577, 990, 463, 40, 920, 955,
+ 17, 649, 533, 82, 103, 896, 862, 728, 259, 86, 466, 87, 253, 556, 323,
+ 457, 963, 432, 845, 527, 745, 849, 863, 1015, 888, 488, 567, 727, 132,
+ 674, 764, 109, 669, 6, 1003, 552, 246, 542, 96, 324, 781, 912, 248, 694,
+ 239, 980, 210, 880, 683, 144, 177, 325, 546, 491, 326, 339, 623, 941, 92,
+ 207, 783, 462, 263, 483, 517, 1012, 9, 620, 220, 984, 548, 512, 878, 421,
+ 113, 973, 280, 962, 159, 310, 945, 268, 465, 806, 889, 199, 76, 873, 865,
+ 34, 645, 227, 290, 418, 693, 926, 80, 569, 639, 11, 50, 291, 141, 206,
+ 544, 949, 185, 518, 133, 909, 135, 467, 376, 646, 914, 678, 841, 954,
+ 318, 242, 939, 951, 743, 1017, 976, 359, 167, 264, 100, 241, 218, 51, 12,
+ 758, 368, 453, 309, 192, 648, 826, 553, 473, 101, 478, 673, 397, 1001,
+ 118, 265, 331, 650, 356, 982, 652, 655, 510, 634, 145, 414, 830, 924,
+ 526, 966, 298, 737, 18, 504, 401, 697, 360, 288, 1020, 842, 203, 698,
+ 537, 676, 279, 581, 619, 536, 907, 876, 1019, 398, 152, 1010, 994, 68,
+ 42, 454, 580, 836, 99, 565, 137, 379, 503, 22, 77, 582, 282, 412, 352,
+ 611, 347, 300, 266, 570, 270, 911, 729, 44, 557, 108, 946, 637, 597, 461,
+ 630, 615, 238, 763, 681, 718, 334, 528, 200, 459, 413, 79, 24, 229, 713,
+ 906, 579, 384, 48, 893, 370, 923, 202, 917, 98, 794, 754, 197, 530, 662,
+ 52, 712, 677, 56, 62, 981, 509, 267, 789, 885, 561, 316, 684, 596, 226,
+ 13, 985, 779, 123, 720, 576, 753, 948, 406, 125, 315, 104, 519, 426, 502,
+ 313, 566, 1016, 767, 796, 281, 749, 740, 136, 84, 908, 424, 936, 198,
+ 355, 274, 735, 967, 5, 154, 428, 541, 785, 704, 486, 671, 600, 532, 381,
+ 540, 574, 187, 88, 378, 216, 621, 499, 419, 922, 485, 494, 476, 255, 114,
+ 188, 668, 297, 400, 918, 787, 158, 25, 458, 178, 564, 422, 768, 73, 1011,
+ 717, 575, 404, 547, 196, 829, 237, 394, 301, 37, 65, 176, 106, 89, 85,
+ 675, 979, 534, 803, 995, 363, 593, 120, 417, 452, 26, 699, 822, 223, 169,
+ 416, 235, 609, 773, 211, 607, 208, 302, 852, 965, 603, 357, 761, 247,
+ 817, 539, 250, 232, 272, 129, 568, 848, 624, 396, 710, 525, 183, 686, 10,
+ 285, 856, 307, 811, 160, 972, 55, 441, 289, 723, 305, 373, 351, 153, 733,
+ 409, 506, 975, 838, 573, 970, 988, 913, 471, 205, 337, 49, 594, 777, 549,
+ 815, 277, 27, 916, 333, 353, 844, 800, 146, 751, 186, 375, 769, 358, 392,
+ 883, 474, 788, 602, 74, 130, 329, 212, 155, 131, 102, 687, 293, 870, 742,
+ 726, 427, 217, 834, 904, 29, 127, 869, 407, 338, 832, 470, 482, 810, 399,
+ 439, 393, 604, 929, 682, 447, 714, 251, 455, 875, 319, 477, 464, 521,
+ 258, 377, 937, 489, 792, 172, 314, 327, 124, 20, 531, 953, 591, 886, 320,
+ 696, 71, 859, 578, 175, 587, 707, 663, 283, 179, 795, 989, 702, 940, 371,
+ 692, 689, 555, 903, 410, 651, 75, 429, 818, 362, 894, 515, 31, 545, 666,
+ 706, 952, 864, 269, 254, 349, 711, 802, 716, 784, 1007, 925, 801, 445,
+ 148, 260, 658, 385, 287, 262, 204, 126, 586, 1004, 236, 165, 854, 411,
+ 932, 560, 19, 215, 1002, 775, 653, 928, 901, 964, 884, 798, 839, 786,
+ 433, 610, 116, 855, 180, 479, 910, 1014, 599, 915, 905, 306, 516, 731,
+ 626, 978, 825, 344, 605, 654, 209
+};
+// As above, GF1024_EXP contains all elements of GF(1024) except 0
+static_assert(std::size(GF1024_EXP) == 1023, "GF1024_EXP length should be 1023");
+
+const int16_t GF1024_LOG[] = {
+ -1, 0, 99, 363, 198, 726, 462, 132, 297, 495, 825, 528, 561, 693, 231,
+ 66, 396, 429, 594, 990, 924, 264, 627, 33, 660, 759, 792, 858, 330, 891,
+ 165, 957, 104, 259, 518, 208, 280, 776, 416, 13, 426, 333, 618, 339, 641,
+ 52, 388, 140, 666, 852, 529, 560, 678, 213, 26, 832, 681, 309, 70, 194,
+ 97, 35, 682, 341, 203, 777, 358, 312, 617, 125, 307, 931, 379, 765, 875,
+ 951, 515, 628, 112, 659, 525, 196, 432, 134, 717, 781, 438, 440, 740,
+ 780, 151, 408, 487, 169, 239, 293, 467, 21, 672, 622, 557, 571, 881, 433,
+ 704, 376, 779, 22, 643, 460, 398, 116, 172, 503, 751, 389, 1004, 18, 576,
+ 415, 789, 6, 192, 696, 923, 702, 981, 892, 302, 816, 876, 880, 457, 537,
+ 411, 539, 716, 624, 224, 295, 406, 531, 7, 233, 478, 586, 864, 268, 974,
+ 338, 27, 392, 614, 839, 727, 879, 211, 250, 758, 507, 830, 129, 369, 384,
+ 36, 985, 12, 555, 232, 796, 221, 321, 920, 263, 42, 934, 778, 479, 761,
+ 939, 1006, 344, 381, 823, 44, 535, 866, 739, 752, 385, 119, 91, 566, 80,
+ 120, 117, 771, 675, 721, 514, 656, 271, 670, 602, 980, 850, 532, 488,
+ 803, 1022, 475, 801, 878, 57, 121, 991, 742, 888, 559, 105, 497, 291,
+ 215, 795, 236, 167, 692, 520, 272, 661, 229, 391, 814, 340, 184, 798,
+ 984, 773, 650, 473, 345, 558, 548, 326, 202, 145, 465, 810, 471, 158,
+ 813, 908, 412, 441, 964, 750, 401, 50, 915, 437, 975, 126, 979, 491, 556,
+ 577, 636, 685, 510, 963, 638, 367, 815, 310, 723, 349, 323, 857, 394,
+ 606, 505, 713, 630, 938, 106, 826, 332, 978, 599, 834, 521, 530, 248,
+ 883, 32, 153, 90, 754, 592, 304, 635, 775, 804, 1, 150, 836, 1013, 828,
+ 324, 565, 508, 113, 154, 708, 921, 703, 689, 138, 547, 911, 929, 82, 228,
+ 443, 468, 480, 483, 922, 135, 877, 61, 578, 111, 860, 654, 15, 331, 851,
+ 895, 484, 320, 218, 420, 190, 1019, 143, 362, 634, 141, 965, 10, 838,
+ 632, 861, 34, 722, 580, 808, 869, 554, 598, 65, 954, 787, 337, 187, 281,
+ 146, 563, 183, 668, 944, 171, 837, 23, 867, 541, 916, 741, 625, 123, 736,
+ 186, 357, 665, 977, 179, 156, 219, 220, 216, 67, 870, 902, 774, 98, 820,
+ 574, 613, 900, 755, 596, 370, 390, 769, 314, 701, 894, 56, 841, 949, 987,
+ 631, 658, 587, 204, 797, 790, 522, 745, 9, 502, 763, 86, 719, 288, 706,
+ 887, 728, 952, 311, 336, 446, 1002, 348, 96, 58, 199, 11, 901, 230, 833,
+ 188, 352, 351, 973, 3, 906, 335, 301, 266, 244, 791, 564, 619, 909, 371,
+ 444, 760, 657, 328, 647, 490, 425, 913, 511, 439, 540, 283, 40, 897, 849,
+ 60, 570, 872, 257, 749, 912, 572, 1007, 170, 407, 898, 492, 79, 747, 732,
+ 206, 454, 918, 375, 482, 399, 92, 748, 325, 163, 274, 405, 744, 260, 346,
+ 707, 626, 595, 118, 842, 136, 279, 684, 584, 101, 500, 422, 149, 956,
+ 1014, 493, 536, 705, 51, 914, 225, 409, 55, 822, 590, 448, 655, 205, 676,
+ 925, 735, 431, 784, 54, 609, 604, 39, 812, 737, 729, 466, 14, 533, 958,
+ 481, 770, 499, 855, 238, 182, 464, 569, 72, 947, 442, 642, 24, 87, 989,
+ 688, 88, 47, 762, 623, 709, 455, 817, 526, 637, 258, 84, 845, 738, 768,
+ 698, 423, 933, 664, 620, 607, 629, 212, 347, 249, 982, 935, 131, 89, 252,
+ 927, 189, 788, 853, 237, 691, 646, 403, 1010, 734, 253, 874, 807, 903,
+ 1020, 100, 802, 71, 799, 1003, 633, 355, 276, 300, 649, 64, 306, 161,
+ 608, 496, 743, 180, 485, 819, 383, 1016, 226, 308, 393, 648, 107, 19, 37,
+ 585, 2, 175, 645, 247, 527, 5, 419, 181, 317, 327, 519, 542, 289, 567,
+ 430, 579, 950, 582, 994, 1021, 583, 234, 240, 976, 41, 160, 109, 677,
+ 937, 210, 95, 959, 242, 753, 461, 114, 733, 368, 573, 458, 782, 605, 680,
+ 544, 299, 73, 652, 905, 477, 690, 93, 824, 882, 277, 946, 361, 17, 945,
+ 523, 472, 334, 930, 597, 603, 793, 404, 290, 942, 316, 731, 270, 960,
+ 936, 133, 122, 821, 966, 679, 662, 907, 282, 968, 767, 653, 20, 697, 222,
+ 164, 835, 30, 285, 886, 456, 436, 640, 286, 1015, 380, 840, 245, 724,
+ 137, 593, 173, 130, 715, 85, 885, 551, 246, 449, 103, 366, 372, 714, 313,
+ 865, 241, 699, 674, 374, 68, 421, 562, 292, 59, 809, 342, 651, 459, 227,
+ 46, 711, 764, 868, 53, 413, 278, 800, 255, 993, 318, 854, 319, 695, 315,
+ 469, 166, 489, 969, 730, 1001, 757, 873, 686, 197, 303, 919, 155, 673,
+ 940, 712, 25, 999, 63, 863, 972, 967, 785, 152, 296, 512, 402, 377, 45,
+ 899, 829, 354, 77, 69, 856, 417, 811, 953, 124, 418, 75, 794, 162, 414,
+ 1018, 568, 254, 265, 772, 588, 16, 896, 157, 889, 298, 621, 110, 844,
+ 1000, 108, 545, 601, 78, 862, 447, 185, 195, 818, 450, 387, 49, 805, 102,
+ 986, 1005, 827, 329, 28, 932, 410, 287, 435, 451, 962, 517, 48, 174, 43,
+ 893, 884, 261, 251, 516, 395, 910, 611, 29, 501, 223, 476, 364, 144, 871,
+ 998, 687, 928, 115, 453, 513, 176, 94, 168, 667, 955, 353, 434, 382, 400,
+ 139, 365, 996, 343, 948, 890, 1012, 663, 610, 718, 538, 1008, 639, 470,
+ 848, 543, 1011, 859, 671, 756, 83, 427, 159, 746, 669, 589, 971, 524,
+ 356, 995, 904, 256, 201, 988, 62, 397, 81, 720, 917, 209, 549, 943, 486,
+ 76, 148, 207, 509, 644, 386, 700, 534, 177, 550, 961, 926, 546, 428, 284,
+ 127, 294, 8, 269, 359, 506, 445, 997, 806, 591, 725, 178, 262, 846, 373,
+ 831, 504, 305, 843, 553, 378, 1017, 783, 474, 683, 581, 200, 498, 694,
+ 191, 217, 847, 941, 424, 235, 38, 74, 616, 786, 147, 4, 273, 214, 142,
+ 575, 992, 463, 983, 243, 360, 970, 350, 267, 615, 766, 494, 31, 1009,
+ 452, 710, 552, 128, 612, 600, 275, 322, 193
+};
+static_assert(std::size(GF1024_LOG) == 1024, "GF1024_EXP length should be 1024");
+
/* Determine the final constant to use for the specified encoding. */
uint32_t EncodingConstant(Encoding encoding) {
assert(encoding == Encoding::BECH32 || encoding == Encoding::BECH32M);
@@ -127,12 +305,116 @@ uint32_t PolyMod(const data& v)
return c;
}
+/** Syndrome computes the values s_j = R(e^j) for j in [997, 998, 999]. As described above, the
+ * generator polynomial G is the LCM of the minimal polynomials of (e)^997, (e)^998, and (e)^999.
+ *
+ * Consider a codeword with errors, of the form R(x) = C(x) + E(x). The residue is the bit-packed
+ * result of computing R(x) mod G(X), where G is the generator of the code. Because C(x) is a valid
+ * codeword, it is a multiple of G(X), so the residue is in fact just E(x) mod G(x). Note that all
+ * of the (e)^j are roots of G(x) by definition, so R((e)^j) = E((e)^j).
+ *
+ * Syndrome returns the three values packed into a 30-bit integer, where each 10 bits is one value.
+ */
+uint32_t Syndrome(const uint32_t residue) {
+ // Let R(x) = r1*x^5 + r2*x^4 + r3*x^3 + r4*x^2 + r5*x + r6
+ // low is the first 5 bits, corresponding to the r6 in the residue
+ // (the constant term of the polynomial).
+
+ uint32_t low = residue & 0x1f;
+
+ // Recall that XOR corresponds to addition in a characteristic 2 field.
+ //
+ // To compute R((e)^j), we are really computing:
+ // r1*(e)^(j*5) + r2*(e)^(j*4) + r3*(e)^(j*3) + r4*(e)^(j*2) + r5*(e)^j + r6
+ // Now note that all of the (e)^(j*i) for i in [5..0] are constants and can be precomputed
+ // for efficiency. But even more than that, we can consider each coefficient as a bit-string.
+ // For example, take r5 = (b_5, b_4, b_3, b_2, b_1) written out as 5 bits. Then:
+ // r5*(e)^j = b_1*(e)^j + b_2*(2*(e)^j) + b_3*(4*(e)^j) + b_4*(8*(e)^j) + b_5*(16*(e)^j)
+ // where all the (2^i*(e)^j) are constants and can be precomputed. Then we just add each
+ // of these corresponding constants to our final value based on the bit values b_i.
+ // This is exactly what is done below. Note that all three values of s_j for j in (997, 998,
+ // 999) are computed simultaneously.
+ //
+ // We begin by setting s_j = low = r6 for all three values of j, because these are unconditional.
+ // Then for each following bit, we add the corresponding precomputed constant if the bit is 1.
+ // For example, 0x31edd3c4 is 1100011110 1101110100 1111000100 when unpacked in groups of 10
+ // bits, corresponding exactly to a^999 || a^998 || a^997 (matching the corresponding values in
+ // GF1024_EXP above).
+ //
+ // The following sage code reproduces these constants:
+ // for k in range(1, 6):
+ // for b in [1,2,4,8,16]:
+ // c0 = GF1024_EXP[(997*k + GF1024_LOG[b]) % 1023]
+ // c1 = GF1024_EXP[(998*k + GF1024_LOG[b]) % 1023]
+ // c2 = GF1024_EXP[(999*k + GF1024_LOG[b]) % 1023]
+ // c = c2 << 20 | c1 << 10 | c0
+ // print("0x%x" % c)
+
+ return low ^ (low << 10) ^ (low << 20) ^
+ ((residue >> 5) & 1 ? 0x31edd3c4 : 0) ^
+ ((residue >> 6) & 1 ? 0x335f86a8 : 0) ^
+ ((residue >> 7) & 1 ? 0x363b8870 : 0) ^
+ ((residue >> 8) & 1 ? 0x3e6390c9 : 0) ^
+ ((residue >> 9) & 1 ? 0x2ec72192 : 0) ^
+ ((residue >> 10) & 1 ? 0x1046f79d : 0) ^
+ ((residue >> 11) & 1 ? 0x208d4e33 : 0) ^
+ ((residue >> 12) & 1 ? 0x130ebd6f : 0) ^
+ ((residue >> 13) & 1 ? 0x2499fade : 0) ^
+ ((residue >> 14) & 1 ? 0x1b27d4b5 : 0) ^
+ ((residue >> 15) & 1 ? 0x04be1eb4 : 0) ^
+ ((residue >> 16) & 1 ? 0x0968b861 : 0) ^
+ ((residue >> 17) & 1 ? 0x1055f0c2 : 0) ^
+ ((residue >> 18) & 1 ? 0x20ab4584 : 0) ^
+ ((residue >> 19) & 1 ? 0x1342af08 : 0) ^
+ ((residue >> 20) & 1 ? 0x24f1f318 : 0) ^
+ ((residue >> 21) & 1 ? 0x1be34739 : 0) ^
+ ((residue >> 22) & 1 ? 0x35562f7b : 0) ^
+ ((residue >> 23) & 1 ? 0x3a3c5bff : 0) ^
+ ((residue >> 24) & 1 ? 0x266c96f7 : 0) ^
+ ((residue >> 25) & 1 ? 0x25c78b65 : 0) ^
+ ((residue >> 26) & 1 ? 0x1b1f13ea : 0) ^
+ ((residue >> 27) & 1 ? 0x34baa2f4 : 0) ^
+ ((residue >> 28) & 1 ? 0x3b61c0e1 : 0) ^
+ ((residue >> 29) & 1 ? 0x265325c2 : 0);
+}
+
/** Convert to lower case. */
inline unsigned char LowerCase(unsigned char c)
{
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
}
+void push_range(int from, int to, std::vector<int>& vec)
+{
+ for (int i = from; i < to; i++) {
+ vec.push_back(i);
+ }
+}
+
+/** Return index of first invalid character in a Bech32 string. */
+bool CheckCharacters(const std::string& str, std::vector<int>& errors) {
+ bool lower = false, upper = false;
+ for (size_t i = 0; i < str.size(); ++i) {
+ unsigned char c = str[i];
+ if (c >= 'a' && c <= 'z') {
+ if (upper) {
+ errors.push_back(i);
+ } else {
+ lower = true;
+ }
+ } else if (c >= 'A' && c <= 'Z') {
+ if (lower) {
+ errors.push_back(i);
+ } else {
+ upper = true;
+ }
+ } else if (c < 33 || c > 126) {
+ errors.push_back(i);
+ }
+ }
+ return errors.empty();
+}
+
/** Expand a HRP for use in checksum computation. */
data ExpandHRP(const std::string& hrp)
{
@@ -196,14 +478,8 @@ std::string Encode(Encoding encoding, const std::string& hrp, const data& values
/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str) {
- bool lower = false, upper = false;
- for (size_t i = 0; i < str.size(); ++i) {
- unsigned char c = str[i];
- if (c >= 'a' && c <= 'z') lower = true;
- else if (c >= 'A' && c <= 'Z') upper = true;
- else if (c < 33 || c > 126) return {};
- }
- if (lower && upper) return {};
+ std::vector<int> errors;
+ if (!CheckCharacters(str, errors)) return {};
size_t pos = str.rfind('1');
if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
return {};
@@ -227,4 +503,163 @@ DecodeResult Decode(const std::string& str) {
return {result, std::move(hrp), data(values.begin(), values.end() - 6)};
}
+/** Find index of an incorrect character in a Bech32 string. */
+std::string LocateErrors(const std::string& str, std::vector<int>& error_locations) {
+ if (str.size() > 90) {
+ push_range(90, str.size(), error_locations);
+ return "Bech32 string too long";
+ }
+ if (!CheckCharacters(str, error_locations)){
+ return "Invalid character or mixed case";
+ }
+ size_t pos = str.rfind('1');
+ if (pos == str.npos) {
+ return "Missing separator";
+ }
+ if (pos == 0 || pos + 7 > str.size()) {
+ error_locations.push_back(pos);
+ return "Invalid separator position";
+ }
+ std::string hrp;
+ for (size_t i = 0; i < pos; ++i) {
+ hrp += LowerCase(str[i]);
+ }
+
+ size_t length = str.size() - 1 - pos; // length of data part
+ data values(length);
+ for (size_t i = pos + 1; i < str.size(); ++i) {
+ unsigned char c = str[i];
+ int8_t rev = CHARSET_REV[c];
+ if (rev == -1) {
+ error_locations.push_back(i);
+ return "Invalid Base 32 character";
+ }
+ values[i - pos - 1] = rev;
+ }
+
+ // We attempt error detection with both bech32 and bech32m, and choose the one with the fewest errors
+ // We can't simply use the segwit version, because that may be one of the errors
+ for (Encoding encoding : {Encoding::BECH32, Encoding::BECH32M}) {
+ std::vector<int> possible_errors;
+ // Recall that (ExpandHRP(hrp) ++ values) is interpreted as a list of coefficients of a polynomial
+ // over GF(32). PolyMod computes the "remainder" of this polynomial modulo the generator G(x).
+ uint32_t residue = PolyMod(Cat(ExpandHRP(hrp), values)) ^ EncodingConstant(encoding);
+
+ // All valid codewords should be multiples of G(x), so this remainder (after XORing with the encoding
+ // constant) should be 0 - hence 0 indicates there are no errors present.
+ if (residue != 0) {
+ // If errors are present, our polynomial must be of the form C(x) + E(x) where C is the valid
+ // codeword (a multiple of G(x)), and E encodes the errors.
+ uint32_t syn = Syndrome(residue);
+
+ // Unpack the three 10-bit syndrome values
+ int s0 = syn & 0x3FF;
+ int s1 = (syn >> 10) & 0x3FF;
+ int s2 = syn >> 20;
+
+ // Get the discrete logs of these values in GF1024 for more efficient computation
+ int l_s0 = GF1024_LOG[s0];
+ int l_s1 = GF1024_LOG[s1];
+ int l_s2 = GF1024_LOG[s2];
+
+ // First, suppose there is only a single error. Then E(x) = e1*x^p1 for some position p1
+ // Then s0 = E((e)^997) = e1*(e)^(997*p1) and s1 = E((e)^998) = e1*(e)^(998*p1)
+ // Therefore s1/s0 = (e)^p1, and by the same logic, s2/s1 = (e)^p1 too.
+ // Hence, s1^2 == s0*s2, which is exactly the condition we check first:
+ if (l_s0 != -1 && l_s1 != -1 && l_s2 != -1 && (2 * l_s1 - l_s2 - l_s0 + 2046) % 1023 == 0) {
+ // Compute the error position p1 as l_s1 - l_s0 = p1 (mod 1023)
+ size_t p1 = (l_s1 - l_s0 + 1023) % 1023; // the +1023 ensures it is positive
+ // Now because s0 = e1*(e)^(997*p1), we get e1 = s0/((e)^(997*p1)). Remember that (e)^1023 = 1,
+ // so 1/((e)^997) = (e)^(1023-997).
+ int l_e1 = l_s0 + (1023 - 997) * p1;
+ // Finally, some sanity checks on the result:
+ // - The error position should be within the length of the data
+ // - e1 should be in GF(32), which implies that e1 = (e)^(33k) for some k (the 31 non-zero elements
+ // of GF(32) form an index 33 subgroup of the 1023 non-zero elements of GF(1024)).
+ if (p1 < length && !(l_e1 % 33)) {
+ // Polynomials run from highest power to lowest, so the index p1 is from the right.
+ // We don't return e1 because it is dangerous to suggest corrections to the user,
+ // the user should check the address themselves.
+ possible_errors.push_back(str.size() - p1 - 1);
+ }
+ // Otherwise, suppose there are two errors. Then E(x) = e1*x^p1 + e2*x^p2.
+ } else {
+ // For all possible first error positions p1
+ for (size_t p1 = 0; p1 < length; ++p1) {
+ // We have guessed p1, and want to solve for p2. Recall that E(x) = e1*x^p1 + e2*x^p2, so
+ // s0 = E((e)^997) = e1*(e)^(997^p1) + e2*(e)^(997*p2), and similar for s1 and s2.
+ //
+ // Consider s2 + s1*(e)^p1
+ // = 2e1*(e)^(999^p1) + e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1
+ // = e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1
+ // (Because we are working in characteristic 2.)
+ // = e2*(e)^(998*p2) ((e)^p2 + (e)^p1)
+ //
+ int s2_s1p1 = s2 ^ (s1 == 0 ? 0 : GF1024_EXP[(l_s1 + p1) % 1023]);
+ if (s2_s1p1 == 0) continue;
+ int l_s2_s1p1 = GF1024_LOG[s2_s1p1];
+
+ // Similarly, s1 + s0*(e)^p1
+ // = e2*(e)^(997*p2) ((e)^p2 + (e)^p1)
+ int s1_s0p1 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p1) % 1023]);
+ if (s1_s0p1 == 0) continue;
+ int l_s1_s0p1 = GF1024_LOG[s1_s0p1];
+
+ // So, putting these together, we can compute the second error position as
+ // (e)^p2 = (s2 + s1^p1)/(s1 + s0^p1)
+ // p2 = log((e)^p2)
+ size_t p2 = (l_s2_s1p1 - l_s1_s0p1 + 1023) % 1023;
+
+ // Sanity checks that p2 is a valid position and not the same as p1
+ if (p2 >= length || p1 == p2) continue;
+
+ // Now we want to compute the error values e1 and e2.
+ // Similar to above, we compute s1 + s0*(e)^p2
+ // = e1*(e)^(997*p1) ((e)^p1 + (e)^p2)
+ int s1_s0p2 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p2) % 1023]);
+ if (s1_s0p2 == 0) continue;
+ int l_s1_s0p2 = GF1024_LOG[s1_s0p2];
+
+ // And compute (the log of) 1/((e)^p1 + (e)^p2))
+ int inv_p1_p2 = 1023 - GF1024_LOG[GF1024_EXP[p1] ^ GF1024_EXP[p2]];
+
+ // Then (s1 + s0*(e)^p1) * (1/((e)^p1 + (e)^p2)))
+ // = e2*(e)^(997*p2)
+ // Then recover e2 by dividing by (e)^(997*p2)
+ int l_e2 = l_s1_s0p1 + inv_p1_p2 + (1023 - 997) * p2;
+ // Check that e2 is in GF(32)
+ if (l_e2 % 33) continue;
+
+ // In the same way, (s1 + s0*(e)^p2) * (1/((e)^p1 + (e)^p2)))
+ // = e1*(e)^(997*p1)
+ // So recover e1 by dividing by (e)^(997*p1)
+ int l_e1 = l_s1_s0p2 + inv_p1_p2 + (1023 - 997) * p1;
+ // Check that e1 is in GF(32)
+ if (l_e1 % 33) continue;
+
+ // Again, we do not return e1 or e2 for safety.
+ // Order the error positions from the left of the string and return them
+ if (p1 > p2) {
+ possible_errors.push_back(str.size() - p1 - 1);
+ possible_errors.push_back(str.size() - p2 - 1);
+ } else {
+ possible_errors.push_back(str.size() - p2 - 1);
+ possible_errors.push_back(str.size() - p1 - 1);
+ }
+ break;
+ }
+ }
+ } else {
+ // No errors
+ error_locations.clear();
+ return "";
+ }
+
+ if (error_locations.empty() || (!possible_errors.empty() && possible_errors.size() < error_locations.size())) {
+ error_locations = std::move(possible_errors);
+ }
+ }
+ return "Invalid checksum";
+}
+
} // namespace bech32
diff --git a/src/bech32.h b/src/bech32.h
index e9450ccc2b..7e92d5d23a 100644
--- a/src/bech32.h
+++ b/src/bech32.h
@@ -1,4 +1,5 @@
// Copyright (c) 2017, 2021 Pieter Wuille
+// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -44,6 +45,9 @@ struct DecodeResult
/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str);
+/** Return the positions of errors in a Bech32 string. */
+std::string LocateErrors(const std::string& str, std::vector<int>& error_locations);
+
} // namespace bech32
#endif // BITCOIN_BECH32_H
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index d5275b0b76..dae3a47cd7 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -45,7 +45,7 @@ static void CCoinsCaching(benchmark::Bench& bench)
// Benchmark.
const CTransaction tx_1(t1);
bench.run([&] {
- bool success = AreInputsStandard(tx_1, coins, false);
+ bool success{AreInputsStandard(tx_1, coins)};
assert(success);
});
ECC_Stop();
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index f6a8c56743..3c24fee60f 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -18,7 +18,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<st
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(1);
tx.vout[0].nValue = nValue;
- wtxs.push_back(std::make_unique<CWalletTx>(MakeTransactionRef(std::move(tx))));
+ wtxs.push_back(std::make_unique<CWalletTx>(MakeTransactionRef(std::move(tx)), TxStateInactive{}));
}
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
index f1eeef8885..67c827d0d3 100644
--- a/src/bench/rpc_mempool.cpp
+++ b/src/bench/rpc_mempool.cpp
@@ -12,7 +12,7 @@
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
{
LockPoints lp;
- pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
+ pool.addUnchecked(CTxMemPoolEntry(tx, fee, /*time=*/0, /*entry_height=*/1, /*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
}
static void RpcMempool(benchmark::Bench& bench)
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 338d32ef6b..279521a761 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -49,6 +49,7 @@ static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;
static constexpr int8_t UNKNOWN_NETWORK{-1};
+static constexpr std::array NETWORKS{"ipv4", "ipv6", "onion", "i2p", "cjdns"};
/** Default number of blocks to generate for RPC generatetoaddress. */
static const std::string DEFAULT_NBLOCKS = "1";
@@ -242,11 +243,10 @@ public:
class AddrinfoRequestHandler : public BaseRequestHandler
{
private:
- static constexpr std::array m_networks{"ipv4", "ipv6", "onion", "i2p"};
int8_t NetworkStringToId(const std::string& str) const
{
- for (size_t i = 0; i < m_networks.size(); ++i) {
- if (str == m_networks.at(i)) return i;
+ for (size_t i = 0; i < NETWORKS.size(); ++i) {
+ if (str == NETWORKS[i]) return i;
}
return UNKNOWN_NETWORK;
}
@@ -269,7 +269,7 @@ public:
throw std::runtime_error("-addrinfo requires bitcoind server to be running v22.0 and up");
}
// Count the number of peers known to our node, by network.
- std::array<uint64_t, m_networks.size()> counts{{}};
+ std::array<uint64_t, NETWORKS.size()> counts{{}};
for (const UniValue& node : nodes) {
std::string network_name{node["network"].get_str()};
const int8_t network_id{NetworkStringToId(network_name)};
@@ -279,8 +279,8 @@ public:
// Prepare result to return to user.
UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ};
uint64_t total{0}; // Total address count
- for (size_t i = 0; i < m_networks.size(); ++i) {
- addresses.pushKV(m_networks.at(i), counts.at(i));
+ for (size_t i = 0; i < NETWORKS.size(); ++i) {
+ addresses.pushKV(NETWORKS[i], counts.at(i));
total += counts.at(i);
}
addresses.pushKV("total", total);
@@ -363,14 +363,13 @@ class NetinfoRequestHandler : public BaseRequestHandler
{
private:
static constexpr uint8_t MAX_DETAIL_LEVEL{4};
- static constexpr std::array m_networks{"ipv4", "ipv6", "onion", "i2p"};
- std::array<std::array<uint16_t, m_networks.size() + 1>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total)
+ std::array<std::array<uint16_t, NETWORKS.size() + 1>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total)
uint8_t m_block_relay_peers_count{0};
uint8_t m_manual_peers_count{0};
int8_t NetworkStringToId(const std::string& str) const
{
- for (size_t i = 0; i < m_networks.size(); ++i) {
- if (str == m_networks.at(i)) return i;
+ for (size_t i = 0; i < NETWORKS.size(); ++i) {
+ if (str == NETWORKS[i]) return i;
}
return UNKNOWN_NETWORK;
}
@@ -471,10 +470,10 @@ public:
const bool is_outbound{!peer["inbound"].get_bool()};
const bool is_block_relay{!peer["relaytxes"].get_bool()};
const std::string conn_type{peer["connection_type"].get_str()};
- ++m_counts.at(is_outbound).at(network_id); // in/out by network
- ++m_counts.at(is_outbound).at(m_networks.size()); // in/out overall
- ++m_counts.at(2).at(network_id); // total by network
- ++m_counts.at(2).at(m_networks.size()); // total overall
+ ++m_counts.at(is_outbound).at(network_id); // in/out by network
+ ++m_counts.at(is_outbound).at(NETWORKS.size()); // in/out overall
+ ++m_counts.at(2).at(network_id); // total by network
+ ++m_counts.at(2).at(NETWORKS.size()); // total overall
if (conn_type == "block-relay-only") ++m_block_relay_peers_count;
if (conn_type == "manual") ++m_manual_peers_count;
if (DetailsRequested()) {
@@ -571,7 +570,7 @@ public:
for (int8_t n : reachable_networks) {
result += strprintf("%8i", m_counts.at(i).at(n)); // network peers count
}
- result += strprintf(" %5i", m_counts.at(i).at(m_networks.size())); // total peers count
+ result += strprintf(" %5i", m_counts.at(i).at(NETWORKS.size())); // total peers count
if (i == 1) { // the outbound row has two extra columns for block relay and manual peer counts
result += strprintf(" %5i", m_block_relay_peers_count);
if (m_manual_peers_count) result += strprintf(" %5i", m_manual_peers_count);
diff --git a/src/chain.cpp b/src/chain.cpp
index c09113a866..5d182e1af8 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -5,9 +5,6 @@
#include <chain.h>
-/**
- * CChain implementation
- */
void CChain::SetTip(CBlockIndex *pindex) {
if (pindex == nullptr) {
vChain.clear();
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 7c20e2013c..760dfbddc1 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -167,16 +167,24 @@ public:
//! Add a batch of checks to the queue
void Add(std::vector<T>& vChecks)
{
- LOCK(m_mutex);
- for (T& check : vChecks) {
- queue.push_back(T());
- check.swap(queue.back());
+ if (vChecks.empty()) {
+ return;
}
- nTodo += vChecks.size();
- if (vChecks.size() == 1)
+
+ {
+ LOCK(m_mutex);
+ for (T& check : vChecks) {
+ queue.emplace_back();
+ check.swap(queue.back());
+ }
+ nTodo += vChecks.size();
+ }
+
+ if (vChecks.size() == 1) {
m_worker_cv.notify_one();
- else if (vChecks.size() > 1)
+ } else {
m_worker_cv.notify_all();
+ }
}
//! Stop all of the worker threads.
diff --git a/src/coins.cpp b/src/coins.cpp
index ce0b131de6..daead6055e 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -7,6 +7,7 @@
#include <consensus/consensus.h>
#include <logging.h>
#include <random.h>
+#include <util/trace.h>
#include <version.h>
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
@@ -95,6 +96,12 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
it->second.coin = std::move(coin);
it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
+ TRACE5(utxocache, add,
+ outpoint.hash.data(),
+ (uint32_t)outpoint.n,
+ (uint32_t)coin.nHeight,
+ (int64_t)coin.out.nValue,
+ (bool)coin.IsCoinBase());
}
void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) {
@@ -120,6 +127,12 @@ bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
CCoinsMap::iterator it = FetchCoin(outpoint);
if (it == cacheCoins.end()) return false;
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
+ TRACE5(utxocache, spent,
+ outpoint.hash.data(),
+ (uint32_t)outpoint.n,
+ (uint32_t)it->second.coin.nHeight,
+ (int64_t)it->second.coin.out.nValue,
+ (bool)it->second.coin.IsCoinBase());
if (moveout) {
*moveout = std::move(it->second.coin);
}
@@ -231,6 +244,12 @@ void CCoinsViewCache::Uncache(const COutPoint& hash)
CCoinsMap::iterator it = cacheCoins.find(hash);
if (it != cacheCoins.end() && it->second.flags == 0) {
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
+ TRACE5(utxocache, uncache,
+ hash.hash.data(),
+ (uint32_t)hash.n,
+ (uint32_t)it->second.coin.nHeight,
+ (int64_t)it->second.coin.out.nValue,
+ (bool)it->second.coin.IsCoinBase());
cacheCoins.erase(it);
}
}
diff --git a/src/consensus/amount.h b/src/consensus/amount.h
index 96566ea13f..59b8e3417a 100644
--- a/src/consensus/amount.h
+++ b/src/consensus/amount.h
@@ -26,4 +26,4 @@ static constexpr CAmount COIN = 100000000;
static constexpr CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
-#endif // BITCOIN_CONSENSUS_AMOUNT_H
+#endif // BITCOIN_CONSENSUS_AMOUNT_H
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 2fdc54464a..dbae2c45f2 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -136,6 +136,10 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
TryCreateDirectories(path);
LogPrintf("Opening LevelDB in %s\n", fs::PathToString(path));
}
+ // PathToString() return value is safe to pass to leveldb open function,
+ // because on POSIX leveldb passes the byte string directly to ::open(), and
+ // on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
+ // (see env_posix.cc and env_windows.cc).
leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(path), &pdb);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
diff --git a/src/fs.h b/src/fs.h
index 4a0bf39e95..3cf4371fb4 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -94,31 +94,34 @@ static inline path operator+(path p1, path p2)
/**
* Convert path object to byte string. On POSIX, paths natively are byte
- * strings so this is trivial. On Windows, paths natively are Unicode, so an
- * encoding step is necessary.
+ * strings, so this is trivial. On Windows, paths natively are Unicode, so an
+ * encoding step is necessary. The inverse of \ref PathToString is \ref
+ * PathFromString. The strings returned and parsed by these functions can be
+ * used to call POSIX APIs, and for roundtrip conversion, logging, and
+ * debugging.
*
- * The inverse of \ref PathToString is \ref PathFromString. The strings
- * returned and parsed by these functions can be used to call POSIX APIs, and
- * for roundtrip conversion, logging, and debugging. But they are not
- * guaranteed to be valid UTF-8, and are generally meant to be used internally,
- * not externally. When communicating with external programs and libraries that
- * require UTF-8, fs::path::u8string() and fs::u8path() methods can be used.
- * For other applications, if support for non UTF-8 paths is required, or if
- * higher-level JSON or XML or URI or C-style escapes are preferred, it may be
- * also be appropriate to use different path encoding functions.
- *
- * Implementation note: On Windows, the std::filesystem::path(string)
- * constructor and std::filesystem::path::string() method are not safe to use
- * here, because these methods encode the path using C++'s narrow multibyte
- * encoding, which on Windows corresponds to the current "code page", which is
- * unpredictable and typically not able to represent all valid paths. So
- * std::filesystem::path::u8string() and std::filesystem::u8path() functions
- * are used instead on Windows. On POSIX, u8string/u8path functions are not
- * safe to use because paths are not always valid UTF-8, so plain string
- * methods which do not transform the path there are used.
+ * Because \ref PathToString and \ref PathFromString functions don't specify an
+ * encoding, they are meant to be used internally, not externally. They are not
+ * appropriate to use in applications requiring UTF-8, where
+ * fs::path::u8string() and fs::u8path() methods should be used instead. Other
+ * applications could require still different encodings. For example, JSON, XML,
+ * or URI applications might prefer to use higher level escapes (\uXXXX or
+ * &XXXX; or %XX) instead of multibyte encoding. Rust, Python, Java applications
+ * may require encoding paths with their respective UTF-8 derivatives WTF-8,
+ * PEP-383, and CESU-8 (see https://en.wikipedia.org/wiki/UTF-8#Derivatives).
*/
static inline std::string PathToString(const path& path)
{
+ // Implementation note: On Windows, the std::filesystem::path(string)
+ // constructor and std::filesystem::path::string() method are not safe to
+ // use here, because these methods encode the path using C++'s narrow
+ // multibyte encoding, which on Windows corresponds to the current "code
+ // page", which is unpredictable and typically not able to represent all
+ // valid paths. So std::filesystem::path::u8string() and
+ // std::filesystem::u8path() functions are used instead on Windows. On
+ // POSIX, u8string/u8path functions are not safe to use because paths are
+ // not always valid UTF-8, so plain string methods which do not transform
+ // the path there are used.
#ifdef WIN32
return path.u8string();
#else
diff --git a/src/httprpc.h b/src/httprpc.h
index 5a3b990646..6daf7d28f5 100644
--- a/src/httprpc.h
+++ b/src/httprpc.h
@@ -31,4 +31,4 @@ void InterruptREST();
*/
void StopREST();
-#endif
+#endif // BITCOIN_HTTPRPC_H
diff --git a/src/i2p.h b/src/i2p.h
index cb2efedba8..86643de637 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -267,4 +267,4 @@ private:
} // namespace sam
} // namespace i2p
-#endif /* BITCOIN_I2P_H */
+#endif // BITCOIN_I2P_H
diff --git a/src/init.cpp b/src/init.cpp
index f659de3a02..d5c3acbaad 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -29,13 +29,13 @@
#include <interfaces/init.h>
#include <interfaces/node.h>
#include <mapport.h>
-#include <miner.h>
#include <net.h>
#include <net_permissions.h>
#include <net_processing.h>
#include <netbase.h>
#include <node/blockstorage.h>
#include <node/context.h>
+#include <node/miner.h>
#include <node/ui_interface.h>
#include <policy/feerate.h>
#include <policy/fees.h>
@@ -59,6 +59,7 @@
#include <util/asmap.h>
#include <util/check.h>
#include <util/moneystr.h>
+#include <util/strencodings.h>
#include <util/string.h>
#include <util/syscall_sandbox.h>
#include <util/system.h>
@@ -436,7 +437,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-i2pacceptincoming", "If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -1109,6 +1110,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
{
const ArgsManager& args = *Assert(node.args);
const CChainParams& chainparams = Params();
+
+ auto opt_max_upload = ParseByteUnits(args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET), ByteUnit::M);
+ if (!opt_max_upload) {
+ return InitError(strprintf(_("Unable to parse -maxuploadtarget: '%s' (possible integer overflow?)"), args.GetArg("-maxuploadtarget", "")));
+ }
+
// ********************************************************* Step 4a: application initialization
if (!CreatePidFile(args)) {
// Detailed error printed inside CreatePidFile().
@@ -1760,8 +1767,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
connOptions.nSendBufferMaxSize = 1000 * args.GetIntArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000 * args.GetIntArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
connOptions.m_added_nodes = args.GetArgs("-addnode");
-
- connOptions.nMaxOutboundLimit = 1024 * 1024 * args.GetIntArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET);
+ connOptions.nMaxOutboundLimit = *opt_max_upload;
connOptions.m_peer_connect_timeout = peer_connect_timeout;
for (const std::string& bind_arg : args.GetArgs("-bind")) {
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index d4ceb517dd..38004ce95d 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -287,9 +287,6 @@ public:
//! to be prepared to handle this by ignoring notifications about unknown
//! removed transactions and already added new transactions.
virtual void requestMempoolTransactions(Notifications& notifications) = 0;
-
- //! Check if Taproot has activated
- virtual bool isTaprootActive() = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index ea1cb5ed72..974156e6e1 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -30,6 +30,7 @@ class RPCTimerInterface;
class UniValue;
class proxyType;
enum class SynchronizationState;
+enum class TransactionError;
struct CNodeStateStats;
struct NodeContext;
struct bilingual_str;
@@ -183,6 +184,9 @@ public:
//! Get unspent outputs associated with a transaction.
virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
+ //! Broadcast transaction.
+ virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0;
+
//! Get wallet client.
virtual WalletClient& walletClient() = 0;
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 490563426c..a56ed8802d 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -13,12 +13,13 @@
#include <util/message.h>
#include <util/ui_change_type.h>
+#include <cstdint>
#include <functional>
#include <map>
#include <memory>
-#include <stdint.h>
#include <string>
#include <tuple>
+#include <type_traits>
#include <utility>
#include <vector>
@@ -34,7 +35,7 @@ struct CRecipient;
struct PartiallySignedTransaction;
struct WalletContext;
struct bilingual_str;
-typedef uint8_t isminefilter;
+using isminefilter = std::underlying_type<isminetype>::type;
namespace interfaces {
diff --git a/src/key.cpp b/src/key.cpp
index 7688254515..86081b3464 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -275,7 +275,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
return true;
}
-bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256* aux) const
+bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const
{
assert(sig.size() == 64);
secp256k1_keypair keypair;
@@ -288,7 +288,7 @@ bool CKey::SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint2
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
if (!secp256k1_keypair_xonly_tweak_add(GetVerifyContext(), &keypair, tweak.data())) return false;
}
- bool ret = secp256k1_schnorrsig_sign(secp256k1_context_sign, sig.data(), hash.data(), &keypair, aux ? (unsigned char*)aux->data() : nullptr);
+ bool ret = secp256k1_schnorrsig_sign(secp256k1_context_sign, sig.data(), hash.data(), &keypair, (unsigned char*)aux.data());
if (ret) {
// Additional verification step to prevent using a potentially corrupted signature
secp256k1_xonly_pubkey pubkey_verify;
diff --git a/src/key.h b/src/key.h
index af8d2e72d8..eab18b284a 100644
--- a/src/key.h
+++ b/src/key.h
@@ -130,7 +130,7 @@ public:
/**
* Create a BIP-340 Schnorr signature, for the xonly-pubkey corresponding to *this,
- * optionally tweaked by *merkle_root. Additional nonce entropy can be provided through
+ * optionally tweaked by *merkle_root. Additional nonce entropy is provided through
* aux.
*
* merkle_root is used to optionally perform tweaking of the private key, as specified
@@ -143,7 +143,7 @@ public:
* (this is used for key path spending, with specific
* Merkle root of the script tree).
*/
- bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root = nullptr, const uint256* aux = nullptr) const;
+ bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const;
//! Derive BIP32 child key.
bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 615f4c9312..6908c5ea52 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -76,12 +76,16 @@ public:
std::string operator()(const CNoDestination& no) const { return {}; }
};
-CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations)
{
std::vector<unsigned char> data;
uint160 hash;
error_str = "";
- if (DecodeBase58Check(str, data, 21)) {
+
+ // Note this will be false if it is a valid Bech32 address for a different network
+ bool is_bech32 = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP());
+
+ if (!is_bech32 && DecodeBase58Check(str, data, 21)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
@@ -98,15 +102,27 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return ScriptHash(hash);
}
- // Set potential error message.
- // This message may be changed if the address can also be interpreted as a Bech32 address.
- error_str = "Invalid prefix for Base58-encoded address";
+ if (!std::equal(script_prefix.begin(), script_prefix.end(), data.begin()) &&
+ !std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
+ error_str = "Invalid prefix for Base58-encoded address";
+ } else {
+ error_str = "Invalid length for Base58 address";
+ }
+ return CNoDestination();
+ } else if (!is_bech32) {
+ // Try Base58 decoding without the checksum, using a much larger max length
+ if (!DecodeBase58(str, data, 100)) {
+ error_str = "Invalid HRP or Base58 character in address";
+ } else {
+ error_str = "Invalid checksum or length of Base58 address";
+ }
+ return CNoDestination();
}
+
data.clear();
const auto dec = bech32::Decode(str);
if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0) {
// Bech32 decoding
- error_str = "";
if (dec.hrp != params.Bech32HRP()) {
error_str = "Invalid prefix for Bech32 address";
return CNoDestination();
@@ -168,8 +184,13 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
}
- // Set error message if address can't be interpreted as Base58 or Bech32.
- if (error_str.empty()) error_str = "Invalid address format";
+ // Perform Bech32 error location
+ if (!error_locations) {
+ std::vector<int> dummy_errors;
+ error_str = bech32::LocateErrors(str, dummy_errors);
+ } else {
+ error_str = bech32::LocateErrors(str, *error_locations);
+ }
return CNoDestination();
}
@@ -258,9 +279,9 @@ std::string EncodeDestination(const CTxDestination& dest)
return std::visit(DestinationEncoder(Params()), dest);
}
-CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations)
{
- return DecodeDestination(str, Params(), error_msg);
+ return DecodeDestination(str, Params(), error_msg, error_locations);
}
CTxDestination DecodeDestination(const std::string& str)
@@ -272,7 +293,7 @@ CTxDestination DecodeDestination(const std::string& str)
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
std::string error_msg;
- return IsValidDestination(DecodeDestination(str, params, error_msg));
+ return IsValidDestination(DecodeDestination(str, params, error_msg, nullptr));
}
bool IsValidDestinationString(const std::string& str)
diff --git a/src/key_io.h b/src/key_io.h
index bd81f7847e..2062bb4c44 100644
--- a/src/key_io.h
+++ b/src/key_io.h
@@ -23,7 +23,7 @@ std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
-CTxDestination DecodeDestination(const std::string& str, std::string& error_msg);
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations = nullptr);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
diff --git a/src/net.cpp b/src/net.cpp
index 82e55d4189..db496c2185 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -326,8 +326,8 @@ bool IsLocal(const CService& addr)
CNode* CConnman::FindNode(const CNetAddr& ip)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (static_cast<CNetAddr>(pnode->addr) == ip) {
return pnode;
}
@@ -337,8 +337,8 @@ CNode* CConnman::FindNode(const CNetAddr& ip)
CNode* CConnman::FindNode(const CSubNet& subNet)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (subNet.Match(static_cast<CNetAddr>(pnode->addr))) {
return pnode;
}
@@ -348,8 +348,8 @@ CNode* CConnman::FindNode(const CSubNet& subNet)
CNode* CConnman::FindNode(const std::string& addrName)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (pnode->m_addr_name == addrName) {
return pnode;
}
@@ -359,8 +359,8 @@ CNode* CConnman::FindNode(const std::string& addrName)
CNode* CConnman::FindNode(const CService& addr)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (static_cast<CService>(pnode->addr) == addr) {
return pnode;
}
@@ -375,8 +375,8 @@ bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
bool CConnman::CheckIncomingNonce(uint64_t nonce)
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn() && pnode->GetLocalNonce() == nonce)
return false;
}
@@ -435,7 +435,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created.
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
if (pnode) {
LogPrintf("Failed to open new connection, already connected\n");
@@ -1056,8 +1056,8 @@ bool CConnman::AttemptToEvictConnection()
std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
- LOCK(cs_vNodes);
- for (const CNode* node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* node : m_nodes) {
if (node->HasPermission(NetPermissionFlags::NoBan))
continue;
if (!node->IsInboundConn())
@@ -1084,8 +1084,8 @@ bool CConnman::AttemptToEvictConnection()
if (!node_id_to_evict) {
return false;
}
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (pnode->GetId() == *node_id_to_evict) {
LogPrint(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId());
pnode->fDisconnect = true;
@@ -1141,8 +1141,8 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
}
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->IsInboundConn()) nInbound++;
}
}
@@ -1210,8 +1210,8 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
{
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ LOCK(m_nodes_mutex);
+ m_nodes.push_back(pnode);
}
// We received a new connection, harvest entropy from the time (and our peer count)
@@ -1238,8 +1238,8 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
} // no default case, so the compiler can warn about missing cases
// Count existing connections
- int existing_connections = WITH_LOCK(cs_vNodes,
- return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
+ int existing_connections = WITH_LOCK(m_nodes_mutex,
+ return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
// Max connections of specified type already exist
if (max_connections != std::nullopt && existing_connections >= max_connections) return false;
@@ -1255,11 +1255,11 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
void CConnman::DisconnectNodes()
{
{
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
if (!fNetworkActive) {
// Disconnect any connected nodes
- for (CNode* pnode : vNodes) {
+ for (CNode* pnode : m_nodes) {
if (!pnode->fDisconnect) {
LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId());
pnode->fDisconnect = true;
@@ -1268,13 +1268,13 @@ void CConnman::DisconnectNodes()
}
// Disconnect unused nodes
- std::vector<CNode*> vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy)
+ std::vector<CNode*> nodes_copy = m_nodes;
+ for (CNode* pnode : nodes_copy)
{
if (pnode->fDisconnect)
{
- // remove from vNodes
- vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
+ // remove from m_nodes
+ m_nodes.erase(remove(m_nodes.begin(), m_nodes.end(), pnode), m_nodes.end());
// release outbound grant (if any)
pnode->grantOutbound.Release();
@@ -1284,18 +1284,18 @@ void CConnman::DisconnectNodes()
// hold in disconnected pool until all refs are released
pnode->Release();
- vNodesDisconnected.push_back(pnode);
+ m_nodes_disconnected.push_back(pnode);
}
}
}
{
// Delete disconnected nodes
- std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
- for (CNode* pnode : vNodesDisconnectedCopy)
+ std::list<CNode*> nodes_disconnected_copy = m_nodes_disconnected;
+ for (CNode* pnode : nodes_disconnected_copy)
{
// Destroy the object only after other threads have stopped using it.
if (pnode->GetRefCount() <= 0) {
- vNodesDisconnected.remove(pnode);
+ m_nodes_disconnected.remove(pnode);
DeleteNode(pnode);
}
}
@@ -1304,15 +1304,15 @@ void CConnman::DisconnectNodes()
void CConnman::NotifyNumConnectionsChanged()
{
- size_t vNodesSize;
+ size_t nodes_size;
{
- LOCK(cs_vNodes);
- vNodesSize = vNodes.size();
+ LOCK(m_nodes_mutex);
+ nodes_size = m_nodes.size();
}
- if(vNodesSize != nPrevNodeCount) {
- nPrevNodeCount = vNodesSize;
+ if(nodes_size != nPrevNodeCount) {
+ nPrevNodeCount = nodes_size;
if (m_client_interface) {
- m_client_interface->NotifyNumConnectionsChanged(vNodesSize);
+ m_client_interface->NotifyNumConnectionsChanged(nodes_size);
}
}
}
@@ -1353,46 +1353,45 @@ bool CConnman::InactivityCheck(const CNode& node) const
return false;
}
-bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set)
{
for (const ListenSocket& hListenSocket : vhListenSocket) {
recv_set.insert(hListenSocket.socket);
}
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
+ for (CNode* pnode : nodes) {
+ // Implement the following logic:
+ // * If there is data to send, select() for sending data. As this only
+ // happens when optimistic write failed, we choose to first drain the
+ // write buffer in this case before receiving more. This avoids
+ // needlessly queueing received data, if the remote peer is not themselves
+ // receiving data. This means properly utilizing TCP flow control signalling.
+ // * Otherwise, if there is space left in the receive buffer, select() for
+ // receiving data.
+ // * Hand off all complete messages to the processor, to be handled without
+ // blocking here.
+
+ bool select_recv = !pnode->fPauseRecv;
+ bool select_send;
{
- // Implement the following logic:
- // * If there is data to send, select() for sending data. As this only
- // happens when optimistic write failed, we choose to first drain the
- // write buffer in this case before receiving more. This avoids
- // needlessly queueing received data, if the remote peer is not themselves
- // receiving data. This means properly utilizing TCP flow control signalling.
- // * Otherwise, if there is space left in the receive buffer, select() for
- // receiving data.
- // * Hand off all complete messages to the processor, to be handled without
- // blocking here.
-
- bool select_recv = !pnode->fPauseRecv;
- bool select_send;
- {
- LOCK(pnode->cs_vSend);
- select_send = !pnode->vSendMsg.empty();
- }
+ LOCK(pnode->cs_vSend);
+ select_send = !pnode->vSendMsg.empty();
+ }
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
- error_set.insert(pnode->hSocket);
- if (select_send) {
- send_set.insert(pnode->hSocket);
- continue;
- }
- if (select_recv) {
- recv_set.insert(pnode->hSocket);
- }
+ error_set.insert(pnode->hSocket);
+ if (select_send) {
+ send_set.insert(pnode->hSocket);
+ continue;
+ }
+ if (select_recv) {
+ recv_set.insert(pnode->hSocket);
}
}
@@ -1400,10 +1399,13 @@ bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &s
}
#ifdef USE_POLL
-void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set)
{
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
- if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
+ if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
return;
}
@@ -1442,10 +1444,13 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
}
}
#else
-void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set)
{
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
- if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
+ if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
return;
}
@@ -1519,34 +1524,33 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
void CConnman::SocketHandler()
{
- std::set<SOCKET> recv_set, send_set, error_set;
- SocketEvents(recv_set, send_set, error_set);
-
- if (interruptNet) return;
+ std::set<SOCKET> recv_set;
+ std::set<SOCKET> send_set;
+ std::set<SOCKET> error_set;
- //
- // Accept new connections
- //
- for (const ListenSocket& hListenSocket : vhListenSocket)
{
- if (hListenSocket.socket != INVALID_SOCKET && recv_set.count(hListenSocket.socket) > 0)
- {
- AcceptConnection(hListenSocket);
- }
- }
+ const NodesSnapshot snap{*this, /*shuffle=*/false};
- //
- // Service each socket
- //
- std::vector<CNode*> vNodesCopy;
- {
- LOCK(cs_vNodes);
- vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy)
- pnode->AddRef();
+ // Check for the readiness of the already connected sockets and the
+ // listening sockets in one call ("readiness" as in poll(2) or
+ // select(2)). If none are ready, wait for a short while and return
+ // empty sets.
+ SocketEvents(snap.Nodes(), recv_set, send_set, error_set);
+
+ // Service (send/receive) each of the already connected nodes.
+ SocketHandlerConnected(snap.Nodes(), recv_set, send_set, error_set);
}
- for (CNode* pnode : vNodesCopy)
- {
+
+ // Accept new connections from listening sockets.
+ SocketHandlerListening(recv_set);
+}
+
+void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
+ const std::set<SOCKET>& recv_set,
+ const std::set<SOCKET>& send_set,
+ const std::set<SOCKET>& error_set)
+{
+ for (CNode* pnode : nodes) {
if (interruptNet)
return;
@@ -1628,10 +1632,17 @@ void CConnman::SocketHandler()
if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
}
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodesCopy)
- pnode->Release();
+}
+
+void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
+{
+ for (const ListenSocket& listen_socket : vhListenSocket) {
+ if (interruptNet) {
+ return;
+ }
+ if (listen_socket.socket != INVALID_SOCKET && recv_set.count(listen_socket.socket) > 0) {
+ AcceptConnection(listen_socket);
+ }
}
}
@@ -1705,8 +1716,8 @@ void CConnman::ThreadDNSAddressSeed()
int nRelevant = 0;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
}
}
@@ -1814,8 +1825,8 @@ int CConnman::GetExtraFullOutboundCount() const
{
int full_outbound_peers = 0;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsFullOutboundConn()) {
++full_outbound_peers;
}
@@ -1828,8 +1839,8 @@ int CConnman::GetExtraBlockRelayCount() const
{
int block_relay_peers = 0;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) {
++block_relay_peers;
}
@@ -1900,8 +1911,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// Checking !dnsseed is cheaper before locking 2 mutexes.
if (!add_fixed_seeds_now && !dnsseed) {
- LOCK2(m_addr_fetches_mutex, cs_vAddedNodes);
- if (m_addr_fetches.empty() && vAddedNodes.empty()) {
+ LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex);
+ if (m_addr_fetches.empty() && m_added_nodes.empty()) {
add_fixed_seeds_now = true;
LogPrintf("Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n");
}
@@ -1926,8 +1937,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
std::set<std::vector<unsigned char> > setConnected;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
@@ -2115,8 +2126,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
{
std::vector<CAddress> ret;
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->IsBlockOnlyConn()) {
ret.push_back(pnode->addr);
}
@@ -2131,9 +2142,9 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
std::list<std::string> lAddresses(0);
{
- LOCK(cs_vAddedNodes);
- ret.reserve(vAddedNodes.size());
- std::copy(vAddedNodes.cbegin(), vAddedNodes.cend(), std::back_inserter(lAddresses));
+ LOCK(m_added_nodes_mutex);
+ ret.reserve(m_added_nodes.size());
+ std::copy(m_added_nodes.cbegin(), m_added_nodes.cend(), std::back_inserter(lAddresses));
}
@@ -2141,8 +2152,8 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
std::map<CService, bool> mapConnected;
std::map<std::string, std::pair<bool, CService>> mapConnectedByName;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->addr.IsValid()) {
mapConnected[pnode->addr] = pnode->IsInboundConn();
}
@@ -2238,57 +2249,42 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
m_msgproc->InitializeNode(pnode);
{
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ LOCK(m_nodes_mutex);
+ m_nodes.push_back(pnode);
}
}
void CConnman::ThreadMessageHandler()
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::MESSAGE_HANDLER);
- FastRandomContext rng;
while (!flagInterruptMsgProc)
{
- std::vector<CNode*> vNodesCopy;
- {
- LOCK(cs_vNodes);
- vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy) {
- pnode->AddRef();
- }
- }
-
bool fMoreWork = false;
- // Randomize the order in which we process messages from/to our peers.
- // This prevents attacks in which an attacker exploits having multiple
- // consecutive connections in the vNodes list.
- Shuffle(vNodesCopy.begin(), vNodesCopy.end(), rng);
-
- for (CNode* pnode : vNodesCopy)
{
- if (pnode->fDisconnect)
- continue;
+ // Randomize the order in which we process messages from/to our peers.
+ // This prevents attacks in which an attacker exploits having multiple
+ // consecutive connections in the m_nodes list.
+ const NodesSnapshot snap{*this, /*shuffle=*/true};
- // Receive messages
- bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
- fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
- if (flagInterruptMsgProc)
- return;
- // Send messages
- {
- LOCK(pnode->cs_sendProcessing);
- m_msgproc->SendMessages(pnode);
- }
+ for (CNode* pnode : snap.Nodes()) {
+ if (pnode->fDisconnect)
+ continue;
- if (flagInterruptMsgProc)
- return;
- }
+ // Receive messages
+ bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
+ fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
+ if (flagInterruptMsgProc)
+ return;
+ // Send messages
+ {
+ LOCK(pnode->cs_sendProcessing);
+ m_msgproc->SendMessages(pnode);
+ }
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodesCopy)
- pnode->Release();
+ if (flagInterruptMsgProc)
+ return;
+ }
}
WAIT_LOCK(mutexMsgProc, lock);
@@ -2698,7 +2694,7 @@ void CConnman::StopNodes()
// Delete peer connections.
std::vector<CNode*> nodes;
- WITH_LOCK(cs_vNodes, nodes.swap(vNodes));
+ WITH_LOCK(m_nodes_mutex, nodes.swap(m_nodes));
for (CNode* pnode : nodes) {
pnode->CloseSocketDisconnect();
DeleteNode(pnode);
@@ -2713,10 +2709,10 @@ void CConnman::StopNodes()
}
}
- for (CNode* pnode : vNodesDisconnected) {
+ for (CNode* pnode : m_nodes_disconnected) {
DeleteNode(pnode);
}
- vNodesDisconnected.clear();
+ m_nodes_disconnected.clear();
vhListenSocket.clear();
semOutbound.reset();
semAddnode.reset();
@@ -2789,21 +2785,21 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
bool CConnman::AddNode(const std::string& strNode)
{
- LOCK(cs_vAddedNodes);
- for (const std::string& it : vAddedNodes) {
+ LOCK(m_added_nodes_mutex);
+ for (const std::string& it : m_added_nodes) {
if (strNode == it) return false;
}
- vAddedNodes.push_back(strNode);
+ m_added_nodes.push_back(strNode);
return true;
}
bool CConnman::RemoveAddedNode(const std::string& strNode)
{
- LOCK(cs_vAddedNodes);
- for(std::vector<std::string>::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
+ LOCK(m_added_nodes_mutex);
+ for(std::vector<std::string>::iterator it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) {
if (strNode == *it) {
- vAddedNodes.erase(it);
+ m_added_nodes.erase(it);
return true;
}
}
@@ -2812,12 +2808,12 @@ bool CConnman::RemoveAddedNode(const std::string& strNode)
size_t CConnman::GetNodeCount(ConnectionDirection flags) const
{
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
if (flags == ConnectionDirection::Both) // Shortcut if we want total
- return vNodes.size();
+ return m_nodes.size();
int nNum = 0;
- for (const auto& pnode : vNodes) {
+ for (const auto& pnode : m_nodes) {
if (flags & (pnode->IsInboundConn() ? ConnectionDirection::In : ConnectionDirection::Out)) {
nNum++;
}
@@ -2829,9 +2825,9 @@ size_t CConnman::GetNodeCount(ConnectionDirection flags) const
void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
{
vstats.clear();
- LOCK(cs_vNodes);
- vstats.reserve(vNodes.size());
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ vstats.reserve(m_nodes.size());
+ for (CNode* pnode : m_nodes) {
vstats.emplace_back();
pnode->CopyStats(vstats.back());
vstats.back().m_mapped_as = pnode->addr.GetMappedAS(addrman.GetAsmap());
@@ -2840,7 +2836,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
bool CConnman::DisconnectNode(const std::string& strNode)
{
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
if (CNode* pnode = FindNode(strNode)) {
LogPrint(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId());
pnode->fDisconnect = true;
@@ -2852,8 +2848,8 @@ bool CConnman::DisconnectNode(const std::string& strNode)
bool CConnman::DisconnectNode(const CSubNet& subnet)
{
bool disconnected = false;
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (subnet.Match(pnode->addr)) {
LogPrint(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId());
pnode->fDisconnect = true;
@@ -2870,8 +2866,8 @@ bool CConnman::DisconnectNode(const CNetAddr& addr)
bool CConnman::DisconnectNode(NodeId id)
{
- LOCK(cs_vNodes);
- for(CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for(CNode* pnode : m_nodes) {
if (id == pnode->GetId()) {
LogPrint(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId());
pnode->fDisconnect = true;
@@ -2883,7 +2879,6 @@ bool CConnman::DisconnectNode(NodeId id)
void CConnman::RecordBytesRecv(uint64_t bytes)
{
- LOCK(cs_totalBytesRecv);
nTotalBytesRecv += bytes;
}
@@ -2960,7 +2955,6 @@ uint64_t CConnman::GetOutboundTargetBytesLeft() const
uint64_t CConnman::GetTotalBytesRecv() const
{
- LOCK(cs_totalBytesRecv);
return nTotalBytesRecv;
}
@@ -3024,7 +3018,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
size_t nMessageSize = msg.data.size();
LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
if (gArgs.GetBoolArg("-capturemessages", false)) {
- CaptureMessage(pnode->addr, msg.m_type, msg.data, /* incoming */ false);
+ CaptureMessage(pnode->addr, msg.m_type, msg.data, /*is_incoming=*/false);
}
TRACE6(net, outbound_message,
@@ -3063,8 +3057,8 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
{
CNode* found = nullptr;
- LOCK(cs_vNodes);
- for (auto&& pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (auto&& pnode : m_nodes) {
if(pnode->GetId() == id) {
found = pnode;
break;
diff --git a/src/net.h b/src/net.h
index 878f10cd42..dd5cc66a04 100644
--- a/src/net.h
+++ b/src/net.h
@@ -70,7 +70,7 @@ static const bool DEFAULT_LISTEN = true;
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
-static constexpr uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
+static const std::string DEFAULT_MAX_UPLOAD_TARGET{"0M"};
/** Default for blocks only*/
static const bool DEFAULT_BLOCKSONLY = false;
/** -peertimeout default */
@@ -791,8 +791,8 @@ public:
}
vWhitelistedRange = connOptions.vWhitelistedRange;
{
- LOCK(cs_vAddedNodes);
- vAddedNodes = connOptions.m_added_nodes;
+ LOCK(m_added_nodes_mutex);
+ m_added_nodes = connOptions.m_added_nodes;
}
m_onion_binds = connOptions.onion_binds;
}
@@ -823,8 +823,8 @@ public:
using NodeFn = std::function<void(CNode*)>;
void ForEachNode(const NodeFn& func)
{
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (auto&& node : m_nodes) {
if (NodeFullyConnected(node))
func(node);
}
@@ -832,8 +832,8 @@ public:
void ForEachNode(const NodeFn& func) const
{
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (auto&& node : m_nodes) {
if (NodeFullyConnected(node))
func(node);
}
@@ -968,7 +968,7 @@ private:
/**
* Create a `CNode` object from a socket that has just been accepted and add the node to
- * the `vNodes` member.
+ * the `m_nodes` member.
* @param[in] hSocket Connected socket to communicate with the peer.
* @param[in] permissionFlags The peer's permissions.
* @param[in] addr_bind The address and port at our side of the connection.
@@ -983,9 +983,57 @@ private:
void NotifyNumConnectionsChanged();
/** Return true if the peer is inactive and should be disconnected. */
bool InactivityCheck(const CNode& node) const;
- bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
- void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
+
+ /**
+ * Generate a collection of sockets to check for IO readiness.
+ * @param[in] nodes Select from these nodes' sockets.
+ * @param[out] recv_set Sockets to check for read readiness.
+ * @param[out] send_set Sockets to check for write readiness.
+ * @param[out] error_set Sockets to check for errors.
+ * @return true if at least one socket is to be checked (the returned set is not empty)
+ */
+ bool GenerateSelectSet(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set);
+
+ /**
+ * Check which sockets are ready for IO.
+ * @param[in] nodes Select from these nodes' sockets.
+ * @param[out] recv_set Sockets which are ready for read.
+ * @param[out] send_set Sockets which are ready for write.
+ * @param[out] error_set Sockets which have errors.
+ * This calls `GenerateSelectSet()` to gather a list of sockets to check.
+ */
+ void SocketEvents(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set);
+
+ /**
+ * Check connected and listening sockets for IO readiness and process them accordingly.
+ */
void SocketHandler();
+
+ /**
+ * Do the read/write for connected sockets that are ready for IO.
+ * @param[in] nodes Nodes to process. The socket of each node is checked against
+ * `recv_set`, `send_set` and `error_set`.
+ * @param[in] recv_set Sockets that are ready for read.
+ * @param[in] send_set Sockets that are ready for send.
+ * @param[in] error_set Sockets that have an exceptional condition (error).
+ */
+ void SocketHandlerConnected(const std::vector<CNode*>& nodes,
+ const std::set<SOCKET>& recv_set,
+ const std::set<SOCKET>& send_set,
+ const std::set<SOCKET>& error_set);
+
+ /**
+ * Accept incoming connections, one from each read-ready listening socket.
+ * @param[in] recv_set Sockets that are ready for read.
+ */
+ void SocketHandlerListening(const std::set<SOCKET>& recv_set);
+
void ThreadSocketHandler();
void ThreadDNSAddressSeed();
@@ -1026,9 +1074,8 @@ private:
static bool NodeFullyConnected(const CNode* pnode);
// Network usage totals
- mutable RecursiveMutex cs_totalBytesRecv;
mutable RecursiveMutex cs_totalBytesSent;
- uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0};
+ std::atomic<uint64_t> nTotalBytesRecv{0};
uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
// outbound limit & stats
@@ -1051,12 +1098,12 @@ private:
bool fAddressesInitialized{false};
AddrMan& addrman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
- RecursiveMutex m_addr_fetches_mutex;
- std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
- mutable RecursiveMutex cs_vAddedNodes;
- std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
- std::list<CNode*> vNodesDisconnected;
- mutable RecursiveMutex cs_vNodes;
+ Mutex m_addr_fetches_mutex;
+ std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
+ mutable Mutex m_added_nodes_mutex;
+ std::vector<CNode*> m_nodes GUARDED_BY(m_nodes_mutex);
+ std::list<CNode*> m_nodes_disconnected;
+ mutable RecursiveMutex m_nodes_mutex;
std::atomic<NodeId> nLastNodeId{0};
unsigned int nPrevNodeCount{0};
@@ -1177,6 +1224,43 @@ private:
*/
std::vector<CService> m_onion_binds;
+ /**
+ * RAII helper to atomically create a copy of `m_nodes` and add a reference
+ * to each of the nodes. The nodes are released when this object is destroyed.
+ */
+ class NodesSnapshot
+ {
+ public:
+ explicit NodesSnapshot(const CConnman& connman, bool shuffle)
+ {
+ {
+ LOCK(connman.m_nodes_mutex);
+ m_nodes_copy = connman.m_nodes;
+ for (auto& node : m_nodes_copy) {
+ node->AddRef();
+ }
+ }
+ if (shuffle) {
+ Shuffle(m_nodes_copy.begin(), m_nodes_copy.end(), FastRandomContext{});
+ }
+ }
+
+ ~NodesSnapshot()
+ {
+ for (auto& node : m_nodes_copy) {
+ node->Release();
+ }
+ }
+
+ const std::vector<CNode*>& Nodes() const
+ {
+ return m_nodes_copy;
+ }
+
+ private:
+ std::vector<CNode*> m_nodes_copy;
+ };
+
friend struct CConnmanTest;
friend struct ConnmanTestMsg;
};
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 2185ccc700..3f755eb178 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3206,6 +3206,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return;
}
+ // Stop processing the transaction early if we are still in IBD since we don't
+ // have enough information to validate it yet. Sending unsolicited transactions
+ // is not considered a protocol violation, so don't punish the peer.
+ if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) return;
+
CTransactionRef ptx;
vRecv >> ptx;
const CTransaction& tx = *ptx;
@@ -4105,7 +4110,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
);
if (gArgs.GetBoolArg("-capturemessages", false)) {
- CaptureMessage(pfrom->addr, msg.m_command, MakeUCharSpan(msg.m_recv), /* incoming */ true);
+ CaptureMessage(pfrom->addr, msg.m_command, MakeUCharSpan(msg.m_recv), /*is_incoming=*/true);
}
msg.SetVersion(pfrom->GetCommonVersion());
diff --git a/src/netaddress.h b/src/netaddress.h
index b0b1c5ca9e..a5b74eb35b 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -385,6 +385,12 @@ private:
/**
* Unserialize from a pre-ADDRv2/BIP155 format from an array.
+ *
+ * This function is only called from UnserializeV1Stream() and is a wrapper
+ * for SetLegacyIPv6(); however, we keep it for symmetry with
+ * SerializeV1Array() to have pairs of ser/unser functions and to make clear
+ * that if one is altered, a corresponding reverse modification should be
+ * applied to the other.
*/
void UnserializeV1Array(uint8_t (&arr)[V1_SERIALIZATION_SIZE])
{
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 9f457570fa..e5f2753123 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -276,6 +276,10 @@ public:
LOCK(::cs_main);
return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
}
+ TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
+ {
+ return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
+ }
WalletClient& walletClient() override
{
return *Assert(m_context->wallet_client);
@@ -536,8 +540,11 @@ public:
const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving
- // output uninitialized.
- return FillBlock(ancestor, ancestor_out, lock, active) & FillBlock(block1, block1_out, lock, active) & FillBlock(block2, block2_out, lock, active);
+ // output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
+ // compiler warnings.
+ return int{FillBlock(ancestor, ancestor_out, lock, active)} &
+ int{FillBlock(block1, block1_out, lock, active)} &
+ int{FillBlock(block2, block2_out, lock, active)};
}
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
double guessVerificationProgress(const uint256& block_hash) override
@@ -717,12 +724,6 @@ public:
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
}
}
- bool isTaprootActive() override
- {
- LOCK(::cs_main);
- const CBlockIndex* tip = Assert(m_node.chainman)->ActiveChain().Tip();
- return DeploymentActiveAfter(tip, Params().GetConsensus(), Consensus::DEPLOYMENT_TAPROOT);
- }
NodeContext& m_node;
};
} // namespace
diff --git a/src/miner.cpp b/src/node/miner.cpp
index 1ef246cd14..8778a79f8b 100644
--- a/src/miner.cpp
+++ b/src/node/miner.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <miner.h>
+#include <node/miner.h>
#include <chain.h>
#include <chainparams.h>
@@ -21,6 +21,7 @@
#include <timedata.h>
#include <util/moneystr.h>
#include <util/system.h>
+#include <validation.h>
#include <algorithm>
#include <utility>
diff --git a/src/miner.h b/src/node/miner.h
index 10a80f4392..0e8c02793a 100644
--- a/src/miner.h
+++ b/src/node/miner.h
@@ -3,20 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_MINER_H
-#define BITCOIN_MINER_H
+#ifndef BITCOIN_NODE_MINER_H
+#define BITCOIN_NODE_MINER_H
#include <primitives/block.h>
#include <txmempool.h>
-#include <validation.h>
#include <memory>
#include <optional>
#include <stdint.h>
-#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index_container.hpp>
+class ChainstateManager;
class CBlockIndex;
class CChainParams;
class CScript;
@@ -205,4 +205,4 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
-#endif // BITCOIN_MINER_H
+#endif // BITCOIN_NODE_MINER_H
diff --git a/src/minisketchwrapper.cpp b/src/node/minisketchwrapper.cpp
index fb176fb153..572df63463 100644
--- a/src/minisketchwrapper.cpp
+++ b/src/node/minisketchwrapper.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <minisketchwrapper.h>
+#include <node/minisketchwrapper.h>
#include <logging.h>
#include <util/time.h>
diff --git a/src/minisketchwrapper.h b/src/node/minisketchwrapper.h
index 409221de79..a8aef68d01 100644
--- a/src/minisketchwrapper.h
+++ b/src/node/minisketchwrapper.h
@@ -2,10 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_MINISKETCHWRAPPER_H
-#define BITCOIN_MINISKETCHWRAPPER_H
+#ifndef BITCOIN_NODE_MINISKETCHWRAPPER_H
+#define BITCOIN_NODE_MINISKETCHWRAPPER_H
#include <minisketch.h>
+
#include <cstddef>
#include <cstdint>
@@ -14,4 +15,4 @@ Minisketch MakeMinisketch32(size_t capacity);
/** Wrapper around Minisketch::CreateFP. */
Minisketch MakeMinisketch32FP(size_t max_elements, uint32_t fpbits);
-#endif // BITCOIN_DBWRAPPER_H
+#endif // BITCOIN_NODE_MINISKETCHWRAPPER_H
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 8ba896bb01..13c7ec2002 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -67,4 +67,4 @@ public:
SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
};
-#endif // BITCOIN_POLICY_FEERATE_H
+#endif // BITCOIN_POLICY_FEERATE_H
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index fced397e51..2c30b20d5b 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -161,13 +161,13 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
*
* Note that only the non-witness portion of the transaction is checked here.
*/
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
- if (tx.IsCoinBase())
+ if (tx.IsCoinBase()) {
return true; // Coinbases don't use vin normally
+ }
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
@@ -189,9 +189,6 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
return false;
}
- } else if (whichType == TxoutType::WITNESS_V1_TAPROOT) {
- // Don't allow Taproot spends unless Taproot is active.
- if (!taproot_active) return false;
}
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index f2a3f35546..f6ac6500f6 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -105,10 +105,9 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
-* @param[in] taproot_active Whether or taproot consensus rules are active (used to decide whether spends of them are permitted)
* @return True if all inputs (scriptSigs) use only standard transaction forms
*/
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active);
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
/**
* Check if the transaction is over standard P2WSH resources limit:
* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 5445bc8aa1..6585766807 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -223,7 +223,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio
// Construct a would-be spend of this output, to update sigdata with.
// Note that ProduceSignature is used to fill in metadata (not actual signatures),
// so provider does not need to provide any private keys (it can be a HidingSigningProvider).
- MutableTransactionSignatureCreator creator(&tx, /* index */ 0, out.nValue, SIGHASH_ALL);
+ MutableTransactionSignatureCreator creator(&tx, /*input_idx=*/0, out.nValue, SIGHASH_ALL);
ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
// Put redeem_script, witness_script, key paths, into PSBTOutput.
@@ -247,7 +247,7 @@ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction&
return txdata;
}
-bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata)
+bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
{
PSBTInput& input = psbt.inputs.at(index);
const CMutableTransaction& tx = *psbt.tx;
@@ -295,6 +295,10 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
}
// Verify that a witness signature was produced in case one was required.
if (require_witness_sig && !sigdata.witness) return false;
+
+ // If we are not finalizing, set sigdata.complete to false to not set the scriptWitness
+ if (!finalize && sigdata.complete) sigdata.complete = false;
+
input.FromSignatureData(sigdata);
// If we have a witness signature, put a witness UTXO.
@@ -324,7 +328,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx)
bool complete = true;
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL);
+ complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
}
return complete;
diff --git a/src/psbt.h b/src/psbt.h
index f6b82b43de..7808a247c0 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -578,7 +578,7 @@ bool PSBTInputSigned(const PSBTInput& input);
* txdata should be the output of PrecomputePSBTData (which can be shared across
* multiple SignPSBTInput calls). If it is nullptr, a dummy signature will be created.
**/
-bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr);
+bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
/** Counts the unsigned inputs of a PSBT. */
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt);
diff --git a/src/pubkey.h b/src/pubkey.h
index f174ad8d85..ae6356c246 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -141,7 +141,7 @@ public:
template <typename Stream>
void Unserialize(Stream& s)
{
- unsigned int len = ::ReadCompactSize(s);
+ const unsigned int len(::ReadCompactSize(s));
if (len <= SIZE) {
s.read((char*)vch, len);
if (len != size()) {
@@ -149,9 +149,7 @@ public:
}
} else {
// invalid pubkey, skip available data
- char dummy;
- while (len--)
- s.read(&dummy, 1);
+ s.ignore(len);
Invalidate();
}
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index b68ce39b53..81a1d88d20 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -870,7 +870,7 @@ void BitcoinGUI::showHelpMessageClicked()
#ifdef ENABLE_WALLET
void BitcoinGUI::openClicked()
{
- OpenURIDialog dlg(this);
+ OpenURIDialog dlg(platformStyle, this);
if(dlg.exec())
{
Q_EMIT receivedURI(dlg.getURI());
diff --git a/src/qt/forms/openuridialog.ui b/src/qt/forms/openuridialog.ui
index 1b7291ab9d..97399e59a2 100644
--- a/src/qt/forms/openuridialog.ui
+++ b/src/qt/forms/openuridialog.ui
@@ -30,6 +30,27 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="pasteButton">
+ <property name="toolTip">
+ <string extracomment="Tooltip text for button that allows you to paste an address that is in your clipboard.">Paste address from clipboard</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/editpaste</normaloff>:/icons/editpaste
+ </iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>22</width>
+ <height>22</height>
+ </size>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 1c22124616..6b3a4630a3 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -33,7 +33,7 @@
<string>Automatically start %1 after logging in to the system.</string>
</property>
<property name="text">
- <string>Start %1 on system &amp;login</string>
+ <string>&amp;Start %1 on system login</string>
</property>
</widget>
</item>
@@ -192,7 +192,7 @@
<string extracomment="Tooltip text for Options window setting that enables the RPC server.">This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</string>
</property>
<property name="text">
- <string extracomment="An Options window setting to enable the RPC server.">Enable RPC &amp;server</string>
+ <string extracomment="An Options window setting to enable the RPC server.">Enable R&amp;PC server</string>
</property>
</widget>
</item>
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 10bf82d532..a68eee718e 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -6,15 +6,20 @@
#include <qt/forms/ui_openuridialog.h>
#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
#include <qt/sendcoinsrecipient.h>
+#include <QAbstractButton>
+#include <QLineEdit>
#include <QUrl>
-OpenURIDialog::OpenURIDialog(QWidget *parent) :
- QDialog(parent, GUIUtil::dialog_flags),
- ui(new Ui::OpenURIDialog)
+OpenURIDialog::OpenURIDialog(const PlatformStyle* platformStyle, QWidget* parent) : QDialog(parent, GUIUtil::dialog_flags),
+ ui(new Ui::OpenURIDialog),
+ m_platform_style(platformStyle)
{
ui->setupUi(this);
+ ui->pasteButton->setIcon(m_platform_style->SingleColorIcon(":/icons/editpaste"));
+ QObject::connect(ui->pasteButton, &QAbstractButton::clicked, ui->uriEdit, &QLineEdit::paste);
GUIUtil::handleCloseWindowShortcut(this);
}
@@ -32,11 +37,19 @@ QString OpenURIDialog::getURI()
void OpenURIDialog::accept()
{
SendCoinsRecipient rcp;
- if(GUIUtil::parseBitcoinURI(getURI(), &rcp))
- {
+ if (GUIUtil::parseBitcoinURI(getURI(), &rcp)) {
/* Only accept value URIs */
QDialog::accept();
} else {
ui->uriEdit->setValid(false);
}
}
+
+void OpenURIDialog::changeEvent(QEvent* e)
+{
+ if (e->type() == QEvent::PaletteChange) {
+ ui->pasteButton->setIcon(m_platform_style->SingleColorIcon(":/icons/editpaste"));
+ }
+
+ QDialog::changeEvent(e);
+}
diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h
index efe4b86f37..f3a8b0ba22 100644
--- a/src/qt/openuridialog.h
+++ b/src/qt/openuridialog.h
@@ -7,6 +7,8 @@
#include <QDialog>
+class PlatformStyle;
+
namespace Ui {
class OpenURIDialog;
}
@@ -16,16 +18,19 @@ class OpenURIDialog : public QDialog
Q_OBJECT
public:
- explicit OpenURIDialog(QWidget *parent);
+ explicit OpenURIDialog(const PlatformStyle* platformStyle, QWidget* parent);
~OpenURIDialog();
QString getURI();
protected Q_SLOTS:
void accept() override;
+ void changeEvent(QEvent* e) override;
private:
- Ui::OpenURIDialog *ui;
+ Ui::OpenURIDialog* ui;
+
+ const PlatformStyle* m_platform_style;
};
#endif // BITCOIN_QT_OPENURIDIALOG_H
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 34d56e5506..3e598bfab9 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -110,8 +110,8 @@ void PSBTOperationsDialog::broadcastTransaction()
CTransactionRef tx = MakeTransactionRef(mtx);
std::string err_string;
- TransactionError error = BroadcastTransaction(
- *m_client_model->node().context(), tx, err_string, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true, /* await_callback */ false);
+ TransactionError error =
+ m_client_model->node().broadcastTransaction(tx, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), err_string);
if (error == TransactionError::OK) {
showStatus(tr("Transaction broadcast successfully! Transaction ID: %1")
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 0c3332ab76..6bcdcc4c29 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -866,7 +866,11 @@ void RPCConsole::clear(bool keep_prompt)
}
// Set default style sheet
+#ifdef Q_OS_MAC
+ QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont(/*use_embedded_font=*/true));
+#else
QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
+#endif
ui->messagesWidget->document()->setDefaultStyleSheet(
QString(
"table { }"
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index b26cddf4ae..e7a3d724bb 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -69,7 +69,7 @@ int main(int argc, char* argv[])
#if defined(WIN32)
if (getenv("QT_QPA_PLATFORM") == nullptr) _putenv_s("QT_QPA_PLATFORM", "minimal");
#else
- setenv("QT_QPA_PLATFORM", "minimal", /* overwrite */ 0);
+ setenv("QT_QPA_PLATFORM", "minimal", 0 /* overwrite */);
#endif
// Don't remove this, it's needed to access
diff --git a/src/randomenv.h b/src/randomenv.h
index 46cea6f6f2..746516b79b 100644
--- a/src/randomenv.h
+++ b/src/randomenv.h
@@ -14,4 +14,4 @@ void RandAddDynamicEnv(CSHA512& hasher);
/** Gather non-cryptographic environment data that does not change over time. */
void RandAddStaticEnv(CSHA512& hasher);
-#endif
+#endif // BITCOIN_RANDOMENV_H
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index d9c6761f47..65f6b1429e 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -67,4 +67,4 @@ CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context);
*/
UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFile& afile);
-#endif
+#endif // BITCOIN_RPC_BLOCKCHAIN_H
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 93e49cb9a8..90fbd823a4 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -115,6 +115,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "walletcreatefundedpsbt", 4, "bip32derivs" },
{ "walletprocesspsbt", 1, "sign" },
{ "walletprocesspsbt", 3, "bip32derivs" },
+ { "walletprocesspsbt", 4, "finalize" },
{ "createpsbt", 0, "inputs" },
{ "createpsbt", 1, "outputs" },
{ "createpsbt", 2, "locktime" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 518c41d12a..89abdd057c 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -13,9 +13,9 @@
#include <deploymentinfo.h>
#include <deploymentstatus.h>
#include <key_io.h>
-#include <miner.h>
#include <net.h>
#include <node/context.h>
+#include <node/miner.h>
#include <policy/fees.h>
#include <pow.h>
#include <rpc/blockchain.h>
@@ -1010,7 +1010,7 @@ static RPCHelpMan submitblock()
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
- bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
+ bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /*force_processing=*/true, /*new_block=*/&new_block);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 39bd9c6091..2bd8a6b050 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -52,6 +52,10 @@ static RPCHelpMan validateaddress()
{RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
{RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
{RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
+ {RPCResult::Type::ARR, "error_locations", "Indices of likely error locations in address, if known (e.g. Bech32 errors)",
+ {
+ {RPCResult::Type::NUM, "index", "index of a potential error"},
+ }},
}
},
RPCExamples{
@@ -61,7 +65,8 @@ static RPCHelpMan validateaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::string error_msg;
- CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
+ std::vector<int> error_locations;
+ CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg, &error_locations);
const bool isValid = IsValidDestination(dest);
CHECK_NONFATAL(isValid == error_msg.empty());
@@ -77,6 +82,9 @@ static RPCHelpMan validateaddress()
UniValue detail = DescribeAddress(dest);
ret.pushKVs(detail);
} else {
+ UniValue error_indices(UniValue::VARR);
+ for (int i : error_locations) error_indices.push_back(i);
+ ret.pushKV("error_locations", error_indices);
ret.pushKV("error", error_msg);
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 89f2309cb7..2dd121c6f6 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1619,7 +1619,7 @@ static RPCHelpMan utxoupdatepsbt()
}
}
// We don't actually need private keys further on; hide them as a precaution.
- HidingSigningProvider public_provider(&provider, /* nosign */ true, /* nobip32derivs */ false);
+ HidingSigningProvider public_provider(&provider, /*hide_secret=*/true, /*hide_origin=*/false);
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
@@ -1658,7 +1658,7 @@ static RPCHelpMan utxoupdatepsbt()
// Update script/keypath information using descriptor data.
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
// we don't actually care about those here, in fact.
- SignPSBTInput(public_provider, psbtx, i, &txdata, /* sighash_type */ 1);
+ SignPSBTInput(public_provider, psbtx, i, &txdata, /*sighash=*/1);
}
// Update script/keypath information using descriptor data.
diff --git a/src/scheduler.h b/src/scheduler.h
index 9eec8c0fa0..be878661db 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -146,4 +146,4 @@ public:
size_t CallbacksPending();
};
-#endif
+#endif // BITCOIN_SCHEDULER_H
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 621a1b9fd6..c3b4d1ddaa 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -851,6 +851,7 @@ protected:
builder.Finalize(xpk);
WitnessV1Taproot output = builder.GetOutput();
out.tr_spenddata[output].Merge(builder.GetSpendData());
+ out.pubkeys.emplace(keys[0].GetID(), keys[0]);
return Vector(GetScriptForDestination(output));
}
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index eafa9840d7..d83ec7192b 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1483,7 +1483,7 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
-static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
+const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index ab49e84577..513eaaf94c 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -229,6 +229,7 @@ static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32;
static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
+extern const CHashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
extern const CHashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
extern const CHashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 4cb2125747..8e044b1e00 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -17,16 +17,16 @@
typedef std::vector<unsigned char> valtype;
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn)
- : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn, MissingDataBehavior::FAIL),
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, int hash_type)
+ : txTo{tx}, nIn{input_idx}, nHashType{hash_type}, amount{amount}, checker{txTo, nIn, amount, MissingDataBehavior::FAIL},
m_txdata(nullptr)
{
}
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn)
- : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn),
- checker(txdata ? MutableTransactionSignatureChecker(txTo, nIn, amount, *txdata, MissingDataBehavior::FAIL) :
- MutableTransactionSignatureChecker(txTo, nIn, amount, MissingDataBehavior::FAIL)),
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, const PrecomputedTransactionData* txdata, int hash_type)
+ : txTo{tx}, nIn{input_idx}, nHashType{hash_type}, amount{amount},
+ checker{txdata ? MutableTransactionSignatureChecker{txTo, nIn, amount, *txdata, MissingDataBehavior::FAIL} :
+ MutableTransactionSignatureChecker{txTo, nIn, amount, MissingDataBehavior::FAIL}},
m_txdata(txdata)
{
}
@@ -81,7 +81,8 @@ bool MutableTransactionSignatureCreator::CreateSchnorrSig(const SigningProvider&
uint256 hash;
if (!SignatureHashSchnorr(hash, execdata, *txTo, nIn, nHashType, sigversion, *m_txdata, MissingDataBehavior::FAIL)) return false;
sig.resize(64);
- if (!key.SignSchnorr(hash, sig, merkle_root, nullptr)) return false;
+ // Use uint256{} as aux_rnd for now.
+ if (!key.SignSchnorr(hash, sig, merkle_root, {})) return false;
if (nHashType) sig.push_back(nHashType);
return true;
}
diff --git a/src/script/sign.h b/src/script/sign.h
index 6d3479c143..62335b644a 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -45,8 +45,8 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator {
const PrecomputedTransactionData* m_txdata;
public:
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn);
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn);
+ MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, int hash_type);
+ MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, const PrecomputedTransactionData* txdata, int hash_type);
const BaseSignatureChecker& Checker() const override { return checker; }
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const override;
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index b80fbe22ce..17f97fa30c 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -190,8 +190,8 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{
- // Only supports destinations which map to single public keys, i.e. P2PKH,
- // P2WPKH, and P2SH-P2WPKH.
+ // Only supports destinations which map to single public keys:
+ // P2PKH, P2WPKH, P2SH-P2WPKH, P2TR
if (auto id = std::get_if<PKHash>(&dest)) {
return ToKeyID(*id);
}
@@ -208,5 +208,15 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
}
}
}
+ if (auto output_key = std::get_if<WitnessV1Taproot>(&dest)) {
+ TaprootSpendData spenddata;
+ CPubKey pub;
+ if (store.GetTaprootSpendData(*output_key, spenddata)
+ && !spenddata.internal_key.IsNull()
+ && spenddata.merkle_root.IsNull()
+ && store.GetPubKeyByXOnly(spenddata.internal_key, pub)) {
+ return pub.GetID();
+ }
+ }
return CKeyID();
}
diff --git a/src/shutdown.h b/src/shutdown.h
index ff56c6bd87..9df601d478 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -32,4 +32,4 @@ bool ShutdownRequested();
*/
void WaitForShutdown();
-#endif
+#endif // BITCOIN_SHUTDOWN_H
diff --git a/src/span.h b/src/span.h
index 830164514b..746e41f2f4 100644
--- a/src/span.h
+++ b/src/span.h
@@ -30,7 +30,11 @@
/** A Span is an object that can refer to a contiguous sequence of objects.
*
- * It implements a subset of C++20's std::span.
+ * This file implements a subset of C++20's std::span. It can be considered
+ * temporary compatibility code until C++20 and is designed to be a
+ * self-contained abstraction without depending on other project files. For this
+ * reason, Clang lifetimebound is defined here instead of including
+ * <attributes.h>, which also defines it.
*
* Things to be aware of when writing code that deals with Spans:
*
@@ -60,7 +64,7 @@
* types that expose a data() and size() member function), functions that
* accept a Span as input parameter can be called with any compatible
* range-like object. For example, this works:
-*
+ *
* void Foo(Span<const int> arg);
*
* Foo(std::vector<int>{1, 2, 3}); // Works
@@ -180,6 +184,7 @@ public:
return m_data[m_size - 1];
}
constexpr std::size_t size() const noexcept { return m_size; }
+ constexpr std::size_t size_bytes() const noexcept { return sizeof(C) * m_size; }
constexpr bool empty() const noexcept { return size() == 0; }
CONSTEXPR_IF_NOT_DEBUG C& operator[](std::size_t pos) const noexcept
{
@@ -236,11 +241,35 @@ T& SpanPopBack(Span<T>& span)
return back;
}
+// From C++20 as_bytes and as_writeable_bytes
+template <typename T>
+Span<const std::byte> AsBytes(Span<T> s) noexcept
+{
+ return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
+}
+template <typename T>
+Span<std::byte> AsWritableBytes(Span<T> s) noexcept
+{
+ return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
+}
+
+template <typename V>
+Span<const std::byte> MakeByteSpan(V&& v) noexcept
+{
+ return AsBytes(MakeSpan(std::forward<V>(v)));
+}
+template <typename V>
+Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
+{
+ return AsWritableBytes(MakeSpan(std::forward<V>(v)));
+}
+
// Helper functions to safely cast to unsigned char pointers.
inline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }
inline unsigned char* UCharCast(unsigned char* c) { return c; }
inline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }
inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
+inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }
// Helper function to safely convert a Span to a Span<[const] unsigned char>.
template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }
@@ -248,4 +277,4 @@ template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename s
/** Like MakeSpan, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
template <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(MakeSpan(std::forward<V>(v)))) { return UCharSpanCast(MakeSpan(std::forward<V>(v))); }
-#endif
+#endif // BITCOIN_SPAN_H
diff --git a/src/streams.h b/src/streams.h
index 31407287ae..9e8f379cd2 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -226,7 +226,7 @@ public:
: nType{nTypeIn},
nVersion{nVersionIn} {}
- explicit CDataStream(Span<const uint8_t> sp, int nTypeIn, int nVersionIn)
+ explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)
: vch(sp.data(), sp.data() + sp.size()),
nType{nTypeIn},
nVersion{nVersionIn} {}
@@ -254,17 +254,17 @@ public:
iterator end() { return vch.end(); }
size_type size() const { return vch.size() - nReadPos; }
bool empty() const { return vch.size() == nReadPos; }
- void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
+ void resize(size_type n, value_type c = value_type{}) { vch.resize(n + nReadPos, c); }
void reserve(size_type n) { vch.reserve(n + nReadPos); }
const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
reference operator[](size_type pos) { return vch[pos + nReadPos]; }
void clear() { vch.clear(); nReadPos = 0; }
- iterator insert(iterator it, const uint8_t x) { return vch.insert(it, x); }
- void insert(iterator it, size_type n, const uint8_t x) { vch.insert(it, n, x); }
+ iterator insert(iterator it, const value_type x) { return vch.insert(it, x); }
+ void insert(iterator it, size_type n, const value_type x) { vch.insert(it, n, x); }
value_type* data() { return vch.data() + nReadPos; }
const value_type* data() const { return vch.data() + nReadPos; }
- void insert(iterator it, std::vector<uint8_t>::const_iterator first, std::vector<uint8_t>::const_iterator last)
+ void insert(iterator it, std::vector<value_type>::const_iterator first, std::vector<value_type>::const_iterator last)
{
if (last == first) return;
assert(last - first > 0);
@@ -278,7 +278,7 @@ public:
vch.insert(it, first, last);
}
- void insert(iterator it, const char* first, const char* last)
+ void insert(iterator it, const value_type* first, const value_type* last)
{
if (last == first) return;
assert(last - first > 0);
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index 9d1dfd46f1..c5fce7bec0 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -23,6 +23,16 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}
+ {
+ const std::vector<uint8_t> in_u{0xff, 0x01, 0xff};
+ const std::vector<std::byte> in_b{std::byte{0xff}, std::byte{0x01}, std::byte{0xff}};
+ const std::string in_s{"\xff\x01\xff"};
+ const std::string out_exp{"/wH/"};
+ BOOST_CHECK_EQUAL(EncodeBase64(in_u), out_exp);
+ BOOST_CHECK_EQUAL(EncodeBase64(in_b), out_exp);
+ BOOST_CHECK_EQUAL(EncodeBase64(in_s), out_exp);
+ }
+
// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase64("invalid\0"s, &failure);
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
index c0344b3cbb..8eed959228 100644
--- a/src/test/bech32_tests.cpp
+++ b/src/test/bech32_tests.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2017 Pieter Wuille
+// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -68,10 +69,36 @@ BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
"1qzzfhee",
"a12UEL5L",
"A12uEL5L",
+ "abcdef1qpzrz9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
};
+ static const std::pair<std::string, int> ERRORS[] = {
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Bech32 string too long", 90},
+ {"Missing separator", -1},
+ {"Invalid separator position", 0},
+ {"Invalid Base 32 character", 2},
+ {"Invalid separator position", 2},
+ {"Invalid character or mixed case", 8},
+ {"Invalid checksum", -1}, // The checksum is calculated using the uppercase form so the entire string is invalid, not just a few characters
+ {"Invalid separator position", 0},
+ {"Invalid separator position", 0},
+ {"Invalid character or mixed case", 3},
+ {"Invalid character or mixed case", 3},
+ {"Invalid checksum", 11}
+ };
+ int i = 0;
for (const std::string& str : CASES) {
+ const auto& err = ERRORS[i];
const auto dec = bech32::Decode(str);
BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
+ std::vector<int> error_locations;
+ std::string error = bech32::LocateErrors(str, error_locations);
+ BOOST_CHECK_EQUAL(err.first, error);
+ if (err.second == -1) BOOST_CHECK(error_locations.empty());
+ else BOOST_CHECK_EQUAL(err.second, error_locations[0]);
+ i++;
}
}
@@ -91,11 +118,37 @@ BOOST_AUTO_TEST_CASE(bech32m_testvectors_invalid)
"au1s5cgom",
"M1VUXWEZ",
"16plkw9",
- "1p2gdwpf"
+ "1p2gdwpf",
+ "abcdef1l7aum6echk45nj2s0wdvt2fg8x9yrzpqzd3ryx",
+ };
+ static const std::pair<std::string, int> ERRORS[] = {
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Bech32 string too long", 90},
+ {"Missing separator", -1},
+ {"Invalid separator position", 0},
+ {"Invalid Base 32 character", 2},
+ {"Invalid Base 32 character", 3},
+ {"Invalid separator position", 2},
+ {"Invalid Base 32 character", 8},
+ {"Invalid Base 32 character", 7},
+ {"Invalid checksum", -1},
+ {"Invalid separator position", 0},
+ {"Invalid separator position", 0},
+ {"Invalid checksum", 21},
};
+ int i = 0;
for (const std::string& str : CASES) {
+ const auto& err = ERRORS[i];
const auto dec = bech32::Decode(str);
BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
+ std::vector<int> error_locations;
+ std::string error = bech32::LocateErrors(str, error_locations);
+ BOOST_CHECK_EQUAL(err.first, error);
+ if (err.second == -1) BOOST_CHECK(error_locations.empty());
+ else BOOST_CHECK_EQUAL(err.second, error_locations[0]);
+ i++;
}
}
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 2eb653e9ec..7d50def509 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -6,7 +6,7 @@
#include <chainparams.h>
#include <consensus/validation.h>
#include <index/blockfilterindex.h>
-#include <miner.h>
+#include <node/miner.h>
#include <pow.h>
#include <script/standard.h>
#include <test/util/blockfilter.h>
diff --git a/src/test/data/bip341_wallet_vectors.json b/src/test/data/bip341_wallet_vectors.json
new file mode 100644
index 0000000000..11261b00ba
--- /dev/null
+++ b/src/test/data/bip341_wallet_vectors.json
@@ -0,0 +1,452 @@
+{
+ "version": 1,
+ "scriptPubKey": [
+ {
+ "given": {
+ "internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d",
+ "scriptTree": null
+ },
+ "intermediary": {
+ "merkleRoot": null,
+ "tweak": "b86e7be8f39bab32a6f2c0443abbc210f0edac0e2c53d501b36b64437d9c6c70",
+ "tweakedPubkey": "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343"
+ },
+ "expected": {
+ "scriptPubKey": "512053a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
+ "bip350Address": "bc1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dps59h4z5"
+ }
+ },
+ {
+ "given": {
+ "internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
+ "scriptTree": {
+ "id": 0,
+ "script": "20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
+ "leafVersion": 192
+ }
+ },
+ "intermediary": {
+ "leafHashes": [
+ "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
+ ],
+ "merkleRoot": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
+ "tweak": "cbd8679ba636c1110ea247542cfbd964131a6be84f873f7f3b62a777528ed001",
+ "tweakedPubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3"
+ },
+ "expected": {
+ "scriptPubKey": "5120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
+ "bip350Address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586",
+ "scriptPathControlBlocks": [
+ "c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27"
+ ]
+ }
+ },
+ {
+ "given": {
+ "internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
+ "scriptTree": {
+ "id": 0,
+ "script": "20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac",
+ "leafVersion": 192
+ }
+ },
+ "intermediary": {
+ "leafHashes": [
+ "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
+ ],
+ "merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
+ "tweak": "6af9e28dbf9d6aaf027696e2598a5b3d056f5fd2355a7fd5a37a0e5008132d30",
+ "tweakedPubkey": "e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e"
+ },
+ "expected": {
+ "scriptPubKey": "5120e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
+ "bip350Address": "bc1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58qqfuag5",
+ "scriptPathControlBlocks": [
+ "c093478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820"
+ ]
+ }
+ },
+ {
+ "given": {
+ "internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
+ "scriptTree": [
+ {
+ "id": 0,
+ "script": "20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac",
+ "leafVersion": 192
+ },
+ {
+ "id": 1,
+ "script": "06424950333431",
+ "leafVersion": 250
+ }
+ ]
+ },
+ "intermediary": {
+ "leafHashes": [
+ "8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7",
+ "f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
+ ],
+ "merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
+ "tweak": "9e0517edc8259bb3359255400b23ca9507f2a91cd1e4250ba068b4eafceba4a9",
+ "tweakedPubkey": "712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5"
+ },
+ "expected": {
+ "scriptPubKey": "5120712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5",
+ "bip350Address": "bc1pwyjywgrd0ffr3tx8laflh6228dj98xkjj8rum0zfpd6h0e930h6saqxrrm",
+ "scriptPathControlBlocks": [
+ "c0ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
+ "faee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf37865928ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
+ ]
+ }
+ },
+ {
+ "given": {
+ "internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
+ "scriptTree": [
+ {
+ "id": 0,
+ "script": "2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac",
+ "leafVersion": 192
+ },
+ {
+ "id": 1,
+ "script": "07546170726f6f74",
+ "leafVersion": 192
+ }
+ ]
+ },
+ "intermediary": {
+ "leafHashes": [
+ "64512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89",
+ "2cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
+ ],
+ "merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
+ "tweak": "639f0281b7ac49e742cd25b7f188657626da1ad169209078e2761cefd91fd65e",
+ "tweakedPubkey": "77e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220"
+ },
+ "expected": {
+ "scriptPubKey": "512077e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220",
+ "bip350Address": "bc1pwl3s54fzmk0cjnpl3w9af39je7pv5ldg504x5guk2hpecpg2kgsqaqstjq",
+ "scriptPathControlBlocks": [
+ "c1f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd82cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
+ "c1f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd864512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89"
+ ]
+ }
+ },
+ {
+ "given": {
+ "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
+ "scriptTree": [
+ {
+ "id": 0,
+ "script": "2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac",
+ "leafVersion": 192
+ },
+ [
+ {
+ "id": 1,
+ "script": "202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac",
+ "leafVersion": 192
+ },
+ {
+ "id": 2,
+ "script": "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
+ "leafVersion": 192
+ }
+ ]
+ ]
+ },
+ "intermediary": {
+ "leafHashes": [
+ "2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
+ "ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c",
+ "9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf6"
+ ],
+ "merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
+ "tweak": "b57bfa183d28eeb6ad688ddaabb265b4a41fbf68e5fed2c72c74de70d5a786f4",
+ "tweakedPubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605"
+ },
+ "expected": {
+ "scriptPubKey": "512091b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
+ "bip350Address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
+ "scriptPathControlBlocks": [
+ "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
+ "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
+ "c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
+ ]
+ }
+ },
+ {
+ "given": {
+ "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
+ "scriptTree": [
+ {
+ "id": 0,
+ "script": "2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac",
+ "leafVersion": 192
+ },
+ [
+ {
+ "id": 1,
+ "script": "20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac",
+ "leafVersion": 192
+ },
+ {
+ "id": 2,
+ "script": "20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac",
+ "leafVersion": 192
+ }
+ ]
+ ]
+ },
+ "intermediary": {
+ "leafHashes": [
+ "f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
+ "737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711",
+ "d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7"
+ ],
+ "merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
+ "tweak": "6579138e7976dc13b6a92f7bfd5a2fc7684f5ea42419d43368301470f3b74ed9",
+ "tweakedPubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831"
+ },
+ "expected": {
+ "scriptPubKey": "512075169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
+ "bip350Address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe",
+ "scriptPathControlBlocks": [
+ "c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d3cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
+ "c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312dd7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
+ "c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
+ ]
+ }
+ }
+ ],
+ "keyPathSpending": [
+ {
+ "given": {
+ "rawUnsignedTx": "02000000097de20cbff686da83a54981d2b9bab3586f4ca7e48f57f5b55963115f3b334e9c010000000000000000d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd990000000000fffffffff8e1f583384333689228c5d28eac13366be082dc57441760d957275419a418420000000000fffffffff0689180aa63b30cb162a73c6d2a38b7eeda2a83ece74310fda0843ad604853b0100000000feffffffaa5202bdf6d8ccd2ee0f0202afbbb7461d9264a25e5bfd3c5a52ee1239e0ba6c0000000000feffffff956149bdc66faa968eb2be2d2faa29718acbfe3941215893a2a3446d32acd050000000000000000000e664b9773b88c09c32cb70a2a3e4da0ced63b7ba3b22f848531bbb1d5d5f4c94010000000000000000e9aa6b8e6c9de67619e6a3924ae25696bb7b694bb677a632a74ef7eadfd4eabf0000000000ffffffffa778eb6a263dc090464cd125c466b5a99667720b1c110468831d058aa1b82af10100000000ffffffff0200ca9a3b000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac807840cb0000000020ac9a87f5594be208f8532db38cff670c450ed2fea8fcdefcc9a663f78bab962b0065cd1d",
+ "utxosSpent": [
+ {
+ "scriptPubKey": "512053a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
+ "amountSats": 420000000
+ },
+ {
+ "scriptPubKey": "5120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
+ "amountSats": 462000000
+ },
+ {
+ "scriptPubKey": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac",
+ "amountSats": 294000000
+ },
+ {
+ "scriptPubKey": "5120e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
+ "amountSats": 504000000
+ },
+ {
+ "scriptPubKey": "512091b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
+ "amountSats": 630000000
+ },
+ {
+ "scriptPubKey": "00147dd65592d0ab2fe0d0257d571abf032cd9db93dc",
+ "amountSats": 378000000
+ },
+ {
+ "scriptPubKey": "512075169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
+ "amountSats": 672000000
+ },
+ {
+ "scriptPubKey": "5120712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5",
+ "amountSats": 546000000
+ },
+ {
+ "scriptPubKey": "512077e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220",
+ "amountSats": 588000000
+ }
+ ]
+ },
+ "intermediary": {
+ "hashAmounts": "58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde6",
+ "hashOutputs": "a2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc5",
+ "hashPrevouts": "e3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f",
+ "hashScriptPubkeys": "23ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e21",
+ "hashSequences": "18959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957e"
+ },
+ "inputSpending": [
+ {
+ "given": {
+ "txinIndex": 0,
+ "internalPrivkey": "6b973d88838f27366ed61c9ad6367663045cb456e28335c109e30717ae0c6baa",
+ "merkleRoot": null,
+ "hashType": 3
+ },
+ "intermediary": {
+ "internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d",
+ "tweak": "b86e7be8f39bab32a6f2c0443abbc210f0edac0e2c53d501b36b64437d9c6c70",
+ "tweakedPrivkey": "2405b971772ad26915c8dcdf10f238753a9b837e5f8e6a86fd7c0cce5b7296d9",
+ "sigMsg": "0003020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957e0000000000d0418f0e9a36245b9a50ec87f8bf5be5bcae434337b87139c3a5b1f56e33cba0",
+ "precomputedUsed": [
+ "hashAmounts",
+ "hashPrevouts",
+ "hashScriptPubkeys",
+ "hashSequences"
+ ],
+ "sigHash": "2514a6272f85cfa0f45eb907fcb0d121b808ed37c6ea160a5a9046ed5526d555"
+ },
+ "expected": {
+ "witness": [
+ "ed7c1647cb97379e76892be0cacff57ec4a7102aa24296ca39af7541246d8ff14d38958d4cc1e2e478e4d4a764bbfd835b16d4e314b72937b29833060b87276c03"
+ ]
+ }
+ },
+ {
+ "given": {
+ "txinIndex": 1,
+ "internalPrivkey": "1e4da49f6aaf4e5cd175fe08a32bb5cb4863d963921255f33d3bc31e1343907f",
+ "merkleRoot": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
+ "hashType": 131
+ },
+ "intermediary": {
+ "internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
+ "tweak": "cbd8679ba636c1110ea247542cfbd964131a6be84f873f7f3b62a777528ed001",
+ "tweakedPrivkey": "ea260c3b10e60f6de018455cd0278f2f5b7e454be1999572789e6a9565d26080",
+ "sigMsg": "0083020000000065cd1d00d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd9900000000808f891b00000000225120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3ffffffffffcef8fb4ca7efc5433f591ecfc57391811ce1e186a3793024def5c884cba51d",
+ "precomputedUsed": [],
+ "sigHash": "325a644af47e8a5a2591cda0ab0723978537318f10e6a63d4eed783b96a71a4d"
+ },
+ "expected": {
+ "witness": [
+ "052aedffc554b41f52b521071793a6b88d6dbca9dba94cf34c83696de0c1ec35ca9c5ed4ab28059bd606a4f3a657eec0bb96661d42921b5f50a95ad33675b54f83"
+ ]
+ }
+ },
+ {
+ "given": {
+ "txinIndex": 3,
+ "internalPrivkey": "d3c7af07da2d54f7a7735d3d0fc4f0a73164db638b2f2f7c43f711f6d4aa7e64",
+ "merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
+ "hashType": 1
+ },
+ "intermediary": {
+ "internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
+ "tweak": "6af9e28dbf9d6aaf027696e2598a5b3d056f5fd2355a7fd5a37a0e5008132d30",
+ "tweakedPrivkey": "97323385e57015b75b0339a549c56a948eb961555973f0951f555ae6039ef00d",
+ "sigMsg": "0001020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957ea2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc50003000000",
+ "precomputedUsed": [
+ "hashAmounts",
+ "hashOutputs",
+ "hashPrevouts",
+ "hashScriptPubkeys",
+ "hashSequences"
+ ],
+ "sigHash": "bf013ea93474aa67815b1b6cc441d23b64fa310911d991e713cd34c7f5d46669"
+ },
+ "expected": {
+ "witness": [
+ "ff45f742a876139946a149ab4d9185574b98dc919d2eb6754f8abaa59d18b025637a3aa043b91817739554f4ed2026cf8022dbd83e351ce1fabc272841d2510a01"
+ ]
+ }
+ },
+ {
+ "given": {
+ "txinIndex": 4,
+ "internalPrivkey": "f36bb07a11e469ce941d16b63b11b9b9120a84d9d87cff2c84a8d4affb438f4e",
+ "merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
+ "hashType": 0
+ },
+ "intermediary": {
+ "internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
+ "tweak": "b57bfa183d28eeb6ad688ddaabb265b4a41fbf68e5fed2c72c74de70d5a786f4",
+ "tweakedPrivkey": "a8e7aa924f0d58854185a490e6c41f6efb7b675c0f3331b7f14b549400b4d501",
+ "sigMsg": "0000020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957ea2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc50004000000",
+ "precomputedUsed": [
+ "hashAmounts",
+ "hashOutputs",
+ "hashPrevouts",
+ "hashScriptPubkeys",
+ "hashSequences"
+ ],
+ "sigHash": "4f900a0bae3f1446fd48490c2958b5a023228f01661cda3496a11da502a7f7ef"
+ },
+ "expected": {
+ "witness": [
+ "b4010dd48a617db09926f729e79c33ae0b4e94b79f04a1ae93ede6315eb3669de185a17d2b0ac9ee09fd4c64b678a0b61a0a86fa888a273c8511be83bfd6810f"
+ ]
+ }
+ },
+ {
+ "given": {
+ "txinIndex": 6,
+ "internalPrivkey": "415cfe9c15d9cea27d8104d5517c06e9de48e2f986b695e4f5ffebf230e725d8",
+ "merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
+ "hashType": 2
+ },
+ "intermediary": {
+ "internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
+ "tweak": "6579138e7976dc13b6a92f7bfd5a2fc7684f5ea42419d43368301470f3b74ed9",
+ "tweakedPrivkey": "241c14f2639d0d7139282aa6abde28dd8a067baa9d633e4e7230287ec2d02901",
+ "sigMsg": "0002020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957e0006000000",
+ "precomputedUsed": [
+ "hashAmounts",
+ "hashPrevouts",
+ "hashScriptPubkeys",
+ "hashSequences"
+ ],
+ "sigHash": "15f25c298eb5cdc7eb1d638dd2d45c97c4c59dcaec6679cfc16ad84f30876b85"
+ },
+ "expected": {
+ "witness": [
+ "a3785919a2ce3c4ce26f298c3d51619bc474ae24014bcdd31328cd8cfbab2eff3395fa0a16fe5f486d12f22a9cedded5ae74feb4bbe5351346508c5405bcfee002"
+ ]
+ }
+ },
+ {
+ "given": {
+ "txinIndex": 7,
+ "internalPrivkey": "c7b0e81f0a9a0b0499e112279d718cca98e79a12e2f137c72ae5b213aad0d103",
+ "merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
+ "hashType": 130
+ },
+ "intermediary": {
+ "internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
+ "tweak": "9e0517edc8259bb3359255400b23ca9507f2a91cd1e4250ba068b4eafceba4a9",
+ "tweakedPrivkey": "65b6000cd2bfa6b7cf736767a8955760e62b6649058cbc970b7c0871d786346b",
+ "sigMsg": "0082020000000065cd1d00e9aa6b8e6c9de67619e6a3924ae25696bb7b694bb677a632a74ef7eadfd4eabf00000000804c8b2000000000225120712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5ffffffff",
+ "precomputedUsed": [],
+ "sigHash": "cd292de50313804dabe4685e83f923d2969577191a3e1d2882220dca88cbeb10"
+ },
+ "expected": {
+ "witness": [
+ "ea0c6ba90763c2d3a296ad82ba45881abb4f426b3f87af162dd24d5109edc1cdd11915095ba47c3a9963dc1e6c432939872bc49212fe34c632cd3ab9fed429c482"
+ ]
+ }
+ },
+ {
+ "given": {
+ "txinIndex": 8,
+ "internalPrivkey": "77863416be0d0665e517e1c375fd6f75839544eca553675ef7fdf4949518ebaa",
+ "merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
+ "hashType": 129
+ },
+ "intermediary": {
+ "internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
+ "tweak": "639f0281b7ac49e742cd25b7f188657626da1ad169209078e2761cefd91fd65e",
+ "tweakedPrivkey": "ec18ce6af99f43815db543f47b8af5ff5df3b2cb7315c955aa4a86e8143d2bf5",
+ "sigMsg": "0081020000000065cd1da2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc500a778eb6a263dc090464cd125c466b5a99667720b1c110468831d058aa1b82af101000000002b0c230000000022512077e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220ffffffff",
+ "precomputedUsed": [
+ "hashOutputs"
+ ],
+ "sigHash": "cccb739eca6c13a8a89e6e5cd317ffe55669bbda23f2fd37b0f18755e008edd2"
+ },
+ "expected": {
+ "witness": [
+ "bbc9584a11074e83bc8c6759ec55401f0ae7b03ef290c3139814f545b58a9f8127258000874f44bc46db7646322107d4d86aec8e73b8719a61fff761d75b5dd981"
+ ]
+ }
+ }
+ ],
+ "auxiliary": {
+ "fullySignedTx": "020000000001097de20cbff686da83a54981d2b9bab3586f4ca7e48f57f5b55963115f3b334e9c010000000000000000d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd990000000000fffffffff8e1f583384333689228c5d28eac13366be082dc57441760d957275419a41842000000006b4830450221008f3b8f8f0537c420654d2283673a761b7ee2ea3c130753103e08ce79201cf32a022079e7ab904a1980ef1c5890b648c8783f4d10103dd62f740d13daa79e298d50c201210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff0689180aa63b30cb162a73c6d2a38b7eeda2a83ece74310fda0843ad604853b0100000000feffffffaa5202bdf6d8ccd2ee0f0202afbbb7461d9264a25e5bfd3c5a52ee1239e0ba6c0000000000feffffff956149bdc66faa968eb2be2d2faa29718acbfe3941215893a2a3446d32acd050000000000000000000e664b9773b88c09c32cb70a2a3e4da0ced63b7ba3b22f848531bbb1d5d5f4c94010000000000000000e9aa6b8e6c9de67619e6a3924ae25696bb7b694bb677a632a74ef7eadfd4eabf0000000000ffffffffa778eb6a263dc090464cd125c466b5a99667720b1c110468831d058aa1b82af10100000000ffffffff0200ca9a3b000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac807840cb0000000020ac9a87f5594be208f8532db38cff670c450ed2fea8fcdefcc9a663f78bab962b0141ed7c1647cb97379e76892be0cacff57ec4a7102aa24296ca39af7541246d8ff14d38958d4cc1e2e478e4d4a764bbfd835b16d4e314b72937b29833060b87276c030141052aedffc554b41f52b521071793a6b88d6dbca9dba94cf34c83696de0c1ec35ca9c5ed4ab28059bd606a4f3a657eec0bb96661d42921b5f50a95ad33675b54f83000141ff45f742a876139946a149ab4d9185574b98dc919d2eb6754f8abaa59d18b025637a3aa043b91817739554f4ed2026cf8022dbd83e351ce1fabc272841d2510a010140b4010dd48a617db09926f729e79c33ae0b4e94b79f04a1ae93ede6315eb3669de185a17d2b0ac9ee09fd4c64b678a0b61a0a86fa888a273c8511be83bfd6810f0247304402202b795e4de72646d76eab3f0ab27dfa30b810e856ff3a46c9a702df53bb0d8cc302203ccc4d822edab5f35caddb10af1be93583526ccfbade4b4ead350781e2f8adcd012102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f90141a3785919a2ce3c4ce26f298c3d51619bc474ae24014bcdd31328cd8cfbab2eff3395fa0a16fe5f486d12f22a9cedded5ae74feb4bbe5351346508c5405bcfee0020141ea0c6ba90763c2d3a296ad82ba45881abb4f426b3f87af162dd24d5109edc1cdd11915095ba47c3a9963dc1e6c432939872bc49212fe34c632cd3ab9fed429c4820141bbc9584a11074e83bc8c6759ec55401f0ae7b03ef290c3139814f545b58a9f8127258000874f44bc46db7646322107d4d86aec8e73b8719a61fff761d75b5dd9810065cd1d"
+ }
+ }
+ ]
+}
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 668ff150ee..765663e0ef 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress(), /* pszDest */ "", ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false);
+ CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false);
dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1);
@@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
static void AddRandomOutboundPeer(std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman)
{
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
- vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress(), /* pszDest */ "", ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false));
+ vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false));
CNode &node = *vNodes.back();
node.SetCommonVersion(PROTOCOL_VERSION);
@@ -212,9 +212,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
std::array<CNode*, 3> nodes;
banman->ClearBanned();
- nodes[0] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[0], /* nKeyedNetGroupIn */ 0,
- /* nLocalHostNonceIn */ 0, CAddress(), /* pszDest */ "",
- ConnectionType::INBOUND, /* inbound_onion */ false};
+ nodes[0] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[0], /*nKeyedNetGroupIn=*/0,
+ /*nLocalHostNonceIn */ 0, CAddress(), /*addrNameIn=*/"",
+ ConnectionType::INBOUND, /*inbound_onion=*/false};
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(nodes[0]);
nodes[0]->fSuccessfullyConnected = true;
@@ -228,9 +228,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_CHECK(nodes[0]->fDisconnect);
BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
- nodes[1] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[1], /* nKeyedNetGroupIn */ 1,
- /* nLocalHostNonceIn */ 1, CAddress(), /* pszDest */ "",
- ConnectionType::INBOUND, /* inbound_onion */ false};
+ nodes[1] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[1], /*nKeyedNetGroupIn=*/1,
+ /*nLocalHostNonceIn */ 1, CAddress(), /*addrNameIn=*/"",
+ ConnectionType::INBOUND, /*inbound_onion=*/false};
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(nodes[1]);
nodes[1]->fSuccessfullyConnected = true;
@@ -259,9 +259,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
// Make sure non-IP peers are discouraged and disconnected properly.
- nodes[2] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[2], /* nKeyedNetGroupIn */ 1,
- /* nLocalHostNonceIn */ 1, CAddress(), /* pszDest */ "",
- ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false};
+ nodes[2] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[2], /*nKeyedNetGroupIn=*/1,
+ /*nLocalHostNonceIn */ 1, CAddress(), /*addrNameIn=*/"",
+ ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false};
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(nodes[2]);
nodes[2]->fSuccessfullyConnected = true;
@@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 4, /* nLocalHostNonceIn */ 4, CAddress(), /* pszDest */ "", ConnectionType::INBOUND, /* inbound_onion */ false);
+ CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/4, /*nLocalHostNonceIn=*/4, CAddress(), /*addrNameIn=*/"", ConnectionType::INBOUND, /*inbound_onion=*/false);
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode);
dummyNode.fSuccessfullyConnected = true;
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 325a9a170e..2f33598348 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -221,8 +221,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
assert(expected_code_path);
},
[&] {
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
+ (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
},
[&] {
TxValidationState state;
diff --git a/src/test/fuzz/minisketch.cpp b/src/test/fuzz/minisketch.cpp
new file mode 100644
index 0000000000..93954bd3cf
--- /dev/null
+++ b/src/test/fuzz/minisketch.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <minisketch.h>
+#include <node/minisketchwrapper.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <util/check.h>
+
+#include <map>
+#include <numeric>
+
+FUZZ_TARGET(minisketch)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const auto capacity{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 200)};
+ Minisketch sketch_a{Assert(MakeMinisketch32(capacity))};
+ Minisketch sketch_b{Assert(MakeMinisketch32(capacity))};
+
+ // Fill two sets and keep the difference in a map
+ std::map<uint32_t, bool> diff;
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
+ {
+ const auto entry{fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, std::numeric_limits<uint32_t>::max() - 1)};
+ const auto KeepDiff{[&] {
+ bool& mut{diff[entry]};
+ mut = !mut;
+ }};
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ sketch_a.Add(entry);
+ KeepDiff();
+ },
+ [&] {
+ sketch_b.Add(entry);
+ KeepDiff();
+ },
+ [&] {
+ sketch_a.Add(entry);
+ sketch_b.Add(entry);
+ });
+ }
+ const auto num_diff{std::accumulate(diff.begin(), diff.end(), size_t{0}, [](auto n, const auto& e) { return n + e.second; })};
+
+ Minisketch sketch_ar{MakeMinisketch32(capacity)};
+ Minisketch sketch_br{MakeMinisketch32(capacity)};
+ sketch_ar.Deserialize(sketch_a.Serialize());
+ sketch_br.Deserialize(sketch_b.Serialize());
+
+ Minisketch sketch_diff{std::move(fuzzed_data_provider.ConsumeBool() ? sketch_a : sketch_ar)};
+ sketch_diff.Merge(fuzzed_data_provider.ConsumeBool() ? sketch_b : sketch_br);
+
+ if (capacity >= num_diff) {
+ const auto max_elements{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(num_diff, capacity)};
+ const auto dec{*Assert(sketch_diff.Decode(max_elements))};
+ Assert(dec.size() == num_diff);
+ for (auto d : dec) {
+ Assert(diff.at(d));
+ }
+ }
+}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index a21e5cea0c..ba6c500543 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -98,8 +98,7 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
CCoinsView coins_view;
const CCoinsViewCache coins_view_cache(&coins_view);
- (void)AreInputsStandard(tx, coins_view_cache, false);
- (void)AreInputsStandard(tx, coins_view_cache, true);
+ (void)AreInputsStandard(tx, coins_view_cache);
(void)IsWitnessStandard(tx, coins_view_cache);
UniValue u(UniValue::VOBJ);
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 17b5ef88b9..ac1fb657f1 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/validation.h>
-#include <miner.h>
+#include <node/miner.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@@ -93,7 +93,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CCh
const auto info_all = tx_pool.infoAll();
if (!info_all.empty()) {
const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
- WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
+ WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, MemPoolRemovalReason::BLOCK /* dummy */));
std::vector<uint256> all_txids;
tx_pool.queryHashes(all_txids);
assert(all_txids.size() < info_all.size());
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index b915982d98..2769dde367 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -321,7 +321,7 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
key.Set(sec.begin(), sec.end(), true);
XOnlyPubKey pubkey(key.GetPubKey());
BOOST_CHECK(std::equal(pubkey.begin(), pubkey.end(), pub.begin(), pub.end()));
- bool ok = key.SignSchnorr(msg256, sig64, nullptr, &aux256);
+ bool ok = key.SignSchnorr(msg256, sig64, nullptr, aux256);
BOOST_CHECK(ok);
BOOST_CHECK(std::vector<unsigned char>(sig64, sig64 + 64) == sig);
// Verify those signatures for good measure.
@@ -337,7 +337,7 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
BOOST_CHECK(tweaked);
XOnlyPubKey tweaked_key = tweaked->first;
aux256 = InsecureRand256();
- bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, &aux256);
+ bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256);
BOOST_CHECK(ok);
BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64));
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 7f44dcf20e..bdc6ff6130 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -7,7 +7,7 @@
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
-#include <miner.h>
+#include <node/miner.h>
#include <policy/policy.h>
#include <script/standard.h>
#include <txmempool.h>
diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp
index 6798331936..f7dd18923b 100644
--- a/src/test/minisketch_tests.cpp
+++ b/src/test/minisketch_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <minisketch.h>
-#include <minisketchwrapper.h>
+#include <node/minisketchwrapper.h>
#include <random.h>
#include <test/util/setup_common.h>
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index d8a44a65dd..17b3359624 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end());
txTo.vin[4].scriptSig << std::vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end());
- BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins, false));
+ BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins));
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txTo), coins), 22U);
@@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd1.vin[0].scriptSig << std::vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end());
- BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins, false));
+ BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd1), coins), 16U);
CMutableTransaction txToNonStd2;
@@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd2.vin[0].scriptSig << std::vector<unsigned char>(twentySigops.begin(), twentySigops.end());
- BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins, false));
+ BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd2), coins), 20U);
}
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index bf8ff5f5e2..5a5cc6ab29 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -2,6 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <test/data/bip341_wallet_vectors.json.h>
+
#include <key.h>
#include <key_io.h>
#include <script/script.h>
@@ -12,6 +14,8 @@
#include <boost/test/unit_test.hpp>
+#include <univalue.h>
+
BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup)
@@ -385,4 +389,46 @@ BOOST_AUTO_TEST_CASE(script_standard_taproot_builder)
BOOST_CHECK_EQUAL(EncodeDestination(builder.GetOutput()), "bc1pj6gaw944fy0xpmzzu45ugqde4rz7mqj5kj0tg8kmr5f0pjq8vnaqgynnge");
}
+BOOST_AUTO_TEST_CASE(bip341_spk_test_vectors)
+{
+ using control_set = decltype(TaprootSpendData::scripts)::mapped_type;
+
+ UniValue tests;
+ tests.read((const char*)json_tests::bip341_wallet_vectors, sizeof(json_tests::bip341_wallet_vectors));
+
+ const auto& vectors = tests["scriptPubKey"];
+
+ for (const auto& vec : vectors.getValues()) {
+ TaprootBuilder spktest;
+ std::map<std::pair<CScript, int>, int> scriptposes;
+ std::function<void (const UniValue&, int)> parse_tree = [&](const UniValue& node, int depth) {
+ if (node.isNull()) return;
+ if (node.isObject()) {
+ auto script_bytes = ParseHex(node["script"].get_str());
+ CScript script(script_bytes.begin(), script_bytes.end());
+ int idx = node["id"].get_int();
+ int leaf_version = node["leafVersion"].get_int();
+ scriptposes[{script, leaf_version}] = idx;
+ spktest.Add(depth, script, leaf_version);
+ } else {
+ parse_tree(node[0], depth + 1);
+ parse_tree(node[1], depth + 1);
+ }
+ };
+ parse_tree(vec["given"]["scriptTree"], 0);
+ spktest.Finalize(XOnlyPubKey(ParseHex(vec["given"]["internalPubkey"].get_str())));
+ BOOST_CHECK_EQUAL(HexStr(GetScriptForDestination(spktest.GetOutput())), vec["expected"]["scriptPubKey"].get_str());
+ BOOST_CHECK_EQUAL(EncodeDestination(spktest.GetOutput()), vec["expected"]["bip350Address"].get_str());
+ auto spend_data = spktest.GetSpendData();
+ BOOST_CHECK_EQUAL(vec["intermediary"]["merkleRoot"].isNull(), spend_data.merkle_root.IsNull());
+ if (!spend_data.merkle_root.IsNull()) {
+ BOOST_CHECK_EQUAL(vec["intermediary"]["merkleRoot"].get_str(), HexStr(spend_data.merkle_root));
+ }
+ BOOST_CHECK_EQUAL(spend_data.scripts.size(), scriptposes.size());
+ for (const auto& scriptpos : scriptposes) {
+ BOOST_CHECK(spend_data.scripts[scriptpos.first] == control_set{ParseHex(vec["expected"]["scriptPathControlBlocks"][scriptpos.second].get_str())});
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 2c39cbffb9..a89eab68e9 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/data/script_tests.json.h>
+#include <test/data/bip341_wallet_vectors.json.h>
#include <core_io.h>
#include <fs.h>
@@ -1743,4 +1744,79 @@ BOOST_AUTO_TEST_CASE(script_assets_test)
file.close();
}
+BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
+{
+ UniValue tests;
+ tests.read((const char*)json_tests::bip341_wallet_vectors, sizeof(json_tests::bip341_wallet_vectors));
+
+ const auto& vectors = tests["keyPathSpending"];
+
+ for (const auto& vec : vectors.getValues()) {
+ auto txhex = ParseHex(vec["given"]["rawUnsignedTx"].get_str());
+ CMutableTransaction tx;
+ VectorReader(SER_NETWORK, PROTOCOL_VERSION, txhex, 0) >> tx;
+ std::vector<CTxOut> utxos;
+ for (const auto& utxo_spent : vec["given"]["utxosSpent"].getValues()) {
+ auto script_bytes = ParseHex(utxo_spent["scriptPubKey"].get_str());
+ CScript script{script_bytes.begin(), script_bytes.end()};
+ CAmount amount{utxo_spent["amountSats"].get_int()};
+ utxos.emplace_back(amount, script);
+ }
+
+ PrecomputedTransactionData txdata;
+ txdata.Init(tx, std::vector<CTxOut>{utxos}, true);
+
+ BOOST_CHECK(txdata.m_bip341_taproot_ready);
+ BOOST_CHECK_EQUAL(HexStr(txdata.m_spent_amounts_single_hash), vec["intermediary"]["hashAmounts"].get_str());
+ BOOST_CHECK_EQUAL(HexStr(txdata.m_outputs_single_hash), vec["intermediary"]["hashOutputs"].get_str());
+ BOOST_CHECK_EQUAL(HexStr(txdata.m_prevouts_single_hash), vec["intermediary"]["hashPrevouts"].get_str());
+ BOOST_CHECK_EQUAL(HexStr(txdata.m_spent_scripts_single_hash), vec["intermediary"]["hashScriptPubkeys"].get_str());
+ BOOST_CHECK_EQUAL(HexStr(txdata.m_sequences_single_hash), vec["intermediary"]["hashSequences"].get_str());
+
+ for (const auto& input : vec["inputSpending"].getValues()) {
+ int txinpos = input["given"]["txinIndex"].get_int();
+ int hashtype = input["given"]["hashType"].get_int();
+
+ // Load key.
+ auto privkey = ParseHex(input["given"]["internalPrivkey"].get_str());
+ CKey key;
+ key.Set(privkey.begin(), privkey.end(), true);
+
+ // Load Merkle root.
+ uint256 merkle_root;
+ if (!input["given"]["merkleRoot"].isNull()) {
+ merkle_root = uint256{ParseHex(input["given"]["merkleRoot"].get_str())};
+ }
+
+ // Compute and verify (internal) public key.
+ XOnlyPubKey pubkey{key.GetPubKey()};
+ BOOST_CHECK_EQUAL(HexStr(pubkey), input["intermediary"]["internalPubkey"].get_str());
+
+ // Sign and verify signature.
+ FlatSigningProvider provider;
+ provider.keys[key.GetPubKey().GetID()] = key;
+ MutableTransactionSignatureCreator creator(&tx, txinpos, utxos[txinpos].nValue, &txdata, hashtype);
+ std::vector<unsigned char> signature;
+ BOOST_CHECK(creator.CreateSchnorrSig(provider, signature, pubkey, nullptr, &merkle_root, SigVersion::TAPROOT));
+ BOOST_CHECK_EQUAL(HexStr(signature), input["expected"]["witness"][0].get_str());
+
+ // We can't observe the tweak used inside the signing logic, so verify by recomputing it.
+ BOOST_CHECK_EQUAL(HexStr(pubkey.ComputeTapTweakHash(merkle_root.IsNull() ? nullptr : &merkle_root)), input["intermediary"]["tweak"].get_str());
+
+ // We can't observe the sighash used inside the signing logic, so verify by recomputing it.
+ ScriptExecutionData sed;
+ sed.m_annex_init = true;
+ sed.m_annex_present = false;
+ uint256 sighash;
+ BOOST_CHECK(SignatureHashSchnorr(sighash, sed, tx, txinpos, hashtype, SigVersion::TAPROOT, txdata, MissingDataBehavior::FAIL));
+ BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());
+
+ // To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
+ BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << MakeSpan(ParseHex(input["intermediary"]["sigMsg"].get_str()))).GetSHA256()), input["intermediary"]["sigHash"].get_str());
+ }
+
+ }
+
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
index 352797f18d..3937366f01 100644
--- a/src/test/scriptnum10.h
+++ b/src/test/scriptnum10.h
@@ -179,4 +179,4 @@ private:
};
-#endif // BITCOIN_TEST_BIGNUM_H
+#endif // BITCOIN_TEST_SCRIPTNUM10_H
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 54f04d2e67..b8d76c9608 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
- std::string(ds.begin(), ds.end()));
+ ds.str());
in.push_back('\x0f');
in.push_back('\xf0');
@@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
- std::string(ds.begin(), ds.end()));
+ ds.str());
// Multi character key
@@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
- std::string(ds.begin(), ds.end()));
+ ds.str());
}
BOOST_AUTO_TEST_CASE(streams_buffered_file)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 252a85c282..e05781a6f0 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1;
- BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins, false));
+ BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins));
}
static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index 537a6ccea1..8d92bee221 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -73,19 +73,19 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
CKey parent_key;
parent_key.MakeNewKey(true);
CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
- auto mtx_parent = CreateValidMempoolTransaction(/* input_transaction */ m_coinbase_txns[0], /* vout */ 0,
- /* input_height */ 0, /* input_signing_key */ coinbaseKey,
- /* output_destination */ parent_locking_script,
- /* output_amount */ CAmount(49 * COIN), /* submit */ false);
+ auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/ m_coinbase_txns[0], /*input_vout=*/0,
+ /*input_height=*/ 0, /*input_signing_key=*/coinbaseKey,
+ /*output_destination=*/ parent_locking_script,
+ /*output_amount=*/ CAmount(49 * COIN), /*submit=*/false);
CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
CKey child_key;
child_key.MakeNewKey(true);
CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
- auto mtx_child = CreateValidMempoolTransaction(/* input_transaction */ tx_parent, /* vout */ 0,
- /* input_height */ 101, /* input_signing_key */ parent_key,
- /* output_destination */ child_locking_script,
- /* output_amount */ CAmount(48 * COIN), /* submit */ false);
+ auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/ tx_parent, /*input_vout=*/0,
+ /*input_height=*/ 101, /*input_signing_key=*/parent_key,
+ /*output_destination */ child_locking_script,
+ /*output_amount=*/ CAmount(48 * COIN), /*submit=*/false);
CTransactionRef tx_child = MakeTransactionRef(mtx_child);
const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /* test_accept */ true);
BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(),
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index f6a11bc02e..8b9069bea3 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -7,8 +7,8 @@
#include <chainparams.h>
#include <consensus/merkle.h>
#include <key_io.h>
-#include <miner.h>
#include <node/context.h>
+#include <node/miner.h>
#include <pow.h>
#include <script/standard.h>
#include <test/util/script.h>
diff --git a/src/test/util/net.h b/src/test/util/net.h
index d89fc34b75..2de6e712a2 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -25,16 +25,16 @@ struct ConnmanTestMsg : public CConnman {
void AddTestNode(CNode& node)
{
- LOCK(cs_vNodes);
- vNodes.push_back(&node);
+ LOCK(m_nodes_mutex);
+ m_nodes.push_back(&node);
}
void ClearTestNodes()
{
- LOCK(cs_vNodes);
- for (CNode* node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* node : m_nodes) {
delete node;
}
- vNodes.clear();
+ m_nodes.clear();
}
void ProcessMessagesOnce(CNode& node) { m_msgproc->ProcessMessages(&node, flagInterruptMsgProc); }
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 5a0c8e152a..cdb8238095 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -13,9 +13,9 @@
#include <crypto/sha256.h>
#include <init.h>
#include <interfaces/chain.h>
-#include <miner.h>
#include <net.h>
#include <net_processing.h>
+#include <node/miner.h>
#include <noui.h>
#include <policy/fees.h>
#include <pow.h>
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 7518cdb042..eb7bc071e5 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -227,4 +227,4 @@ private:
const std::string m_reason;
};
-#endif
+#endif // BITCOIN_TEST_UTIL_SETUP_COMMON_H
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b1300d06ba..76a690fd28 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -151,12 +151,25 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
HexStr(Span<const unsigned char>(ParseHex_expected, ParseHex_expected)),
"");
- std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
+ {
+ const std::vector<char> in_s{ParseHex_expected, ParseHex_expected + 5};
+ const Span<const uint8_t> in_u{MakeUCharSpan(in_s)};
+ const Span<const std::byte> in_b{MakeByteSpan(in_s)};
+ const std::string out_exp{"04678afdb0"};
+
+ BOOST_CHECK_EQUAL(HexStr(in_u), out_exp);
+ BOOST_CHECK_EQUAL(HexStr(in_s), out_exp);
+ BOOST_CHECK_EQUAL(HexStr(in_b), out_exp);
+ }
+}
- BOOST_CHECK_EQUAL(
- HexStr(ParseHex_vec),
- "04678afdb0"
- );
+BOOST_AUTO_TEST_CASE(span_write_bytes)
+{
+ std::array mut_arr{uint8_t{0xaa}, uint8_t{0xbb}};
+ const auto mut_bytes{MakeWritableByteSpan(mut_arr)};
+ mut_bytes[1] = std::byte{0x11};
+ BOOST_CHECK_EQUAL(mut_arr.at(0), 0xaa);
+ BOOST_CHECK_EQUAL(mut_arr.at(1), 0x11);
}
BOOST_AUTO_TEST_CASE(util_Join)
@@ -2456,4 +2469,52 @@ BOOST_AUTO_TEST_CASE(remove_prefix)
BOOST_CHECK_EQUAL(RemovePrefix("", ""), "");
}
+BOOST_AUTO_TEST_CASE(util_ParseByteUnits)
+{
+ auto noop = ByteUnit::NOOP;
+
+ // no multiplier
+ BOOST_CHECK_EQUAL(ParseByteUnits("1", noop).value(), 1);
+ BOOST_CHECK_EQUAL(ParseByteUnits("0", noop).value(), 0);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("1k", noop).value(), 1000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("1K", noop).value(), 1ULL << 10);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("2m", noop).value(), 2'000'000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("2M", noop).value(), 2ULL << 20);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("3g", noop).value(), 3'000'000'000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("3G", noop).value(), 3ULL << 30);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("4t", noop).value(), 4'000'000'000'000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("4T", noop).value(), 4ULL << 40);
+
+ // check default multiplier
+ BOOST_CHECK_EQUAL(ParseByteUnits("5", ByteUnit::K).value(), 5ULL << 10);
+
+ // NaN
+ BOOST_CHECK(!ParseByteUnits("", noop));
+ BOOST_CHECK(!ParseByteUnits("foo", noop));
+
+ // whitespace
+ BOOST_CHECK(!ParseByteUnits("123m ", noop));
+ BOOST_CHECK(!ParseByteUnits(" 123m", noop));
+
+ // no +-
+ BOOST_CHECK(!ParseByteUnits("-123m", noop));
+ BOOST_CHECK(!ParseByteUnits("+123m", noop));
+
+ // zero padding
+ BOOST_CHECK_EQUAL(ParseByteUnits("020M", noop).value(), 20ULL << 20);
+
+ // fractions not allowed
+ BOOST_CHECK(!ParseByteUnits("0.5T", noop));
+
+ // overflow
+ BOOST_CHECK(!ParseByteUnits("18446744073709551615g", noop));
+
+ // invalid unit
+ BOOST_CHECK(!ParseByteUnits("1x", noop));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 8a48d539f8..3efa74fcc3 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -7,7 +7,7 @@
#include <chainparams.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
-#include <miner.h>
+#include <node/miner.h>
#include <pow.h>
#include <random.h>
#include <script/standard.h>
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
{
bool ignored;
auto ProcessBlock = [&](std::shared_ptr<const CBlock> block) -> bool {
- return Assert(m_node.chainman)->ProcessNewBlock(Params(), block, /* fForceProcessing */ true, /* fNewBlock */ &ignored);
+ return Assert(m_node.chainman)->ProcessNewBlock(Params(), block, /*force_processing=*/true, /*new_block=*/&ignored);
};
// Process all mined blocks
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
index 2665f8a5be..42470c70ee 100644
--- a/src/threadinterrupt.h
+++ b/src/threadinterrupt.h
@@ -33,4 +33,4 @@ private:
std::atomic<bool> flag;
};
-#endif //BITCOIN_THREADINTERRUPT_H
+#endif // BITCOIN_THREADINTERRUPT_H
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 55618a5c57..776981b7f7 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -22,19 +22,17 @@
#include <deque>
#include <functional>
#include <set>
-#include <stdlib.h>
#include <vector>
-#include <boost/signals2/signal.hpp>
-#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/split.hpp>
-#include <event2/bufferevent.h>
#include <event2/buffer.h>
-#include <event2/util.h>
+#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/thread.h>
+#include <event2/util.h>
/** Default control port */
const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051";
@@ -277,9 +275,15 @@ std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
if (j == 3 && value[i] > '3') {
j--;
}
- escaped_value.push_back(strtol(value.substr(i, j).c_str(), nullptr, 8));
+ const auto end{i + j};
+ uint8_t val{0};
+ while (i < end) {
+ val *= 8;
+ val += value[i++] - '0';
+ }
+ escaped_value.push_back(char(val));
// Account for automatic incrementing at loop end
- i += j - 1;
+ --i;
} else {
escaped_value.push_back(value[i]);
}
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 7258f27cb6..8fc852f843 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -157,4 +157,4 @@ public:
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
};
-#endif /* BITCOIN_TORCONTROL_H */
+#endif // BITCOIN_TORCONTROL_H
diff --git a/src/util/overloaded.h b/src/util/overloaded.h
new file mode 100644
index 0000000000..6be7453f81
--- /dev/null
+++ b/src/util/overloaded.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_OVERLOADED_H
+#define BITCOIN_UTIL_OVERLOADED_H
+
+namespace util {
+//! Overloaded helper for std::visit. This helper and std::visit in general are
+//! useful to write code that switches on a variant type. Unlike if/else-if and
+//! switch/case statements, std::visit will trigger compile errors if there are
+//! unhandled cases.
+//!
+//! Implementation comes from and example usage can be found at
+//! https://en.cppreference.com/w/cpp/utility/variant/visit#Example
+template<class... Ts> struct Overloaded : Ts... { using Ts::operator()...; };
+
+//! Explicit deduction guide (not needed as of C++20)
+template<class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
+} // namespace util
+
+#endif // BITCOIN_UTIL_OVERLOADED_H
diff --git a/src/util/readwritefile.h b/src/util/readwritefile.h
index 1dab874b38..a59d0be131 100644
--- a/src/util/readwritefile.h
+++ b/src/util/readwritefile.h
@@ -25,4 +25,4 @@ std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size_t maxs
*/
bool WriteBinaryFile(const fs::path &filename, const std::string &data);
-#endif /* BITCOIN_UTIL_READWRITEFILE_H */
+#endif // BITCOIN_UTIL_READWRITEFILE_H
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 15bd07b374..430f1963ea 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -11,6 +11,7 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
+#include <limits>
#include <optional>
static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -138,11 +139,6 @@ std::string EncodeBase64(Span<const unsigned char> input)
return str;
}
-std::string EncodeBase64(const std::string& str)
-{
- return EncodeBase64(MakeUCharSpan(str));
-}
-
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
{
static const int decode64_table[256] =
@@ -526,3 +522,48 @@ std::string HexStr(const Span<const uint8_t> s)
assert(it == rv.end());
return rv;
}
+
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier)
+{
+ if (str.empty()) {
+ return std::nullopt;
+ }
+ auto multiplier = default_multiplier;
+ char unit = str.back();
+ switch (unit) {
+ case 'k':
+ multiplier = ByteUnit::k;
+ break;
+ case 'K':
+ multiplier = ByteUnit::K;
+ break;
+ case 'm':
+ multiplier = ByteUnit::m;
+ break;
+ case 'M':
+ multiplier = ByteUnit::M;
+ break;
+ case 'g':
+ multiplier = ByteUnit::g;
+ break;
+ case 'G':
+ multiplier = ByteUnit::G;
+ break;
+ case 't':
+ multiplier = ByteUnit::t;
+ break;
+ case 'T':
+ multiplier = ByteUnit::T;
+ break;
+ default:
+ unit = 0;
+ break;
+ }
+
+ uint64_t unit_amount = static_cast<uint64_t>(multiplier);
+ auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
+ if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
+ return std::nullopt;
+ }
+ return *parsed_num * unit_amount;
+}
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index eedb5ec2f8..08a5465de1 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -30,6 +30,23 @@ enum SafeChars
};
/**
+ * Used by ParseByteUnits()
+ * Lowercase base 1000
+ * Uppercase base 1024
+*/
+enum class ByteUnit : uint64_t {
+ NOOP = 1ULL,
+ k = 1000ULL,
+ K = 1024ULL,
+ m = 1'000'000ULL,
+ M = 1ULL << 20,
+ g = 1'000'000'000ULL,
+ G = 1ULL << 30,
+ t = 1'000'000'000'000ULL,
+ T = 1ULL << 40,
+};
+
+/**
* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
* addresses, but avoid anything even possibly remotely dangerous like & or >
* @param[in] str The string to sanitize
@@ -50,7 +67,8 @@ bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
std::string EncodeBase64(Span<const unsigned char> input);
-std::string EncodeBase64(const std::string& str);
+inline std::string EncodeBase64(Span<const std::byte> input) { return EncodeBase64(MakeUCharSpan(input)); }
+inline std::string EncodeBase64(const std::string& str) { return EncodeBase64(MakeUCharSpan(str)); }
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
@@ -189,6 +207,7 @@ std::optional<T> ToIntegral(const std::string& str)
*/
std::string HexStr(const Span<const uint8_t> s);
inline std::string HexStr(const Span<const char> s) { return HexStr(MakeUCharSpan(s)); }
+inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCharSpan(s)); }
/**
* Format a paragraph of text to a fixed width, adding spaces for
@@ -305,4 +324,17 @@ std::string ToUpper(const std::string& str);
*/
std::string Capitalize(std::string str);
+/**
+ * Parse a string with suffix unit [k|K|m|M|g|G|t|T].
+ * Must be a whole integer, fractions not allowed (0.5t), no whitespace or +-
+ * Lowercase units are 1000 base. Uppercase units are 1024 base.
+ * Examples: 2m,27M,19g,41T
+ *
+ * @param[in] str the string to convert into bytes
+ * @param[in] default_multiplier if no unit is found in str use this unit
+ * @returns optional uint64_t bytes from str or nullopt
+ * if ToIntegral is false, str is empty, trailing whitespace or overflow
+ */
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier);
+
#endif // BITCOIN_UTIL_STRENCODINGS_H
diff --git a/src/util/string.h b/src/util/string.h
index 5617e4acc1..07c87cfcda 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -103,4 +103,4 @@ template <typename T1, size_t PREFIX_LEN>
std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
}
-#endif // BITCOIN_UTIL_STRENCODINGS_H
+#endif // BITCOIN_UTIL_STRING_H
diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp
index bc69df44f4..6e1cc9b457 100644
--- a/src/util/syscall_sandbox.cpp
+++ b/src/util/syscall_sandbox.cpp
@@ -581,7 +581,7 @@ public:
allowed_syscalls.insert(__NR_fdatasync); // synchronize a file's in-core state with storage device
allowed_syscalls.insert(__NR_flock); // apply or remove an advisory lock on an open file
allowed_syscalls.insert(__NR_fstat); // get file status
- allowed_syscalls.insert(__NR_newfstatat); // get file status
+ allowed_syscalls.insert(__NR_fstatfs); // get file system status
allowed_syscalls.insert(__NR_fsync); // synchronize a file's in-core state with storage device
allowed_syscalls.insert(__NR_ftruncate); // truncate a file to a specified length
allowed_syscalls.insert(__NR_getcwd); // get current working directory
@@ -589,6 +589,7 @@ public:
allowed_syscalls.insert(__NR_getdents64); // get directory entries
allowed_syscalls.insert(__NR_lstat); // get file status
allowed_syscalls.insert(__NR_mkdir); // create a directory
+ allowed_syscalls.insert(__NR_newfstatat); // get file status
allowed_syscalls.insert(__NR_open); // open and possibly create a file
allowed_syscalls.insert(__NR_openat); // open and possibly create a file
allowed_syscalls.insert(__NR_readlink); // read value of a symbolic link
diff --git a/src/util/trace.h b/src/util/trace.h
index 9c92cb10e7..bb901e05da 100644
--- a/src/util/trace.h
+++ b/src/util/trace.h
@@ -42,4 +42,4 @@
#endif
-#endif /* BITCOIN_UTIL_TRACE_H */
+#endif // BITCOIN_UTIL_TRACE_H
diff --git a/src/validation.cpp b/src/validation.cpp
index f163130a18..86d2ae7577 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -723,8 +723,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
// Check for non-standard pay-to-script-hash in inputs
- const bool taproot_active = DeploymentActiveAfter(m_active_chainstate.m_chain.Tip(), args.m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_TAPROOT);
- if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_active)) {
+ if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
}
@@ -2044,7 +2043,7 @@ bool CChainState::FlushStateToDisk(
fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
// Write blocks and block index to disk.
if (fDoFullFlush || fPeriodicWrite) {
- // Depend on nMinDiskSpace to ensure we can write block index
+ // Ensure we can write block index
if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
}
@@ -2102,6 +2101,13 @@ bool CChainState::FlushStateToDisk(
nLastFlush = nNow;
full_flush_completed = true;
}
+ TRACE6(utxocache, flush,
+ (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
+ (u_int32_t)mode,
+ (u_int64_t)coins_count,
+ (u_int64_t)coins_mem_usage,
+ (bool)fFlushForPrune,
+ (bool)fDoFullFlush);
}
if (full_flush_completed) {
// Update best block in wallet (so we can detect restored wallets).
diff --git a/src/wallet/context.h b/src/wallet/context.h
index a382fb9021..dbd172e88e 100644
--- a/src/wallet/context.h
+++ b/src/wallet/context.h
@@ -34,6 +34,8 @@ using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wall
struct WalletContext {
interfaces::Chain* chain{nullptr};
ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
+ // It is unsafe to lock this after locking a CWallet::cs_wallet mutex because
+ // this could introduce inconsistent lock ordering and cause deadlocks.
Mutex wallets_mutex;
std::vector<std::shared_ptr<CWallet>> wallets GUARDED_BY(wallets_mutex);
std::list<LoadWalletFn> wallet_load_fns GUARDED_BY(wallets_mutex);
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index efef1ec754..6a73efb472 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -60,10 +60,10 @@ bool ExternalSignerScriptPubKeyMan::DisplayAddress(const CScript scriptPubKey, c
}
// If sign is true, transaction must previously have been filled
-TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
+TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
{
if (!sign) {
- return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed);
+ return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed, finalize);
}
// Already complete if every input is now signed
@@ -79,6 +79,6 @@ TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransact
tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason);
return TransactionError::EXTERNAL_SIGNER_FAILED;
}
- FinalizePSBT(psbt); // This won't work in a multisig setup
+ if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup
return TransactionError::OK;
}
diff --git a/src/wallet/external_signer_scriptpubkeyman.h b/src/wallet/external_signer_scriptpubkeyman.h
index 61df3d0015..53d65d9e46 100644
--- a/src/wallet/external_signer_scriptpubkeyman.h
+++ b/src/wallet/external_signer_scriptpubkeyman.h
@@ -28,6 +28,6 @@ class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan
bool DisplayAddress(const CScript scriptPubKey, const ExternalSigner &signer) const;
- TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;
+ TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
};
#endif // BITCOIN_WALLET_EXTERNAL_SIGNER_SCRIPTPUBKEYMAN_H
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 7a5526a4cb..4ff049170e 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -43,9 +43,9 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions(ArgsManager& argsman) const
{
- argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting many (possibly all) or none, instead of selecting on a per-output basis. Privacy is improved as addresses are mostly swept with fewer transactions and outputs are aggregated in clean change addresses. It may result in higher fees due to less optimal coin selection caused by this added limitation and possibly a larger-than-necessary number of inputs being used. Always enabled for wallets with \"avoid_reuse\" enabled, otherwise default: %u.", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
- argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-consolidatefeerate=<amt>", strprintf("The maximum feerate (in %s/kvB) at which transaction building may use more inputs than strictly necessary so that the wallet's UTXO pool can be reduced (default: %s).", CURRENCY_UNIT, FormatMoney(DEFAULT_CONSOLIDATE_FEERATE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 57f1a6a67a..6489e2a5fc 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -82,7 +82,10 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
{
WalletTxStatus result;
- result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max();
+ result.block_height =
+ wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height :
+ wtx.state<TxStateConflicted>() ? wtx.state<TxStateConflicted>()->conflicting_block_height :
+ std::numeric_limits<int>::max();
result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx);
result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx);
result.time_received = wtx.nTimeReceived;
diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h
index 38ed7e7770..8605547cf2 100644
--- a/src/wallet/ismine.h
+++ b/src/wallet/ismine.h
@@ -8,8 +8,9 @@
#include <script/standard.h>
-#include <stdint.h>
#include <bitset>
+#include <cstdint>
+#include <type_traits>
class CWallet;
class CScript;
@@ -35,8 +36,7 @@ class CScript;
* ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user.
*
*/
-enum isminetype : unsigned int
-{
+enum isminetype : unsigned int {
ISMINE_NO = 0,
ISMINE_WATCH_ONLY = 1 << 0,
ISMINE_SPENDABLE = 1 << 1,
@@ -46,7 +46,7 @@ enum isminetype : unsigned int
ISMINE_ENUM_ELEMENTS,
};
/** used for bitflags of isminetype */
-typedef uint8_t isminefilter;
+using isminefilter = std::underlying_type<isminetype>::type;
/**
* Cachable amount subdivided into watchonly and spendable parts.
diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp
new file mode 100644
index 0000000000..275eb2f1f7
--- /dev/null
+++ b/src/wallet/rpc/signmessage.cpp
@@ -0,0 +1,68 @@
+// Copyright (c) 2011-2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <key_io.h>
+#include <rpc/util.h>
+#include <util/message.h>
+#include <wallet/rpcwallet.h>
+#include <wallet/wallet.h>
+
+#include <univalue.h>
+
+RPCHelpMan signmessage()
+{
+ return RPCHelpMan{"signmessage",
+ "\nSign a message with the private key of an address" +
+ HELP_REQUIRING_PASSPHRASE,
+ {
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."},
+ {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
+ },
+ RPCResult{
+ RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
+ },
+ RPCExamples{
+ "\nUnlock the wallet for 30 seconds\n"
+ + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
+ "\nCreate the signature\n"
+ + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
+ "\nVerify the signature\n"
+ + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+ {
+ const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
+ if (!pwallet) return NullUniValue;
+
+ LOCK(pwallet->cs_wallet);
+
+ EnsureWalletIsUnlocked(*pwallet);
+
+ std::string strAddress = request.params[0].get_str();
+ std::string strMessage = request.params[1].get_str();
+
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
+
+ const PKHash* pkhash = std::get_if<PKHash>(&dest);
+ if (!pkhash) {
+ throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
+
+ std::string signature;
+ SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature);
+ if (err == SigningResult::SIGNING_FAILED) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err));
+ } else if (err != SigningResult::OK) {
+ throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err));
+ }
+
+ return signature;
+ },
+ };
+}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 403c978680..ece75dc43f 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -369,11 +369,9 @@ RPCHelpMan importprunedfunds()
unsigned int txnIndex = vIndex[it - vMatch.begin()];
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex);
-
CTransactionRef tx_ref = MakeTransactionRef(tx);
if (pwallet->IsMine(*tx_ref)) {
- pwallet->AddToWallet(std::move(tx_ref), confirm);
+ pwallet->AddToWallet(std::move(tx_ref), TxStateConfirmed{merkleBlock.header.GetHash(), height, static_cast<int>(txnIndex)});
return NullUniValue;
}
@@ -1548,18 +1546,6 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
}
}
- // Taproot descriptors cannot be imported if Taproot is not yet active.
- // Check if this is a Taproot descriptor
- CTxDestination dest;
- ExtractDestination(scripts[0], dest);
- if (std::holds_alternative<WitnessV1Taproot>(dest)) {
- // Check if Taproot is active
- if (!wallet.chain().isTaprootActive()) {
- // Taproot is not active, raise an error
- throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import tr() descriptor when Taproot is not active");
- }
- }
-
// If private keys are enabled, check some things.
if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (keys.keys.empty()) {
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index babb61b03a..beda86e4b4 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -20,7 +20,6 @@
#include <script/sign.h>
#include <util/bip32.h>
#include <util/fees.h>
-#include <util/message.h> // For MessageSign()
#include <util/moneystr.h>
#include <util/string.h>
#include <util/system.h>
@@ -48,7 +47,7 @@
using interfaces::FoundBlock;
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
-static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
+const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
@@ -166,13 +165,13 @@ static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue
entry.pushKV("confirmations", confirms);
if (wtx.IsCoinBase())
entry.pushKV("generated", true);
- if (confirms > 0)
+ if (auto* conf = wtx.state<TxStateConfirmed>())
{
- entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
- entry.pushKV("blockheight", wtx.m_confirm.block_height);
- entry.pushKV("blockindex", wtx.m_confirm.nIndex);
+ entry.pushKV("blockhash", conf->confirmed_block_hash.GetHex());
+ entry.pushKV("blockheight", conf->confirmed_block_height);
+ entry.pushKV("blockindex", conf->position_in_block);
int64_t block_time;
- CHECK_NONFATAL(chain.findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(block_time)));
+ CHECK_NONFATAL(chain.findBlock(conf->confirmed_block_hash, FoundBlock().time(block_time)));
entry.pushKV("blocktime", block_time);
} else {
entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx));
@@ -612,63 +611,6 @@ static RPCHelpMan listaddressgroupings()
};
}
-static RPCHelpMan signmessage()
-{
- return RPCHelpMan{"signmessage",
- "\nSign a message with the private key of an address" +
- HELP_REQUIRING_PASSPHRASE,
- {
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."},
- {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
- },
- RPCResult{
- RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
- },
- RPCExamples{
- "\nUnlock the wallet for 30 seconds\n"
- + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
- "\nCreate the signature\n"
- + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
- "\nVerify the signature\n"
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
- "\nAs a JSON-RPC call\n"
- + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
- },
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
-{
- const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
-
- LOCK(pwallet->cs_wallet);
-
- EnsureWalletIsUnlocked(*pwallet);
-
- std::string strAddress = request.params[0].get_str();
- std::string strMessage = request.params[1].get_str();
-
- CTxDestination dest = DecodeDestination(strAddress);
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
- }
-
- const PKHash* pkhash = std::get_if<PKHash>(&dest);
- if (!pkhash) {
- throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
- }
-
- std::string signature;
- SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature);
- if (err == SigningResult::SIGNING_FAILED) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err));
- } else if (err != SigningResult::OK){
- throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err));
- }
-
- return signature;
-},
- };
-}
-
static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
std::set<CTxDestination> address_set;
@@ -2522,7 +2464,6 @@ static RPCHelpMan getwalletinfo()
size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
const auto bal = GetBalance(*pwallet);
- int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
obj.pushKV("walletname", pwallet->GetName());
obj.pushKV("walletversion", pwallet->GetVersion());
obj.pushKV("format", pwallet->GetDatabase().Format());
@@ -2530,8 +2471,9 @@ static RPCHelpMan getwalletinfo()
obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
obj.pushKV("txcount", (int)pwallet->mapWallet.size());
- if (kp_oldest > 0) {
- obj.pushKV("keypoololdest", kp_oldest);
+ const auto kp_oldest = pwallet->GetOldestKeyPoolTime();
+ if (kp_oldest.has_value()) {
+ obj.pushKV("keypoololdest", kp_oldest.value());
}
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
@@ -4551,6 +4493,7 @@ static RPCHelpMan walletprocesspsbt()
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\""},
{"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
+ {"finalize", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also finalize inputs if possible"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -4572,7 +4515,7 @@ static RPCHelpMan walletprocesspsbt()
// the user could have gotten from another RPC command prior to now
wallet.BlockUntilSyncedToCurrentChain();
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
+ RPCTypeCheck(request.params, {UniValue::VSTR});
// Unserialize the transaction
PartiallySignedTransaction psbtx;
@@ -4587,11 +4530,12 @@ static RPCHelpMan walletprocesspsbt()
// Fill transaction with our data and also sign
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
+ bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool();
bool complete = true;
if (sign) EnsureWalletIsUnlocked(*pwallet);
- const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs)};
+ const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs, nullptr, finalize)};
if (err != TransactionError::OK) {
throw JSONRPCTransactionError(err);
}
@@ -4860,6 +4804,7 @@ RPCHelpMan removeprunedfunds();
RPCHelpMan importmulti();
RPCHelpMan importdescriptors();
RPCHelpMan listdescriptors();
+RPCHelpMan signmessage();
Span<const CRPCCommand> GetWalletRPCCommands()
{
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 3a85fc0c64..fda685e9ee 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -21,6 +21,8 @@ class CTransaction;
struct PartiallySignedTransaction;
struct WalletContext;
+extern const std::string HELP_REQUIRING_PASSPHRASE;
+
Span<const CRPCCommand> GetWalletRPCCommands();
/**
@@ -38,4 +40,4 @@ const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wal
RPCHelpMan getaddressinfo();
RPCHelpMan signrawtransactionwithwallet();
-#endif //BITCOIN_WALLET_RPCWALLET_H
+#endif // BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 9173c790d4..a82eaa4879 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -528,7 +528,7 @@ static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, Walle
return keypool.nTime;
}
-int64_t LegacyScriptPubKeyMan::GetOldestKeyPoolTime() const
+std::optional<int64_t> LegacyScriptPubKeyMan::GetOldestKeyPoolTime() const
{
LOCK(cs_KeyStore);
@@ -610,7 +610,7 @@ SigningResult LegacyScriptPubKeyMan::SignMessage(const std::string& message, con
return SigningResult::SIGNING_FAILED;
}
-TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
+TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
{
if (n_signed) {
*n_signed = 0;
@@ -639,7 +639,7 @@ TransactionError LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psb
}
SignatureData sigdata;
input.FillSignatureData(sigdata);
- SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type);
+ SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
bool signed_one = PSBTInputSigned(input);
if (n_signed && (signed_one || !sign)) {
@@ -1876,12 +1876,6 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal)
{
- if (addr_type == OutputType::BECH32M) {
- // Don't allow setting up taproot descriptors yet
- // TODO: Allow setting up taproot descriptors
- return false;
- }
-
LOCK(cs_desc_man);
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
@@ -1911,7 +1905,10 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
desc_prefix = "wpkh(" + xpub + "/84'";
break;
}
- case OutputType::BECH32M: assert(false); // TODO: Setup taproot descriptor
+ case OutputType::BECH32M: {
+ desc_prefix = "tr(" + xpub + "/86'";
+ break;
+ }
} // no default case, so the compiler can warn about missing cases
assert(!desc_prefix.empty());
@@ -1970,11 +1967,10 @@ bool DescriptorScriptPubKeyMan::HavePrivateKeys() const
return m_map_keys.size() > 0 || m_map_crypted_keys.size() > 0;
}
-int64_t DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const
+std::optional<int64_t> DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const
{
// This is only used for getwalletinfo output and isn't relevant to descriptor wallets.
- // The magic number 0 indicates that it shouldn't be displayed so that's what we return.
- return 0;
+ return std::nullopt;
}
@@ -2078,7 +2074,7 @@ SigningResult DescriptorScriptPubKeyMan::SignMessage(const std::string& message,
return SigningResult::OK;
}
-TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed) const
+TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbtx, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const
{
if (n_signed) {
*n_signed = 0;
@@ -2128,7 +2124,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
}
}
- SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type);
+ SignPSBTInput(HidingSigningProvider(keys.get(), !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
bool signed_one = PSBTInputSigned(input);
if (n_signed && (signed_one || !sign)) {
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index ef74638751..9d2304a542 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -19,6 +19,7 @@
#include <boost/signals2/signal.hpp>
+#include <optional>
#include <unordered_map>
enum class OutputType;
@@ -203,7 +204,7 @@ public:
//! The action to do when the DB needs rewrite
virtual void RewriteDB() {}
- virtual int64_t GetOldestKeyPoolTime() const { return GetTime(); }
+ virtual std::optional<int64_t> GetOldestKeyPoolTime() const { return GetTime(); }
virtual unsigned int GetKeyPoolSize() const { return 0; }
@@ -223,7 +224,7 @@ public:
/** Sign a message with the given script */
virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; };
/** Adds script and derivation path information to a PSBT, and optionally signs it. */
- virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const { return TransactionError::INVALID_PSBT; }
+ virtual TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const { return TransactionError::INVALID_PSBT; }
virtual uint256 GetID() const { return uint256(); }
@@ -371,7 +372,7 @@ public:
void RewriteDB() override;
- int64_t GetOldestKeyPoolTime() const override;
+ std::optional<int64_t> GetOldestKeyPoolTime() const override;
size_t KeypoolCountExternalKeys() const;
unsigned int GetKeyPoolSize() const override;
@@ -387,7 +388,7 @@ public:
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
- TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;
+ TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
uint256 GetID() const override;
@@ -577,7 +578,7 @@ public:
bool HavePrivateKeys() const override;
- int64_t GetOldestKeyPoolTime() const override;
+ std::optional<int64_t> GetOldestKeyPoolTime() const override;
unsigned int GetKeyPoolSize() const override;
int64_t GetTimeFirstKey() const override;
@@ -592,7 +593,7 @@ public:
bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const override;
SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const override;
- TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr) const override;
+ TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override;
uint256 GetID() const override;
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index a8a7e12a32..8f985f31ee 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -74,7 +74,7 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
uint256 txid = tx.GetHash();
LOCK(wallet.cs_wallet);
- auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx))));
+ auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{}));
assert(ret.second);
CWalletTx& wtx = (*ret.first).second;
if (fIsFromMe)
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index e8b49f1220..0601c492cd 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -68,9 +68,6 @@ struct FuzzedWallet {
CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
{
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
- if (type == OutputType::BECH32M) {
- type = OutputType::BECH32; // TODO: Setup taproot descriptor and remove this line
- }
CTxDestination dest;
bilingual_str error;
if (fuzzed_data_provider.ConsumeBool()) {
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index dd24fa2c19..7bc2bb5583 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -34,12 +34,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1;
- m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1, TxStateInactive{}));
CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx2;
s_prev_tx2 >> prev_tx2;
- m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2, TxStateInactive{}));
// Import descriptors for keys and scripts
import_descriptor(m_wallet, "sh(multi(2,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/0h,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/1h))");
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 4499eb5903..9842089cf8 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -330,7 +330,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
- CWalletTx wtx(m_coinbase_txns.back());
+ CWalletTx wtx{m_coinbase_txns.back(), TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*position_in_block=*/0}};
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -338,9 +338,6 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash(), 0);
- wtx.m_confirm = confirm;
-
// Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0.
BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0);
@@ -355,7 +352,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
{
CMutableTransaction tx;
- CWalletTx::Confirmation confirm;
+ TxState state = TxStateInactive{};
tx.nLockTime = lockTime;
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
@@ -367,13 +364,13 @@ static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lock
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash;
- confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0};
+ state = TxStateConfirmed{hash, block->nHeight, /*position_in_block=*/0};
}
-
- // If transaction is already in map, to avoid inconsistencies, unconfirmation
- // is needed before confirm again with different block.
- return wallet.AddToWallet(MakeTransactionRef(tx), confirm, [&](CWalletTx& wtx, bool /* new_tx */) {
- wtx.setUnconfirmed();
+ return wallet.AddToWallet(MakeTransactionRef(tx), state, [&](CWalletTx& wtx, bool /* new_tx */) {
+ // Assign wtx.m_state to simplify test and avoid the need to simulate
+ // reorg events. Without this, AddToWallet asserts false when the same
+ // transaction is confirmed in different blocks.
+ wtx.m_state = state;
return true;
})->nTimeSmart;
}
@@ -534,8 +531,7 @@ public:
wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, m_node.chainman->ActiveChain().Tip()->GetBlockHash());
auto it = wallet->mapWallet.find(tx->GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash(), 1);
- it->second.m_confirm = confirm;
+ it->second.m_state = TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*position_in_block=*/1};
return it->second;
}
@@ -783,18 +779,14 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
// deadlock during the sync and simulates a new block notification happening
// as soon as possible.
addtx_count = 0;
- auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet, context.wallets_mutex) {
+ auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) {
BOOST_CHECK(rescan_completed);
m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error));
- LEAVE_CRITICAL_SECTION(context.wallets_mutex);
- LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
SyncWithValidationInterfaceQueue();
- ENTER_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
- ENTER_CRITICAL_SECTION(context.wallets_mutex);
});
wallet = TestLoadWallet(context);
BOOST_CHECK_EQUAL(addtx_count, 4);
diff --git a/src/wallet/test/wallet_transaction_tests.cpp b/src/wallet/test/wallet_transaction_tests.cpp
new file mode 100644
index 0000000000..5ef2904f66
--- /dev/null
+++ b/src/wallet/test/wallet_transaction_tests.cpp
@@ -0,0 +1,24 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <wallet/transaction.h>
+
+#include <wallet/test/wallet_test_fixture.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(wallet_transaction_tests, WalletTestingSetup)
+
+BOOST_AUTO_TEST_CASE(roundtrip)
+{
+ for (uint8_t hash = 0; hash < 5; ++hash) {
+ for (int index = -2; index < 3; ++index) {
+ TxState state = TxStateInterpretSerialized(TxStateUnrecognized{uint256{hash}, index});
+ BOOST_CHECK_EQUAL(TxStateSerializedBlockHash(state), uint256{hash});
+ BOOST_CHECK_EQUAL(TxStateSerializedIndex(state), index);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/transaction.cpp b/src/wallet/transaction.cpp
index cf98b516f1..a926c0ecc1 100644
--- a/src/wallet/transaction.cpp
+++ b/src/wallet/transaction.cpp
@@ -15,7 +15,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
bool CWalletTx::InMempool() const
{
- return fInMempool;
+ return state<TxStateInMempool>();
}
int64_t CWalletTx::GetTxTime() const
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index 1ccef31056..52d72cccf3 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -11,12 +11,102 @@
#include <wallet/ismine.h>
#include <threadsafety.h>
#include <tinyformat.h>
+#include <util/overloaded.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <list>
+#include <variant>
#include <vector>
+//! State of transaction confirmed in a block.
+struct TxStateConfirmed {
+ uint256 confirmed_block_hash;
+ int confirmed_block_height;
+ int position_in_block;
+
+ explicit TxStateConfirmed(const uint256& block_hash, int height, int index) : confirmed_block_hash(block_hash), confirmed_block_height(height), position_in_block(index) {}
+};
+
+//! State of transaction added to mempool.
+struct TxStateInMempool {
+};
+
+//! State of rejected transaction that conflicts with a confirmed block.
+struct TxStateConflicted {
+ uint256 conflicting_block_hash;
+ int conflicting_block_height;
+
+ explicit TxStateConflicted(const uint256& block_hash, int height) : conflicting_block_hash(block_hash), conflicting_block_height(height) {}
+};
+
+//! State of transaction not confirmed or conflicting with a known block and
+//! not in the mempool. May conflict with the mempool, or with an unknown block,
+//! or be abandoned, never broadcast, or rejected from the mempool for another
+//! reason.
+struct TxStateInactive {
+ bool abandoned;
+
+ explicit TxStateInactive(bool abandoned = false) : abandoned(abandoned) {}
+};
+
+//! State of transaction loaded in an unrecognized state with unexpected hash or
+//! index values. Treated as inactive (with serialized hash and index values
+//! preserved) by default, but may enter another state if transaction is added
+//! to the mempool, or confirmed, or abandoned, or found conflicting.
+struct TxStateUnrecognized {
+ uint256 block_hash;
+ int index;
+
+ TxStateUnrecognized(const uint256& block_hash, int index) : block_hash(block_hash), index(index) {}
+};
+
+//! All possible CWalletTx states
+using TxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateConflicted, TxStateInactive, TxStateUnrecognized>;
+
+//! Subset of states transaction sync logic is implemented to handle.
+using SyncTxState = std::variant<TxStateConfirmed, TxStateInMempool, TxStateInactive>;
+
+//! Try to interpret deserialized TxStateUnrecognized data as a recognized state.
+static inline TxState TxStateInterpretSerialized(TxStateUnrecognized data)
+{
+ if (data.block_hash == uint256::ZERO) {
+ if (data.index == 0) return TxStateInactive{};
+ } else if (data.block_hash == uint256::ONE) {
+ if (data.index == -1) return TxStateInactive{/*abandoned=*/true};
+ } else if (data.index >= 0) {
+ return TxStateConfirmed{data.block_hash, /*height=*/-1, data.index};
+ } else if (data.index == -1) {
+ return TxStateConflicted{data.block_hash, /*height=*/-1};
+ }
+ return data;
+}
+
+//! Get TxState serialized block hash. Inverse of TxStateInterpretSerialized.
+static inline uint256 TxStateSerializedBlockHash(const TxState& state)
+{
+ return std::visit(util::Overloaded{
+ [](const TxStateInactive& inactive) { return inactive.abandoned ? uint256::ONE : uint256::ZERO; },
+ [](const TxStateInMempool& in_mempool) { return uint256::ZERO; },
+ [](const TxStateConfirmed& confirmed) { return confirmed.confirmed_block_hash; },
+ [](const TxStateConflicted& conflicted) { return conflicted.conflicting_block_hash; },
+ [](const TxStateUnrecognized& unrecognized) { return unrecognized.block_hash; }
+ }, state);
+}
+
+//! Get TxState serialized block index. Inverse of TxStateInterpretSerialized.
+static inline int TxStateSerializedIndex(const TxState& state)
+{
+ return std::visit(util::Overloaded{
+ [](const TxStateInactive& inactive) { return inactive.abandoned ? -1 : 0; },
+ [](const TxStateInMempool& in_mempool) { return 0; },
+ [](const TxStateConfirmed& confirmed) { return confirmed.position_in_block; },
+ [](const TxStateConflicted& conflicted) { return -1; },
+ [](const TxStateUnrecognized& unrecognized) { return unrecognized.index; }
+ }, state);
+}
+
+
typedef std::map<std::string, std::string> mapValue_t;
/** Legacy class used for deserializing vtxPrev for backwards compatibility.
@@ -45,12 +135,6 @@ public:
*/
class CWalletTx
{
-private:
- /** Constant used in hashBlock to indicate tx has been abandoned, only used at
- * serialization/deserialization to avoid ambiguity with conflicted.
- */
- static constexpr const uint256& ABANDON_HASH = uint256::ONE;
-
public:
/**
* Key/value map with information about the transaction.
@@ -111,11 +195,9 @@ public:
*/
mutable bool m_is_cache_empty{true};
mutable bool fChangeCached;
- mutable bool fInMempool;
mutable CAmount nChangeCached;
- CWalletTx(CTransactionRef arg)
- : tx(std::move(arg))
+ CWalletTx(CTransactionRef tx, const TxState& state) : tx(std::move(tx)), m_state(state)
{
Init();
}
@@ -129,44 +211,12 @@ public:
nTimeSmart = 0;
fFromMe = false;
fChangeCached = false;
- fInMempool = false;
nChangeCached = 0;
nOrderPos = -1;
- m_confirm = Confirmation{};
}
CTransactionRef tx;
-
- /** New transactions start as UNCONFIRMED. At BlockConnected,
- * they will transition to CONFIRMED. In case of reorg, at BlockDisconnected,
- * they roll back to UNCONFIRMED. If we detect a conflicting transaction at
- * block connection, we update conflicted tx and its dependencies as CONFLICTED.
- * If tx isn't confirmed and outside of mempool, the user may switch it to ABANDONED
- * by using the abandontransaction call. This last status may be override by a CONFLICTED
- * or CONFIRMED transition.
- */
- enum Status {
- UNCONFIRMED,
- CONFIRMED,
- CONFLICTED,
- ABANDONED
- };
-
- /** Confirmation includes tx status and a triplet of {block height/block hash/tx index in block}
- * at which tx has been confirmed. All three are set to 0 if tx is unconfirmed or abandoned.
- * Meaning of these fields changes with CONFLICTED state where they instead point to block hash
- * and block height of the deepest conflicting tx.
- */
- struct Confirmation {
- Status status;
- int block_height;
- uint256 hashBlock;
- int nIndex;
- Confirmation(Status status = UNCONFIRMED, int block_height = 0, uint256 block_hash = uint256(), int block_index = 0)
- : status{status}, block_height{block_height}, hashBlock{block_hash}, nIndex{block_index} {}
- };
-
- Confirmation m_confirm;
+ TxState m_state;
template<typename Stream>
void Serialize(Stream& s) const
@@ -184,8 +234,8 @@ public:
std::vector<uint8_t> dummy_vector1; //!< Used to be vMerkleBranch
std::vector<uint8_t> dummy_vector2; //!< Used to be vtxPrev
bool dummy_bool = false; //!< Used to be fSpent
- uint256 serializedHash = isAbandoned() ? ABANDON_HASH : m_confirm.hashBlock;
- int serializedIndex = isAbandoned() || isConflicted() ? -1 : m_confirm.nIndex;
+ uint256 serializedHash = TxStateSerializedBlockHash(m_state);
+ int serializedIndex = TxStateSerializedIndex(m_state);
s << tx << serializedHash << dummy_vector1 << serializedIndex << dummy_vector2 << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << dummy_bool;
}
@@ -197,24 +247,11 @@ public:
std::vector<uint256> dummy_vector1; //!< Used to be vMerkleBranch
std::vector<CMerkleTx> dummy_vector2; //!< Used to be vtxPrev
bool dummy_bool; //! Used to be fSpent
+ uint256 serialized_block_hash;
int serializedIndex;
- s >> tx >> m_confirm.hashBlock >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_bool;
-
- /* At serialization/deserialization, an nIndex == -1 means that hashBlock refers to
- * the earliest block in the chain we know this or any in-wallet ancestor conflicts
- * with. If nIndex == -1 and hashBlock is ABANDON_HASH, it means transaction is abandoned.
- * In same context, an nIndex >= 0 refers to a confirmed transaction (if hashBlock set) or
- * unconfirmed one. Older clients interpret nIndex == -1 as unconfirmed for backward
- * compatibility (pre-commit 9ac63d6).
- */
- if (serializedIndex == -1 && m_confirm.hashBlock == ABANDON_HASH) {
- setAbandoned();
- } else if (serializedIndex == -1) {
- setConflicted();
- } else if (!m_confirm.hashBlock.IsNull()) {
- m_confirm.nIndex = serializedIndex;
- setConfirmed();
- }
+ s >> tx >> serialized_block_hash >> dummy_vector1 >> serializedIndex >> dummy_vector2 >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> dummy_bool;
+
+ m_state = TxStateInterpretSerialized({serialized_block_hash, serializedIndex});
const auto it_op = mapValue.find("n");
nOrderPos = (it_op != mapValue.end()) ? LocaleIndependentAtoi<int64_t>(it_op->second) : -1;
@@ -250,20 +287,13 @@ public:
int64_t GetTxTime() const;
- bool isAbandoned() const { return m_confirm.status == CWalletTx::ABANDONED; }
- void setAbandoned()
- {
- m_confirm.status = CWalletTx::ABANDONED;
- m_confirm.hashBlock = uint256();
- m_confirm.block_height = 0;
- m_confirm.nIndex = 0;
- }
- bool isConflicted() const { return m_confirm.status == CWalletTx::CONFLICTED; }
- void setConflicted() { m_confirm.status = CWalletTx::CONFLICTED; }
- bool isUnconfirmed() const { return m_confirm.status == CWalletTx::UNCONFIRMED; }
- void setUnconfirmed() { m_confirm.status = CWalletTx::UNCONFIRMED; }
- bool isConfirmed() const { return m_confirm.status == CWalletTx::CONFIRMED; }
- void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
+ template<typename T> const T* state() const { return std::get_if<T>(&m_state); }
+ template<typename T> T* state() { return std::get_if<T>(&m_state); }
+
+ bool isAbandoned() const { return state<TxStateInactive>() && state<TxStateInactive>()->abandoned; }
+ bool isConflicted() const { return state<TxStateConflicted>(); }
+ bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
+ bool isConfirmed() const { return state<TxStateConfirmed>(); }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 7f60dd6906..e4c3822305 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -99,7 +99,11 @@ static void UpdateWalletSetting(interfaces::Chain& chain,
*/
static void RefreshMempoolStatus(CWalletTx& tx, interfaces::Chain& chain)
{
- tx.fInMempool = chain.isInMempool(tx.GetHash());
+ if (chain.isInMempool(tx.GetHash())) {
+ tx.m_state = TxStateInMempool();
+ } else if (tx.state<TxStateInMempool>()) {
+ tx.m_state = TxStateInactive();
+ }
}
bool AddWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet)
@@ -885,7 +889,7 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const
return false;
}
-CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose, bool rescanning_old_block)
+CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose, bool rescanning_old_block)
{
LOCK(cs_wallet);
@@ -906,12 +910,11 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
}
// Inserts only if not already there, returns tx inserted or tx found
- auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx));
+ auto ret = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(tx, state));
CWalletTx& wtx = (*ret.first).second;
bool fInsertedNew = ret.second;
bool fUpdated = update_wtx && update_wtx(wtx, fInsertedNew);
if (fInsertedNew) {
- wtx.m_confirm = confirm;
wtx.nTimeReceived = chain().getAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&batch);
wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
@@ -921,16 +924,12 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
if (!fInsertedNew)
{
- if (confirm.status != wtx.m_confirm.status) {
- wtx.m_confirm.status = confirm.status;
- wtx.m_confirm.nIndex = confirm.nIndex;
- wtx.m_confirm.hashBlock = confirm.hashBlock;
- wtx.m_confirm.block_height = confirm.block_height;
+ if (state.index() != wtx.m_state.index()) {
+ wtx.m_state = state;
fUpdated = true;
} else {
- assert(wtx.m_confirm.nIndex == confirm.nIndex);
- assert(wtx.m_confirm.hashBlock == confirm.hashBlock);
- assert(wtx.m_confirm.block_height == confirm.block_height);
+ assert(TxStateSerializedIndex(wtx.m_state) == TxStateSerializedIndex(state));
+ assert(TxStateSerializedBlockHash(wtx.m_state) == TxStateSerializedBlockHash(state));
}
// If we have a witness-stripped version of this transaction, and we
// see a new version with a witness, then we must be upgrading a pre-segwit
@@ -964,10 +963,10 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
if (!strCmd.empty())
{
boost::replace_all(strCmd, "%s", hash.GetHex());
- if (confirm.status == CWalletTx::Status::CONFIRMED)
+ if (auto* conf = wtx.state<TxStateConfirmed>())
{
- boost::replace_all(strCmd, "%b", confirm.hashBlock.GetHex());
- boost::replace_all(strCmd, "%h", ToString(confirm.block_height));
+ boost::replace_all(strCmd, "%b", conf->confirmed_block_hash.GetHex());
+ boost::replace_all(strCmd, "%h", ToString(conf->confirmed_block_height));
} else {
boost::replace_all(strCmd, "%b", "unconfirmed");
boost::replace_all(strCmd, "%h", "-1");
@@ -990,7 +989,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx)
{
- const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr));
+ const auto& ins = mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(nullptr, TxStateInactive{}));
CWalletTx& wtx = ins.first->second;
if (!fill_wtx(wtx, ins.second)) {
return false;
@@ -998,22 +997,21 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
// If wallet doesn't have a chain (e.g wallet-tool), don't bother to update txn.
if (HaveChain()) {
bool active;
- int height;
- if (chain().findBlock(wtx.m_confirm.hashBlock, FoundBlock().inActiveChain(active).height(height)) && active) {
- // Update cached block height variable since it not stored in the
- // serialized transaction.
- wtx.m_confirm.block_height = height;
- } else if (wtx.isConflicted() || wtx.isConfirmed()) {
+ auto lookup_block = [&](const uint256& hash, int& height, TxState& state) {
// If tx block (or conflicting block) was reorged out of chain
// while the wallet was shutdown, change tx status to UNCONFIRMED
// and reset block height, hash, and index. ABANDONED tx don't have
// associated blocks and don't need to be updated. The case where a
// transaction was reorged out while online and then reconfirmed
// while offline is covered by the rescan logic.
- wtx.setUnconfirmed();
- wtx.m_confirm.hashBlock = uint256();
- wtx.m_confirm.block_height = 0;
- wtx.m_confirm.nIndex = 0;
+ if (!chain().findBlock(hash, FoundBlock().inActiveChain(active).height(height)) || !active) {
+ state = TxStateInactive{};
+ }
+ };
+ if (auto* conf = wtx.state<TxStateConfirmed>()) {
+ lookup_block(conf->confirmed_block_hash, conf->confirmed_block_height, wtx.m_state);
+ } else if (auto* conf = wtx.state<TxStateConflicted>()) {
+ lookup_block(conf->conflicting_block_hash, conf->conflicting_block_height, wtx.m_state);
}
}
if (/* insertion took place */ ins.second) {
@@ -1024,27 +1022,27 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
auto it = mapWallet.find(txin.prevout.hash);
if (it != mapWallet.end()) {
CWalletTx& prevtx = it->second;
- if (prevtx.isConflicted()) {
- MarkConflicted(prevtx.m_confirm.hashBlock, prevtx.m_confirm.block_height, wtx.GetHash());
+ if (auto* prev = prevtx.state<TxStateConflicted>()) {
+ MarkConflicted(prev->conflicting_block_hash, prev->conflicting_block_height, wtx.GetHash());
}
}
}
return true;
}
-bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool fUpdate, bool rescanning_old_block)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block)
{
const CTransaction& tx = *ptx;
{
AssertLockHeld(cs_wallet);
- if (!confirm.hashBlock.IsNull()) {
+ if (auto* conf = std::get_if<TxStateConfirmed>(&state)) {
for (const CTxIn& txin : tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
- WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), confirm.hashBlock.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
- MarkConflicted(confirm.hashBlock, confirm.block_height, range.first->second);
+ WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), conf->confirmed_block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
+ MarkConflicted(conf->confirmed_block_hash, conf->confirmed_block_height, range.first->second);
}
range.first++;
}
@@ -1070,7 +1068,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co
// Block disconnection override an abandoned tx as unconfirmed
// which means user may have to call abandontransaction again
- return AddToWallet(MakeTransactionRef(tx), confirm, /* update_wtx= */ nullptr, /* fFlushOnClose= */ false, rescanning_old_block);
+ TxState tx_state = std::visit([](auto&& s) -> TxState { return s; }, state);
+ return AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
}
}
return false;
@@ -1126,7 +1125,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
if (currentconfirm == 0 && !wtx.isAbandoned()) {
// If the orig tx was not in block/mempool, none of its spends can be in mempool
assert(!wtx.InMempool());
- wtx.setAbandoned();
+ wtx.m_state = TxStateInactive{/*abandoned=*/true};
wtx.MarkDirty();
batch.WriteTx(wtx);
NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
@@ -1178,10 +1177,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block.
- wtx.m_confirm.nIndex = 0;
- wtx.m_confirm.hashBlock = hashBlock;
- wtx.m_confirm.block_height = conflicting_height;
- wtx.setConflicted();
+ wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
wtx.MarkDirty();
batch.WriteTx(wtx);
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
@@ -1199,9 +1195,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
}
}
-void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool update_tx, bool rescanning_old_block)
+void CWallet::SyncTransaction(const CTransactionRef& ptx, const SyncTxState& state, bool update_tx, bool rescanning_old_block)
{
- if (!AddToWalletIfInvolvingMe(ptx, confirm, update_tx, rescanning_old_block))
+ if (!AddToWalletIfInvolvingMe(ptx, state, update_tx, rescanning_old_block))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -1212,7 +1208,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmatio
void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {
LOCK(cs_wallet);
- SyncTransaction(tx, {CWalletTx::Status::UNCONFIRMED, /*block_height=*/0, /*block_hash=*/{}, /*block_index=*/0});
+ SyncTransaction(tx, TxStateInMempool{});
auto it = mapWallet.find(tx->GetHash());
if (it != mapWallet.end()) {
@@ -1253,7 +1249,7 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
// distinguishing between conflicted and unconfirmed transactions are
// imperfect, and could be improved in general, see
// https://github.com/bitcoin-core/bitcoin-devwiki/wiki/Wallet-Transaction-Conflict-Tracking
- SyncTransaction(tx, {CWalletTx::Status::UNCONFIRMED, /*block_height=*/0, /*block_hash=*/{}, /*block_index=*/0});
+ SyncTransaction(tx, TxStateInactive{});
}
}
@@ -1265,7 +1261,7 @@ void CWallet::blockConnected(const CBlock& block, int height)
m_last_block_processed_height = height;
m_last_block_processed = block_hash;
for (size_t index = 0; index < block.vtx.size(); index++) {
- SyncTransaction(block.vtx[index], {CWalletTx::Status::CONFIRMED, height, block_hash, (int)index});
+ SyncTransaction(block.vtx[index], TxStateConfirmed{block_hash, height, static_cast<int>(index)});
transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
}
}
@@ -1281,7 +1277,7 @@ void CWallet::blockDisconnected(const CBlock& block, int height)
m_last_block_processed_height = height - 1;
m_last_block_processed = block.hashPrevBlock;
for (const CTransactionRef& ptx : block.vtx) {
- SyncTransaction(ptx, {CWalletTx::Status::UNCONFIRMED, /*block_height=*/0, /*block_hash=*/{}, /*block_index=*/0});
+ SyncTransaction(ptx, TxStateInactive{});
}
}
@@ -1645,7 +1641,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
break;
}
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
- SyncTransaction(block.vtx[posInBlock], {CWalletTx::Status::CONFIRMED, block_height, block_hash, (int)posInBlock}, fUpdate, /* rescanning_old_block */ true);
+ SyncTransaction(block.vtx[posInBlock], TxStateConfirmed{block_hash, block_height, static_cast<int>(posInBlock)}, fUpdate, /*rescanning_old_block=*/true);
}
// scan succeeded, record block as most recent successfully scanned
result.last_scanned_block = block_hash;
@@ -1720,7 +1716,7 @@ void CWallet::ReacceptWalletTransactions()
}
}
-bool CWallet::SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_string, bool relay) const
+bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const
{
// Can't relay if wallet is not broadcasting
if (!GetBroadcastTransactions()) return false;
@@ -1734,17 +1730,17 @@ bool CWallet::SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_
// Submit transaction to mempool for relay
WalletLogPrintf("Submitting wtx %s to mempool for relay\n", wtx.GetHash().ToString());
- // We must set fInMempool here - while it will be re-set to true by the
+ // We must set TxStateInMempool here. Even though it will also be set later by the
// entered-mempool callback, if we did not there would be a race where a
// user could call sendmoney in a loop and hit spurious out of funds errors
// because we think that this newly generated transaction's change is
// unavailable as we're not yet aware that it is in the mempool.
//
- // Irrespective of the failure reason, un-marking fInMempool
- // out-of-order is incorrect - it should be unmarked when
+ // If broadcast fails for any reason, trying to set wtx.m_state here would be incorrect.
+ // If transaction was previously in the mempool, it should be updated when
// TransactionRemovedFromMempool fires.
bool ret = chain().broadcastTransaction(wtx.tx, m_default_max_tx_fee, relay, err_string);
- wtx.fInMempool |= ret;
+ if (ret) wtx.m_state = TxStateInMempool{};
return ret;
}
@@ -1831,7 +1827,8 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const
return false;
}
const CWalletTx& wtx = mi->second;
- coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], wtx.m_confirm.block_height, wtx.IsCoinBase());
+ int prev_height = wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height : 0;
+ coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], prev_height, wtx.IsCoinBase());
}
std::map<int, bilingual_str> input_errors;
return SignTransaction(tx, coins, SIGHASH_DEFAULT, input_errors);
@@ -1852,7 +1849,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint,
return false;
}
-TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed) const
+TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool bip32derivs, size_t * n_signed, bool finalize) const
{
if (n_signed) {
*n_signed = 0;
@@ -1884,7 +1881,7 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
// Fill in information from ScriptPubKeyMans
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
int n_signed_this_spkm = 0;
- TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm);
+ TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm, finalize);
if (res != TransactionError::OK) {
return res;
}
@@ -1956,7 +1953,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
- AddToWallet(tx, {}, [&](CWalletTx& wtx, bool new_tx) {
+ AddToWallet(tx, TxStateInactive{}, [&](CWalletTx& wtx, bool new_tx) {
CHECK_NONFATAL(wtx.mapValue.empty());
CHECK_NONFATAL(wtx.vOrderForm.empty());
wtx.mapValue = std::move(mapValue);
@@ -1974,7 +1971,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
}
// Get the inserted-CWalletTx from mapWallet so that the
- // fInMempool flag is cached properly
+ // wtx cached mempool state is updated correctly
CWalletTx& wtx = mapWallet.at(tx->GetHash());
if (!fBroadcastTransactions) {
@@ -2169,14 +2166,18 @@ bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& des
return true;
}
-int64_t CWallet::GetOldestKeyPoolTime() const
+std::optional<int64_t> CWallet::GetOldestKeyPoolTime() const
{
LOCK(cs_wallet);
- int64_t oldestKey = std::numeric_limits<int64_t>::max();
+ if (m_spk_managers.empty()) {
+ return std::nullopt;
+ }
+
+ std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
for (const auto& spk_man_pair : m_spk_managers) {
- oldestKey = std::min(oldestKey, spk_man_pair.second->GetOldestKeyPoolTime());
+ oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
}
- return oldestKey;
+ return oldest_key;
}
void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations) {
@@ -2321,10 +2322,10 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
mapKeyBirth.clear();
// map in which we'll infer heights of other keys
- std::map<CKeyID, const CWalletTx::Confirmation*> mapKeyFirstBlock;
- CWalletTx::Confirmation max_confirm;
- max_confirm.block_height = GetLastBlockHeight() > 144 ? GetLastBlockHeight() - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
- CHECK_NONFATAL(chain().findAncestorByHeight(GetLastBlockHash(), max_confirm.block_height, FoundBlock().hash(max_confirm.hashBlock)));
+ std::map<CKeyID, const TxStateConfirmed*> mapKeyFirstBlock;
+ TxStateConfirmed max_confirm{uint256{}, /*height=*/-1, /*index=*/-1};
+ max_confirm.confirmed_block_height = GetLastBlockHeight() > 144 ? GetLastBlockHeight() - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
+ CHECK_NONFATAL(chain().findAncestorByHeight(GetLastBlockHash(), max_confirm.confirmed_block_height, FoundBlock().hash(max_confirm.confirmed_block_hash)));
{
LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
@@ -2352,15 +2353,15 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
const CWalletTx &wtx = entry.second;
- if (wtx.m_confirm.status == CWalletTx::CONFIRMED) {
+ if (auto* conf = wtx.state<TxStateConfirmed>()) {
// ... which are already in a block
for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *spk_man)) {
// ... and all their affected keys
auto rit = mapKeyFirstBlock.find(keyid);
- if (rit != mapKeyFirstBlock.end() && wtx.m_confirm.block_height < rit->second->block_height) {
- rit->second = &wtx.m_confirm;
+ if (rit != mapKeyFirstBlock.end() && conf->confirmed_block_height < rit->second->confirmed_block_height) {
+ rit->second = conf;
}
}
}
@@ -2371,7 +2372,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
// Extract block timestamps for those keys
for (const auto& entry : mapKeyFirstBlock) {
int64_t block_time;
- CHECK_NONFATAL(chain().findBlock(entry.second->hashBlock, FoundBlock().time(block_time)));
+ CHECK_NONFATAL(chain().findBlock(entry.second->confirmed_block_hash, FoundBlock().time(block_time)));
mapKeyBirth[entry.first] = block_time - TIMESTAMP_WINDOW; // block times can be 2h off
}
}
@@ -2401,11 +2402,18 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
*/
unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const
{
+ std::optional<uint256> block_hash;
+ if (auto* conf = wtx.state<TxStateConfirmed>()) {
+ block_hash = conf->confirmed_block_hash;
+ } else if (auto* conf = wtx.state<TxStateConflicted>()) {
+ block_hash = conf->conflicting_block_hash;
+ }
+
unsigned int nTimeSmart = wtx.nTimeReceived;
- if (!wtx.isUnconfirmed() && !wtx.isAbandoned()) {
+ if (block_hash) {
int64_t blocktime;
int64_t block_max_time;
- if (chain().findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(blocktime).maxTime(block_max_time))) {
+ if (chain().findBlock(*block_hash, FoundBlock().time(blocktime).maxTime(block_max_time))) {
if (rescanning_old_block) {
nTimeSmart = block_max_time;
} else {
@@ -2437,7 +2445,7 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old
nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
}
} else {
- WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.m_confirm.hashBlock.ToString());
+ WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), block_hash->ToString());
}
}
return nTimeSmart;
@@ -2755,8 +2763,6 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
- LOCK(walletInstance->cs_wallet);
-
if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
return nullptr;
}
@@ -2768,9 +2774,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
}
}
- walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
-
{
+ LOCK(walletInstance->cs_wallet);
+ walletInstance->SetBroadcastTransactions(args.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size());
@@ -2944,9 +2950,13 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn)
int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
{
AssertLockHeld(cs_wallet);
- if (wtx.isUnconfirmed() || wtx.isAbandoned()) return 0;
-
- return (GetLastBlockHeight() - wtx.m_confirm.block_height + 1) * (wtx.isConflicted() ? -1 : 1);
+ if (auto* conf = wtx.state<TxStateConfirmed>()) {
+ return GetLastBlockHeight() - conf->confirmed_block_height + 1;
+ } else if (auto* conf = wtx.state<TxStateConflicted>()) {
+ return -1 * (GetLastBlockHeight() - conf->conflicting_block_height + 1);
+ } else {
+ return 0;
+ }
}
int CWallet::GetTxBlocksToMaturity(const CWalletTx& wtx) const
@@ -3164,11 +3174,6 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- if (t == OutputType::BECH32M) {
- // Skip taproot (bech32m) for now
- // TODO: Setup taproot (bech32m) descriptors by default
- continue;
- }
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
if (IsCrypted()) {
if (IsLocked()) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3855ad821d..e294358609 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -275,7 +275,7 @@ private:
* Should be called with rescanning_old_block set to true, if the transaction is
* not discovered in real time, but during a rescan of old blocks.
*/
- bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const SyncTxState& state, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
void MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx);
@@ -285,7 +285,7 @@ private:
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- void SyncTransaction(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool update_tx = true, bool rescanning_old_block = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void SyncTransaction(const CTransactionRef& tx, const SyncTxState& state, bool update_tx = true, bool rescanning_old_block = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** WalletFlags set on this wallet. */
std::atomic<uint64_t> m_wallet_flags{0};
@@ -508,7 +508,7 @@ public:
//! @return true if wtx is changed and needs to be saved to disk, otherwise false
using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
- CWalletTx* AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
+ CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
void blockConnected(const CBlock& block, int height) override;
@@ -555,6 +555,8 @@ public:
* @param[in] sighash_type the sighash type to use when signing (if PSBT does not specify)
* @param[in] sign whether to sign or not
* @param[in] bip32derivs whether to fill in bip32 derivation information if available
+ * @param[out] n_signed the number of inputs signed by this wallet
+ * @param[in] finalize whether to create the final scriptSig or scriptWitness if possible
* return error
*/
TransactionError FillPSBT(PartiallySignedTransaction& psbtx,
@@ -562,7 +564,8 @@ public:
int sighash_type = 1 /* SIGHASH_ALL */,
bool sign = true,
bool bip32derivs = true,
- size_t* n_signed = nullptr) const;
+ size_t* n_signed = nullptr,
+ bool finalize = true) const;
/**
* Submit the transaction to the node's mempool and then relay to peers.
@@ -576,7 +579,7 @@ public:
void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
/** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */
- bool SubmitTxMemoryPoolAndRelay(const CWalletTx& wtx, std::string& err_string, bool relay) const;
+ bool SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const;
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, const CCoinControl* coin_control = nullptr) const
{
@@ -632,7 +635,7 @@ public:
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0);
- int64_t GetOldestKeyPoolTime() const;
+ std::optional<int64_t> GetOldestKeyPoolTime() const;
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index c920d4af51..f392649bd9 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -987,7 +987,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWal
uint256 hash;
ssKey >> hash;
vTxHash.push_back(hash);
- vWtx.emplace_back(nullptr /* tx */);
+ vWtx.emplace_back(/*tx=*/nullptr, TxStateInactive{});
ssValue >> vWtx.back();
}
}
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index b609ba6881..d6717ebbca 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -26,7 +26,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag
{
LOCK(wallet_instance->cs_wallet);
- wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
+ wallet_instance->SetMinVersion(FEATURE_LATEST);
wallet_instance->AddWalletFlags(wallet_creation_flags);
if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
diff --git a/src/warnings.h b/src/warnings.h
index c38edb4570..7ab0a93e3f 100644
--- a/src/warnings.h
+++ b/src/warnings.h
@@ -20,4 +20,4 @@ void SetfLargeWorkInvalidChainFound(bool flag);
*/
bilingual_str GetWarnings(bool verbose);
-#endif // BITCOIN_WARNINGS_H
+#endif // BITCOIN_WARNINGS_H
diff --git a/src/zmq/zmqrpc.h b/src/zmq/zmqrpc.h
index 5a810a16fb..8538adf9d3 100644
--- a/src/zmq/zmqrpc.h
+++ b/src/zmq/zmqrpc.h
@@ -9,4 +9,4 @@ class CRPCTable;
void RegisterZMQRPCCommands(CRPCTable& t);
-#endif // BITCOIN_ZMQ_ZMRRPC_H
+#endif // BITCOIN_ZMQ_ZMQRPC_H
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index 71dfb4c01a..33c81bde13 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Combine logs from multiple bitcoin nodes as well as the test_framework log.
diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py
index cde0399d8b..33d6282961 100644
--- a/test/functional/data/invalid_txs.py
+++ b/test/functional/data/invalid_txs.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index 2473edcfe9..2ad96da854 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""An example functional test
diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py
index bb67dc88a6..32cf4a47f4 100755
--- a/test/functional/feature_abortnode.py
+++ b/test/functional/feature_abortnode.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test bitcoind aborts if can't disconnect a block.
diff --git a/test/functional/feature_anchors.py b/test/functional/feature_anchors.py
index 7be393a4ea..713c0826d3 100755
--- a/test/functional/feature_anchors.py
+++ b/test/functional/feature_anchors.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test block-relay-only anchors functionality"""
@@ -8,18 +8,12 @@ import os
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
+from test_framework.util import check_node_connections
INBOUND_CONNECTIONS = 5
BLOCK_RELAY_CONNECTIONS = 2
-def check_node_connections(*, node, num_in, num_out):
- info = node.getnetworkinfo()
- assert_equal(info["connections_in"], num_in)
- assert_equal(info["connections_out"], num_out)
-
-
class AnchorsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
diff --git a/test/functional/feature_asmap.py b/test/functional/feature_asmap.py
index 02c000eb95..9440ba11f5 100755
--- a/test/functional/feature_asmap.py
+++ b/test/functional/feature_asmap.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test asmap config argument for ASN-based IP bucketing.
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 66092de317..67cacaa9ce 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test logic for skipping signature validation on old blocks.
@@ -122,10 +122,8 @@ class AssumeValidTest(BitcoinTestFramework):
tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE])))
tx.calc_sha256()
- block102 = create_block(self.tip, create_coinbase(height), self.block_time)
+ block102 = create_block(self.tip, create_coinbase(height), self.block_time, txlist=[tx])
self.block_time += 1
- block102.vtx.extend([tx])
- block102.hashMerkleRoot = block102.calc_merkle_root()
block102.solve()
self.blocks.append(block102)
self.tip = block102.sha256
@@ -135,7 +133,6 @@ class AssumeValidTest(BitcoinTestFramework):
# Bury the assumed valid block 2100 deep
for _ in range(2100):
block = create_block(self.tip, create_coinbase(height), self.block_time)
- block.nVersion = 4
block.solve()
self.blocks.append(block)
self.tip = block.sha256
diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py
index e65525a023..476a6a0c14 100755
--- a/test/functional/feature_backwards_compatibility.py
+++ b/test/functional/feature_backwards_compatibility.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Backwards compatibility functional test
@@ -66,8 +66,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
def run_test(self):
self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, self.nodes[0].getnewaddress())
- self.sync_blocks()
-
# Sanity check the test framework:
res = self.nodes[self.num_nodes - 1].getblockchaininfo()
assert_equal(res['blocks'], COINBASE_MATURITY + 1)
@@ -93,7 +91,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(address, 10)
self.sync_mempools()
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# Create a conflicting transaction using RBF
return_address = self.nodes[0].getnewaddress()
tx1_id = self.nodes[1].sendtoaddress(return_address, 1)
@@ -101,7 +98,6 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
# Confirm the transaction
self.sync_mempools()
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# Create another conflicting transaction using RBF
tx3_id = self.nodes[1].sendtoaddress(return_address, 1)
tx4_id = self.nodes[1].bumpfee(tx3_id)["txid"]
diff --git a/test/functional/feature_bind_extra.py b/test/functional/feature_bind_extra.py
index 6802da8d48..af26f94033 100755
--- a/test/functional/feature_bind_extra.py
+++ b/test/functional/feature_bind_extra.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2021 The Bitcoin Core developers
+# Copyright (c) 2014-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 0c29a782b1..05d274a9fe 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP68 implementation."""
@@ -388,9 +388,7 @@ class BIP68Test(BitcoinTestFramework):
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, tx3.serialize().hex())
# make a block that violates bip68; ensure that the tip updates
- block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS))
- block.vtx.extend([tx1, tx2, tx3])
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[tx1, tx2, tx3])
add_witness_commitment(block)
block.solve()
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 7831984b81..a3253763bd 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test block processing."""
@@ -1361,11 +1361,10 @@ class FullBlockTest(BitcoinTestFramework):
else:
coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees
coinbase.rehash()
- block = create_block(base_block_hash, coinbase, block_time, version=version)
tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi
self.sign_tx(tx, spend)
- self.add_transactions_to_block(block, [tx])
- block.hashMerkleRoot = block.calc_merkle_root()
+ tx.rehash()
+ block = create_block(base_block_hash, coinbase, block_time, version=version, txlist=[tx])
# Block is created. Find a valid nonce.
block.solve()
self.tip = block
diff --git a/test/functional/feature_blockfilterindex_prune.py b/test/functional/feature_blockfilterindex_prune.py
index b740f2cc27..39eb700b4f 100755
--- a/test/functional/feature_blockfilterindex_prune.py
+++ b/test/functional/feature_blockfilterindex_prune.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test blockfilterindex in conjunction with prune."""
@@ -26,9 +26,7 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework):
assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0)
# Mine two batches of blocks to avoid hitting NODE_NETWORK_LIMITED_MIN_BLOCKS disconnection
self.generate(self.nodes[0], 250)
- self.sync_all()
self.generate(self.nodes[0], 250)
- self.sync_all()
self.sync_index(height=700)
self.log.info("prune some blocks")
diff --git a/test/functional/feature_blocksdir.py b/test/functional/feature_blocksdir.py
index 28e6d6cdf9..e8d2ec3676 100755
--- a/test/functional/feature_blocksdir.py
+++ b/test/functional/feature_blocksdir.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the blocksdir option.
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 3dc858f5d2..eb90b2c598 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP65 (CHECKLOCKTIMEVERIFY).
@@ -120,10 +120,7 @@ class BIP65Test(BitcoinTestFramework):
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
- block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time)
- block.nVersion = 3
- block.vtx.extend(invalid_cltv_txs)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time, version=3, txlist=invalid_cltv_txs)
block.solve()
self.test_cltv_info(is_active=False) # Not active as of current tip and next block does not need to obey rules
@@ -134,8 +131,7 @@ class BIP65Test(BitcoinTestFramework):
self.log.info("Test that blocks must now be at least version 4")
tip = block.sha256
block_time += 1
- block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
- block.nVersion = 3
+ block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time, version=3)
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=[f'{block.hash}, bad-version(0x00000003)']):
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index b996b16b9c..19bb908b64 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test coinstatsindex across nodes.
@@ -72,8 +72,6 @@ class CoinStatsIndexTest(BitcoinTestFramework):
node.sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
self.generate(node, 1)
- self.sync_blocks(timeout=120)
-
self.log.info("Test that gettxoutsetinfo() output is consistent with or without coinstatsindex option")
res0 = node.gettxoutsetinfo('none')
@@ -170,7 +168,6 @@ class CoinStatsIndexTest(BitcoinTestFramework):
# Include both txs in a block
self.generate(self.nodes[0], 1)
- self.sync_all()
for hash_option in index_hash_options:
# Check all amounts were registered correctly
@@ -271,7 +268,6 @@ class CoinStatsIndexTest(BitcoinTestFramework):
# Add another block, so we don't depend on reconsiderblock remembering which
# blocks were touched by invalidateblock
self.generate(index_node, 1)
- self.sync_all()
# Ensure that removing and re-adding blocks yields consistent results
block = index_node.getblockhash(99)
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 3d9d8b7441..eea5fa24ee 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test various command line arguments and configuration file parameters."""
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index c4e2252487..c200445e81 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test CSV soft fork activation.
@@ -173,10 +173,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
return test_blocks
def create_test_block(self, txs):
- block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600)
- block.nVersion = 4
- block.vtx.extend(txs)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600, txlist=txs)
block.solve()
return block
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 1bda4a29b5..3e60efbb3c 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test recovery from a crash during chainstate writing.
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index eba3809d24..b7cb32c842 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test BIP66 (DER SIG).
@@ -85,9 +85,7 @@ class BIP66Test(BitcoinTestFramework):
tip = self.nodes[0].getbestblockhash()
block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1
- block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time)
- block.vtx.append(spendtx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time, txlist=[spendtx])
block.solve()
assert_equal(self.nodes[0].getblockcount(), DERSIG_HEIGHT - 2)
@@ -100,8 +98,7 @@ class BIP66Test(BitcoinTestFramework):
self.log.info("Test that blocks must now be at least version 3")
tip = block.sha256
block_time += 1
- block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time)
- block.nVersion = 2
+ block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time, version=2)
block.solve()
with self.nodes[0].assert_debug_log(expected_msgs=[f'{block.hash}, bad-version(0x00000002)']):
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 2a8dd1fb7b..46d5bcf1a6 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test fee estimation code."""
@@ -218,7 +218,6 @@ class EstimateFeeTest(BitcoinTestFramework):
self.fees_per_kb.append(float(fee) / tx_kbytes)
self.sync_mempools(wait=.1)
mined = mining_node.getblock(self.generate(mining_node, 1)[0], True)["tx"]
- self.sync_blocks(wait=.1)
# update which txouts are confirmed
newmem = []
for utx in self.memutxo:
@@ -278,8 +277,6 @@ class EstimateFeeTest(BitcoinTestFramework):
# Finish by mining a normal-sized block:
while len(self.nodes[1].getrawmempool()) > 0:
self.generate(self.nodes[1], 1)
-
- self.sync_blocks(self.nodes[0:3], wait=.1)
self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb)
@@ -322,7 +319,6 @@ class EstimateFeeTest(BitcoinTestFramework):
for txid in txids_to_replace:
miner.prioritisetransaction(txid=txid, fee_delta=-COIN)
self.generate(miner, 1)
- self.sync_blocks(wait=.1, nodes=[node, miner])
# RBF the low-fee transactions
while True:
try:
@@ -334,7 +330,6 @@ class EstimateFeeTest(BitcoinTestFramework):
# Mine the last replacement txs
self.sync_mempools(wait=.1, nodes=[node, miner])
self.generate(miner, 1)
- self.sync_blocks(wait=.1, nodes=[node, miner])
# Only 10% of the transactions were really confirmed with a low feerate,
# the rest needed to be RBF'd. We must return the 90% conf rate feerate.
diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py
index 0fc654e10a..945ece6a33 100755
--- a/test/functional/feature_filelock.py
+++ b/test/functional/feature_filelock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Check that it's not possible to start a second bitcoind instance using the same datadir or wallet."""
diff --git a/test/functional/feature_help.py b/test/functional/feature_help.py
index 837e95c128..4b66030b47 100755
--- a/test/functional/feature_help.py
+++ b/test/functional/feature_help.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Verify that starting bitcoin with -h works as expected."""
diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py
index 448182eded..818e4c923b 100755
--- a/test/functional/feature_includeconf.py
+++ b/test/functional/feature_includeconf.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests the includeconf argument
diff --git a/test/functional/feature_loadblock.py b/test/functional/feature_loadblock.py
index 079630546e..7f030c6773 100755
--- a/test/functional/feature_loadblock.py
+++ b/test/functional/feature_loadblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test loadblock option
diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py
index 722219518a..fe4f02dfe6 100755
--- a/test/functional/feature_logging.py
+++ b/test/functional/feature_logging.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test debug logging."""
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index ac4d40638e..b4e0df8a11 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test behavior of -maxuploadtarget.
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py
index a77f022ddd..489a729cfc 100755
--- a/test/functional/feature_minchainwork.py
+++ b/test/functional/feature_minchainwork.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test logic for setting nMinimumChainWork on command line.
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 612b724fa5..e038afa1ad 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the -alertnotify, -blocknotify and -walletnotify options."""
@@ -112,7 +112,6 @@ class NotificationsTest(BitcoinTestFramework):
self.log.info("test -walletnotify with conflicting transactions")
self.nodes[0].rescanblockchain()
self.generatetoaddress(self.nodes[0], 100, ADDRESS_BCRT1_UNSPENDABLE)
- self.sync_blocks()
# Generate transaction on node 0, sync mempools, and check for
# notification on node 1.
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 04c4e7e50c..7a84098a83 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test NULLDUMMY softfork.
@@ -22,7 +22,10 @@ from test_framework.blocktools import (
create_transaction,
)
from test_framework.messages import CTransaction
-from test_framework.script import CScript
+from test_framework.script import (
+ OP_0,
+ OP_TRUE,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -32,16 +35,11 @@ from test_framework.util import (
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
-def trueDummy(tx):
- scriptSig = CScript(tx.vin[0].scriptSig)
- newscript = []
- for i in scriptSig:
- if len(newscript) == 0:
- assert len(i) == 0
- newscript.append(b'\x51')
- else:
- newscript.append(i)
- tx.vin[0].scriptSig = CScript(newscript)
+def invalidate_nulldummy_tx(tx):
+ """Transform a NULLDUMMY compliant tx (i.e. scriptSig starts with OP_0)
+ to be non-NULLDUMMY compliant by replacing the dummy with OP_TRUE"""
+ assert_equal(tx.vin[0].scriptSig[0], OP_0)
+ tx.vin[0].scriptSig = bytes([OP_TRUE]) + tx.vin[0].scriptSig[1:]
tx.rehash()
@@ -94,7 +92,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
test2tx = create_transaction(self.nodes[0], txid2, self.ms_address, amount=47)
- trueDummy(test2tx)
+ invalidate_nulldummy_tx(test2tx)
assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test2tx.serialize_with_witness().hex(), 0)
self.log.info(f"Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [{COINBASE_MATURITY + 4}]")
@@ -103,7 +101,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
test4tx = create_transaction(self.nodes[0], test2tx.hash, self.address, amount=46)
test6txs = [CTransaction(test4tx)]
- trueDummy(test4tx)
+ invalidate_nulldummy_tx(test4tx)
assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test4tx.serialize_with_witness().hex(), 0)
self.block_submit(self.nodes[0], [test4tx], accept=False)
@@ -123,11 +121,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
assert_equal(tmpl['previousblockhash'], self.lastblockhash)
assert_equal(tmpl['height'], self.lastblockheight + 1)
- block = create_block(tmpl=tmpl, ntime=self.lastblocktime + 1)
- for tx in txs:
- tx.rehash()
- block.vtx.append(tx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(tmpl=tmpl, ntime=self.lastblocktime + 1, txlist=txs)
if with_witness:
add_witness_commitment(block)
block.solve()
diff --git a/test/functional/feature_presegwit_node_upgrade.py b/test/functional/feature_presegwit_node_upgrade.py
index aac42d4dbf..3d762c8197 100755
--- a/test/functional/feature_presegwit_node_upgrade.py
+++ b/test/functional/feature_presegwit_node_upgrade.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test a pre-segwit node upgrading to segwit consensus"""
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 70b9e019c1..7d9e5b70fc 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test bitcoind with different proxy configuration.
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 125b219bd4..0edf1d66c8 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the pruning code.
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 39859d0151..e540cc1574 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the RBF code."""
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index f0435b21b2..44040f426f 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test running bitcoind with -reindex and -reindex-chainstate options.
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index acb7469c6a..6d7f1def88 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the SegWit changeover logic."""
@@ -191,7 +191,6 @@ class SegWitTest(BitcoinTestFramework):
p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999")))
self.generate(self.nodes[0], 1) # block 163
- self.sync_blocks()
# Make sure all nodes recognize the transactions as theirs
assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
@@ -199,7 +198,6 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))
self.generate(self.nodes[0], 260) # block 423
- self.sync_blocks()
self.log.info("Verify witness txs are skipped for mining before the fork")
self.skip_mine(self.nodes[2], wit_ids[NODE_2][P2WPKH][0], True) # block 424
@@ -216,7 +214,6 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify previous witness txs skipped for mining can now be mined")
assert_equal(len(self.nodes[2].getrawmempool()), 4)
blockhash = self.generate(self.nodes[2], 1)[0] # block 432 (first block with new rules; 432 = 144 * 3)
- self.sync_blocks()
assert_equal(len(self.nodes[2].getrawmempool()), 0)
segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"]
assert_equal(len(segwit_tx_list), 5)
@@ -630,7 +627,6 @@ class SegWitTest(BitcoinTestFramework):
signresults = self.nodes[0].signrawtransactionwithwallet(tx.serialize_without_witness().hex())['hex']
txid = self.nodes[0].sendrawtransaction(hexstring=signresults, maxfeerate=0)
txs_mined[txid] = self.generate(self.nodes[0], 1)[0]
- self.sync_blocks()
watchcount = 0
spendcount = 0
for i in self.nodes[0].listunspent():
@@ -680,7 +676,6 @@ class SegWitTest(BitcoinTestFramework):
signresults = self.nodes[0].signrawtransactionwithwallet(tx.serialize_without_witness().hex())['hex']
self.nodes[0].sendrawtransaction(hexstring=signresults, maxfeerate=0)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
if __name__ == '__main__':
diff --git a/test/functional/feature_settings.py b/test/functional/feature_settings.py
index 26048d37f6..20018f010f 100755
--- a/test/functional/feature_settings.py
+++ b/test/functional/feature_settings.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test various command line arguments and configuration file parameters."""
diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py
index 268da62faf..6578caee3f 100755
--- a/test/functional/feature_signet.py
+++ b/test/functional/feature_signet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test basic signet functionality"""
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 5f90e49de1..e9da6edaf6 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# Test Taproot softfork (BIPs 340-342)
@@ -22,11 +22,17 @@ from test_framework.messages import (
)
from test_framework.script import (
ANNEX_TAG,
+ BIP341_sha_amounts,
+ BIP341_sha_outputs,
+ BIP341_sha_prevouts,
+ BIP341_sha_scriptpubkeys,
+ BIP341_sha_sequences,
CScript,
CScriptNum,
CScriptOp,
+ hash256,
LEAF_VERSION_TAPSCRIPT,
- LegacySignatureHash,
+ LegacySignatureMsg,
LOCKTIME_THRESHOLD,
MAX_SCRIPT_ELEMENT_SIZE,
OP_0,
@@ -70,13 +76,15 @@ from test_framework.script import (
SIGHASH_NONE,
SIGHASH_SINGLE,
SIGHASH_ANYONECANPAY,
- SegwitV0SignatureHash,
- TaprootSignatureHash,
+ SegwitV0SignatureMsg,
+ TaggedHash,
+ TaprootSignatureMsg,
is_op_success,
taproot_construct,
)
from test_framework.script_util import (
key_to_p2pk_script,
+ key_to_p2pkh_script,
key_to_p2wpkh_script,
keyhash_to_p2pkh_script,
script_to_p2sh_script,
@@ -87,14 +95,19 @@ from test_framework.util import assert_raises_rpc_error, assert_equal
from test_framework.key import generate_privkey, compute_xonly_pubkey, sign_schnorr, tweak_add_privkey, ECKey
from test_framework.address import (
hash160,
+ program_to_witness
)
from collections import OrderedDict, namedtuple
+from enum import Enum
from io import BytesIO
import json
import hashlib
import os
import random
+# Whether or not to output generated test vectors, in JSON format.
+GEN_TEST_VECTORS = False
+
# === Framework for building spending transactions. ===
#
# The computation is represented as a "context" dict, whose entries store potentially-unevaluated expressions that
@@ -194,8 +207,8 @@ def default_controlblock(ctx):
"""Default expression for "controlblock": combine leafversion, negflag, pubkey_internal, merklebranch."""
return bytes([get(ctx, "leafversion") + get(ctx, "negflag")]) + get(ctx, "pubkey_internal") + get(ctx, "merklebranch")
-def default_sighash(ctx):
- """Default expression for "sighash": depending on mode, compute BIP341, BIP143, or legacy sighash."""
+def default_sigmsg(ctx):
+ """Default expression for "sigmsg": depending on mode, compute BIP341, BIP143, or legacy sigmsg."""
tx = get(ctx, "tx")
idx = get(ctx, "idx")
hashtype = get(ctx, "hashtype_actual")
@@ -208,18 +221,30 @@ def default_sighash(ctx):
codeseppos = get(ctx, "codeseppos")
leaf_ver = get(ctx, "leafversion")
script = get(ctx, "script_taproot")
- return TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex)
+ return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex)
else:
- return TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=False, annex=annex)
+ return TaprootSignatureMsg(tx, utxos, hashtype, idx, scriptpath=False, annex=annex)
elif mode == "witv0":
# BIP143 signature hash
scriptcode = get(ctx, "scriptcode")
utxos = get(ctx, "utxos")
- return SegwitV0SignatureHash(scriptcode, tx, idx, hashtype, utxos[idx].nValue)
+ return SegwitV0SignatureMsg(scriptcode, tx, idx, hashtype, utxos[idx].nValue)
else:
# Pre-segwit signature hash
scriptcode = get(ctx, "scriptcode")
- return LegacySignatureHash(scriptcode, tx, idx, hashtype)[0]
+ return LegacySignatureMsg(scriptcode, tx, idx, hashtype)[0]
+
+def default_sighash(ctx):
+ """Default expression for "sighash": depending on mode, compute tagged hash or dsha256 of sigmsg."""
+ msg = get(ctx, "sigmsg")
+ mode = get(ctx, "mode")
+ if mode == "taproot":
+ return TaggedHash("TapSighash", msg)
+ else:
+ if msg is None:
+ return (1).to_bytes(32, 'little')
+ else:
+ return hash256(msg)
def default_tweak(ctx):
"""Default expression for "tweak": None if a leaf is specified, tap[0] otherwise."""
@@ -239,14 +264,18 @@ def default_key_tweaked(ctx):
def default_signature(ctx):
"""Default expression for "signature": BIP340 signature or ECDSA signature depending on mode."""
sighash = get(ctx, "sighash")
+ deterministic = get(ctx, "deterministic")
if get(ctx, "mode") == "taproot":
key = get(ctx, "key_tweaked")
flip_r = get(ctx, "flag_flip_r")
flip_p = get(ctx, "flag_flip_p")
- return sign_schnorr(key, sighash, flip_r=flip_r, flip_p=flip_p)
+ aux = bytes([0] * 32)
+ if not deterministic:
+ aux = random.getrandbits(256).to_bytes(32, 'big')
+ return sign_schnorr(key, sighash, flip_r=flip_r, flip_p=flip_p, aux=aux)
else:
key = get(ctx, "key")
- return key.sign_ecdsa(sighash)
+ return key.sign_ecdsa(sighash, rfc6979=deterministic)
def default_hashtype_actual(ctx):
"""Default expression for "hashtype_actual": hashtype, unless mismatching SIGHASH_SINGLE in taproot."""
@@ -340,6 +369,8 @@ DEFAULT_CONTEXT = {
"key_tweaked": default_key_tweaked,
# The tweak to use (None for script path spends, the actual tweak for key path spends).
"tweak": default_tweak,
+ # The sigmsg value (preimage of sighash)
+ "sigmsg": default_sigmsg,
# The sighash value (32 bytes)
"sighash": default_sighash,
# The information about the chosen script path spend (TaprootLeafInfo object).
@@ -376,6 +407,8 @@ DEFAULT_CONTEXT = {
"leaf": None,
# The input arguments to provide to the executed script
"inputs": [],
+ # Use deterministic signing nonces
+ "deterministic": False,
# == Parameters to be set before evaluation: ==
# - mode: what spending style to use ("taproot", "witv0", or "legacy").
@@ -396,6 +429,7 @@ def flatten(lst):
ret.append(elem)
return ret
+
def spend(tx, idx, utxos, **kwargs):
"""Sign transaction input idx of tx, provided utxos is the list of outputs being spent.
@@ -423,7 +457,7 @@ def spend(tx, idx, utxos, **kwargs):
# Each spender is a tuple of:
# - A scriptPubKey which is to be spent from (CScript)
# - A comment describing the test (string)
-# - Whether the spending (on itself) is expected to be standard (bool)
+# - Whether the spending (on itself) is expected to be standard (Enum.Standard)
# - A tx-signing lambda returning (scriptsig, witness_stack), taking as inputs:
# - A transaction to sign (CTransaction)
# - An input position (int)
@@ -435,8 +469,14 @@ def spend(tx, idx, utxos, **kwargs):
# - Whether this test demands being placed in a txin with no corresponding txout (for testing SIGHASH_SINGLE behavior)
Spender = namedtuple("Spender", "script,comment,is_standard,sat_function,err_msg,sigops_weight,no_fail,need_vin_vout_mismatch")
+# The full node versions that treat the tx standard.
+# ALL means any version
+# V23 means the major version 23.0 and any later version
+# NONE means no version
+Standard = Enum('Standard', 'ALL V23 NONE')
-def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=False, spk_mutate_pre_p2sh=None, failure=None, standard=True, err_msg=None, sigops_weight=0, need_vin_vout_mismatch=False, **kwargs):
+
+def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=False, spk_mutate_pre_p2sh=None, failure=None, standard=Standard.ALL, err_msg=None, sigops_weight=0, need_vin_vout_mismatch=False, **kwargs):
"""Helper for constructing Spender objects using the context signing framework.
* tap: a TaprootInfo object (see taproot_construct), for Taproot spends (cannot be combined with pkh, witv0, or script)
@@ -446,13 +486,18 @@ def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=
* p2sh: whether the output is P2SH wrapper (this is supported even for Taproot, where it makes the output unencumbered)
* spk_mutate_pre_psh: a callable to be applied to the script (before potentially P2SH-wrapping it)
* failure: a dict of entries to override in the context when intentionally failing to spend (if None, no_fail will be set)
- * standard: whether the (valid version of) spending is expected to be standard
+ * standard: whether the (valid version of) spending is expected to be standard (True is mapped to Standard.ALL, False is mapped to Standard.NONE)
* err_msg: a string with an expected error message for failure (or None, if not cared about)
* sigops_weight: the pre-taproot sigops weight consumed by a successful spend
* need_vin_vout_mismatch: whether this test requires being tested in a transaction input that has no corresponding
transaction output.
"""
+ if standard == True:
+ standard = Standard.ALL
+ elif standard == False:
+ standard = Standard.NONE
+
conf = dict()
# Compute scriptPubKey and set useful defaults based on the inputs.
@@ -1137,12 +1182,12 @@ def spenders_taproot_inactive():
tap = taproot_construct(pub, scripts)
# Test that keypath spending is valid & non-standard, regardless of validity.
- add_spender(spenders, "inactive/keypath_valid", key=sec, tap=tap, standard=False)
+ add_spender(spenders, "inactive/keypath_valid", key=sec, tap=tap, standard=Standard.V23)
add_spender(spenders, "inactive/keypath_invalidsig", key=sec, tap=tap, standard=False, sighash=bitflipper(default_sighash))
add_spender(spenders, "inactive/keypath_empty", key=sec, tap=tap, standard=False, witness=[])
# Same for scriptpath spending (and features like annex, leaf versions, or OP_SUCCESS don't change this)
- add_spender(spenders, "inactive/scriptpath_valid", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")])
+ add_spender(spenders, "inactive/scriptpath_valid", key=sec, tap=tap, leaf="pk", standard=Standard.V23, inputs=[getter("sign")])
add_spender(spenders, "inactive/scriptpath_invalidsig", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")], sighash=bitflipper(default_sighash))
add_spender(spenders, "inactive/scriptpath_invalidcb", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")], controlblock=bitflipper(default_controlblock))
add_spender(spenders, "inactive/scriptpath_valid_unkleaf", key=sec, tap=tap, leaf="future_leaf", standard=False, inputs=[getter("sign")])
@@ -1172,7 +1217,7 @@ def dump_json_test(tx, input_utxos, idx, success, failure):
# The "final" field indicates that a spend should be always valid, even with more validation flags enabled
# than the listed ones. Use standardness as a proxy for this (which gives a conservative underestimate).
- if spender.is_standard:
+ if spender.is_standard == Standard.ALL:
fields.append(("final", True))
def dump_witness(wit):
@@ -1233,12 +1278,8 @@ class TaprootTest(BitcoinTestFramework):
# transactions.
extra_output_script = CScript([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR))
- block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees), self.lastblocktime + 1)
- block.nVersion = 4
- for tx in txs:
- tx.rehash()
- block.vtx.append(tx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ coinbase_tx = create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees)
+ block = create_block(self.tip, coinbase_tx, self.lastblocktime + 1, txlist=txs)
witness and add_witness_commitment(block)
block.solve()
block_response = node.submitblock(block.serialize().hex())
@@ -1253,6 +1294,14 @@ class TaprootTest(BitcoinTestFramework):
else:
assert node.getbestblockhash() == self.lastblockhash, "Failed to reject: " + msg
+ def init_blockinfo(self, node):
+ # Initialize variables used by block_submit().
+ self.lastblockhash = node.getbestblockhash()
+ self.tip = int(self.lastblockhash, 16)
+ block = node.getblock(self.lastblockhash)
+ self.lastblockheight = block['height']
+ self.lastblocktime = block['time']
+
def test_spenders(self, node, spenders, input_counts):
"""Run randomized tests with a number of "spenders".
@@ -1279,12 +1328,7 @@ class TaprootTest(BitcoinTestFramework):
host_spks.append(spk)
host_pubkeys.append(bytes.fromhex(info['pubkey']))
- # Initialize variables used by block_submit().
- self.lastblockhash = node.getbestblockhash()
- self.tip = int(self.lastblockhash, 16)
- block = node.getblock(self.lastblockhash)
- self.lastblockheight = block['height']
- self.lastblocktime = block['time']
+ self.init_blockinfo(node)
# Create transactions spending up to 50 of the wallet's inputs, with one output for each spender, and
# one change output at the end. The transaction is constructed on the Python side to enable
@@ -1438,8 +1482,13 @@ class TaprootTest(BitcoinTestFramework):
for i in range(len(input_utxos)):
tx.vin[i].scriptSig = input_data[i][i != fail_input][0]
tx.wit.vtxinwit[i].scriptWitness.stack = input_data[i][i != fail_input][1]
+ taproot_spend_policy = Standard.V23 if node.version is None else Standard.ALL
# Submit to mempool to check standardness
- is_standard_tx = fail_input is None and all(utxo.spender.is_standard for utxo in input_utxos) and tx.nVersion >= 1 and tx.nVersion <= 2
+ is_standard_tx = (
+ fail_input is None # Must be valid to be standard
+ and (all(utxo.spender.is_standard == Standard.ALL or utxo.spender.is_standard == taproot_spend_policy for utxo in input_utxos)) # All inputs must be standard
+ and tx.nVersion >= 1 # The tx version must be standard
+ and tx.nVersion <= 2)
tx.rehash()
msg = ','.join(utxo.spender.comment + ("*" if n == fail_input else "") for n, utxo in enumerate(input_utxos))
if is_standard_tx:
@@ -1458,10 +1507,239 @@ class TaprootTest(BitcoinTestFramework):
assert len(mismatching_utxos) == 0
self.log.info(" - Done")
+ def gen_test_vectors(self):
+ """Run a scenario that corresponds (and optionally produces) to BIP341 test vectors."""
+
+ self.log.info("Unit test scenario...")
+
+ # Deterministically mine coins to OP_TRUE in block 1
+ assert self.nodes[1].getblockcount() == 0
+ coinbase = CTransaction()
+ coinbase.nVersion = 1
+ coinbase.vin = [CTxIn(COutPoint(0, 0xffffffff), CScript([OP_1, OP_1]), 0xffffffff)]
+ coinbase.vout = [CTxOut(5000000000, CScript([OP_1]))]
+ coinbase.nLockTime = 0
+ coinbase.rehash()
+ assert coinbase.hash == "f60c73405d499a956d3162e3483c395526ef78286458a4cb17b125aa92e49b20"
+ # Mine it
+ block = create_block(hashprev=int(self.nodes[1].getbestblockhash(), 16), coinbase=coinbase)
+ block.rehash()
+ block.solve()
+ self.nodes[1].submitblock(block.serialize().hex())
+ assert self.nodes[1].getblockcount() == 1
+ self.generate(self.nodes[1], COINBASE_MATURITY)
+
+ SEED = 317
+ VALID_LEAF_VERS = list(range(0xc0, 0x100, 2)) + [0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba, 0xbc, 0xbe]
+ # Generate private keys
+ prvs = [hashlib.sha256(SEED.to_bytes(2, 'big') + bytes([i])).digest() for i in range(100)]
+ # Generate corresponding public x-only pubkeys
+ pubs = [compute_xonly_pubkey(prv)[0] for prv in prvs]
+ # Generate taproot objects
+ inner_keys = [pubs[i] for i in range(7)]
+
+ script_lists = [
+ None,
+ [("0", CScript([pubs[50], OP_CHECKSIG]), 0xc0)],
+ [("0", CScript([pubs[51], OP_CHECKSIG]), 0xc0)],
+ [("0", CScript([pubs[52], OP_CHECKSIG]), 0xc0), ("1", CScript([b"BIP341"]), VALID_LEAF_VERS[pubs[99][0] % 41])],
+ [("0", CScript([pubs[53], OP_CHECKSIG]), 0xc0), ("1", CScript([b"Taproot"]), VALID_LEAF_VERS[pubs[99][1] % 41])],
+ [("0", CScript([pubs[54], OP_CHECKSIG]), 0xc0), [("1", CScript([pubs[55], OP_CHECKSIG]), 0xc0), ("2", CScript([pubs[56], OP_CHECKSIG]), 0xc0)]],
+ [("0", CScript([pubs[57], OP_CHECKSIG]), 0xc0), [("1", CScript([pubs[58], OP_CHECKSIG]), 0xc0), ("2", CScript([pubs[59], OP_CHECKSIG]), 0xc0)]],
+ ]
+ taps = [taproot_construct(inner_keys[i], script_lists[i]) for i in range(len(inner_keys))]
+
+ # Require negated taps[0]
+ assert taps[0].negflag
+ # Require one negated and one non-negated in taps 1 and 2.
+ assert taps[1].negflag != taps[2].negflag
+ # Require one negated and one non-negated in taps 3 and 4.
+ assert taps[3].negflag != taps[4].negflag
+ # Require one negated and one non-negated in taps 5 and 6.
+ assert taps[5].negflag != taps[6].negflag
+
+ cblks = [{leaf: get({**DEFAULT_CONTEXT, 'tap': taps[i], 'leaf': leaf}, 'controlblock') for leaf in taps[i].leaves} for i in range(7)]
+ # Require one swapped and one unswapped in taps 3 and 4.
+ assert (cblks[3]['0'][33:65] < cblks[3]['1'][33:65]) != (cblks[4]['0'][33:65] < cblks[4]['1'][33:65])
+ # Require one swapped and one unswapped in taps 5 and 6, both at the top and child level.
+ assert (cblks[5]['0'][33:65] < cblks[5]['1'][65:]) != (cblks[6]['0'][33:65] < cblks[6]['1'][65:])
+ assert (cblks[5]['1'][33:65] < cblks[5]['2'][33:65]) != (cblks[6]['1'][33:65] < cblks[6]['2'][33:65])
+ # Require within taps 5 (and thus also 6) that one level is swapped and the other is not.
+ assert (cblks[5]['0'][33:65] < cblks[5]['1'][65:]) != (cblks[5]['1'][33:65] < cblks[5]['2'][33:65])
+
+ # Compute a deterministic set of scriptPubKeys
+ tap_spks = []
+ old_spks = []
+ spend_info = {}
+ # First, taproot scriptPubKeys, for the tap objects constructed above
+ for i, tap in enumerate(taps):
+ tap_spks.append(tap.scriptPubKey)
+ d = {'key': prvs[i], 'tap': tap, 'mode': 'taproot'}
+ spend_info[tap.scriptPubKey] = d
+ # Then, a number of deterministically generated (keys 0x1,0x2,0x3) with 2x P2PKH, 1x P2WPKH spks.
+ for i in range(1, 4):
+ prv = ECKey()
+ prv.set(i.to_bytes(32, 'big'), True)
+ pub = prv.get_pubkey().get_bytes()
+ d = {"key": prv}
+ d["scriptcode"] = key_to_p2pkh_script(pub)
+ d["inputs"] = [getter("sign"), pub]
+ if i < 3:
+ # P2PKH
+ d['spk'] = key_to_p2pkh_script(pub)
+ d['mode'] = 'legacy'
+ else:
+ # P2WPKH
+ d['spk'] = key_to_p2wpkh_script(pub)
+ d['mode'] = 'witv0'
+ old_spks.append(d['spk'])
+ spend_info[d['spk']] = d
+
+ # Construct a deterministic chain of transactions creating UTXOs to the test's spk's (so that they
+ # come from distinct txids).
+ txn = []
+ lasttxid = coinbase.sha256
+ amount = 5000000000
+ for i, spk in enumerate(old_spks + tap_spks):
+ val = 42000000 * (i + 7)
+ tx = CTransaction()
+ tx.nVersion = 1
+ tx.vin = [CTxIn(COutPoint(lasttxid, i & 1), CScript([]), 0xffffffff)]
+ tx.vout = [CTxOut(val, spk), CTxOut(amount - val, CScript([OP_1]))]
+ if i & 1:
+ tx.vout = list(reversed(tx.vout))
+ tx.nLockTime = 0
+ tx.rehash()
+ amount -= val
+ lasttxid = tx.sha256
+ txn.append(tx)
+ spend_info[spk]['prevout'] = COutPoint(tx.sha256, i & 1)
+ spend_info[spk]['utxo'] = CTxOut(val, spk)
+ # Mine those transactions
+ self.init_blockinfo(self.nodes[1])
+ self.block_submit(self.nodes[1], txn, "Crediting txn", None, sigops_weight=10, accept=True)
+
+ # scriptPubKey computation
+ tests = {"version": 1}
+ spk_tests = tests.setdefault("scriptPubKey", [])
+ for i, tap in enumerate(taps):
+ test_case = {}
+ given = test_case.setdefault("given", {})
+ given['internalPubkey'] = tap.internal_pubkey.hex()
+
+ def pr(node):
+ if node is None:
+ return None
+ elif isinstance(node, tuple):
+ return {"id": int(node[0]), "script": node[1].hex(), "leafVersion": node[2]}
+ elif len(node) == 1:
+ return pr(node[0])
+ elif len(node) == 2:
+ return [pr(node[0]), pr(node[1])]
+ else:
+ assert False
+
+ given['scriptTree'] = pr(script_lists[i])
+ intermediary = test_case.setdefault("intermediary", {})
+ if len(tap.leaves):
+ leafhashes = intermediary.setdefault('leafHashes', [None] * len(tap.leaves))
+ for leaf in tap.leaves:
+ leafhashes[int(leaf)] = tap.leaves[leaf].leaf_hash.hex()
+ intermediary['merkleRoot'] = tap.merkle_root.hex() if tap.merkle_root else None
+ intermediary['tweak'] = tap.tweak.hex()
+ intermediary['tweakedPubkey'] = tap.output_pubkey.hex()
+ expected = test_case.setdefault("expected", {})
+ expected['scriptPubKey'] = tap.scriptPubKey.hex()
+ expected['bip350Address'] = program_to_witness(1, bytes(tap.output_pubkey), True)
+ if len(tap.leaves):
+ control_blocks = expected.setdefault("scriptPathControlBlocks", [None] * len(tap.leaves))
+ for leaf in tap.leaves:
+ ctx = {**DEFAULT_CONTEXT, 'tap': tap, 'leaf': leaf}
+ control_blocks[int(leaf)] = get(ctx, "controlblock").hex()
+ spk_tests.append(test_case)
+
+ # Construct a deterministic transaction spending all outputs created above.
+ tx = CTransaction()
+ tx.nVersion = 2
+ tx.vin = []
+ inputs = []
+ input_spks = [tap_spks[0], tap_spks[1], old_spks[0], tap_spks[2], tap_spks[5], old_spks[2], tap_spks[6], tap_spks[3], tap_spks[4]]
+ sequences = [0, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffffe, 0, 0, 0xffffffff, 0xffffffff]
+ hashtypes = [SIGHASH_SINGLE, SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, SIGHASH_ALL, SIGHASH_ALL, SIGHASH_DEFAULT, SIGHASH_ALL, SIGHASH_NONE, SIGHASH_NONE|SIGHASH_ANYONECANPAY, SIGHASH_ALL|SIGHASH_ANYONECANPAY]
+ for i, spk in enumerate(input_spks):
+ tx.vin.append(CTxIn(spend_info[spk]['prevout'], CScript(), sequences[i]))
+ inputs.append(spend_info[spk]['utxo'])
+ tx.vout.append(CTxOut(1000000000, old_spks[1]))
+ tx.vout.append(CTxOut(3410000000, pubs[98]))
+ tx.nLockTime = 500000000
+ precomputed = {
+ "hashAmounts": BIP341_sha_amounts(inputs),
+ "hashPrevouts": BIP341_sha_prevouts(tx),
+ "hashScriptPubkeys": BIP341_sha_scriptpubkeys(inputs),
+ "hashSequences": BIP341_sha_sequences(tx),
+ "hashOutputs": BIP341_sha_outputs(tx)
+ }
+ keypath_tests = tests.setdefault("keyPathSpending", [])
+ tx_test = {}
+ global_given = tx_test.setdefault("given", {})
+ global_given['rawUnsignedTx'] = tx.serialize().hex()
+ utxos_spent = global_given.setdefault("utxosSpent", [])
+ for i in range(len(input_spks)):
+ utxos_spent.append({"scriptPubKey": inputs[i].scriptPubKey.hex(), "amountSats": inputs[i].nValue})
+ global_intermediary = tx_test.setdefault("intermediary", {})
+ for key in sorted(precomputed.keys()):
+ global_intermediary[key] = precomputed[key].hex()
+ test_list = tx_test.setdefault('inputSpending', [])
+ for i in range(len(input_spks)):
+ ctx = {
+ **DEFAULT_CONTEXT,
+ **spend_info[input_spks[i]],
+ 'tx': tx,
+ 'utxos': inputs,
+ 'idx': i,
+ 'hashtype': hashtypes[i],
+ 'deterministic': True
+ }
+ if ctx['mode'] == 'taproot':
+ test_case = {}
+ given = test_case.setdefault("given", {})
+ given['txinIndex'] = i
+ given['internalPrivkey'] = get(ctx, 'key').hex()
+ if get(ctx, "tap").merkle_root != bytes():
+ given['merkleRoot'] = get(ctx, "tap").merkle_root.hex()
+ else:
+ given['merkleRoot'] = None
+ given['hashType'] = get(ctx, "hashtype")
+ intermediary = test_case.setdefault("intermediary", {})
+ intermediary['internalPubkey'] = get(ctx, "tap").internal_pubkey.hex()
+ intermediary['tweak'] = get(ctx, "tap").tweak.hex()
+ intermediary['tweakedPrivkey'] = get(ctx, "key_tweaked").hex()
+ sigmsg = get(ctx, "sigmsg")
+ intermediary['sigMsg'] = sigmsg.hex()
+ intermediary['precomputedUsed'] = [key for key in sorted(precomputed.keys()) if sigmsg.count(precomputed[key])]
+ intermediary['sigHash'] = get(ctx, "sighash").hex()
+ expected = test_case.setdefault("expected", {})
+ expected['witness'] = [get(ctx, "sign").hex()]
+ test_list.append(test_case)
+ tx.wit.vtxinwit.append(CTxInWitness())
+ tx.vin[i].scriptSig = CScript(flatten(get(ctx, "scriptsig")))
+ tx.wit.vtxinwit[i].scriptWitness.stack = flatten(get(ctx, "witness"))
+ aux = tx_test.setdefault("auxiliary", {})
+ aux['fullySignedTx'] = tx.serialize().hex()
+ keypath_tests.append(tx_test)
+ assert_equal(hashlib.sha256(tx.serialize()).hexdigest(), "24bab662cb55a7f3bae29b559f651674c62bcc1cd442d44715c0133939107b38")
+ # Mine the spending transaction
+ self.block_submit(self.nodes[1], [tx], "Spending txn", None, sigops_weight=10000, accept=True, witness=True)
+
+ if GEN_TEST_VECTORS:
+ print(json.dumps(tests, indent=4, sort_keys=False))
+
+
def run_test(self):
+ self.gen_test_vectors()
+
# Post-taproot activation tests go first (pre-taproot tests' blocks are invalid post-taproot).
self.log.info("Post-activation tests...")
- self.generate(self.nodes[1], COINBASE_MATURITY + 1)
self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3])
# Re-connect nodes in case they have been disconnected
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index d74ef5e088..e83dd7f446 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test version bits warning system.
@@ -48,8 +48,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
tip = int(tip, 16)
for _ in range(numblocks):
- block = create_block(tip, create_coinbase(height + 1), block_time)
- block.nVersion = version
+ block = create_block(tip, create_coinbase(height + 1), block_time, version=version)
block.solve()
peer.send_message(msg_block(block))
block_time += 1
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index ae665958b9..6076dceeaf 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test bitcoin-cli"""
diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py
index 075224c011..6e32009e05 100755
--- a/test/functional/interface_http.py
+++ b/test/functional/interface_http.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the RPC HTTP basics."""
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index 868bb42604..a2f84573da 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the REST API."""
@@ -81,9 +81,7 @@ class RESTTest (BitcoinTestFramework):
not_related_address = "2MxqoHEdNQTyYeX1mHcbrrpzgojbosTpCvJ"
self.generate(self.nodes[0], 1)
- self.sync_all()
self.generatetoaddress(self.nodes[1], 100, not_related_address)
- self.sync_all()
assert_equal(self.nodes[0].getbalance(), 50)
@@ -108,7 +106,6 @@ class RESTTest (BitcoinTestFramework):
self.log.info("Query an unspent TXO using the /getutxos URI")
self.generatetoaddress(self.nodes[1], 1, not_related_address)
- self.sync_all()
bb_hash = self.nodes[0].getbestblockhash()
assert_equal(self.nodes[1].getbalance(), Decimal("0.1"))
@@ -183,7 +180,6 @@ class RESTTest (BitcoinTestFramework):
assert_equal(len(json_obj['utxos']), 0)
self.generate(self.nodes[0], 1)
- self.sync_all()
json_obj = self.test_rest_request(f"/getutxos/{spending[0]}-{spending[1]}")
assert_equal(len(json_obj['utxos']), 1)
@@ -204,7 +200,6 @@ class RESTTest (BitcoinTestFramework):
self.test_rest_request(f"/getutxos/checkmempool/{long_uri}", http_method='POST', status=200)
self.generate(self.nodes[0], 1) # generate block to not affect upcoming tests
- self.sync_all()
self.log.info("Test the /block, /blockhashbyheight and /headers URIs")
bb_hash = self.nodes[0].getbestblockhash()
@@ -275,7 +270,6 @@ class RESTTest (BitcoinTestFramework):
# See if we can get 5 headers in one response
self.generate(self.nodes[1], 5)
- self.sync_all()
json_obj = self.test_rest_request(f"/headers/5/{bb_hash}")
assert_equal(len(json_obj), 5) # now we should have 5 header objects
@@ -310,7 +304,6 @@ class RESTTest (BitcoinTestFramework):
# Now mine the transactions
newblockhash = self.generate(self.nodes[1], 1)
- self.sync_all()
# Check if the 3 tx show up in the new block
json_obj = self.test_rest_request(f"/block/{newblockhash[0]}")
diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py
index 89a7d29b24..48082f3a17 100755
--- a/test/functional/interface_rpc.py
+++ b/test/functional/interface_rpc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests some generic aspects of the RPC interface."""
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 5bf75e2064..1ee12c0040 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the ZMQ notification interface."""
@@ -18,7 +18,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
CTransaction,
hash256,
- tx_from_hex,
)
from test_framework.util import (
assert_equal,
@@ -190,8 +189,6 @@ class ZMQTest (BitcoinTestFramework):
self.log.info(f"Generate {num_blocks} blocks (and {num_blocks} coinbase txes)")
genhashes = self.generatetoaddress(self.nodes[0], num_blocks, ADDRESS_BCRT1_UNSPENDABLE)
- self.sync_all()
-
for x in range(num_blocks):
# Should receive the coinbase txid.
txid = hashtx.receive()
@@ -353,7 +350,6 @@ class ZMQTest (BitcoinTestFramework):
# removed from the mempool by the block mining it.
mempool_size = len(self.nodes[0].getrawmempool())
c_block = self.generatetoaddress(self.nodes[0], 1, ADDRESS_BCRT1_UNSPENDABLE)[0]
- self.sync_all()
# Make sure the number of mined transactions matches the number of txs out of mempool
mempool_size_delta = mempool_size - len(self.nodes[0].getrawmempool())
assert_equal(len(self.nodes[0].getblock(c_block)["tx"])-1, mempool_size_delta)
@@ -393,7 +389,6 @@ class ZMQTest (BitcoinTestFramework):
# Other things may happen but aren't wallet-deterministic so we don't test for them currently
self.nodes[0].reconsiderblock(best_hash)
self.generatetoaddress(self.nodes[1], 1, ADDRESS_BCRT1_UNSPENDABLE)
- self.sync_all()
self.log.info("Evict mempool transaction by block conflict")
orig_txid = self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1.0, replaceable=True)
@@ -406,12 +401,8 @@ class ZMQTest (BitcoinTestFramework):
raw_tx = self.nodes[0].getrawtransaction(orig_txid)
bump_info = self.nodes[0].bumpfee(orig_txid)
# Mine the pre-bump tx
- block = create_block(int(self.nodes[0].getbestblockhash(), 16), create_coinbase(self.nodes[0].getblockcount()+1))
- tx = tx_from_hex(raw_tx)
- block.vtx.append(tx)
- for txid in more_tx:
- tx = tx_from_hex(self.nodes[0].getrawtransaction(txid))
- block.vtx.append(tx)
+ txs_to_add = [raw_tx] + [self.nodes[0].getrawtransaction(txid) for txid in more_tx]
+ block = create_block(int(self.nodes[0].getbestblockhash(), 16), create_coinbase(self.nodes[0].getblockcount()+1), txlist=txs_to_add)
add_witness_commitment(block)
block.solve()
assert_equal(self.nodes[0].submitblock(block.serialize().hex()), None)
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 71be2b4a82..44db8bb00a 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool acceptance of raw transactions."""
diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py
index d450b40582..c545a7f68d 100755
--- a/test/functional/mempool_compatibility.py
+++ b/test/functional/mempool_compatibility.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that mempool.dat is both backward and forward compatible between versions
diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py
index 942f79e8b0..f301b29c25 100755
--- a/test/functional/mempool_expiry.py
+++ b/test/functional/mempool_expiry.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests that a mempool transaction expires after a given timeout and that its
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index 79f6f9dc70..3619e05761 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool limiting together/eviction with the wallet."""
diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py
index 69c21f32bc..a6fb1dcf35 100755
--- a/test/functional/mempool_package_onemore.py
+++ b/test/functional/mempool_package_onemore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test descendant package tracking carve-out allowing one final transaction in
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index ff5e45519f..dcbd340f11 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test descendant package tracking code."""
@@ -192,7 +192,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Check that prioritising a tx before it's added to the mempool works
# First clear the mempool by mining a block.
self.generate(self.nodes[0], 1)
- self.sync_blocks()
assert_equal(len(self.nodes[0].getrawmempool()), 0)
# Prioritise a transaction that has been mined, then add it back to the
# mempool by using invalidateblock.
@@ -283,7 +282,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Test reorg handling
# First, the basics:
self.generate(self.nodes[0], 1)
- self.sync_blocks()
self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash())
self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash())
@@ -330,7 +328,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Mine these in a block
self.generate(self.nodes[0], 1)
- self.sync_all()
# Now generate tx8, with a big fee
inputs = [ {'txid' : tx1_id, 'vout': 0}, {'txid' : txid, 'vout': 0} ]
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index 9bcd4cf6b1..8c9379b90b 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool persistence.
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index 509a003746..7e940fa3ca 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool re-org scenarios.
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 4fce07dad3..3e610d02ac 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test resurrection of mined transactions when the blockchain is re-organized."""
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index 4e1dd80ba7..5afa6be925 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test spending coinbase transactions.
diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py
index 88194a09b4..adf7326dac 100755
--- a/test/functional/mempool_unbroadcast.py
+++ b/test/functional/mempool_unbroadcast.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that the mempool ensures transaction delivery by periodically sending
diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py
index 22f136d1a5..16c15e3f74 100755
--- a/test/functional/mempool_updatefromblock.py
+++ b/test/functional/mempool_updatefromblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mempool descendants/ancestors information update.
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index 3d1f804ddc..f8d002e664 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mining RPCs
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index 0879fb9f2d..e928ee4936 100755
--- a/test/functional/mining_getblocktemplate_longpoll.py
+++ b/test/functional/mining_getblocktemplate_longpoll.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test longpolling with getblocktemplate."""
@@ -64,7 +64,6 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
# Add enough mature utxos to the wallets, so that all txs spend confirmed coins
self.generate(self.nodes[0], COINBASE_MATURITY)
- self.sync_blocks()
self.log.info("Test that introducing a new transaction into the mempool will terminate the longpoll")
thr = LongpollThread(self.nodes[0])
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index 01d8501b6b..6f2ac805a0 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the prioritisetransaction mining RPC."""
diff --git a/test/functional/mocks/signer.py b/test/functional/mocks/signer.py
index 676d0a0a4d..b732b26a53 100755
--- a/test/functional/mocks/signer.py
+++ b/test/functional/mocks/signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,7 @@ def perform_pre_checks():
sys.exit(int(mock_result[0]))
def enumerate(args):
- sys.stdout.write(json.dumps([{"fingerprint": "00000001", "type": "trezor", "model": "trezor_t"}, {"fingerprint": "00000002"}]))
+ sys.stdout.write(json.dumps([{"fingerprint": "00000001", "type": "trezor", "model": "trezor_t"}, {"fingerprint": "00000002"}]))
def getdescriptors(args):
xpub = "tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B"
@@ -93,7 +93,7 @@ parser_signtx.set_defaults(func=signtx)
if not sys.stdin.isatty():
buffer = sys.stdin.read()
if buffer and buffer.rstrip() != "":
- sys.argv.extend(buffer.rstrip().split(" "))
+ sys.argv.extend(buffer.rstrip().split(" "))
args = parser.parse_args()
diff --git a/test/functional/p2p_add_connections.py b/test/functional/p2p_add_connections.py
index a04ba5db2d..b86502dc85 100755
--- a/test/functional/p2p_add_connections.py
+++ b/test/functional/p2p_add_connections.py
@@ -6,13 +6,7 @@
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-
-
-def check_node_connections(*, node, num_in, num_out):
- info = node.getnetworkinfo()
- assert_equal(info["connections_in"], num_in)
- assert_equal(info["connections_out"], num_out)
+from test_framework.util import check_node_connections
class P2PAddConnections(BitcoinTestFramework):
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index 9df74ad3a0..5532056dbe 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py
index f4be893d2c..9ab190871f 100755
--- a/test/functional/p2p_addrv2_relay.py
+++ b/test/functional/p2p_addrv2_relay.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py
index b67a0b3f7e..e73fad439f 100755
--- a/test/functional/p2p_blockfilters.py
+++ b/test/functional/p2p_blockfilters.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests NODE_COMPACT_FILTERS (BIP 157/158).
@@ -57,7 +57,6 @@ class CompactFiltersTest(BitcoinTestFramework):
# Nodes 0 & 1 share the same first 999 blocks in the chain.
self.generate(self.nodes[0], 999)
- self.sync_blocks(timeout=600)
# Stale blocks by disconnecting nodes 0 & 1, mining, then reconnecting
self.disconnect_nodes(0, 1)
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index 94ae758d46..6e48341259 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test p2p blocksonly mode & block-relay-only connections."""
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 3f01d552b2..a314e8edfd 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test compact blocks (BIP 152).
diff --git a/test/functional/p2p_compactblocks_hb.py b/test/functional/p2p_compactblocks_hb.py
index 72b3897b4f..c985a1f98d 100755
--- a/test/functional/p2p_compactblocks_hb.py
+++ b/test/functional/p2p_compactblocks_hb.py
@@ -31,7 +31,6 @@ class CompactBlocksConnectionTest(BitcoinTestFramework):
"""Relay a new block through peer peer, and return HB status between 1 and [2,3,4,5]."""
self.connect_nodes(peer, 0)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
self.disconnect_nodes(peer, 0)
status_to = [self.peer_info(1, i)['bip152_hb_to'] for i in range(2, 6)]
status_from = [self.peer_info(i, 1)['bip152_hb_from'] for i in range(2, 6)]
@@ -45,7 +44,6 @@ class CompactBlocksConnectionTest(BitcoinTestFramework):
for i in range(1, 6):
self.connect_nodes(i, 0)
self.generate(self.nodes[0], 2)
- self.sync_blocks()
for i in range(1, 6):
self.disconnect_nodes(i, 0)
diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py
index 52a47c9bc2..fde1e4bfa2 100755
--- a/test/functional/p2p_dos_header_tree.py
+++ b/test/functional/p2p_dos_header_tree.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that we reject low difficulty headers to prevent our block tree from filling up with useless bloat"""
diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py
index 4ccc942164..1f4797a89d 100755
--- a/test/functional/p2p_eviction.py
+++ b/test/functional/p2p_eviction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index 60adc2c7fa..b65e927d5b 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test processing of feefilter messages."""
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 0d8c298bea..2192363a89 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py
index 2962dc8085..e8bba8555f 100755
--- a/test/functional/p2p_fingerprint.py
+++ b/test/functional/p2p_fingerprint.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test various fingerprinting protections.
diff --git a/test/functional/p2p_ibd_txrelay.py b/test/functional/p2p_ibd_txrelay.py
index c35053d9d4..65a94ad31c 100755
--- a/test/functional/p2p_ibd_txrelay.py
+++ b/test/functional/p2p_ibd_txrelay.py
@@ -1,12 +1,31 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test fee filters during and after IBD."""
+"""Test transaction relay behavior during IBD:
+- Set fee filters to MAX_MONEY
+- Don't request transactions
+- Ignore all transaction messages
+"""
from decimal import Decimal
+import time
-from test_framework.messages import COIN
+from test_framework.messages import (
+ CInv,
+ COIN,
+ CTransaction,
+ from_hex,
+ msg_inv,
+ msg_tx,
+ MSG_WTX,
+)
+from test_framework.p2p import (
+ NONPREF_PEER_TX_DELAY,
+ P2PDataStore,
+ P2PInterface,
+ p2p_lock
+)
from test_framework.test_framework import BitcoinTestFramework
MAX_FEE_FILTER = Decimal(9170997) / COIN
@@ -28,15 +47,43 @@ class P2PIBDTxRelayTest(BitcoinTestFramework):
assert node.getblockchaininfo()['initialblockdownload']
self.wait_until(lambda: all(peer['minfeefilter'] == MAX_FEE_FILTER for peer in node.getpeerinfo()))
+ self.log.info("Check that nodes don't send getdatas for transactions while still in IBD")
+ peer_inver = self.nodes[0].add_p2p_connection(P2PDataStore())
+ txid = 0xdeadbeef
+ peer_inver.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=txid)]))
+ # The node should not send a getdata, but if it did, it would first delay 2 seconds
+ self.nodes[0].setmocktime(int(time.time() + NONPREF_PEER_TX_DELAY))
+ peer_inver.sync_send_with_ping()
+ with p2p_lock:
+ assert txid not in peer_inver.getdata_requests
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info("Check that nodes don't process unsolicited transactions while still in IBD")
+ # A transaction hex pulled from tx_valid.json. There are no valid transactions since no UTXOs
+ # exist yet, but it should be a well-formed transaction.
+ rawhex = "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff473" + \
+ "04402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e168" + \
+ "1a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696a" + \
+ "d990364e555c271ad504b88ac00000000"
+ assert self.nodes[1].decoderawtransaction(rawhex) # returns a dict, should not throw
+ tx = from_hex(CTransaction(), rawhex)
+ peer_txer = self.nodes[0].add_p2p_connection(P2PInterface())
+ with self.nodes[0].assert_debug_log(expected_msgs=["received: tx"], unexpected_msgs=["was not accepted"]):
+ peer_txer.send_and_ping(msg_tx(tx))
+ self.nodes[0].disconnect_p2ps()
+
# Come out of IBD by generating a block
self.generate(self.nodes[0], 1)
- self.sync_all()
self.log.info("Check that nodes reset minfilter after coming out of IBD")
for node in self.nodes:
assert not node.getblockchaininfo()['initialblockdownload']
self.wait_until(lambda: all(peer['minfeefilter'] == NORMAL_FEE_FILTER for peer in node.getpeerinfo()))
+ self.log.info("Check that nodes process the same transaction, even when unsolicited, when no longer in IBD")
+ peer_txer = self.nodes[0].add_p2p_connection(P2PInterface())
+ with self.nodes[0].assert_debug_log(expected_msgs=["was not accepted"]):
+ peer_txer.send_and_ping(msg_tx(tx))
if __name__ == '__main__':
P2PIBDTxRelayTest().main()
diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py
index 6eb8b8767d..0dfa25174b 100755
--- a/test/functional/p2p_invalid_block.py
+++ b/test/functional/p2p_invalid_block.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid blocks.
@@ -15,9 +15,14 @@ becomes valid.
import copy
import time
-from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script
+from test_framework.blocktools import (
+ create_block,
+ create_coinbase,
+ create_tx_with_script,
+)
from test_framework.messages import COIN
from test_framework.p2p import P2PDataStore
+from test_framework.script import OP_TRUE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -66,15 +71,10 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
# For more information on merkle-root malleability see src/consensus/merkle.cpp.
self.log.info("Test merkle root malleability.")
- block2 = create_block(tip, create_coinbase(height), block_time)
+ tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)
+ tx2 = create_tx_with_script(tx1, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)
+ block2 = create_block(tip, create_coinbase(height), block_time, txlist=[tx1, tx2])
block_time += 1
-
- # b'0x51' is OP_TRUE
- tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\x51', amount=50 * COIN)
- tx2 = create_tx_with_script(tx1, 0, script_sig=b'\x51', amount=50 * COIN)
-
- block2.vtx.extend([tx1, tx2])
- block2.hashMerkleRoot = block2.calc_merkle_root()
block2.solve()
orig_hash = block2.sha256
block2_orig = copy.deepcopy(block2)
@@ -99,12 +99,8 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
self.log.info("Test very broken block.")
- block3 = create_block(tip, create_coinbase(height), block_time)
+ block3 = create_block(tip, create_coinbase(height, nValue=100), block_time)
block_time += 1
- block3.vtx[0].vout[0].nValue = 100 * COIN # Too high!
- block3.vtx[0].sha256 = None
- block3.vtx[0].calc_sha256()
- block3.hashMerkleRoot = block3.calc_merkle_root()
block3.solve()
peer.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount')
@@ -123,14 +119,10 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
# Complete testing of CVE-2018-17144, by checking for the inflation bug.
# Create a block that spends the output of a tx in a previous block.
- block4 = create_block(tip, create_coinbase(height), block_time)
- tx3 = create_tx_with_script(tx2, 0, script_sig=b'\x51', amount=50 * COIN)
-
- # Duplicates input
- tx3.vin.append(tx3.vin[0])
+ tx3 = create_tx_with_script(tx2, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN)
+ tx3.vin.append(tx3.vin[0]) # Duplicates input
tx3.rehash()
- block4.vtx.append(tx3)
- block4.hashMerkleRoot = block4.calc_merkle_root()
+ block4 = create_block(tip, create_coinbase(height), block_time, txlist=[tx3])
block4.solve()
self.log.info("Test inflation by duplicating input")
peer.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate')
@@ -140,7 +132,6 @@ class InvalidBlockRequestTest(BitcoinTestFramework):
node.setmocktime(t)
# Set block time +1 second past max future validity
block = create_block(tip, create_coinbase(height), t + MAX_FUTURE_BLOCK_TIME + 1)
- block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
# Need force_send because the block will get rejected without a getdata otherwise
peer.send_blocks_and_test([block], node, force_send=True, success=False, reject_reason='time-too-new')
diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py
index a586b48d4c..626422370a 100755
--- a/test/functional/p2p_invalid_locator.py
+++ b/test/functional/p2p_invalid_locator.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid locators.
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 82c7e94c59..3109ad2b56 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid network messages."""
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 0a3ae23f58..139f4d64e7 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid transactions.
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index de58e07aad..af8e45d578 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test message sending before handshake completion.
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
index 9b80e1b877..4c064b359e 100755
--- a/test/functional/p2p_leak_tx.py
+++ b/test/functional/p2p_leak_tx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that we don't leak txs to inbound peers that we haven't yet announced to"""
diff --git a/test/functional/p2p_message_capture.py b/test/functional/p2p_message_capture.py
index 080b2d93ad..edde9a6ecf 100755
--- a/test/functional/p2p_message_capture.py
+++ b/test/functional/p2p_message_capture.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test per-peer message capture capability.
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index d70870fa56..5a0003d3ef 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests NODE_NETWORK_LIMITED.
@@ -59,8 +59,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.")
self.connect_nodes(0, 1)
- blocks = self.generate(self.nodes[1], 292, sync_fun=self.no_op)
- self.sync_blocks([self.nodes[0], self.nodes[1]])
+ blocks = self.generate(self.nodes[1], 292, sync_fun=lambda: self.sync_blocks([self.nodes[0], self.nodes[1]]))
self.log.info("Make sure we can max retrieve block at tip-288.")
node.send_getdata_for_block(blocks[1]) # last block in valid range
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index 32f2ea14e1..1dc3a5b9a0 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test p2p permission message.
@@ -94,7 +94,6 @@ class P2PPermissionsTests(BitcoinTestFramework):
def check_tx_relay(self):
block_op_true = self.nodes[0].getblock(self.generatetoaddress(self.nodes[0], 100, ADDRESS_BCRT1_P2WSH_OP_TRUE)[0])
- self.sync_all()
self.log.debug("Create a connection from a forcerelay peer that rebroadcasts raw txs")
# A test framework p2p connection is needed to send the raw transaction directly. If a full node was used, it could only
diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py
index d67e97acf7..52dae90d19 100755
--- a/test/functional/p2p_ping.py
+++ b/test/functional/p2p_ping.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test ping message
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 99bf34912f..f377fbaaa6 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test segwit transactions and blocks on P2P network."""
@@ -232,7 +232,6 @@ class SegWitTest(BitcoinTestFramework):
height = self.nodes[0].getblockcount() + 1
block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1
block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.nVersion = 4
block.rehash()
return block
@@ -580,7 +579,6 @@ class SegWitTest(BitcoinTestFramework):
# Mine it on test_node to create the confirmed output.
test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_tx, with_witness=True, accepted=True)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# Now test standardness of v0 P2WSH outputs.
# Start by creating a transaction with two outputs.
@@ -653,7 +651,6 @@ class SegWitTest(BitcoinTestFramework):
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
assert_equal(len(self.nodes[1].getrawmempool()), 0)
@@ -1354,7 +1351,6 @@ class SegWitTest(BitcoinTestFramework):
temp_utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
self.generate(self.nodes[0], 1) # Mine all the transactions
- self.sync_blocks()
assert len(self.nodes[0].getrawmempool()) == 0
# Finally, verify that version 0 -> version 2 transactions
@@ -1425,7 +1421,6 @@ class SegWitTest(BitcoinTestFramework):
# Now test a premature spend.
self.generate(self.nodes[0], 98)
- self.sync_blocks()
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
test_witness_block(self.nodes[0], self.test_node, block2, accepted=False, reason='bad-txns-premature-spend-of-coinbase')
@@ -1744,7 +1739,6 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
test_transaction_acceptance(self.nodes[0], self.test_node, tx, False, True)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# We'll add an unnecessary witness to this transaction that would cause
# it to be non-standard, to test that violating policy with a witness
@@ -1773,7 +1767,6 @@ class SegWitTest(BitcoinTestFramework):
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, False, True)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# Update our utxo list; we spent the first entry.
self.utxo.pop(0)
@@ -1808,7 +1801,6 @@ class SegWitTest(BitcoinTestFramework):
test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# Creating transactions for tests
p2wsh_txs = []
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index 7bf1803780..1ccc447b89 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test behavior of headers messages to announce blocks.
@@ -217,7 +217,6 @@ class SendHeadersTest(BitcoinTestFramework):
# make sure all invalidated blocks are node0's
self.generatetoaddress(self.nodes[0], length, self.nodes[0].get_deterministic_priv_key().address)
- self.sync_blocks(self.nodes, wait=0.1)
for x in self.nodes[0].p2ps:
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
x.clear_block_announcements()
@@ -226,7 +225,6 @@ class SendHeadersTest(BitcoinTestFramework):
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
self.nodes[1].invalidateblock(hash_to_invalidate)
all_hashes = self.generatetoaddress(self.nodes[1], length + 1, self.nodes[1].get_deterministic_priv_key().address) # Must be longer than the orig chain
- self.sync_blocks(self.nodes, wait=0.1)
return [int(x, 16) for x in all_hashes]
def run_test(self):
diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py
index 3e962b4450..7356b8bbb3 100755
--- a/test/functional/p2p_tx_download.py
+++ b/test/functional/p2p_tx_download.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index e037198573..9c4e1dd1b1 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test processing of unrequested blocks.
@@ -225,10 +225,9 @@ class AcceptBlockTest(BitcoinTestFramework):
block_289f.solve()
block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1)
block_290f.solve()
- block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1)
# block_291 spends a coinbase below maturity!
- block_291.vtx.append(create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1))
- block_291.hashMerkleRoot = block_291.calc_merkle_root()
+ tx_to_add = create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1)
+ block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1, txlist=[tx_to_add])
block_291.solve()
block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1)
block_292.solve()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 14e17bada6..4be9616345 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPCs related to blockchainstate.
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 696438ccfe..f56e71ae7a 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test multisig RPCs"""
@@ -46,7 +46,6 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
self.log.info('Generating blocks ...')
self.generate(node0, 149)
- self.sync_all()
self.moved = 0
for self.nkeys in [3, 5]:
@@ -117,7 +116,6 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
def checkbalances(self):
node0, node1, node2 = self.nodes
self.generate(node0, COINBASE_MATURITY)
- self.sync_all()
bal0 = node0.getbalance()
bal1 = node1.getbalance()
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index 5b1514af6f..8c0f48129a 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test decoding scripts via decodescript RPC command."""
@@ -27,29 +27,29 @@ class DecodeScriptTest(BitcoinTestFramework):
# below are test cases for all of the standard transaction types
- # 1) P2PK scriptSig
+ self.log.info("- P2PK")
# the scriptSig of a public key scriptPubKey simply pushes a signature onto the stack
rpc_result = self.nodes[0].decodescript(push_signature)
assert_equal(signature, rpc_result['asm'])
- # 2) P2PKH scriptSig
+ self.log.info("- P2PKH")
rpc_result = self.nodes[0].decodescript(push_signature + push_public_key)
assert_equal(signature + ' ' + public_key, rpc_result['asm'])
- # 3) multisig scriptSig
+ self.log.info("- multisig")
# this also tests the leading portion of a P2SH multisig scriptSig
# OP_0 <A sig> <B sig>
rpc_result = self.nodes[0].decodescript('00' + push_signature + push_signature)
assert_equal('0 ' + signature + ' ' + signature, rpc_result['asm'])
- # 4) P2SH scriptSig
+ self.log.info("- P2SH")
# an empty P2SH redeemScript is valid and makes for a very simple test case.
# thus, such a spending scriptSig would just need to pass the outer redeemScript
# hash test and leave true on the top of the stack.
rpc_result = self.nodes[0].decodescript('5100')
assert_equal('1 0', rpc_result['asm'])
- # 5) null data scriptSig - no such thing because null data scripts can not be spent.
+ # null data scriptSig - no such thing because null data scripts can not be spent.
# thus, no test case for that standard transaction type is here.
def decodescript_script_pub_key(self):
@@ -63,50 +63,58 @@ class DecodeScriptTest(BitcoinTestFramework):
# below are test cases for all of the standard transaction types
- # 1) P2PK scriptPubKey
+ self.log.info("- P2PK")
# <pubkey> OP_CHECKSIG
rpc_result = self.nodes[0].decodescript(push_public_key + 'ac')
assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm'])
+ assert_equal('pubkey', rpc_result['type'])
# P2PK is translated to P2WPKH
assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])
- # 2) P2PKH scriptPubKey
+ self.log.info("- P2PKH")
# OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac')
+ assert_equal('pubkeyhash', rpc_result['type'])
assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm'])
# P2PKH is translated to P2WPKH
+ assert_equal('witness_v0_keyhash', rpc_result['segwit']['type'])
assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])
- # 3) multisig scriptPubKey
+ self.log.info("- multisig")
# <m> <A pubkey> <B pubkey> <C pubkey> <n> OP_CHECKMULTISIG
# just imagine that the pub keys used below are different.
# for our purposes here it does not matter that they are the same even though it is unrealistic.
multisig_script = '52' + push_public_key + push_public_key + push_public_key + '53ae'
rpc_result = self.nodes[0].decodescript(multisig_script)
+ assert_equal('multisig', rpc_result['type'])
assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm'])
# multisig in P2WSH
multisig_script_hash = sha256(bytes.fromhex(multisig_script)).hex()
+ assert_equal('witness_v0_scripthash', rpc_result['segwit']['type'])
assert_equal('0 ' + multisig_script_hash, rpc_result['segwit']['asm'])
- # 4) P2SH scriptPubKey
+ self.log.info ("- P2SH")
# OP_HASH160 <Hash160(redeemScript)> OP_EQUAL.
# push_public_key_hash here should actually be the hash of a redeem script.
# but this works the same for purposes of this test.
rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87')
+ assert_equal('scripthash', rpc_result['type'])
assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm'])
# P2SH does not work in segwit secripts. decodescript should not return a result for it.
assert 'segwit' not in rpc_result
- # 5) null data scriptPubKey
+ self.log.info("- null data")
# use a signature look-alike here to make sure that we do not decode random data as a signature.
# this matters if/when signature sighash decoding comes along.
# would want to make sure that no such decoding takes place in this case.
signature_imposter = '48304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001'
# OP_RETURN <data>
rpc_result = self.nodes[0].decodescript('6a' + signature_imposter)
+ assert_equal('nulldata', rpc_result['type'])
assert_equal('OP_RETURN ' + signature_imposter[2:], rpc_result['asm'])
- # 6) a CLTV redeem script. redeem scripts are in-effect scriptPubKey scripts, so adding a test here.
+ self.log.info("- CLTV redeem script")
+ # redeem scripts are in-effect scriptPubKey scripts, so adding a test here.
# OP_NOP2 is also known as OP_CHECKLOCKTIMEVERIFY.
# just imagine that the pub keys used below are different.
# for our purposes here it does not matter that they are the same even though it is unrealistic.
@@ -121,55 +129,69 @@ class DecodeScriptTest(BitcoinTestFramework):
# lock until block 500,000
cltv_script = '63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac'
rpc_result = self.nodes[0].decodescript(cltv_script)
+ assert_equal('nonstandard', rpc_result['type'])
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
# CLTV script in P2WSH
cltv_script_hash = sha256(bytes.fromhex(cltv_script)).hex()
assert_equal('0 ' + cltv_script_hash, rpc_result['segwit']['asm'])
- # 7) P2PK scriptPubKey
+ self.log.info("- P2PK with uncompressed pubkey")
# <pubkey> OP_CHECKSIG
rpc_result = self.nodes[0].decodescript(push_uncompressed_public_key + 'ac')
+ assert_equal('pubkey', rpc_result['type'])
assert_equal(uncompressed_public_key + ' OP_CHECKSIG', rpc_result['asm'])
# uncompressed pubkeys are invalid for checksigs in segwit scripts.
# decodescript should not return a P2WPKH equivalent.
assert 'segwit' not in rpc_result
- # 8) multisig scriptPubKey with an uncompressed pubkey
+ self.log.info("- multisig with uncompressed pubkey")
# <m> <A pubkey> <B pubkey> <n> OP_CHECKMULTISIG
# just imagine that the pub keys used below are different.
# the purpose of this test is to check that a segwit script is not returned for bare multisig scripts
# with an uncompressed pubkey in them.
rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_uncompressed_public_key +'52ae')
+ assert_equal('multisig', rpc_result['type'])
assert_equal('2 ' + public_key + ' ' + uncompressed_public_key + ' 2 OP_CHECKMULTISIG', rpc_result['asm'])
# uncompressed pubkeys are invalid for checksigs in segwit scripts.
# decodescript should not return a P2WPKH equivalent.
assert 'segwit' not in rpc_result
- # 9) P2WPKH scriptpubkey
+ self.log.info("- P2WPKH")
# 0 <PubKeyHash>
rpc_result = self.nodes[0].decodescript('00' + push_public_key_hash)
+ assert_equal('witness_v0_keyhash', rpc_result['type'])
assert_equal('0 ' + public_key_hash, rpc_result['asm'])
# segwit scripts do not work nested into each other.
# a nested segwit script should not be returned in the results.
assert 'segwit' not in rpc_result
- # 10) P2WSH scriptpubkey
+ self.log.info("- P2WSH")
# 0 <ScriptHash>
# even though this hash is of a P2PK script which is better used as bare P2WPKH, it should not matter
# for the purpose of this test.
rpc_result = self.nodes[0].decodescript('0020' + p2wsh_p2pk_script_hash)
+ assert_equal('witness_v0_scripthash', rpc_result['type'])
assert_equal('0 ' + p2wsh_p2pk_script_hash, rpc_result['asm'])
# segwit scripts do not work nested into each other.
# a nested segwit script should not be returned in the results.
assert 'segwit' not in rpc_result
+ self.log.info("- P2TR")
+ # 1 <x-only pubkey>
+ xonly_public_key = '01'*32 # first ever P2TR output on mainnet
+ rpc_result = self.nodes[0].decodescript('5120' + xonly_public_key)
+ assert_equal('witness_v1_taproot', rpc_result['type'])
+ assert_equal('1 ' + xonly_public_key, rpc_result['asm'])
+ assert 'segwit' not in rpc_result
+
def decoderawtransaction_asm_sighashtype(self):
"""Test decoding scripts via RPC command "decoderawtransaction".
This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
"""
- # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
+ self.log.info("- various mainnet txs")
+ # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])
@@ -185,11 +207,13 @@ class DecodeScriptTest(BitcoinTestFramework):
assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
txSave = tx_from_hex(tx)
+ self.log.info("- tx not passing DER signature checks")
# make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])
+ self.log.info("- tx passing DER signature checks")
# verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
rpc_result = self.nodes[0].decoderawtransaction(tx)
@@ -207,7 +231,7 @@ class DecodeScriptTest(BitcoinTestFramework):
push_signature_2 = '48' + signature_2
signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'
- # 1) P2PK scriptSig
+ self.log.info("- P2PK scriptSig")
txSave.vin[0].scriptSig = bytes.fromhex(push_signature)
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
@@ -217,20 +241,23 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
- # 2) multisig scriptSig
+ self.log.info("- multisig scriptSig")
txSave.vin[0].scriptSig = bytes.fromhex('00' + push_signature + push_signature_2)
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
- # 3) test a scriptSig that contains more than push operations.
+ self.log.info("- scriptSig that contains more than push operations")
# in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
txSave.vin[0].scriptSig = bytes.fromhex('6a143011020701010101010101020601010101010101')
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
def run_test(self):
+ self.log.info("Test decoding of standard input scripts [scriptSig]")
self.decodescript_script_sig()
+ self.log.info("Test decoding of standard output scripts [scriptPubKey]")
self.decodescript_script_pub_key()
+ self.log.info("Test 'asm' script decoding of transactions")
self.decoderawtransaction_asm_sighashtype()
if __name__ == '__main__':
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index fdaed918a1..15c77ed856 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test deprecation of RPC calls."""
diff --git a/test/functional/rpc_dumptxoutset.py b/test/functional/rpc_dumptxoutset.py
index 89388df555..f54f600839 100755
--- a/test/functional/rpc_dumptxoutset.py
+++ b/test/functional/rpc_dumptxoutset.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the generation of UTXO snapshots using `dumptxoutset`.
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 84be772895..93970ff40c 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the fundrawtransaction RPC."""
@@ -99,9 +99,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.fee_tolerance = 2 * self.min_relay_tx_fee / 1000
self.generate(self.nodes[2], 1)
- self.sync_all()
self.generate(self.nodes[0], 121)
- self.sync_all()
self.test_change_position()
self.test_simple()
@@ -164,7 +162,6 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)
self.generate(self.nodes[0], 1)
- self.sync_all()
wwatch.unloadwallet()
@@ -550,7 +547,6 @@ class RawTransactionsTest(BitcoinTestFramework):
# Send 1.2 BTC to msig addr.
self.nodes[0].sendtoaddress(mSigObj, 1.2)
self.generate(self.nodes[0], 1)
- self.sync_all()
oldBalance = self.nodes[1].getbalance()
inputs = []
@@ -561,7 +557,6 @@ class RawTransactionsTest(BitcoinTestFramework):
final_psbt = w2.finalizepsbt(signed_psbt['psbt'])
self.nodes[2].sendrawtransaction(final_psbt['hex'])
self.generate(self.nodes[2], 1)
- self.sync_all()
# Make sure funds are received at node1.
assert_equal(oldBalance+Decimal('1.10000000'), self.nodes[1].getbalance())
@@ -576,12 +571,12 @@ class RawTransactionsTest(BitcoinTestFramework):
if self.options.descriptors:
self.nodes[1].walletpassphrase('test', 10)
self.nodes[1].importdescriptors([{
- 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
+ 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
'timestamp': 'now',
'active': True
},
{
- 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
+ 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
'timestamp': 'now',
'active': True,
'internal': True
@@ -625,7 +620,6 @@ class RawTransactionsTest(BitcoinTestFramework):
signedTx = self.nodes[1].signrawtransactionwithwallet(fundedTx['hex'])
self.nodes[1].sendrawtransaction(signedTx['hex'])
self.generate(self.nodes[1], 1)
- self.sync_all()
# Make sure funds are received at node1.
assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance())
@@ -637,12 +631,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# Empty node1, send some small coins from node0 to node1.
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
self.generate(self.nodes[1], 1)
- self.sync_all()
for _ in range(20):
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Fund a tx with ~20 small inputs.
inputs = []
@@ -665,12 +657,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# Again, empty node1, send some small coins from node0 to node1.
self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True)
self.generate(self.nodes[1], 1)
- self.sync_all()
for _ in range(20):
self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Fund a tx with ~20 small inputs.
oldBalance = self.nodes[0].getbalance()
@@ -682,7 +672,6 @@ class RawTransactionsTest(BitcoinTestFramework):
fundedAndSignedTx = self.nodes[1].signrawtransactionwithwallet(fundedTx['hex'])
self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
self.generate(self.nodes[1], 1)
- self.sync_all()
assert_equal(oldBalance+Decimal('50.19000000'), self.nodes[0].getbalance()) #0.19+block reward
def test_op_return(self):
@@ -760,7 +749,6 @@ class RawTransactionsTest(BitcoinTestFramework):
assert signedtx["complete"]
self.nodes[0].sendrawtransaction(signedtx["hex"])
self.generate(self.nodes[0], 1)
- self.sync_all()
wwatch.unloadwallet()
@@ -790,11 +778,18 @@ class RawTransactionsTest(BitcoinTestFramework):
for param, zero_value in product(["fee_rate", "feeRate"], [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]):
assert_equal(self.nodes[3].fundrawtransaction(rawtx, {param: zero_value})["fee"], 0)
- # With no arguments passed, expect fee of 141 satoshis.
- assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
- # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
- result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
- assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
+ if self.options.descriptors:
+ # With no arguments passed, expect fee of 153 satoshis as descriptor wallets now have a taproot output.
+ assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000153, vspan=0.00000001)
+ # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
+ result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
+ assert_approx(result["fee"], vexp=0.0153, vspan=0.0001)
+ else:
+ # With no arguments passed, expect fee of 141 satoshis as legacy wallets only support up to segwit v0.
+ assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
+ # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
+ result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
+ assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
self.log.info("Test fundrawtxn with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
@@ -1012,7 +1007,6 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(addr, 10)
self.nodes[0].sendtoaddress(wallet.getnewaddress(), 10)
self.generate(self.nodes[0], 6)
- self.sync_all()
ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
@@ -1086,7 +1080,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Make sure the default wallet will not be loaded when restarted with a high minrelaytxfee
self.nodes[0].unloadwallet(self.default_wallet_name, False)
feerate = Decimal("0.1")
- self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0"]) # Set high minrelayfee, set discardfee to 0 for easier calculation
+ self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0", "-changetype=bech32", "-addresstype=bech32"]) # Set high minrelayfee, set discardfee to 0 for easier calculation
self.nodes[0].loadwallet(self.default_wallet_name, True)
funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
@@ -1143,7 +1137,6 @@ class RawTransactionsTest(BitcoinTestFramework):
addr = w.getnewaddress(address_type="bech32")
self.nodes[0].sendtoaddress(addr, 1)
self.generate(self.nodes[0], 1)
- self.sync_all()
# A P2WPKH input costs 68 vbytes; With a single P2WPKH output, the rest of the tx is 42 vbytes for a total of 110 vbytes.
# At a feerate of 1.85 sat/vb, the input will need a fee of 125.8 sats and the rest 77.7 sats
diff --git a/test/functional/rpc_generateblock.py b/test/functional/rpc_generateblock.py
index 3c6b3fb125..7aede0e947 100755
--- a/test/functional/rpc_generateblock.py
+++ b/test/functional/rpc_generateblock.py
@@ -1,11 +1,12 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''Test generateblock rpc.
'''
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import MiniWallet
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
@@ -16,14 +17,13 @@ class GenerateBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def run_test(self):
node = self.nodes[0]
+ miniwallet = MiniWallet(node)
+ miniwallet.rescan_utxos()
self.log.info('Generate an empty block to address')
- address = node.getnewaddress()
+ address = miniwallet.get_address()
hash = self.generateblock(node, output=address, transactions=[])['hash']
block = node.getblock(blockhash=hash, verbose=2)
assert_equal(len(block['tx']), 1)
@@ -51,37 +51,31 @@ class GenerateBlockTest(BitcoinTestFramework):
assert_equal(len(block['tx']), 1)
assert_equal(block['tx'][0]['vout'][0]['scriptPubKey']['address'], combo_address)
- # Generate 110 blocks to spend
- self.generatetoaddress(node, 110, address)
-
# Generate some extra mempool transactions to verify they don't get mined
for _ in range(10):
- node.sendtoaddress(address, 0.001)
+ miniwallet.send_self_transfer(from_node=node)
self.log.info('Generate block with txid')
- txid = node.sendtoaddress(address, 1)
+ txid = miniwallet.send_self_transfer(from_node=node)['txid']
hash = self.generateblock(node, address, [txid])['hash']
block = node.getblock(hash, 1)
assert_equal(len(block['tx']), 2)
assert_equal(block['tx'][1], txid)
self.log.info('Generate block with raw tx')
- utxos = node.listunspent(addresses=[address])
- raw = node.createrawtransaction([{'txid':utxos[0]['txid'], 'vout':utxos[0]['vout']}],[{address:1}])
- signed_raw = node.signrawtransactionwithwallet(raw)['hex']
- hash = self.generateblock(node, address, [signed_raw])['hash']
+ rawtx = miniwallet.create_self_transfer(from_node=node)['hex']
+ hash = self.generateblock(node, address, [rawtx])['hash']
+
block = node.getblock(hash, 1)
assert_equal(len(block['tx']), 2)
txid = block['tx'][1]
- assert_equal(node.gettransaction(txid)['hex'], signed_raw)
+ assert_equal(node.getrawtransaction(txid=txid, verbose=False, blockhash=hash), rawtx)
self.log.info('Fail to generate block with out of order txs')
- raw1 = node.createrawtransaction([{'txid':txid, 'vout':0}],[{address:0.9999}])
- signed_raw1 = node.signrawtransactionwithwallet(raw1)['hex']
- txid1 = node.sendrawtransaction(signed_raw1)
- raw2 = node.createrawtransaction([{'txid':txid1, 'vout':0}],[{address:0.999}])
- signed_raw2 = node.signrawtransactionwithwallet(raw2)['hex']
- assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [signed_raw2, txid1])
+ txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
+ utxo1 = miniwallet.get_utxo(txid=txid1)
+ rawtx2 = miniwallet.create_self_transfer(from_node=node, utxo_to_spend=utxo1)['hex']
+ assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
self.log.info('Fail to generate block with txid not in mempool')
missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
diff --git a/test/functional/rpc_getblockfilter.py b/test/functional/rpc_getblockfilter.py
index 1c456a5b82..b09af9e078 100755
--- a/test/functional/rpc_getblockfilter.py
+++ b/test/functional/rpc_getblockfilter.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the getblockfilter RPC."""
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 456e2cb0ad..8c08d2ced5 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -48,7 +48,6 @@ class GetblockstatsTest(BitcoinTestFramework):
address = self.nodes[0].get_deterministic_priv_key().address
self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
self.generate(self.nodes[0], 1)
- self.sync_all()
self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=False)
diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py
index fb09c81cbd..7efa306c8c 100755
--- a/test/functional/rpc_getchaintips.py
+++ b/test/functional/rpc_getchaintips.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the getchaintips RPC.
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
index de21f43747..ccb380e25b 100755
--- a/test/functional/rpc_help.py
+++ b/test/functional/rpc_help.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC help output."""
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
index 085f6582b5..2567564f15 100755
--- a/test/functional/rpc_invalid_address_message.py
+++ b/test/functional/rpc_invalid_address_message.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test error messages for 'getaddressinfo' and 'validateaddress' RPC commands."""
@@ -12,79 +12,96 @@ from test_framework.util import (
)
BECH32_VALID = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
+BECH32_VALID_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U33RAH7R'
+BECH32_VALID_MULTISIG = 'bcrt1qdg3myrgvzw7ml9q0ejxhlkyxm7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks'
+
BECH32_INVALID_BECH32 = 'bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqdmchcc'
BECH32_INVALID_BECH32M = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7k35mrzd'
BECH32_INVALID_VERSION = 'bcrt130xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqynjegk'
BECH32_INVALID_SIZE = 'bcrt1s0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav25430mtr'
BECH32_INVALID_V0_SIZE = 'bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kqqq5k3my'
BECH32_INVALID_PREFIX = 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx'
+BECH32_TOO_LONG = 'bcrt1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23m'
+BECH32_ONE_ERROR = 'bcrt1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv'
+BECH32_ONE_ERROR_CAPITALS = 'BCRT1QPLMTZKC2XHARPPZDLNPAQL78RSHJ68U32RAH7R'
+BECH32_TWO_ERRORS = 'bcrt1qax9suht3qv95sw33xavx8crpxduefdrsvgsklu' # should be bcrt1qax9suht3qv95sw33wavx8crpxduefdrsvgsklx
+BECH32_NO_SEPARATOR = 'bcrtq049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
+BECH32_INVALID_CHAR = 'bcrt1q04oldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
+BECH32_MULTISIG_TWO_ERRORS = 'bcrt1qdg3myrgvzw7ml8q0ejxhlkyxn7vl9r56yzkfgvzclrf4hkpx9yfqhpsuks'
+BECH32_WRONG_VERSION = 'bcrt1ptmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
BASE58_VALID = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn'
BASE58_INVALID_PREFIX = '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem'
+BASE58_INVALID_CHECKSUM = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJJfn'
+BASE58_INVALID_LENGTH = '2VKf7XKMrp4bVNVmuRbyCewkP8FhGLP2E54LHDPakr9Sq5mtU2'
INVALID_ADDRESS = 'asfah14i8fajz0123f'
+INVALID_ADDRESS_2 = '1q049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- def test_validateaddress(self):
- node = self.nodes[0]
-
- # Bech32
- info = node.validateaddress(BECH32_INVALID_SIZE)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid Bech32 address data size')
-
- info = node.validateaddress(BECH32_INVALID_PREFIX)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid prefix for Bech32 address')
-
- info = node.validateaddress(BECH32_INVALID_BECH32)
- assert not info['isvalid']
- assert_equal(info['error'], 'Version 1+ witness address must use Bech32m checksum')
-
- info = node.validateaddress(BECH32_INVALID_BECH32M)
- assert not info['isvalid']
- assert_equal(info['error'], 'Version 0 witness address must use Bech32 checksum')
-
- info = node.validateaddress(BECH32_INVALID_V0_SIZE)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid Bech32 v0 address data size')
-
- info = node.validateaddress(BECH32_VALID)
+ def check_valid(self, addr):
+ info = self.nodes[0].validateaddress(addr)
assert info['isvalid']
assert 'error' not in info
+ assert 'error_locations' not in info
- info = node.validateaddress(BECH32_INVALID_VERSION)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid Bech32 address witness version')
-
- # Base58
- info = node.validateaddress(BASE58_INVALID_PREFIX)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid prefix for Base58-encoded address')
+ def check_invalid(self, addr, error_str, error_locations=None):
+ res = self.nodes[0].validateaddress(addr)
+ assert not res['isvalid']
+ assert_equal(res['error'], error_str)
+ if error_locations:
+ assert_equal(res['error_locations'], error_locations)
+ else:
+ assert_equal(res['error_locations'], [])
- info = node.validateaddress(BASE58_VALID)
- assert info['isvalid']
- assert 'error' not in info
+ def test_validateaddress(self):
+ # Invalid Bech32
+ self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address data size')
+ self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid HRP or Base58 character in address')
+ self.check_invalid(BECH32_INVALID_BECH32, 'Version 1+ witness address must use Bech32m checksum')
+ self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum')
+ self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version')
+ self.check_invalid(BECH32_INVALID_V0_SIZE, 'Invalid Bech32 v0 address data size')
+ self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 108)))
+ self.check_invalid(BECH32_ONE_ERROR, 'Invalid checksum', [9])
+ self.check_invalid(BECH32_TWO_ERRORS, 'Invalid checksum', [22, 43])
+ self.check_invalid(BECH32_ONE_ERROR_CAPITALS, 'Invalid checksum', [38])
+ self.check_invalid(BECH32_NO_SEPARATOR, 'Missing separator')
+ self.check_invalid(BECH32_INVALID_CHAR, 'Invalid Base 32 character', [8])
+ self.check_invalid(BECH32_MULTISIG_TWO_ERRORS, 'Invalid checksum', [19, 30])
+ self.check_invalid(BECH32_WRONG_VERSION, 'Invalid checksum', [5])
+
+ # Valid Bech32
+ self.check_valid(BECH32_VALID)
+ self.check_valid(BECH32_VALID_CAPITALS)
+ self.check_valid(BECH32_VALID_MULTISIG)
+
+ # Invalid Base58
+ self.check_invalid(BASE58_INVALID_PREFIX, 'Invalid prefix for Base58-encoded address')
+ self.check_invalid(BASE58_INVALID_CHECKSUM, 'Invalid checksum or length of Base58 address')
+ self.check_invalid(BASE58_INVALID_LENGTH, 'Invalid checksum or length of Base58 address')
+
+ # Valid Base58
+ self.check_valid(BASE58_VALID)
# Invalid address format
- info = node.validateaddress(INVALID_ADDRESS)
- assert not info['isvalid']
- assert_equal(info['error'], 'Invalid address format')
+ self.check_invalid(INVALID_ADDRESS, 'Invalid HRP or Base58 character in address')
+ self.check_invalid(INVALID_ADDRESS_2, 'Invalid HRP or Base58 character in address')
def test_getaddressinfo(self):
node = self.nodes[0]
assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
- assert_raises_rpc_error(-5, "Invalid prefix for Bech32 address", node.getaddressinfo, BECH32_INVALID_PREFIX)
+ assert_raises_rpc_error(-5, "Invalid HRP or Base58 character in address", node.getaddressinfo, BECH32_INVALID_PREFIX)
assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX)
- assert_raises_rpc_error(-5, "Invalid address format", node.getaddressinfo, INVALID_ADDRESS)
+ assert_raises_rpc_error(-5, "Invalid HRP or Base58 character in address", node.getaddressinfo, INVALID_ADDRESS)
def run_test(self):
self.test_validateaddress()
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index 9bc02d153e..f1c2537ef9 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the invalidateblock RPC."""
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index e32e562bce..b3abd9d236 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC misc output."""
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 28712fc89e..81a3cfee97 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC calls related to net.
@@ -81,7 +81,6 @@ class NetTest(BitcoinTestFramework):
# Create a few getpeerinfo last_block/last_transaction values.
self.wallet.send_self_transfer(from_node=self.nodes[0]) # Make a transaction so we can see it in the getpeerinfo results
self.generate(self.nodes[1], 1)
- self.sync_all()
time_now = int(time.time())
peer_info = [x.getpeerinfo() for x in self.nodes]
# Verify last_block and last_transaction keys/values.
diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py
index 2e526efd9a..91298937fd 100755
--- a/test/functional/rpc_preciousblock.py
+++ b/test/functional/rpc_preciousblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the preciousblock RPC."""
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index b132ac3d31..a8034849cc 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the Partially Signed Transaction RPCs.
@@ -31,7 +31,7 @@ class PSBTTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 3
self.extra_args = [
- ["-walletrbf=1"],
+ ["-walletrbf=1", "-addresstype=bech32", "-changetype=bech32"], #TODO: Remove address type restrictions once taproot has psbt extensions
["-walletrbf=0", "-changetype=legacy"],
[]
]
@@ -61,7 +61,6 @@ class PSBTTest(BitcoinTestFramework):
wonline.importaddress(offline_addr, "", False)
mining_node.sendtoaddress(address=offline_addr, amount=1.0)
self.generate(mining_node, nblocks=1)
- self.sync_blocks([mining_node, online_node])
# Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
utxos = wonline.listunspent(addresses=[offline_addr])
@@ -76,7 +75,6 @@ class PSBTTest(BitcoinTestFramework):
# Make sure we can mine the resulting transaction
txid = mining_node.sendrawtransaction(mining_node.finalizepsbt(signed_psbt)["hex"])
self.generate(mining_node, 1)
- self.sync_blocks([mining_node, online_node])
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
wonline.unloadwallet()
@@ -122,7 +120,9 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].walletpassphrase(passphrase="password", timeout=1000000)
# Sign the transaction and send
- signed_tx = self.nodes[0].walletprocesspsbt(psbtx)['psbt']
+ signed_tx = self.nodes[0].walletprocesspsbt(psbt=psbtx, finalize=False)['psbt']
+ finalized_tx = self.nodes[0].walletprocesspsbt(psbt=psbtx, finalize=True)['psbt']
+ assert signed_tx != finalized_tx
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
self.nodes[0].sendrawtransaction(final_tx)
@@ -162,7 +162,6 @@ class PSBTTest(BitcoinTestFramework):
signed_tx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])['hex']
txid = self.nodes[0].sendrawtransaction(signed_tx)
self.generate(self.nodes[0], 6)
- self.sync_all()
# Find the output pos
p2sh_pos = -1
@@ -321,7 +320,6 @@ class PSBTTest(BitcoinTestFramework):
txid1 = self.nodes[0].sendtoaddress(node1_addr, 13)
txid2 = self.nodes[0].sendtoaddress(node2_addr, 13)
blockhash = self.generate(self.nodes[0], 6)[0]
- self.sync_all()
vout1 = find_output(self.nodes[1], txid1, 13, blockhash=blockhash)
vout2 = find_output(self.nodes[2], txid2, 13, blockhash=blockhash)
@@ -349,7 +347,6 @@ class PSBTTest(BitcoinTestFramework):
finalized = self.nodes[0].finalizepsbt(combined)['hex']
self.nodes[0].sendrawtransaction(finalized)
self.generate(self.nodes[0], 6)
- self.sync_all()
# Test additional args in walletcreatepsbt
# Make sure both pre-included and funded inputs
@@ -544,7 +541,6 @@ class PSBTTest(BitcoinTestFramework):
txid4 = self.nodes[0].sendtoaddress(addr4, 5)
vout4 = find_output(self.nodes[0], txid4, 5)
self.generate(self.nodes[0], 6)
- self.sync_all()
psbt2 = self.nodes[1].createpsbt([{"txid":txid4, "vout":vout4}], {self.nodes[0].getnewaddress():Decimal('4.999')})
psbt2 = self.nodes[1].walletprocesspsbt(psbt2)['psbt']
psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
@@ -568,7 +564,6 @@ class PSBTTest(BitcoinTestFramework):
txid = self.nodes[0].sendtoaddress(addr, 7)
addrinfo = self.nodes[1].getaddressinfo(addr)
blockhash = self.generate(self.nodes[0], 6)[0]
- self.sync_all()
vout = find_output(self.nodes[0], txid, 7, blockhash=blockhash)
psbt = self.nodes[1].createpsbt([{"txid":txid, "vout":vout}], {self.nodes[0].getnewaddress("", "p2sh-segwit"):Decimal('6.999')})
analyzed = self.nodes[0].analyzepsbt(psbt)
@@ -628,7 +623,6 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(addr, 10)
self.generate(self.nodes[0], 6)
- self.sync_all()
ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index fc812340fa..96691b2686 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the rawtransaction RPCs.
@@ -75,14 +75,11 @@ class RawTransactionsTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Prepare some coins for multiple *rawtransaction commands")
self.generate(self.nodes[2], 1)
- self.sync_all()
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
- self.sync_all()
for amount in [1.5, 1.0, 5.0]:
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), amount)
self.sync_all()
self.generate(self.nodes[0], 5)
- self.sync_all()
self.getrawtransaction_tests()
self.createrawtransaction_tests()
@@ -98,13 +95,11 @@ class RawTransactionsTest(BitcoinTestFramework):
addr = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(addr, 10)
self.generate(self.nodes[0], 1)
- self.sync_all()
vout = find_vout_for_address(self.nodes[1], txid, addr)
rawTx = self.nodes[1].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): 9.999})
rawTxSigned = self.nodes[1].signrawtransactionwithwallet(rawTx)
txId = self.nodes[1].sendrawtransaction(rawTxSigned['hex'])
self.generate(self.nodes[0], 1)
- self.sync_all()
for n in [0, 3]:
self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex")
@@ -137,7 +132,6 @@ class RawTransactionsTest(BitcoinTestFramework):
# Make a tx by sending, then generate 2 blocks; block1 has the tx in it
tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
block1, block2 = self.generate(self.nodes[2], 2)
- self.sync_all()
for n in [0, 3]:
self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex, with blockhash")
# We should be able to get the raw transaction by providing the correct block
@@ -369,7 +363,6 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info("Test sendrawtransaction/testmempoolaccept with tx already in the chain")
self.generate(self.nodes[2], 1)
- self.sync_blocks()
for node in self.nodes:
testres = node.testmempoolaccept([rawTxSigned['hex']])[0]
assert_equal(testres['allowed'], False)
@@ -443,7 +436,6 @@ class RawTransactionsTest(BitcoinTestFramework):
txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
self.sync_all()
self.generate(self.nodes[0], 1)
- self.sync_all()
# node2 has both keys of the 2of2 ms addr, tx should affect the balance
assert_equal(self.nodes[2].getbalance(), bal + Decimal('1.20000000'))
@@ -465,7 +457,6 @@ class RawTransactionsTest(BitcoinTestFramework):
rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
self.sync_all()
self.generate(self.nodes[0], 1)
- self.sync_all()
# THIS IS AN INCOMPLETE FEATURE
# NODE2 HAS TWO OF THREE KEYS AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
@@ -488,7 +479,6 @@ class RawTransactionsTest(BitcoinTestFramework):
rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
self.sync_all()
self.generate(self.nodes[0], 1)
- self.sync_all()
assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx
# 2of2 test for combining transactions
@@ -508,7 +498,6 @@ class RawTransactionsTest(BitcoinTestFramework):
rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex'])
self.sync_all()
self.generate(self.nodes[0], 1)
- self.sync_all()
assert_equal(self.nodes[2].getbalance(), bal) # the funds of a 2of2 multisig tx should not be marked as spendable
@@ -533,7 +522,6 @@ class RawTransactionsTest(BitcoinTestFramework):
rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb)
self.sync_all()
self.generate(self.nodes[0], 1)
- self.sync_all()
assert_equal(self.nodes[0].getbalance(), bal + Decimal('50.00000000') + Decimal('2.19000000')) # block reward + tx
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
index ec8205acd5..8703bfab8e 100755
--- a/test/functional/rpc_scantxoutset.py
+++ b/test/functional/rpc_scantxoutset.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the scantxoutset rpc call."""
diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py
index 36873f964b..97354f480c 100755
--- a/test/functional/rpc_setban.py
+++ b/test/functional/rpc_setban.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the setban rpc call."""
diff --git a/test/functional/rpc_signer.py b/test/functional/rpc_signer.py
index 5c3722ef8f..f1107197c5 100755
--- a/test/functional/rpc_signer.py
+++ b/test/functional/rpc_signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2018 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test external signer.
diff --git a/test/functional/rpc_signmessagewithprivkey.py b/test/functional/rpc_signmessagewithprivkey.py
index 95beba8730..80555eab75 100755
--- a/test/functional/rpc_signmessagewithprivkey.py
+++ b/test/functional/rpc_signmessagewithprivkey.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test RPC commands for signing messages with private key."""
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index c519d0c7d1..e648040278 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test transaction signing using the signrawtransaction* RPCs."""
@@ -203,7 +203,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
self.nodes[0].sendtoaddress(p2sh_p2wsh_address["address"], 49.999)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Get the UTXO info from scantxoutset
unspent_output = self.nodes[1].scantxoutset('start', [p2sh_p2wsh_address['descriptor']])['unspents'][0]
spk = script_to_p2sh_p2wsh_script(p2sh_p2wsh_address['redeemScript']).hex()
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index 2aa3301b89..d04d05962f 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test gettxoutproof and verifytxoutproof RPCs."""
@@ -31,7 +31,6 @@ class MerkleBlockTest(BitcoinTestFramework):
# Add enough mature utxos to the wallet, so that all txs spend confirmed coins
self.generate(miniwallet, 5)
self.generate(self.nodes[0], COINBASE_MATURITY)
- self.sync_all()
chain_height = self.nodes[1].getblockcount()
assert_equal(chain_height, 105)
@@ -57,7 +56,6 @@ class MerkleBlockTest(BitcoinTestFramework):
tx3 = miniwallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=txin_spent)
txid3 = tx3['txid']
self.generate(self.nodes[0], 1)
- self.sync_all()
txid_spent = txin_spent["txid"]
txid_unspent = txid1 # Input was change from txid2, so txid1 should be unspent
diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py
index 6177970872..1a82d1fa41 100755
--- a/test/functional/rpc_uptime.py
+++ b/test/functional/rpc_uptime.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the RPC call related to the uptime command.
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index 89839c9bab..013522a5e1 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Encode and decode Bitcoin addresses.
diff --git a/test/functional/test_framework/bdb.py b/test/functional/test_framework/bdb.py
index d623bcdf6e..41886c09fd 100644
--- a/test/functional/test_framework/bdb.py
+++ b/test/functional/test_framework/bdb.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 5d0113465f..eaa193e357 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for manipulating blocks and transactions."""
diff --git a/test/functional/test_framework/coverage.py b/test/functional/test_framework/coverage.py
index ad8cfe5c9a..4fb4f8bb82 100644
--- a/test/functional/test_framework/coverage.py
+++ b/test/functional/test_framework/coverage.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for doing coverage analysis on the RPC interface.
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index 26526e35fa..e5dea66963 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -8,6 +8,7 @@ keys, and is trivially vulnerable to side channel attacks. Do not use for
anything but tests."""
import csv
import hashlib
+import hmac
import os
import random
import unittest
@@ -326,6 +327,16 @@ def generate_privkey():
"""Generate a valid random 32-byte private key."""
return random.randrange(1, SECP256K1_ORDER).to_bytes(32, 'big')
+def rfc6979_nonce(key):
+ """Compute signing nonce using RFC6979."""
+ v = bytes([1] * 32)
+ k = bytes([0] * 32)
+ k = hmac.new(k, v + b"\x00" + key, 'sha256').digest()
+ v = hmac.new(k, v, 'sha256').digest()
+ k = hmac.new(k, v + b"\x01" + key, 'sha256').digest()
+ v = hmac.new(k, v, 'sha256').digest()
+ return hmac.new(k, v, 'sha256').digest()
+
class ECKey():
"""A secp256k1 private key"""
@@ -368,15 +379,18 @@ class ECKey():
ret.compressed = self.compressed
return ret
- def sign_ecdsa(self, msg, low_s=True):
+ def sign_ecdsa(self, msg, low_s=True, rfc6979=False):
"""Construct a DER-encoded ECDSA signature with this key.
See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
ECDSA signer algorithm."""
assert(self.valid)
z = int.from_bytes(msg, 'big')
- # Note: no RFC6979, but a simple random nonce (some tests rely on distinct transactions for the same operation)
- k = random.randrange(1, SECP256K1_ORDER)
+ # Note: no RFC6979 by default, but a simple random nonce (some tests rely on distinct transactions for the same operation)
+ if rfc6979:
+ k = int.from_bytes(rfc6979_nonce(self.secret.to_bytes(32, 'big') + msg), 'big')
+ else:
+ k = random.randrange(1, SECP256K1_ORDER)
R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, k)]))
r = R[0] % SECP256K1_ORDER
s = (modinv(k, SECP256K1_ORDER) * (z + self.secret * r)) % SECP256K1_ORDER
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 65d90f8448..71ac5c5bfd 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2020 The Bitcoin Core developers
+# Copyright (c) 2010-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Bitcoin test framework primitive and message structures
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index b5f78e0cf3..174dc44a2a 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Linux network utilities.
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index 78c63b57a1..251d3d5eae 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2020 The Bitcoin Core developers
+# Copyright (c) 2010-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test objects for interacting with a bitcoind node over the p2p protocol.
@@ -89,6 +89,8 @@ P2P_SERVICES = NODE_NETWORK | NODE_WITNESS
P2P_SUBVERSION = "/python-p2p-tester:0.0.3/"
# Value for relay that this test framework sends in its `version` message
P2P_VERSION_RELAY = 1
+# Delay after receiving a tx inv before requesting transactions from non-preferred peers, in seconds
+NONPREF_PEER_TX_DELAY = 2
MESSAGEMAP = {
b"addr": msg_addr,
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 3c9b8a6e69..947a1f9808 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Functionality to build scripts, as well as signature hash functions.
@@ -619,16 +619,15 @@ def FindAndDelete(script, sig):
r += script[last_sop_idx:]
return CScript(r)
-def LegacySignatureHash(script, txTo, inIdx, hashtype):
- """Consensus-correct SignatureHash
+def LegacySignatureMsg(script, txTo, inIdx, hashtype):
+ """Preimage of the signature hash, if it exists.
- Returns (hash, err) to precisely match the consensus-critical behavior of
- the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity)
+ Returns either (None, err) to indicate error (which translates to sighash 1),
+ or (msg, None).
"""
- HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
if inIdx >= len(txTo.vin):
- return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin)))
+ return (None, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin)))
txtmp = CTransaction(txTo)
for txin in txtmp.vin:
@@ -645,7 +644,7 @@ def LegacySignatureHash(script, txTo, inIdx, hashtype):
elif (hashtype & 0x1f) == SIGHASH_SINGLE:
outIdx = inIdx
if outIdx >= len(txtmp.vout):
- return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout)))
+ return (None, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout)))
tmp = txtmp.vout[outIdx]
txtmp.vout = []
@@ -665,15 +664,27 @@ def LegacySignatureHash(script, txTo, inIdx, hashtype):
s = txtmp.serialize_without_witness()
s += struct.pack(b"<I", hashtype)
- hash = hash256(s)
+ return (s, None)
+
+def LegacySignatureHash(*args, **kwargs):
+ """Consensus-correct SignatureHash
+
+ Returns (hash, err) to precisely match the consensus-critical behavior of
+ the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity)
+ """
- return (hash, None)
+ HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ msg, err = LegacySignatureMsg(*args, **kwargs)
+ if msg is None:
+ return (HASH_ONE, err)
+ else:
+ return (hash256(msg), err)
# TODO: Allow cached hashPrevouts/hashSequence/hashOutputs to be provided.
# Performance optimization probably not necessary for python tests, however.
# Note that this corresponds to sigversion == 1 in EvalScript, which is used
# for version 0 witnesses.
-def SegwitV0SignatureHash(script, txTo, inIdx, hashtype, amount):
+def SegwitV0SignatureMsg(script, txTo, inIdx, hashtype, amount):
hashPrevouts = 0
hashSequence = 0
@@ -711,8 +722,10 @@ def SegwitV0SignatureHash(script, txTo, inIdx, hashtype, amount):
ss += ser_uint256(hashOutputs)
ss += struct.pack("<i", txTo.nLockTime)
ss += struct.pack("<I", hashtype)
+ return ss
- return hash256(ss)
+def SegwitV0SignatureHash(*args, **kwargs):
+ return hash256(SegwitV0SignatureMsg(*args, **kwargs))
class TestFrameworkScript(unittest.TestCase):
def test_bn2vch(self):
@@ -742,7 +755,22 @@ class TestFrameworkScript(unittest.TestCase):
for value in values:
self.assertEqual(CScriptNum.decode(CScriptNum.encode(CScriptNum(value))), value)
-def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT):
+def BIP341_sha_prevouts(txTo):
+ return sha256(b"".join(i.prevout.serialize() for i in txTo.vin))
+
+def BIP341_sha_amounts(spent_utxos):
+ return sha256(b"".join(struct.pack("<q", u.nValue) for u in spent_utxos))
+
+def BIP341_sha_scriptpubkeys(spent_utxos):
+ return sha256(b"".join(ser_string(u.scriptPubKey) for u in spent_utxos))
+
+def BIP341_sha_sequences(txTo):
+ return sha256(b"".join(struct.pack("<I", i.nSequence) for i in txTo.vin))
+
+def BIP341_sha_outputs(txTo):
+ return sha256(b"".join(o.serialize() for o in txTo.vout))
+
+def TaprootSignatureMsg(txTo, spent_utxos, hash_type, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT):
assert (len(txTo.vin) == len(spent_utxos))
assert (input_index < len(txTo.vin))
out_type = SIGHASH_ALL if hash_type == 0 else hash_type & 3
@@ -752,12 +780,12 @@ def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpa
ss += struct.pack("<i", txTo.nVersion)
ss += struct.pack("<I", txTo.nLockTime)
if in_type != SIGHASH_ANYONECANPAY:
- ss += sha256(b"".join(i.prevout.serialize() for i in txTo.vin))
- ss += sha256(b"".join(struct.pack("<q", u.nValue) for u in spent_utxos))
- ss += sha256(b"".join(ser_string(u.scriptPubKey) for u in spent_utxos))
- ss += sha256(b"".join(struct.pack("<I", i.nSequence) for i in txTo.vin))
+ ss += BIP341_sha_prevouts(txTo)
+ ss += BIP341_sha_amounts(spent_utxos)
+ ss += BIP341_sha_scriptpubkeys(spent_utxos)
+ ss += BIP341_sha_sequences(txTo)
if out_type == SIGHASH_ALL:
- ss += sha256(b"".join(o.serialize() for o in txTo.vout))
+ ss += BIP341_sha_outputs(txTo)
spend_type = 0
if annex is not None:
spend_type |= 1
@@ -783,7 +811,10 @@ def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpa
ss += bytes([0])
ss += struct.pack("<i", codeseparator_pos)
assert len(ss) == 175 - (in_type == SIGHASH_ANYONECANPAY) * 49 - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (annex is not None) * 32 + scriptpath * 37
- return TaggedHash("TapSighash", ss)
+ return ss
+
+def TaprootSignatureHash(*args, **kwargs):
+ return TaggedHash("TapSighash", TaprootSignatureMsg(*args, **kwargs))
def taproot_tree_helper(scripts):
if len(scripts) == 0:
@@ -805,20 +836,20 @@ def taproot_tree_helper(scripts):
h = TaggedHash("TapLeaf", bytes([version]) + ser_string(code))
if name is None:
return ([], h)
- return ([(name, version, code, bytes())], h)
+ return ([(name, version, code, bytes(), h)], h)
elif len(scripts) == 2 and callable(scripts[1]):
# Two entries, and the right one is a function
left, left_h = taproot_tree_helper(scripts[0:1])
right_h = scripts[1](left_h)
- left = [(name, version, script, control + right_h) for name, version, script, control in left]
+ left = [(name, version, script, control + right_h, leaf) for name, version, script, control, leaf in left]
right = []
else:
# Two or more entries: descend into each side
split_pos = len(scripts) // 2
left, left_h = taproot_tree_helper(scripts[0:split_pos])
right, right_h = taproot_tree_helper(scripts[split_pos:])
- left = [(name, version, script, control + right_h) for name, version, script, control in left]
- right = [(name, version, script, control + left_h) for name, version, script, control in right]
+ left = [(name, version, script, control + right_h, leaf) for name, version, script, control, leaf in left]
+ right = [(name, version, script, control + left_h, leaf) for name, version, script, control, leaf in right]
if right_h < left_h:
right_h, left_h = left_h, right_h
h = TaggedHash("TapBranch", left_h + right_h)
@@ -830,13 +861,14 @@ def taproot_tree_helper(scripts):
# - negflag: whether the pubkey in the scriptPubKey was negated from internal_pubkey+tweak*G (bool).
# - tweak: the tweak (32 bytes)
# - leaves: a dict of name -> TaprootLeafInfo objects for all known leaves
-TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,internal_pubkey,negflag,tweak,leaves")
+# - merkle_root: the script tree's Merkle root, or bytes() if no leaves are present
+TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,internal_pubkey,negflag,tweak,leaves,merkle_root,output_pubkey")
# A TaprootLeafInfo object has the following fields:
# - script: the leaf script (CScript or bytes)
# - version: the leaf version (0xc0 for BIP342 tapscript)
# - merklebranch: the merkle branch to use for this leaf (32*N bytes)
-TaprootLeafInfo = namedtuple("TaprootLeafInfo", "script,version,merklebranch")
+TaprootLeafInfo = namedtuple("TaprootLeafInfo", "script,version,merklebranch,leaf_hash")
def taproot_construct(pubkey, scripts=None):
"""Construct a tree of Taproot spending conditions
@@ -858,8 +890,8 @@ def taproot_construct(pubkey, scripts=None):
ret, h = taproot_tree_helper(scripts)
tweak = TaggedHash("TapTweak", pubkey + h)
tweaked, negated = tweak_add_pubkey(pubkey, tweak)
- leaves = dict((name, TaprootLeafInfo(script, version, merklebranch)) for name, version, script, merklebranch in ret)
- return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves)
+ leaves = dict((name, TaprootLeafInfo(script, version, merklebranch, leaf)) for name, version, script, merklebranch, leaf in ret)
+ return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves, h, tweaked)
def is_op_success(o):
return o == 0x50 or o == 0x62 or o == 0x89 or o == 0x8a or o == 0x8d or o == 0x8e or (o >= 0x7e and o <= 0x81) or (o >= 0x83 and o <= 0x86) or (o >= 0x95 and o <= 0x99) or (o >= 0xbb and o <= 0xfe)
diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py
index cbc4a560db..f7d8422eee 100755
--- a/test/functional/test_framework/script_util.py
+++ b/test/functional/test_framework/script_util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful Script constants and utils."""
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index b18c050e0a..6746fbf9f9 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Base class for RPC testing."""
@@ -101,7 +101,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.supports_cli = True
self.bind_to_localhost_only = True
self.parse_args()
- self.disable_syscall_sandbox = self.options.nosandbox
+ self.disable_syscall_sandbox = self.options.nosandbox or self.options.valgrind
self.default_wallet_name = "default_wallet" if self.options.descriptors else ""
self.wallet_data_filename = "wallet.dat"
# Optional list of wallet names that can be set in set_test_params to
@@ -188,7 +188,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
parser.add_argument("--perf", dest="perf", default=False, action="store_true",
help="profile running nodes with perf for the duration of the test")
parser.add_argument("--valgrind", dest="valgrind", default=False, action="store_true",
- help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown, valgrind 3.14 or later required")
+ help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown. valgrind 3.14 or later required. Forces --nosandbox.")
parser.add_argument("--randomseed", type=int,
help="set a random seed for deterministically reproducing a previous test run")
parser.add_argument('--timeout-factor', dest="timeout_factor", type=float, default=1.0, help='adjust test timeouts by a factor. Setting it to 0 disables all timeouts')
@@ -431,7 +431,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
n = self.nodes[node]
if wallet_name is not None:
n.createwallet(wallet_name=wallet_name, descriptors=self.options.descriptors, load_on_startup=True)
- n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase')
+ n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase', rescan=True)
def run_test(self):
"""Tests must override this method to define test logic"""
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index e8ff41a46d..269f2442a9 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Class for bitcoind node under test"""
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index ca1ffd48de..c3a9029d55 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Helpful routines for regression testing."""
@@ -269,6 +269,7 @@ def wait_until_helper(predicate, *, attempts=float('inf'), timeout=float('inf'),
raise AssertionError("Predicate {} not true after {} seconds".format(predicate_source, timeout))
raise RuntimeError('Unreachable')
+
def sha256sum_file(filename):
h = hashlib.sha256()
with open(filename, 'rb') as f:
@@ -445,6 +446,12 @@ def set_node_times(nodes, t):
node.setmocktime(t)
+def check_node_connections(*, node, num_in, num_out):
+ info = node.getnetworkinfo()
+ assert_equal(info["connections_in"], num_in)
+ assert_equal(info["connections_out"], num_out)
+
+
# Transaction/Block functions
#############################
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 5f0b573c6e..f724cb2af3 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""A limited-functionality wallet, which may replace a real wallet in tests"""
diff --git a/test/functional/test_framework/wallet_util.py b/test/functional/test_framework/wallet_util.py
index c307ded542..410d85cd8c 100755
--- a/test/functional/test_framework/wallet_util.py
+++ b/test/functional/test_framework/wallet_util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful util functions for testing the wallet"""
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 37fc549922..b9b4edf0ba 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Run regression test suite.
@@ -217,7 +217,8 @@ BASE_SCRIPTS = [
'rpc_getblockfilter.py',
'rpc_invalidateblock.py',
'feature_utxo_set_hash.py',
- 'feature_rbf.py',
+ 'feature_rbf.py --legacy-wallet',
+ 'feature_rbf.py --descriptors',
'mempool_packages.py',
'mempool_package_onemore.py',
'rpc_createmultisig.py --legacy-wallet',
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index cebaa02524..afe4dba7b4 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test bitcoin-wallet."""
@@ -70,8 +70,8 @@ class ToolWalletTest(BitcoinTestFramework):
def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0):
wallet_name = self.default_wallet_name if name == "" else name
- output_types = 3 # p2pkh, p2sh, segwit
if self.options.descriptors:
+ output_types = 4 # p2pkh, p2sh, segwit, bech32m
return textwrap.dedent('''\
Wallet info
===========
@@ -85,6 +85,7 @@ class ToolWalletTest(BitcoinTestFramework):
Address Book: %d
''' % (wallet_name, keypool * output_types, transactions, address))
else:
+ output_types = 3 # p2pkh, p2sh, segwit. Legacy wallets do not support bech32m.
return textwrap.dedent('''\
Wallet info
===========
@@ -298,8 +299,8 @@ class ToolWalletTest(BitcoinTestFramework):
assert_equal(1000, out['keypoolsize_hd_internal'])
assert_equal(True, 'hdseedid' in out)
else:
- assert_equal(3000, out['keypoolsize'])
- assert_equal(3000, out['keypoolsize_hd_internal'])
+ assert_equal(4000, out['keypoolsize'])
+ assert_equal(4000, out['keypoolsize_hd_internal'])
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
assert_equal(timestamp_before, timestamp_after)
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index edb3779f82..27d9d8da88 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the abandontransaction RPC.
@@ -30,7 +30,6 @@ class AbandonConflictTest(BitcoinTestFramework):
def run_test(self):
self.generate(self.nodes[1], COINBASE_MATURITY)
- self.sync_blocks()
balance = self.nodes[0].getbalance()
txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 7a448e8590..eb6e497951 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that the wallet can send and receive using all combinations of address types.
@@ -121,6 +121,12 @@ class AddressTypeTest(BitcoinTestFramework):
assert_equal(info['witness_version'], 0)
assert_equal(len(info['witness_program']), 40)
assert 'pubkey' in info
+ elif not multisig and typ == "bech32m":
+ # P2TR single sig
+ assert info["isscript"]
+ assert info["iswitness"]
+ assert_equal(info["witness_version"], 1)
+ assert_equal(len(info["witness_program"]), 64)
elif typ == 'legacy':
# P2SH-multisig
assert info['isscript']
@@ -221,7 +227,6 @@ class AddressTypeTest(BitcoinTestFramework):
# Mine 101 blocks on node5 to bring nodes out of IBD and make sure that
# no coinbases are maturing for the nodes-under-test during the test
self.generate(self.nodes[5], COINBASE_MATURITY + 1)
- self.sync_blocks()
uncompressed_1 = "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee"
uncompressed_2 = "047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77"
@@ -306,7 +311,6 @@ class AddressTypeTest(BitcoinTestFramework):
# node5 collects fee and block subsidy to keep accounting simple
self.generate(self.nodes[5], 1)
- self.sync_blocks()
# Verify that the receiving wallet contains a UTXO with the expected address, and expected descriptor
for n, to_node in enumerate(range(from_node, from_node + 4)):
@@ -336,25 +340,36 @@ class AddressTypeTest(BitcoinTestFramework):
# Fund node 4:
self.nodes[5].sendtoaddress(self.nodes[4].getnewaddress(), Decimal("1"))
self.generate(self.nodes[5], 1)
- self.sync_blocks()
assert_equal(self.nodes[4].getbalance(), 1)
self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output (unless changetype is set otherwise):")
self.test_change_output_type(0, [to_address_bech32_1], 'legacy')
- self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:")
- self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
- self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
+ if self.options.descriptors:
+ self.log.info("Nodes with addresstype=p2sh-segwit only use a bech32m change output if any destination address is bech32:")
+ self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
+ self.test_change_output_type(1, [to_address_bech32_1], 'bech32m')
+ self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32m')
+ self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32m')
+ else:
+ self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:")
+ self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
+ self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
self.log.info("Nodes with change_type=bech32 always use a P2WPKH change output:")
self.test_change_output_type(2, [to_address_bech32_1], 'bech32')
self.test_change_output_type(2, [to_address_p2sh], 'bech32')
- self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(3, [to_address_p2sh], 'bech32')
+ if self.options.descriptors:
+ self.log.info("Nodes with addresstype=bech32 always use either a bech32 or bech32m change output (unless changetype is set otherwise):")
+ self.test_change_output_type(3, [to_address_bech32_1], 'bech32m')
+ self.test_change_output_type(3, [to_address_p2sh], 'bech32')
+ else:
+ self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):")
+ self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(3, [to_address_p2sh], 'bech32')
self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')
self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')
@@ -373,10 +388,9 @@ class AddressTypeTest(BitcoinTestFramework):
self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32')
if self.options.descriptors:
- self.log.info("Descriptor wallets do not have bech32m addresses by default yet")
- # TODO: Remove this when they do
- assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getnewaddress, "", "bech32m")
- assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getrawchangeaddress, "bech32m")
+ self.log.info("Descriptor wallets have bech32m addresses")
+ self.test_address(4, self.nodes[4].getnewaddress("", "bech32m"), multisig=False, typ="bech32m")
+ self.test_address(4, self.nodes[4].getrawchangeaddress("bech32m"), multisig=False, typ="bech32m")
else:
self.log.info("Legacy wallets cannot make bech32m addresses")
assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getnewaddress, "", "bech32m")
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index 12357e2d63..dc823c2c60 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the avoid_reuse and setwalletflag features."""
@@ -80,7 +80,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.test_immutable()
self.generate(self.nodes[0], 110)
- self.sync_all()
self.test_change_remains_change(self.nodes[1])
reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
self.test_sending_from_reused_address_without_avoid_reuse()
@@ -175,7 +174,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(fundaddr, 10)
self.generate(self.nodes[0], 1)
- self.sync_all()
# listunspent should show 1 single, unused 10 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
@@ -186,7 +184,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[1].sendtoaddress(retaddr, 5)
self.generate(self.nodes[0], 1)
- self.sync_all()
# listunspent should show 1 single, unused 5 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
@@ -195,7 +192,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(fundaddr, 10)
self.generate(self.nodes[0], 1)
- self.sync_all()
# listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
@@ -229,7 +225,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(fundaddr, 10)
self.generate(self.nodes[0], 1)
- self.sync_all()
# listunspent should show 1 single, unused 10 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
@@ -238,7 +233,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[1].sendtoaddress(retaddr, 5)
self.generate(self.nodes[0], 1)
- self.sync_all()
# listunspent should show 1 single, unused 5 btc output
assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
@@ -260,7 +254,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(new_fundaddr, 10)
self.generate(self.nodes[0], 1)
- self.sync_all()
# listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
@@ -303,7 +296,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(new_addr, 1)
self.generate(self.nodes[0], 1)
- self.sync_all()
# send transaction that should not use all the available outputs
# per the current coin selection algorithm
@@ -335,7 +327,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(new_addr, 1)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Sending a transaction that is smaller than each one of the
# available outputs
@@ -364,7 +355,6 @@ class AvoidReuseTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(new_addr, 1)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Sending a transaction that needs to use the full groups
# of 100 inputs but also the incomplete group of 2 inputs.
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index a07c28c8a4..932df4fbff 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet backup features.
@@ -89,7 +89,6 @@ class WalletBackupTest(BitcoinTestFramework):
# Must sync mempools before mining.
self.sync_mempools()
self.generate(self.nodes[3], 1)
- self.sync_blocks()
# As above, this mirrors the original bash test.
def start_three(self, args=()):
@@ -131,13 +130,9 @@ class WalletBackupTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Generating initial blockchain")
self.generate(self.nodes[0], 1)
- self.sync_blocks()
self.generate(self.nodes[1], 1)
- self.sync_blocks()
self.generate(self.nodes[2], 1)
- self.sync_blocks()
self.generate(self.nodes[3], COINBASE_MATURITY)
- self.sync_blocks()
assert_equal(self.nodes[0].getbalance(), 50)
assert_equal(self.nodes[1].getbalance(), 50)
@@ -166,7 +161,6 @@ class WalletBackupTest(BitcoinTestFramework):
# Generate 101 more blocks, so any fees paid mature
self.generate(self.nodes[3], COINBASE_MATURITY + 1)
- self.sync_all()
balance0 = self.nodes[0].getbalance()
balance1 = self.nodes[1].getbalance()
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index 470cd9f34c..0cfbefb719 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet balance RPC methods."""
@@ -71,10 +71,8 @@ class WalletTest(BitcoinTestFramework):
self.log.info("Mining blocks ...")
self.generate(self.nodes[0], 1)
- self.sync_all()
self.generate(self.nodes[1], 1)
self.generatetoaddress(self.nodes[1], COINBASE_MATURITY + 1, ADDRESS_WATCHONLY)
- self.sync_all()
if not self.options.descriptors:
# Tests legacy watchonly behavior which is not present (and does not need to be tested) in descriptor wallets
@@ -197,7 +195,6 @@ class WalletTest(BitcoinTestFramework):
test_balances(fee_node_1=Decimal('0.02'))
self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY)
- self.sync_all()
# balances are correct after the transactions are confirmed
balance_node0 = Decimal('69.99') # node 1's send plus change from node 0's send
@@ -211,7 +208,6 @@ class WalletTest(BitcoinTestFramework):
txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), Decimal('29.97'), [Decimal('0.01')])
self.nodes[1].sendrawtransaction(txs[0]['hex'])
self.generatetoaddress(self.nodes[1], 2, ADDRESS_WATCHONLY)
- self.sync_all()
# getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
# TODO: fix getbalance tracking of coin spentness depth
@@ -258,7 +254,6 @@ class WalletTest(BitcoinTestFramework):
# Now confirm tx_replace
block_reorg = self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY)[0]
- self.sync_all()
assert_equal(self.nodes[0].getbalance(minconf=0), total_amount)
self.log.info('Put txs back into mempool of node 1 (not node 0)')
@@ -274,7 +269,6 @@ class WalletTest(BitcoinTestFramework):
self.sync_blocks()
self.nodes[1].sendrawtransaction(tx_orig)
self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY)
- self.sync_all()
assert_equal(self.nodes[0].getbalance(minconf=0), total_amount + 1) # The reorg recovered our fee of 1 coin
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 3839360eda..69f9df57d8 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet."""
@@ -342,7 +342,6 @@ class WalletTest(BitcoinTestFramework):
self.sync_all()
self.generate(self.nodes[1], 1) # mine a block
- self.sync_all()
unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output
found = False
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 063211d5c3..f6843d597d 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the bumpfee RPC.
@@ -24,7 +24,6 @@ from test_framework.blocktools import (
)
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
- tx_from_hex,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -62,7 +61,6 @@ class BumpFeeTest(BitcoinTestFramework):
def clear_mempool(self):
# Clear mempool between subtests. The subtests may only depend on chainstate (utxos)
self.generate(self.nodes[1], 1)
- self.sync_all()
def run_test(self):
# Encrypt wallet for test_locked_wallet_fails test
@@ -75,12 +73,10 @@ class BumpFeeTest(BitcoinTestFramework):
# fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)
self.log.info("Mining blocks...")
self.generate(peer_node, 110)
- self.sync_all()
for _ in range(25):
peer_node.sendtoaddress(rbf_node_address, 0.001)
self.sync_all()
self.generate(peer_node, 1)
- self.sync_all()
assert_equal(rbf_node.getbalance(), Decimal("0.025"))
self.log.info("Running tests")
@@ -444,7 +440,6 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
funding_address2 = watcher.getnewaddress(address_type='bech32')
peer_node.sendmany("", {funding_address1: 0.001, funding_address2: 0.001})
self.generate(peer_node, 1)
- self.sync_all()
# Create single-input PSBT for transaction to be bumped
psbt = watcher.walletcreatefundedpsbt([], {dest_address: 0.0005}, 0, {"fee_rate": 1}, True)['psbt']
@@ -592,13 +587,10 @@ def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")):
def submit_block_with_tx(node, tx):
- ctx = tx_from_hex(tx)
tip = node.getbestblockhash()
height = node.getblockcount() + 1
block_time = node.getblockheader(tip)["mediantime"] + 1
- block = create_block(int(tip, 16), create_coinbase(height), block_time)
- block.vtx.append(ctx)
- block.hashMerkleRoot = block.calc_merkle_root()
+ block = create_block(int(tip, 16), create_coinbase(height), block_time, txlist=[tx])
add_witness_commitment(block)
block.solve()
node.submitblock(block.serialize().hex())
diff --git a/test/functional/wallet_coinbase_category.py b/test/functional/wallet_coinbase_category.py
index 3c7abd0800..5a6b6cee59 100755
--- a/test/functional/wallet_coinbase_category.py
+++ b/test/functional/wallet_coinbase_category.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test coinbase transactions return the correct categories.
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index 00ee08002e..a213a261ef 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index d806f8f6d2..4416a9655f 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test createwallet arguments.
@@ -146,7 +146,7 @@ class CreateWalletTest(BitcoinTestFramework):
w6.keypoolrefill(1)
# There should only be 1 key for legacy, 3 for descriptors
walletinfo = w6.getwalletinfo()
- keys = 3 if self.options.descriptors else 1
+ keys = 4 if self.options.descriptors else 1
assert_equal(walletinfo['keypoolsize'], keys)
assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
# Allow empty passphrase, but there should be a warning
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index 4ec44a8a6c..e47d021210 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test descriptor wallet function."""
@@ -37,12 +37,12 @@ class WalletDescriptorTest(BitcoinTestFramework):
self.log.info("Making a descriptor wallet")
self.nodes[0].createwallet(wallet_name="desc1", descriptors=True)
- # A descriptor wallet should have 100 addresses * 3 types = 300 keys
+ # A descriptor wallet should have 100 addresses * 4 types = 400 keys
self.log.info("Checking wallet info")
wallet_info = self.nodes[0].getwalletinfo()
assert_equal(wallet_info['format'], 'sqlite')
- assert_equal(wallet_info['keypoolsize'], 300)
- assert_equal(wallet_info['keypoolsize_hd_internal'], 300)
+ assert_equal(wallet_info['keypoolsize'], 400)
+ assert_equal(wallet_info['keypoolsize_hd_internal'], 400)
assert 'keypoololdest' not in wallet_info
# Check that getnewaddress works
diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py
index d0043e9bbb..2c7996ca6b 100755
--- a/test/functional/wallet_disable.py
+++ b/test/functional/wallet_disable.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2020 The Bitcoin Core developers
+# Copyright (c) 2015-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test a node with the -disablewallet option.
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index 06460e17d2..9f0d666270 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the dumpwallet RPC."""
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index 674c37dc73..acd92097ff 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py
index 802fed6e7d..9052bc7f7f 100755
--- a/test/functional/wallet_groups.py
+++ b/test/functional/wallet_groups.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet group functionality."""
@@ -46,7 +46,6 @@ class WalletGroupTest(BitcoinTestFramework):
[self.nodes[0].sendtoaddress(addr, 0.5) for addr in addrs]
self.generate(self.nodes[0], 1)
- self.sync_all()
# For each node, send 0.2 coins back to 0;
# - node[1] should pick one 0.5 UTXO and leave the rest
@@ -109,13 +108,24 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(input_addrs[0], input_addrs[1])
# Node 2 enforces avoidpartialspends so needs no checking here
+ if self.options.descriptors:
+ # Descriptor wallets will use Taproot change by default which has different fees
+ tx4_ungrouped_fee = 3060
+ tx4_grouped_fee = 4400
+ tx5_6_ungrouped_fee = 5760
+ tx5_6_grouped_fee = 8480
+ else:
+ tx4_ungrouped_fee = 2820
+ tx4_grouped_fee = 4160
+ tx5_6_ungrouped_fee = 5520
+ tx5_6_grouped_fee = 8240
+
self.log.info("Test wallet option maxapsfee")
addr_aps = self.nodes[3].getnewaddress()
self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.generate(self.nodes[0], 1)
- self.sync_all()
- with self.nodes[3].assert_debug_log(['Fee non-grouped = 2820, grouped = 4160, using grouped']):
+ with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx4_ungrouped_fee}, grouped = {tx4_grouped_fee}, using grouped']):
txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
tx4 = self.nodes[3].getrawtransaction(txid4, True)
# tx4 should have 2 inputs and 2 outputs although one output would
@@ -126,8 +136,7 @@ class WalletGroupTest(BitcoinTestFramework):
addr_aps2 = self.nodes[3].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
self.generate(self.nodes[0], 1)
- self.sync_all()
- with self.nodes[3].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using non-grouped']):
+ with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using non-grouped']):
txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
tx5 = self.nodes[3].getrawtransaction(txid5, True)
# tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
@@ -140,8 +149,7 @@ class WalletGroupTest(BitcoinTestFramework):
addr_aps3 = self.nodes[4].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
self.generate(self.nodes[0], 1)
- self.sync_all()
- with self.nodes[4].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using grouped']):
+ with self.nodes[4].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using grouped']):
txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
tx6 = self.nodes[4].getrawtransaction(txid6, True)
# tx6 should have 5 inputs and 2 outputs
@@ -163,7 +171,6 @@ class WalletGroupTest(BitcoinTestFramework):
signed_tx = self.nodes[0].signrawtransactionwithwallet(funded_tx['hex'])
self.nodes[0].sendrawtransaction(signed_tx['hex'])
self.generate(self.nodes[0], 1)
- self.sync_all()
# Check that we can create a transaction that only requires ~100 of our
# utxos, without pulling in all outputs and creating a transaction that
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index f54ae89c04..d78afb4212 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test Hierarchical Deterministic wallet function."""
@@ -136,7 +136,7 @@ class WalletHDTest(BitcoinTestFramework):
keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['address'])['hdkeypath']
if self.options.descriptors:
- assert_equal(keypath[0:14], "m/84'/1'/0'/1/")
+ assert_equal(keypath[0:14], "m/86'/1'/0'/1/")
else:
assert_equal(keypath[0:7], "m/0'/1'")
@@ -229,7 +229,6 @@ class WalletHDTest(BitcoinTestFramework):
txid = self.nodes[0].sendtoaddress(addr, 1)
origin_rpc.sendrawtransaction(self.nodes[0].gettransaction(txid)['hex'])
self.generate(self.nodes[0], 1)
- self.sync_blocks()
origin_rpc.gettransaction(txid)
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', restore_rpc.gettransaction, txid)
out_of_kp_txid = txid
@@ -240,7 +239,6 @@ class WalletHDTest(BitcoinTestFramework):
txid = self.nodes[0].sendtoaddress(last_addr, 1)
origin_rpc.sendrawtransaction(self.nodes[0].gettransaction(txid)['hex'])
self.generate(self.nodes[0], 1)
- self.sync_blocks()
origin_rpc.gettransaction(txid)
restore_rpc.gettransaction(txid)
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', restore_rpc.gettransaction, out_of_kp_txid)
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 6f9cd2e80f..d9acc8cea5 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test wallet import RPCs.
@@ -189,7 +189,6 @@ class ImportRescanTest(BitcoinTestFramework):
self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] + TIMESTAMP_WINDOW + 1,
)
self.generate(self.nodes[0], 1)
- self.sync_all()
# For each variation of wallet key import, invoke the import RPC and
# check the results from getbalance and listtransactions.
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index fc9eac1d74..ac74ff2484 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the importdescriptors RPC.
@@ -53,7 +53,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
result = wrpc.importdescriptors([req])
observed_warnings = []
if 'warnings' in result[0]:
- observed_warnings = result[0]['warnings']
+ observed_warnings = result[0]['warnings']
assert_equal("\n".join(sorted(warnings)), "\n".join(sorted(observed_warnings)))
assert_equal(result[0]['success'], success)
if error_code is not None:
@@ -406,7 +406,6 @@ class ImportDescriptorsTest(BitcoinTestFramework):
ismine=True)
txid = w0.sendtoaddress(address, 49.99995540)
self.generatetoaddress(self.nodes[0], 6, w0.getnewaddress())
- self.sync_blocks()
tx = wpriv.createrawtransaction([{"txid": txid, "vout": 0}], {w0.getnewaddress(): 49.999})
signed_tx = wpriv.signrawtransactionwithwallet(tx)
w1.sendrawtransaction(signed_tx['hex'])
@@ -452,12 +451,10 @@ class ImportDescriptorsTest(BitcoinTestFramework):
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000)
txid = w0.sendtoaddress(addr, 10)
self.generate(self.nodes[0], 6)
- self.sync_all()
send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8)
decoded = wmulti_priv.gettransaction(txid=send_txid, verbose=True)['decoded']
assert_equal(len(decoded['vin'][0]['txinwitness']), 4)
self.generate(self.nodes[0], 6)
- self.sync_all()
self.nodes[1].createwallet(wallet_name="wmulti_pub", disable_private_keys=True, blank=True, descriptors=True)
wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub")
@@ -495,7 +492,6 @@ class ImportDescriptorsTest(BitcoinTestFramework):
vout2 = find_vout_for_address(self.nodes[0], txid2, addr2)
self.generate(self.nodes[0], 6)
- self.sync_all()
assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance())
# Make sure that descriptor wallets containing multiple xpubs in a single descriptor load correctly
@@ -583,7 +579,6 @@ class ImportDescriptorsTest(BitcoinTestFramework):
addr = wmulti_priv_big.getnewaddress()
w0.sendtoaddress(addr, 10)
self.generate(self.nodes[0], 1)
- self.sync_all()
# It is standard and would relay.
txid = wmulti_priv_big.sendtoaddress(w0.getnewaddress(), 9.999)
decoded = wmulti_priv_big.gettransaction(txid=txid, verbose=True)['decoded']
@@ -618,7 +613,6 @@ class ImportDescriptorsTest(BitcoinTestFramework):
addr = multi_priv_big.getnewaddress("", "legacy")
w0.sendtoaddress(addr, 10)
self.generate(self.nodes[0], 6)
- self.sync_all()
# It is standard and would relay.
txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "", True)
decoded = multi_priv_big.gettransaction(txid=txid, verbose=True)['decoded']
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 8289c6b8ce..436711669e 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the importmulti RPC.
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 74c5100f40..cdb5823109 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the importprunedfunds and removeprunedfunds RPCs."""
@@ -27,8 +27,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.log.info("Mining blocks...")
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
- self.sync_all()
-
# address
address1 = self.nodes[0].getnewaddress()
# pubkey
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 5807a92b9d..54c47511a9 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet keypool and interaction with wallet encryption/locking."""
@@ -87,8 +87,8 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].walletlock()
wi = nodes[0].getwalletinfo()
if self.options.descriptors:
- assert_equal(wi['keypoolsize_hd_internal'], 18)
- assert_equal(wi['keypoolsize'], 18)
+ assert_equal(wi['keypoolsize_hd_internal'], 24)
+ assert_equal(wi['keypoolsize'], 24)
else:
assert_equal(wi['keypoolsize_hd_internal'], 6)
assert_equal(wi['keypoolsize'], 6)
@@ -132,8 +132,8 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].keypoolrefill(100)
wi = nodes[0].getwalletinfo()
if self.options.descriptors:
- assert_equal(wi['keypoolsize_hd_internal'], 300)
- assert_equal(wi['keypoolsize'], 300)
+ assert_equal(wi['keypoolsize_hd_internal'], 400)
+ assert_equal(wi['keypoolsize'], 400)
else:
assert_equal(wi['keypoolsize_hd_internal'], 100)
assert_equal(wi['keypoolsize'], 100)
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index f730f82397..4c965b7160 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test HD Wallet keypool restore function.
@@ -66,7 +66,6 @@ class KeypoolRestoreTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1)
self.nodes[0].sendtoaddress(addr_extpool, 5)
self.generate(self.nodes[0], 1)
- self.sync_blocks()
self.log.info("Restart node with wallet backup")
self.stop_node(idx)
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index 150f2b341e..c29b02e661 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2020 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test label RPCs.
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index 436bbdcfcc..202ef92887 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -43,9 +43,9 @@ class ListDescriptorsTest(BitcoinTestFramework):
node.createwallet(wallet_name='w3', descriptors=True)
result = node.get_wallet_rpc('w3').listdescriptors()
assert_equal("w3", result['wallet_name'])
- assert_equal(6, len(result['descriptors']))
- assert_equal(6, len([d for d in result['descriptors'] if d['active']]))
- assert_equal(3, len([d for d in result['descriptors'] if d['internal']]))
+ assert_equal(8, len(result['descriptors']))
+ assert_equal(8, len([d for d in result['descriptors'] if d['active']]))
+ assert_equal(4, len([d for d in result['descriptors'] if d['internal']]))
for item in result['descriptors']:
assert item['desc'] != ''
assert item['next'] == 0
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
index 975bf9a84b..42a2685a0f 100755
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listreceivedbyaddress RPC."""
@@ -25,7 +25,6 @@ class ReceivedByTest(BitcoinTestFramework):
def run_test(self):
# Generate block to get out of IBD
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# save the number of coinbase reward addresses so far
num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))
@@ -44,7 +43,6 @@ class ReceivedByTest(BitcoinTestFramework):
True)
# Bury Tx under 10 block so it will be returned by listreceivedbyaddress
self.generate(self.nodes[1], 10)
- self.sync_all()
assert_array_result(self.nodes[1].listreceivedbyaddress(),
{"address": addr},
{"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]})
@@ -79,7 +77,6 @@ class ReceivedByTest(BitcoinTestFramework):
other_addr = self.nodes[1].getnewaddress()
txid2 = self.nodes[0].sendtoaddress(other_addr, 0.1)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Same test as above should still pass
expected = {"address": addr, "label": "", "amount": Decimal("0.1"), "confirmations": 11, "txids": [txid, ]}
res = self.nodes[1].listreceivedbyaddress(0, True, True, addr)
@@ -116,7 +113,6 @@ class ReceivedByTest(BitcoinTestFramework):
# Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress
self.generate(self.nodes[1], 10)
- self.sync_all()
balance = self.nodes[1].getreceivedbyaddress(addr)
assert_equal(balance, Decimal("0.1"))
@@ -145,7 +141,6 @@ class ReceivedByTest(BitcoinTestFramework):
assert_equal(balance, balance_by_label)
self.generate(self.nodes[1], 10)
- self.sync_all()
# listreceivedbylabel should return updated received list
assert_array_result(self.nodes[1].listreceivedbylabel(),
{"label": label},
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index 815e3e6298..fc06565983 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listsinceblock RPC."""
@@ -31,7 +31,6 @@ class ListSinceBlockTest(BitcoinTestFramework):
# only one connection. (See fPreferredDownload in net_processing)
self.connect_nodes(1, 2)
self.generate(self.nodes[2], COINBASE_MATURITY + 1)
- self.sync_all()
self.test_no_blockhash()
self.test_invalid_blockhash()
@@ -198,7 +197,6 @@ class ListSinceBlockTest(BitcoinTestFramework):
address = key_to_p2wpkh(eckey.get_pubkey().get_bytes())
self.nodes[2].sendtoaddress(address, 10)
self.generate(self.nodes[2], 6)
- self.sync_all()
self.nodes[2].importprivkey(privkey)
utxos = self.nodes[2].listunspent()
utxo = [u for u in utxos if u["address"] == address][0]
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 269ce6925d..8fd15a164c 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listtransactions API."""
@@ -94,7 +94,6 @@ class ListTransactionsTest(BitcoinTestFramework):
self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True)
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
self.generate(self.nodes[1], 1)
- self.sync_all()
assert_equal(len(self.nodes[0].listtransactions(label="watchonly", include_watchonly=True)), 1)
assert_equal(len(self.nodes[0].listtransactions(dummy="watchonly", include_watchonly=True)), 1)
assert len(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=False)) == 0
diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py
index 64799fccda..2b565db137 100755
--- a/test/functional/wallet_multisig_descriptor_psbt.py
+++ b/test/functional/wallet_multisig_descriptor_psbt.py
@@ -111,7 +111,6 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
self.log.info("Send funds to the resulting multisig receiving address...")
coordinator_wallet.sendtoaddress(multisig_receiving_address, deposit_amount)
self.generate(self.nodes[0], 1)
- self.sync_all()
for participant in participants["multisigs"]:
assert_approx(participant.getbalance(), deposit_amount, vspan=0.001)
@@ -137,7 +136,6 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
self.log.info("Check that balances are correct after the transaction has been included in a block.")
self.generate(self.nodes[0], 1)
- self.sync_all()
assert_approx(participants["multisigs"][0].getbalance(), deposit_amount - value, vspan=0.001)
assert_equal(participants["signers"][self.N - 1].getbalance(), value)
@@ -154,7 +152,6 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
self.log.info("Check that balances are correct after the transaction has been included in a block.")
self.generate(self.nodes[0], 1)
- self.sync_all()
assert_approx(participants["multisigs"][0].getbalance(), deposit_amount - (value * 2), vspan=0.001)
assert_equal(participants["signers"][self.N - 1].getbalance(), value * 2)
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 1ed887191b..0b868dde6c 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test multiwallet.
diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py
index ff1d1bd49b..7295db4653 100755
--- a/test/functional/wallet_orphanedreward.py
+++ b/test/functional/wallet_orphanedreward.py
@@ -26,12 +26,10 @@ class OrphanedBlockRewardTest(BitcoinTestFramework):
# it later.
self.sync_blocks()
blk = self.generate(self.nodes[1], 1)[0]
- self.sync_blocks()
# Let the block reward mature and send coins including both
# the existing balance and the block reward.
self.generate(self.nodes[0], 150)
- self.sync_blocks()
assert_equal(self.nodes[1].getbalance(), 10 + 25)
txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 30)
@@ -39,7 +37,6 @@ class OrphanedBlockRewardTest(BitcoinTestFramework):
# from the wallet can still be spent.
self.nodes[0].invalidateblock(blk)
self.generate(self.nodes[0], 152)
- self.sync_blocks()
# Without the following abandontransaction call, the coins are
# not considered available yet.
assert_equal(self.nodes[1].getbalances()["mine"], {
diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py
index 9a86ede5f9..f2bdb114b7 100755
--- a/test/functional/wallet_reorgsrestore.py
+++ b/test/functional/wallet_reorgsrestore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -33,7 +33,6 @@ class ReorgsRestoreTest(BitcoinTestFramework):
# Send a tx from which to conflict outputs later
txid_conflict_from = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
self.generate(self.nodes[0], 1)
- self.sync_blocks()
# Disconnect node1 from others to reorg its chain later
self.disconnect_nodes(0, 1)
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 1e0c4f2883..5aae2c813a 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that the wallet resends transactions periodically."""
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index ec8a4d33a3..d77d554baa 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2020 The Bitcoin Core developers
+# Copyright (c) 2020-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the send RPC command."""
@@ -246,7 +246,6 @@ class WalletSendTest(BitcoinTestFramework):
w0.sendtoaddress(a2_receive, 10) # fund w3
self.generate(self.nodes[0], 1)
- self.sync_blocks()
if not self.options.descriptors:
# w4 has private keys enabled, but only contains watch-only keys (from w2)
@@ -265,7 +264,6 @@ class WalletSendTest(BitcoinTestFramework):
w0.sendtoaddress(a2_receive, 10) # fund w4
self.generate(self.nodes[0], 1)
- self.sync_blocks()
self.log.info("Send to address...")
self.test_send(from_wallet=w0, to_wallet=w1, amount=1)
@@ -502,7 +500,6 @@ class WalletSendTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(addr, 10)
self.nodes[0].sendtoaddress(ext_wallet.getnewaddress(), 10)
self.generate(self.nodes[0], 6)
- self.sync_all()
ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
# An external input without solving data should result in an error
diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py
index c6c1cc8784..6dadc57b1a 100755
--- a/test/functional/wallet_signer.py
+++ b/test/functional/wallet_signer.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2018 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test external signer.
@@ -112,7 +112,6 @@ class WalletSignerTest(BitcoinTestFramework):
self.log.info('Prepare mock PSBT')
self.nodes[0].sendtoaddress(address1, 1)
self.generate(self.nodes[0], 1)
- self.sync_all()
# Load private key into wallet to generate a signed PSBT for the mock
self.nodes[1].createwallet(wallet_name="mock", disable_private_keys=False, blank=True, descriptors=True)
diff --git a/test/functional/wallet_signmessagewithaddress.py b/test/functional/wallet_signmessagewithaddress.py
index bf6f95e3f1..74a8f2eef2 100755
--- a/test/functional/wallet_signmessagewithaddress.py
+++ b/test/functional/wallet_signmessagewithaddress.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test Wallet commands for signing and verifying messages."""
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index b22c171374..17eab25457 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -10,7 +10,12 @@ from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.descriptors import descsum_create
-from test_framework.script import (CScript, OP_CHECKSIG, taproot_construct)
+from test_framework.script import (
+ CScript,
+ OP_1,
+ OP_CHECKSIG,
+ taproot_construct,
+)
from test_framework.segwit_addr import encode_segwit_address
# xprvs/xpubs, and m/* derived x-only pubkeys (created using independent implementation)
@@ -165,7 +170,7 @@ def pk(hex_key):
def compute_taproot_address(pubkey, scripts):
"""Compute the address for a taproot output with given inner key and scripts."""
tap = taproot_construct(pubkey, scripts)
- assert tap.scriptPubKey[0] == 0x51
+ assert tap.scriptPubKey[0] == OP_1
assert tap.scriptPubKey[1] == 0x20
return encode_segwit_address("bcrt", 1, tap.scriptPubKey[2:])
@@ -237,20 +242,15 @@ class WalletTaprootTest(BitcoinTestFramework):
assert_equal(len(rederive), 1)
assert_equal(rederive[0], addr_g)
- # tr descriptors cannot be imported when Taproot is not active
+ # tr descriptors can be imported regardless of Taproot status
result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert(result[0]["success"])
result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
assert(result[0]["success"])
- if desc.startswith("tr"):
- result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
- assert(not result[0]["success"])
- assert_equal(result[0]["error"]["code"], -4)
- assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
- result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
- assert(not result[0]["success"])
- assert_equal(result[0]["error"]["code"], -4)
- assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
+ result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ assert result[0]["success"]
+ result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ assert result[0]["success"]
def do_test_sendtoaddress(self, comment, pattern, privmap, treefn, keys_pay, keys_change):
self.log.info("Testing %s through sendtoaddress" % comment)
diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py
index afa5139da7..d26d1b9bfa 100755
--- a/test/functional/wallet_transactiontime_rescan.py
+++ b/test/functional/wallet_transactiontime_rescan.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test transaction time during old block rescanning
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index 5ca231cb76..5bdde13aa4 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs."""
@@ -129,7 +129,6 @@ class TxnMallTest(BitcoinTestFramework):
self.nodes[2].sendrawtransaction(node0_tx2["hex"])
self.nodes[2].sendrawtransaction(tx2["hex"])
self.generate(self.nodes[2], 1) # Mine another block to make sure we sync
- self.sync_blocks()
# Re-fetch transaction info:
tx1 = self.nodes[0].gettransaction(txid1)
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index 526e5cdd94..206187fb61 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2020 The Bitcoin Core developers
+# Copyright (c) 2014-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet accounts properly when there is a double-spend conflict."""
@@ -124,7 +124,6 @@ class TxnMallTest(BitcoinTestFramework):
# Reconnect the split network, and sync chain:
self.connect_nodes(1, 2)
self.generate(self.nodes[2], 1) # Mine another block to make sure we sync
- self.sync_blocks()
assert_equal(self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2)
# Re-fetch transaction info:
diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py
index db03796df6..36e72f2dd9 100755
--- a/test/functional/wallet_upgradewallet.py
+++ b/test/functional/wallet_upgradewallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""upgradewallet RPC functional test
diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py
index 3a9800111b..69c32ba54c 100755
--- a/test/functional/wallet_watchonly.py
+++ b/test/functional/wallet_watchonly.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test createwallet watchonly arguments.
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index eeff7a4515..e2eab2a0fe 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Run fuzz test targets.
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index 62fcad04b3..177aa74191 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 912bb24f9d..6a8a15d05c 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh
index 1f72aef80e..2af39ed60a 100755
--- a/test/lint/extended-lint-cppcheck.sh
+++ b/test/lint/extended-lint-cppcheck.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Copyright (c) 2019-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
index 8e74f41bb6..ab3866d23e 100755
--- a/test/lint/lint-circular-dependencies.sh
+++ b/test/lint/lint-circular-dependencies.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh
index ac2177bbe3..23f53f027e 100755
--- a/test/lint/lint-include-guards.sh
+++ b/test/lint/lint-include-guards.sh
@@ -17,7 +17,7 @@ for HEADER_FILE in $(git ls-files -- "*.h" | grep -vE "^${REGEXP_EXCLUDE_FILES_W
do
HEADER_ID_BASE=$(cut -f2- -d/ <<< "${HEADER_FILE}" | sed "s/\.h$//g" | tr / _ | tr - _ | tr "[:lower:]" "[:upper:]")
HEADER_ID="${HEADER_ID_PREFIX}${HEADER_ID_BASE}${HEADER_ID_SUFFIX}"
- if [[ $(grep -cE "^#(ifndef|define) ${HEADER_ID}" "${HEADER_FILE}") != 2 ]]; then
+ if [[ $(grep --count --extended-regexp "^#(ifndef|define|endif //) ${HEADER_ID}" "${HEADER_FILE}") != 3 ]]; then
echo "${HEADER_FILE} seems to be missing the expected include guard:"
echo " #ifndef ${HEADER_ID}"
echo " #define ${HEADER_ID}"
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 9b19699dab..98d5021657 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index 712808c748..661bc35175 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -37,15 +37,12 @@ export LC_ALL=C
# See https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings and
# https://stackoverflow.com/a/34878283 for more details.
-# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent stoul/strtol with locale
-# independent ToIntegral<T>(...) or the ParseInt*() functions.
# TODO: Reduce KNOWN_VIOLATIONS by replacing uses of locale dependent snprintf with strprintf.
KNOWN_VIOLATIONS=(
"src/dbwrapper.cpp:.*vsnprintf"
"src/test/dbwrapper_tests.cpp:.*snprintf"
"src/test/fuzz/locale.cpp"
"src/test/fuzz/string.cpp"
- "src/torcontrol.cpp:.*strtol"
)
REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|minisketch/|tinyformat.h|univalue/)"
diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh
index d6c53e8ff3..6d5165f649 100755
--- a/test/lint/lint-logs.sh
+++ b/test/lint/lint-logs.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index 96b34d715e..7d7857d325 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index c8b88a777a..5fa104fce6 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2020 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh
index c98003de8d..b3e558b02a 100755
--- a/test/lint/lint-spelling.sh
+++ b/test/lint/lint-spelling.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index 7967a212e7..9d55c71eb5 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2017-2020 The Bitcoin Core developers
+# Copyright (c) 2017-2021 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 2a729c66d9..6032fe496f 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -88,10 +88,9 @@ implicit-signed-integer-truncation:chain.h
implicit-signed-integer-truncation:crypto/
implicit-signed-integer-truncation:cuckoocache.h
implicit-signed-integer-truncation:leveldb/
-implicit-signed-integer-truncation:miner.cpp
+implicit-signed-integer-truncation:node/miner.cpp
implicit-signed-integer-truncation:net.cpp
implicit-signed-integer-truncation:net_processing.cpp
-implicit-signed-integer-truncation:netaddress.cpp
implicit-signed-integer-truncation:streams.h
implicit-signed-integer-truncation:test/arith_uint256_tests.cpp
implicit-signed-integer-truncation:test/skiplist_tests.cpp