aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml106
-rw-r--r--.python-version2
-rw-r--r--.style.yapf2
-rwxr-xr-xautogen.sh13
-rw-r--r--build-aux/m4/l_filesystem.m447
-rw-r--r--build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in2
-rw-r--r--build_msvc/bitcoin-qt/bitcoin-qt.vcxproj2
-rw-r--r--build_msvc/bitcoin-tx/bitcoin-tx.vcxproj2
-rw-r--r--build_msvc/bitcoin-util/bitcoin-util.vcxproj2
-rw-r--r--build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj2
-rw-r--r--build_msvc/bitcoin.sln2
-rw-r--r--build_msvc/bitcoin_config.h.in5
-rw-r--r--build_msvc/bitcoind/bitcoind.vcxproj2
-rw-r--r--build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj (renamed from build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj)9
-rw-r--r--build_msvc/libsecp256k1/libsecp256k1.vcxproj3
-rw-r--r--build_msvc/libsecp256k1_config.h15
-rw-r--r--build_msvc/libtest_util/libtest_util.vcxproj.in1
-rwxr-xr-xbuild_msvc/msvc-autogen.py1
-rw-r--r--build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj9
-rw-r--r--build_msvc/test_bitcoin/test_bitcoin.vcxproj2
-rw-r--r--build_msvc/vcpkg.json7
-rw-r--r--ci/README.md10
-rwxr-xr-xci/lint/04_install.sh1
-rw-r--r--ci/lint/Dockerfile2
-rwxr-xr-xci/test/00_setup_env.sh5
-rwxr-xr-xci/test/00_setup_env_i686_centos.sh7
-rwxr-xr-xci/test/00_setup_env_i686_multiprocess.sh3
-rwxr-xr-xci/test/00_setup_env_mac.sh7
-rwxr-xr-xci/test/00_setup_env_native_asan.sh13
-rwxr-xr-xci/test/00_setup_env_native_fuzz.sh7
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_msan.sh12
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_valgrind.sh6
-rwxr-xr-xci/test/00_setup_env_native_msan.sh14
-rwxr-xr-xci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh12
-rwxr-xr-xci/test/00_setup_env_native_qt5.sh14
-rwxr-xr-xci/test/00_setup_env_native_tidy.sh8
-rwxr-xr-xci/test/00_setup_env_native_tsan.sh8
-rwxr-xr-xci/test/00_setup_env_native_valgrind.sh6
-rwxr-xr-xci/test/01_base_install.sh95
-rwxr-xr-xci/test/04_install.sh74
-rwxr-xr-xci/test/05_before_script.sh30
-rwxr-xr-xci/test/06_script_a.sh68
-rwxr-xr-xci/test/06_script_b.sh209
-rwxr-xr-xci/test_run_all.sh10
-rw-r--r--configure.ac71
-rwxr-xr-xcontrib/devtools/security-check.py10
-rwxr-xr-xcontrib/devtools/symbol-check.py30
-rwxr-xr-xcontrib/devtools/test-security-check.py16
-rwxr-xr-xcontrib/devtools/test-symbol-check.py2
-rwxr-xr-xcontrib/guix/libexec/build.sh6
-rw-r--r--contrib/guix/manifest.scm90
-rw-r--r--contrib/guix/patches/gcc-broken-longjmp.patch2
-rw-r--r--contrib/guix/patches/glibc-2.27-fcommon.patch4
-rw-r--r--contrib/guix/patches/glibc-2.27-guix-prefix.patch2
-rw-r--r--contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch2
-rw-r--r--contrib/guix/patches/glibc-ldd-x86_64.patch10
-rw-r--r--contrib/guix/patches/glibc-versioned-locpath.patch240
-rw-r--r--contrib/guix/patches/vmov-alignment.patch1
-rw-r--r--contrib/init/bitcoind.service11
-rw-r--r--contrib/seeds/README.md12
-rwxr-xr-xcontrib/seeds/generate-seeds.py2
-rwxr-xr-xcontrib/seeds/makeseeds.py16
-rw-r--r--contrib/seeds/nodes_main.txt1157
-rw-r--r--contrib/seeds/nodes_main_manual.txt71
-rwxr-xr-xcontrib/tracing/mempool_monitor.py8
-rw-r--r--contrib/valgrind.supp21
-rw-r--r--contrib/verify-binaries/README.md88
-rwxr-xr-xcontrib/verify-binaries/test.py59
-rwxr-xr-xcontrib/verify-binaries/verify.py713
-rw-r--r--contrib/verify-commits/trusted-keys1
-rwxr-xr-xcontrib/verify-commits/verify-commits.py15
-rw-r--r--contrib/verifybinaries/README.md30
-rwxr-xr-xcontrib/verifybinaries/verify.py183
-rw-r--r--depends/Makefile6
-rw-r--r--depends/README.md5
-rwxr-xr-xdepends/config.guess1234
-rw-r--r--depends/config.site.in4
-rwxr-xr-xdepends/config.sub109
-rw-r--r--depends/funcs.mk2
-rwxr-xr-xdepends/gen_id6
-rw-r--r--depends/hosts/darwin.mk51
-rw-r--r--depends/hosts/linux.mk2
-rw-r--r--depends/packages/bdb.mk2
-rw-r--r--depends/packages/fontconfig.mk1
-rw-r--r--depends/packages/libevent.mk5
-rw-r--r--depends/packages/libmultiprocess.mk4
-rw-r--r--depends/packages/native_clang.mk10
-rw-r--r--depends/packages/qrencode.mk7
-rw-r--r--depends/packages/qt.mk12
-rw-r--r--doc/JSON-RPC-interface.md35
-rw-r--r--doc/bips.md2
-rw-r--r--doc/build-openbsd.md6
-rw-r--r--doc/build-unix.md99
-rw-r--r--doc/cjdns.md3
-rw-r--r--doc/dependencies.md12
-rw-r--r--doc/developer-notes.md10
-rw-r--r--doc/i2p.md3
-rw-r--r--doc/policy/packages.md37
-rw-r--r--doc/reduce-memory.md2
-rw-r--r--doc/release-note-26194.md4
-rw-r--r--doc/release-notes-19762.md19
-rw-r--r--doc/release-notes-22087.md4
-rw-r--r--doc/release-notes-23395.md8
-rw-r--r--doc/release-notes-25158.md6
-rw-r--r--doc/release-notes-25375.md11
-rw-r--r--doc/release-notes-25412.md5
-rw-r--r--doc/release-notes-25574.md13
-rw-r--r--doc/release-notes-25730.md6
-rw-r--r--doc/release-notes-25934.md8
-rw-r--r--doc/release-notes-25943.md4
-rw-r--r--doc/release-notes-25957.md9
-rw-r--r--doc/release-notes-26076.md13
-rw-r--r--doc/release-notes-26094.md6
-rw-r--r--doc/release-notes-26213.md8
-rw-r--r--doc/release-notes-26265.md6
-rw-r--r--doc/release-notes-26471.md13
-rw-r--r--doc/release-notes-26485.md16
-rw-r--r--doc/release-notes-26618.md4
-rw-r--r--doc/release-notes-26628.md4
-rw-r--r--doc/release-notes-26646.md8
-rw-r--r--doc/release-notes-26896.md7
-rw-r--r--doc/release-notes-26899.md5
-rw-r--r--doc/release-notes-27037.md5
-rw-r--r--doc/release-notes-27068.md6
-rw-r--r--doc/release-notes-27302.md4
-rw-r--r--doc/release-notes-27501.md3
-rw-r--r--doc/release-notes-27632.md5
-rw-r--r--doc/release-notes-27757.md8
-rw-r--r--doc/release-notes-empty-template.md2
-rw-r--r--doc/release-notes/release-notes-23.2.md72
-rw-r--r--doc/release-notes/release-notes-24.1.md99
-rw-r--r--doc/release-notes/release-notes-25.0.md340
-rw-r--r--doc/release-process.md10
-rw-r--r--doc/tor.md15
-rw-r--r--doc/tracing.md8
-rw-r--r--share/qt/Info.plist.in2
-rw-r--r--src/.clang-tidy9
-rw-r--r--src/Makefile.am47
-rw-r--r--src/Makefile.bench.include4
-rw-r--r--src/Makefile.qt.include8
-rw-r--r--src/Makefile.test.include11
-rw-r--r--src/Makefile.test_util.include1
-rw-r--r--src/addrdb.cpp28
-rw-r--r--src/addrdb.h11
-rw-r--r--src/addrman.cpp154
-rw-r--r--src/addrman.h7
-rw-r--r--src/addrman_impl.h12
-rw-r--r--src/attributes.h8
-rw-r--r--src/banman.cpp3
-rw-r--r--src/banman.h2
-rw-r--r--src/bench/addrman.cpp38
-rw-r--r--src/bench/bench.cpp2
-rw-r--r--src/bench/bench.h2
-rw-r--r--src/bench/bench_bitcoin.cpp4
-rw-r--r--src/bench/bip324_ecdh.cpp51
-rw-r--r--src/bench/block_assemble.cpp2
-rw-r--r--src/bench/checkblock.cpp5
-rw-r--r--src/bench/checkqueue.cpp2
-rw-r--r--src/bench/coin_selection.cpp8
-rw-r--r--src/bench/ellswift.cpp31
-rw-r--r--src/bench/load_external.cpp3
-rw-r--r--src/bench/lockedpool.cpp4
-rw-r--r--src/bench/logging.cpp3
-rw-r--r--src/bench/mempool_stress.cpp5
-rw-r--r--src/bench/pool.cpp50
-rw-r--r--src/bench/rpc_blockchain.cpp3
-rw-r--r--src/bench/rpc_mempool.cpp4
-rw-r--r--src/bench/streams_findbyte.cpp31
-rw-r--r--src/bench/util_time.cpp2
-rw-r--r--src/bench/wallet_balance.cpp17
-rw-r--r--src/bench/wallet_create_tx.cpp15
-rw-r--r--src/bench/wallet_loading.cpp53
-rw-r--r--src/bitcoin-chainstate.cpp50
-rw-r--r--src/bitcoin-cli.cpp55
-rw-r--r--src/bitcoin-tx.cpp8
-rw-r--r--src/bitcoin-util.cpp6
-rw-r--r--src/bitcoin-wallet.cpp7
-rw-r--r--src/bitcoind.cpp73
-rw-r--r--src/blockencodings.cpp4
-rw-r--r--src/chainparams.cpp47
-rw-r--r--src/chainparams.h24
-rw-r--r--src/chainparamsbase.cpp25
-rw-r--r--src/chainparamsbase.h18
-rw-r--r--src/chainparamsseeds.h1150
-rw-r--r--src/coins.cpp15
-rw-r--r--src/coins.h20
-rw-r--r--src/common/args.cpp (renamed from src/util/system.cpp)705
-rw-r--r--src/common/args.h (renamed from src/util/system.h)189
-rw-r--r--src/common/config.cpp217
-rw-r--r--src/common/init.cpp48
-rw-r--r--src/common/settings.cpp (renamed from src/util/settings.cpp)21
-rw-r--r--src/common/settings.h (renamed from src/util/settings.h)19
-rw-r--r--src/common/system.cpp107
-rw-r--r--src/common/system.h38
-rw-r--r--src/compat/assumptions.h1
-rw-r--r--src/compat/compat.h9
-rw-r--r--src/consensus/validation.h2
-rw-r--r--src/core_write.cpp2
-rw-r--r--src/crypto/sha256_avx2.cpp3
-rw-r--r--src/crypto/sha256_sse41.cpp3
-rw-r--r--src/crypto/sha256_x86_shani.cpp20
-rw-r--r--src/dbwrapper.cpp4
-rw-r--r--src/dbwrapper.h2
-rw-r--r--src/dummywallet.cpp3
-rw-r--r--src/external_signer.cpp16
-rw-r--r--src/external_signer.h2
-rw-r--r--src/flatfile.cpp2
-rw-r--r--src/flatfile.h2
-rw-r--r--src/headerssync.cpp2
-rw-r--r--src/headerssync.h13
-rw-r--r--src/httprpc.cpp7
-rw-r--r--src/httpserver.cpp18
-rw-r--r--src/i2p.cpp6
-rw-r--r--src/i2p.h2
-rw-r--r--src/index/base.cpp56
-rw-r--r--src/index/blockfilterindex.cpp7
-rw-r--r--src/index/coinstatsindex.cpp12
-rw-r--r--src/index/txindex.cpp6
-rw-r--r--src/init.cpp192
-rw-r--r--src/init.h2
-rw-r--r--src/init/bitcoin-gui.cpp2
-rw-r--r--src/init/bitcoin-node.cpp2
-rw-r--r--src/init/bitcoin-qt.cpp2
-rw-r--r--src/init/bitcoind.cpp2
-rw-r--r--src/init/common.cpp20
-rw-r--r--src/init/common.h6
-rw-r--r--src/interfaces/chain.h13
-rw-r--r--src/interfaces/node.h11
-rw-r--r--src/interfaces/wallet.h15
-rw-r--r--src/ipc/interfaces.cpp4
-rw-r--r--src/ipc/process.cpp2
-rw-r--r--src/ipc/process.h2
-rw-r--r--src/kernel/blockmanager_opts.h12
-rw-r--r--src/kernel/chain.cpp1
-rw-r--r--src/kernel/chainparams.cpp52
-rw-r--r--src/kernel/chainparams.h9
-rw-r--r--src/kernel/chainstatemanager_opts.h5
-rw-r--r--src/kernel/checks.cpp10
-rw-r--r--src/kernel/checks.h9
-rw-r--r--src/kernel/coinstats.cpp2
-rw-r--r--src/kernel/mempool_entry.h32
-rw-r--r--src/kernel/mempool_persist.cpp4
-rw-r--r--src/kernel/mempool_persist.h2
-rw-r--r--src/kernel/notifications_interface.h33
-rw-r--r--src/key.cpp37
-rw-r--r--src/key.h27
-rw-r--r--src/key_io.cpp16
-rw-r--r--src/logging.cpp8
-rw-r--r--src/logging.h4
-rw-r--r--src/mapport.cpp10
-rw-r--r--src/memusage.h20
-rw-r--r--src/net.cpp119
-rw-r--r--src/net.h26
-rw-r--r--src/net_permissions.cpp10
-rw-r--r--src/net_processing.cpp587
-rw-r--r--src/net_processing.h2
-rw-r--r--src/netbase.cpp112
-rw-r--r--src/netbase.h31
-rw-r--r--src/node/blockmanager_args.cpp19
-rw-r--r--src/node/blockmanager_args.h6
-rw-r--r--src/node/blockstorage.cpp117
-rw-r--r--src/node/blockstorage.h59
-rw-r--r--src/node/caches.cpp2
-rw-r--r--src/node/chainstate.cpp7
-rw-r--r--src/node/chainstate.h3
-rw-r--r--src/node/chainstatemanager_args.cpp12
-rw-r--r--src/node/chainstatemanager_args.h6
-rw-r--r--src/node/coins_view_args.cpp2
-rw-r--r--src/node/context.cpp1
-rw-r--r--src/node/context.h6
-rw-r--r--src/node/database_args.cpp2
-rw-r--r--src/node/interfaces.cpp67
-rw-r--r--src/node/kernel_notifications.cpp75
-rw-r--r--src/node/kernel_notifications.h31
-rw-r--r--src/node/mempool_args.cpp14
-rw-r--r--src/node/mempool_args.h4
-rw-r--r--src/node/mempool_persist_args.cpp4
-rw-r--r--src/node/mempool_persist_args.h2
-rw-r--r--src/node/miner.cpp2
-rw-r--r--src/node/miner.h3
-rw-r--r--src/node/mini_miner.cpp371
-rw-r--r--src/node/mini_miner.h121
-rw-r--r--src/node/transaction.cpp4
-rw-r--r--src/node/transaction.h4
-rw-r--r--src/node/txreconciliation.cpp3
-rw-r--r--src/node/utxo_snapshot.cpp7
-rw-r--r--src/node/utxo_snapshot.h4
-rw-r--r--src/node/validation_cache_args.cpp2
-rw-r--r--src/outputtype.cpp2
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/fees.cpp37
-rw-r--r--src/policy/fees.h24
-rw-r--r--src/policy/fees_args.cpp2
-rw-r--r--src/policy/fees_args.h2
-rw-r--r--src/policy/policy.h2
-rw-r--r--src/protocol.cpp4
-rw-r--r--src/protocol.h5
-rw-r--r--src/psbt.cpp32
-rw-r--r--src/psbt.h3
-rw-r--r--src/pubkey.cpp15
-rw-r--r--src/pubkey.h32
-rw-r--r--src/qt/addresstablemodel.cpp41
-rw-r--r--src/qt/addresstablemodel.h11
-rw-r--r--src/qt/bitcoin.cpp25
-rw-r--r--src/qt/bitcoin.h4
-rw-r--r--src/qt/bitcoingui.cpp13
-rw-r--r--src/qt/bitcoinstrings.cpp42
-rw-r--r--src/qt/clientmodel.cpp13
-rw-r--r--src/qt/coincontroldialog.cpp3
-rw-r--r--src/qt/editaddressdialog.cpp6
-rw-r--r--src/qt/forms/psbtoperationsdialog.ui2
-rw-r--r--src/qt/guiutil.cpp48
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/intro.cpp10
-rw-r--r--src/qt/locale/bitcoin_en.ts342
-rw-r--r--src/qt/locale/bitcoin_en.xlf3161
-rw-r--r--src/qt/networkstyle.cpp16
-rw-r--r--src/qt/networkstyle.h4
-rw-r--r--src/qt/optionsdialog.cpp11
-rw-r--r--src/qt/optionsmodel.cpp22
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/psbtoperationsdialog.cpp3
-rw-r--r--src/qt/receivecoinsdialog.cpp8
-rw-r--r--src/qt/rpcconsole.cpp19
-rw-r--r--src/qt/sendcoinsdialog.cpp43
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp9
-rw-r--r--src/qt/test/apptests.cpp2
-rw-r--r--src/qt/test/optiontests.cpp12
-rw-r--r--src/qt/test/optiontests.h4
-rw-r--r--src/qt/test/rpcnestedtests.cpp4
-rw-r--r--src/qt/test/test_main.cpp6
-rw-r--r--src/qt/test/util.cpp2
-rw-r--r--src/qt/test/util.h2
-rw-r--r--src/qt/test/wallettests.cpp263
-rw-r--r--src/qt/trafficgraphwidget.cpp4
-rw-r--r--src/qt/transactiondesc.cpp8
-rw-r--r--src/qt/transactionrecord.cpp2
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/walletframe.cpp4
-rw-r--r--src/qt/walletmodel.cpp31
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/random.cpp39
-rw-r--r--src/random.h3
-rw-r--r--src/randomenv.cpp3
-rw-r--r--src/rest.cpp35
-rw-r--r--src/rpc/blockchain.cpp123
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/client.cpp102
-rw-r--r--src/rpc/client.h5
-rw-r--r--src/rpc/external_signer.cpp7
-rw-r--r--src/rpc/mempool.cpp8
-rw-r--r--src/rpc/mining.cpp47
-rw-r--r--src/rpc/net.cpp26
-rw-r--r--src/rpc/node.cpp4
-rw-r--r--src/rpc/output_script.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp232
-rw-r--r--src/rpc/rawtransaction_util.cpp12
-rw-r--r--src/rpc/request.cpp14
-rw-r--r--src/rpc/server.cpp52
-rw-r--r--src/rpc/server.h13
-rw-r--r--src/rpc/server_util.cpp3
-rw-r--r--src/rpc/txoutproof.cpp5
-rw-r--r--src/rpc/util.cpp130
-rw-r--r--src/rpc/util.h34
-rw-r--r--src/script/descriptor.cpp86
-rw-r--r--src/script/miniscript.h2
-rw-r--r--src/script/sigcache.cpp3
-rw-r--r--src/secp256k1/.cirrus.yml22
-rw-r--r--src/secp256k1/.gitignore2
-rw-r--r--src/secp256k1/CHANGELOG.md40
-rw-r--r--src/secp256k1/CMakeLists.txt181
-rw-r--r--src/secp256k1/CMakePresets.json19
-rw-r--r--src/secp256k1/Makefile.am38
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m426
-rwxr-xr-xsrc/secp256k1/ci/cirrus.sh8
-rw-r--r--src/secp256k1/ci/linux-debian.Dockerfile11
-rw-r--r--src/secp256k1/cmake/CheckArm32Assembly.cmake6
-rw-r--r--src/secp256k1/cmake/CheckStringOptionValue.cmake8
-rw-r--r--src/secp256k1/cmake/CheckX86_64Assembly.cmake (renamed from src/secp256k1/cmake/Check64bitAssembly.cmake)6
-rw-r--r--src/secp256k1/cmake/FindValgrind.cmake2
-rw-r--r--src/secp256k1/cmake/TryAddCompileOption.cmake23
-rw-r--r--src/secp256k1/cmake/TryAppendCFlags.cmake24
-rw-r--r--src/secp256k1/cmake/source_arm32.s9
-rw-r--r--src/secp256k1/configure.ac72
-rw-r--r--src/secp256k1/doc/ellswift.md483
-rw-r--r--src/secp256k1/doc/release-process.md50
-rw-r--r--src/secp256k1/examples/CMakeLists.txt19
-rw-r--r--src/secp256k1/examples/examples_util.h8
-rw-r--r--src/secp256k1/include/secp256k1.h110
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h2
-rw-r--r--src/secp256k1/include/secp256k1_ellswift.h198
-rw-r--r--src/secp256k1/include/secp256k1_extrakeys.h40
-rw-r--r--src/secp256k1/include/secp256k1_preallocated.h14
-rw-r--r--src/secp256k1/include/secp256k1_recovery.h18
-rw-r--r--src/secp256k1/include/secp256k1_schnorrsig.h26
-rw-r--r--src/secp256k1/src/CMakeLists.txt242
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s2
-rw-r--r--src/secp256k1/src/bench.c74
-rw-r--r--src/secp256k1/src/bench.h2
-rw-r--r--src/secp256k1/src/bench_ecmult.c6
-rw-r--r--src/secp256k1/src/bench_internal.c8
-rw-r--r--src/secp256k1/src/ctime_tests.c35
-rw-r--r--src/secp256k1/src/ecdsa_impl.h3
-rw-r--r--src/secp256k1/src/eckey_impl.h12
-rw-r--r--src/secp256k1/src/ecmult_const.h27
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h199
-rw-r--r--src/secp256k1/src/ecmult_gen_compute_table_impl.h2
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h7
-rw-r--r--src/secp256k1/src/ecmult_impl.h30
-rw-r--r--src/secp256k1/src/field.h311
-rw-r--r--src/secp256k1/src/field_10x26.h33
-rw-r--r--src/secp256k1/src/field_10x26_impl.h278
-rw-r--r--src/secp256k1/src/field_5x52.h33
-rw-r--r--src/secp256k1/src/field_5x52_asm_impl.h6
-rw-r--r--src/secp256k1/src/field_5x52_impl.h279
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h1
-rw-r--r--src/secp256k1/src/field_impl.h300
-rw-r--r--src/secp256k1/src/group.h12
-rw-r--r--src/secp256k1/src/group_impl.h150
-rw-r--r--src/secp256k1/src/int128_native_impl.h1
-rw-r--r--src/secp256k1/src/int128_struct_impl.h3
-rw-r--r--src/secp256k1/src/modinv32_impl.h35
-rw-r--r--src/secp256k1/src/modinv64_impl.h31
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/ellswift/Makefile.am.include4
-rw-r--r--src/secp256k1/src/modules/ellswift/bench_impl.h106
-rw-r--r--src/secp256k1/src/modules/ellswift/main_impl.h589
-rw-r--r--src/secp256k1/src/modules/ellswift/tests_impl.h434
-rw-r--r--src/secp256k1/src/modules/extrakeys/main_impl.h3
-rw-r--r--src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h2
-rw-r--r--src/secp256k1/src/modules/recovery/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/schnorrsig/main_impl.h2
-rw-r--r--src/secp256k1/src/modules/schnorrsig/tests_impl.h212
-rw-r--r--src/secp256k1/src/precompute_ecmult.c1
-rw-r--r--src/secp256k1/src/precompute_ecmult_gen.c1
-rw-r--r--src/secp256k1/src/precomputed_ecmult.c1
-rw-r--r--src/secp256k1/src/precomputed_ecmult.h1
-rw-r--r--src/secp256k1/src/precomputed_ecmult_gen.c1
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h28
-rw-r--r--src/secp256k1/src/scalar_8x32_impl.h42
-rw-r--r--src/secp256k1/src/scalar_low_impl.h4
-rw-r--r--src/secp256k1/src/secp256k1.c8
-rw-r--r--src/secp256k1/src/testrand.h2
-rw-r--r--src/secp256k1/src/testrand_impl.h1
-rw-r--r--src/secp256k1/src/tests.c418
-rw-r--r--src/secp256k1/src/tests_exhaustive.c56
-rw-r--r--src/secp256k1/src/util.h58
-rw-r--r--src/secp256k1/src/wycheproof/WYCHEPROOF_COPYING212
-rw-r--r--src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h1564
-rw-r--r--src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json6360
-rwxr-xr-xsrc/secp256k1/tools/tests_wycheproof_generate.py115
-rw-r--r--src/shutdown.cpp7
-rw-r--r--src/shutdown.h4
-rw-r--r--src/signet.cpp7
-rw-r--r--src/span.h1
-rw-r--r--src/streams.h28
-rw-r--r--src/support/allocators/pool.h349
-rw-r--r--src/support/allocators/secure.h4
-rw-r--r--src/support/allocators/zeroafterfree.h4
-rw-r--r--src/test/addrman_tests.cpp175
-rw-r--r--src/test/allocator_tests.cpp3
-rw-r--r--src/test/argsman_tests.cpp59
-rw-r--r--src/test/blockfilter_index_tests.cpp23
-rw-r--r--src/test/blockmanager_tests.cpp22
-rw-r--r--src/test/bloom_tests.cpp2
-rw-r--r--src/test/checkqueue_tests.cpp7
-rw-r--r--src/test/coins_tests.cpp39
-rw-r--r--src/test/denialofservice_tests.cpp2
-rw-r--r--src/test/descriptor_tests.cpp74
-rw-r--r--src/test/flatfile_tests.cpp2
-rw-r--r--src/test/fs_tests.cpp4
-rw-r--r--src/test/fuzz/addrman.cpp5
-rw-r--r--src/test/fuzz/banman.cpp4
-rw-r--r--src/test/fuzz/block.cpp3
-rw-r--r--src/test/fuzz/buffered_file.cpp2
-rw-r--r--src/test/fuzz/coins_view.cpp4
-rw-r--r--src/test/fuzz/connman.cpp4
-rw-r--r--src/test/fuzz/descriptor_parse.cpp3
-rw-r--r--src/test/fuzz/deserialize.cpp2
-rw-r--r--src/test/fuzz/fuzz.cpp29
-rw-r--r--src/test/fuzz/headerssync.cpp118
-rw-r--r--src/test/fuzz/i2p.cpp2
-rw-r--r--src/test/fuzz/integer.cpp6
-rw-r--r--src/test/fuzz/key.cpp84
-rw-r--r--src/test/fuzz/key_io.cpp3
-rw-r--r--src/test/fuzz/message.cpp3
-rw-r--r--src/test/fuzz/mini_miner.cpp193
-rw-r--r--src/test/fuzz/miniscript.cpp2
-rw-r--r--src/test/fuzz/net.cpp4
-rw-r--r--src/test/fuzz/netbase_dns_lookup.cpp28
-rw-r--r--src/test/fuzz/p2p_transport_serialization.cpp3
-rw-r--r--src/test/fuzz/parse_hd_keypath.cpp2
-rw-r--r--src/test/fuzz/parse_univalue.cpp12
-rw-r--r--src/test/fuzz/policy_estimator.cpp2
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/poolresource.cpp174
-rw-r--r--src/test/fuzz/pow.cpp3
-rw-r--r--src/test/fuzz/process_message.cpp83
-rw-r--r--src/test/fuzz/process_messages.cpp2
-rw-r--r--src/test/fuzz/rpc.cpp15
-rw-r--r--src/test/fuzz/script.cpp3
-rw-r--r--src/test/fuzz/script_format.cpp3
-rw-r--r--src/test/fuzz/script_sigcache.cpp1
-rw-r--r--src/test/fuzz/script_sign.cpp4
-rw-r--r--src/test/fuzz/signet.cpp3
-rw-r--r--src/test/fuzz/socks5.cpp8
-rw-r--r--src/test/fuzz/string.cpp170
-rw-r--r--src/test/fuzz/system.cpp8
-rw-r--r--src/test/fuzz/transaction.cpp16
-rw-r--r--src/test/fuzz/tx_pool.cpp5
-rw-r--r--src/test/fuzz/util.h1
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp5
-rw-r--r--src/test/fuzz/utxo_total_supply.cpp168
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp1
-rw-r--r--src/test/fuzz/versionbits.cpp5
-rw-r--r--src/test/getarg_tests.cpp10
-rw-r--r--src/test/httpserver_tests.cpp4
-rw-r--r--src/test/i2p_tests.cpp2
-rw-r--r--src/test/interfaces_tests.cpp2
-rw-r--r--src/test/key_io_tests.cpp21
-rw-r--r--src/test/key_tests.cpp22
-rw-r--r--src/test/logging_tests.cpp12
-rw-r--r--src/test/mempool_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/miniminer_tests.cpp476
-rw-r--r--src/test/miniscript_tests.cpp2
-rw-r--r--src/test/net_tests.cpp31
-rw-r--r--src/test/netbase_tests.cpp13
-rw-r--r--src/test/policyestimator_tests.cpp1
-rw-r--r--src/test/pool_tests.cpp190
-rw-r--r--src/test/pow_tests.cpp33
-rw-r--r--src/test/random_tests.cpp1
-rw-r--r--src/test/rbf_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp148
-rw-r--r--src/test/scheduler_tests.cpp2
-rw-r--r--src/test/script_p2sh_tests.cpp4
-rw-r--r--src/test/script_tests.cpp4
-rw-r--r--src/test/settings_tests.cpp52
-rw-r--r--src/test/sighash_tests.cpp2
-rw-r--r--src/test/sock_tests.cpp2
-rw-r--r--src/test/streams_tests.cpp4
-rw-r--r--src/test/system_tests.cpp4
-rw-r--r--src/test/txindex_tests.cpp6
-rw-r--r--src/test/txpackage_tests.cpp72
-rw-r--r--src/test/txrequest_tests.cpp1
-rw-r--r--src/test/txvalidationcache_tests.cpp3
-rw-r--r--src/test/util/blockfilter.cpp9
-rw-r--r--src/test/util/blockfilter.h6
-rw-r--r--src/test/util/chainstate.h2
-rw-r--r--src/test/util/mining.cpp48
-rw-r--r--src/test/util/mining.h12
-rw-r--r--src/test/util/net.cpp3
-rw-r--r--src/test/util/poolresourcetester.h129
-rw-r--r--src/test/util/setup_common.cpp66
-rw-r--r--src/test/util/setup_common.h44
-rw-r--r--src/test/util/txmempool.cpp4
-rw-r--r--src/test/util_tests.cpp13
-rw-r--r--src/test/util_threadnames_tests.cpp1
-rw-r--r--src/test/validation_block_tests.cpp1
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp30
-rw-r--r--src/test/validation_flush_tests.cpp33
-rw-r--r--src/test/validation_tests.cpp11
-rw-r--r--src/test/validationinterface_tests.cpp2
-rw-r--r--src/test/versionbits_tests.cpp9
-rw-r--r--src/timedata.cpp3
-rw-r--r--src/torcontrol.cpp9
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/txdb.cpp10
-rw-r--r--src/txdb.h10
-rw-r--r--src/txmempool.cpp113
-rw-r--r--src/txmempool.h33
-rw-r--r--src/txorphanage.cpp12
-rw-r--r--src/txorphanage.h2
-rw-r--r--src/txrequest.cpp8
-rw-r--r--src/uint256.h1
-rw-r--r--src/univalue/include/univalue.h6
-rw-r--r--src/univalue/lib/univalue.cpp17
-rw-r--r--src/univalue/test/object.cpp31
-rw-r--r--src/util/any.h26
-rw-r--r--src/util/asmap.cpp2
-rw-r--r--src/util/asmap.h2
-rw-r--r--src/util/batchpriority.cpp26
-rw-r--r--src/util/batchpriority.h15
-rw-r--r--src/util/bip32.cpp10
-rw-r--r--src/util/bip32.h4
-rw-r--r--src/util/chaintype.cpp39
-rw-r--r--src/util/chaintype.h22
-rw-r--r--src/util/fs.cpp (renamed from src/fs.cpp)2
-rw-r--r--src/util/fs.h (renamed from src/fs.h)8
-rw-r--r--src/util/fs_helpers.cpp295
-rw-r--r--src/util/fs_helpers.h63
-rw-r--r--src/util/getuniquepath.cpp2
-rw-r--r--src/util/getuniquepath.h2
-rw-r--r--src/util/insert.h24
-rw-r--r--src/util/readwritefile.cpp2
-rw-r--r--src/util/readwritefile.h2
-rw-r--r--src/util/result.h5
-rw-r--r--src/util/sock.cpp2
-rw-r--r--src/util/strencodings.h4
-rw-r--r--src/util/string.h4
-rw-r--r--src/util/time.cpp13
-rw-r--r--src/util/time.h3
-rw-r--r--src/util/translation.h22
-rw-r--r--src/validation.cpp197
-rw-r--r--src/validation.h21
-rw-r--r--src/version.h3
-rw-r--r--src/wallet/bdb.cpp70
-rw-r--r--src/wallet/bdb.h15
-rw-r--r--src/wallet/coincontrol.cpp70
-rw-r--r--src/wallet/coincontrol.h124
-rw-r--r--src/wallet/coinselection.cpp84
-rw-r--r--src/wallet/coinselection.h17
-rw-r--r--src/wallet/crypter.cpp2
-rw-r--r--src/wallet/db.cpp4
-rw-r--r--src/wallet/db.h48
-rw-r--r--src/wallet/dump.cpp10
-rw-r--r--src/wallet/dump.h2
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp4
-rw-r--r--src/wallet/feebumper.cpp39
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/interfaces.cpp60
-rw-r--r--src/wallet/load.cpp6
-rw-r--r--src/wallet/receive.h2
-rw-r--r--src/wallet/rpc/addresses.cpp33
-rw-r--r--src/wallet/rpc/backup.cpp46
-rw-r--r--src/wallet/rpc/coins.cpp7
-rw-r--r--src/wallet/rpc/spend.cpp22
-rw-r--r--src/wallet/rpc/transactions.cpp16
-rw-r--r--src/wallet/rpc/util.cpp12
-rw-r--r--src/wallet/rpc/util.h10
-rw-r--r--src/wallet/rpc/wallet.cpp46
-rw-r--r--src/wallet/salvage.cpp50
-rw-r--r--src/wallet/salvage.h2
-rw-r--r--src/wallet/scriptpubkeyman.cpp34
-rw-r--r--src/wallet/scriptpubkeyman.h22
-rw-r--r--src/wallet/spend.cpp74
-rw-r--r--src/wallet/spend.h2
-rw-r--r--src/wallet/sqlite.cpp102
-rw-r--r--src/wallet/sqlite.h13
-rw-r--r--src/wallet/test/coinselector_tests.cpp235
-rw-r--r--src/wallet/test/db_tests.cpp129
-rw-r--r--src/wallet/test/fuzz/coincontrol.cpp87
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp19
-rw-r--r--src/wallet/test/fuzz/fees.cpp68
-rw-r--r--src/wallet/test/fuzz/notifications.cpp4
-rw-r--r--src/wallet/test/group_outputs_tests.cpp3
-rw-r--r--src/wallet/test/init_test_fixture.cpp7
-rw-r--r--src/wallet/test/init_test_fixture.h3
-rw-r--r--src/wallet/test/init_tests.cpp2
-rw-r--r--src/wallet/test/ismine_tests.cpp79
-rw-r--r--src/wallet/test/scriptpubkeyman_tests.cpp3
-rw-r--r--src/wallet/test/util.cpp154
-rw-r--r--src/wallet/test/util.h99
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp8
-rw-r--r--src/wallet/test/wallet_test_fixture.h3
-rw-r--r--src/wallet/test/wallet_tests.cpp176
-rw-r--r--src/wallet/test/walletdb_tests.cpp28
-rw-r--r--src/wallet/test/walletload_tests.cpp97
-rw-r--r--src/wallet/transaction.h25
-rw-r--r--src/wallet/types.h (renamed from src/wallet/ismine.h)44
-rw-r--r--src/wallet/wallet.cpp414
-rw-r--r--src/wallet/wallet.h125
-rw-r--r--src/wallet/walletdb.cpp105
-rw-r--r--src/wallet/walletdb.h16
-rw-r--r--src/wallet/wallettool.cpp4
-rw-r--r--src/wallet/walletutil.cpp2
-rw-r--r--src/wallet/walletutil.h26
-rw-r--r--src/warnings.cpp2
-rw-r--r--src/zmq/zmqabstractnotifier.h3
-rw-r--r--src/zmq/zmqnotificationinterface.cpp12
-rw-r--r--src/zmq/zmqnotificationinterface.h5
-rw-r--r--src/zmq/zmqpublishnotifier.cpp12
-rw-r--r--src/zmq/zmqpublishnotifier.h7
-rw-r--r--test/README.md1
-rwxr-xr-xtest/functional/feature_abortnode.py2
-rwxr-xr-xtest/functional/feature_anchors.py18
-rwxr-xr-xtest/functional/feature_assumevalid.py11
-rwxr-xr-xtest/functional/feature_block.py6
-rwxr-xr-xtest/functional/feature_coinstatsindex.py43
-rwxr-xr-xtest/functional/feature_config_args.py96
-rwxr-xr-xtest/functional/feature_dbcrash.py8
-rwxr-xr-xtest/functional/feature_fastprune.py29
-rwxr-xr-xtest/functional/feature_fee_estimation.py101
-rwxr-xr-xtest/functional/feature_init.py48
-rwxr-xr-xtest/functional/feature_logging.py30
-rwxr-xr-xtest/functional/feature_nulldummy.py15
-rwxr-xr-xtest/functional/feature_pruning.py7
-rwxr-xr-xtest/functional/feature_rbf.py4
-rwxr-xr-xtest/functional/feature_signet.py3
-rwxr-xr-xtest/functional/feature_taproot.py19
-rwxr-xr-xtest/functional/interface_rest.py22
-rwxr-xr-xtest/functional/interface_usdt_mempool.py92
-rwxr-xr-xtest/functional/interface_usdt_net.py15
-rwxr-xr-xtest/functional/interface_usdt_utxocache.py51
-rwxr-xr-xtest/functional/interface_usdt_validation.py34
-rwxr-xr-xtest/functional/interface_zmq.py10
-rwxr-xr-xtest/functional/mempool_accept.py8
-rwxr-xr-xtest/functional/mempool_compatibility.py2
-rwxr-xr-xtest/functional/mempool_dust.py9
-rwxr-xr-xtest/functional/mempool_expiry.py12
-rwxr-xr-xtest/functional/mempool_limit.py77
-rwxr-xr-xtest/functional/mempool_package_limits.py129
-rwxr-xr-xtest/functional/mempool_packages.py15
-rwxr-xr-xtest/functional/mempool_persist.py1
-rwxr-xr-xtest/functional/mempool_sigoplimit.py4
-rwxr-xr-xtest/functional/mining_basic.py1
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py65
-rwxr-xr-xtest/functional/p2p_blockfilters.py7
-rwxr-xr-xtest/functional/p2p_compactblocks.py88
-rwxr-xr-xtest/functional/p2p_disconnect_ban.py12
-rwxr-xr-xtest/functional/p2p_filter.py6
-rwxr-xr-xtest/functional/p2p_invalid_messages.py21
-rwxr-xr-xtest/functional/p2p_leak_tx.py65
-rwxr-xr-xtest/functional/p2p_segwit.py12
-rwxr-xr-xtest/functional/p2p_sendheaders.py10
-rwxr-xr-xtest/functional/rpc_createmultisig.py16
-rwxr-xr-xtest/functional/rpc_getblockfrompeer.py4
-rwxr-xr-xtest/functional/rpc_getdescriptorinfo.py4
-rwxr-xr-xtest/functional/rpc_help.py4
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py6
-rwxr-xr-xtest/functional/rpc_packages.py40
-rwxr-xr-xtest/functional/rpc_psbt.py105
-rwxr-xr-xtest/functional/rpc_scanblocks.py4
-rwxr-xr-xtest/functional/rpc_scantxoutset.py10
-rwxr-xr-xtest/functional/rpc_setban.py8
-rwxr-xr-xtest/functional/rpc_signrawtransactionwithkey.py24
-rwxr-xr-xtest/functional/rpc_validateaddress.py203
-rw-r--r--test/functional/test-shell.md16
-rw-r--r--test/functional/test_framework/address.py21
-rw-r--r--test/functional/test_framework/authproxy.py29
-rw-r--r--test/functional/test_framework/blocktools.py3
-rw-r--r--test/functional/test_framework/key.py8
-rwxr-xr-xtest/functional/test_framework/messages.py22
-rw-r--r--test/functional/test_framework/muhash.py4
-rwxr-xr-xtest/functional/test_framework/test_framework.py36
-rwxr-xr-xtest/functional/test_framework/test_node.py15
-rw-r--r--test/functional/test_framework/util.py53
-rw-r--r--test/functional/test_framework/wallet.py47
-rwxr-xr-xtest/functional/test_framework/wallet_util.py23
-rwxr-xr-xtest/functional/test_runner.py17
-rwxr-xr-xtest/functional/tool_wallet.py3
-rwxr-xr-xtest/functional/wallet_abandonconflict.py12
-rwxr-xr-xtest/functional/wallet_address_types.py2
-rwxr-xr-xtest/functional/wallet_avoidreuse.py3
-rwxr-xr-xtest/functional/wallet_backwards_compatibility.py9
-rwxr-xr-xtest/functional/wallet_balance.py35
-rwxr-xr-xtest/functional/wallet_basic.py49
-rwxr-xr-xtest/functional/wallet_blank.py164
-rwxr-xr-xtest/functional/wallet_bumpfee.py153
-rwxr-xr-xtest/functional/wallet_conflicts.py127
-rwxr-xr-xtest/functional/wallet_create_tx.py1
-rwxr-xr-xtest/functional/wallet_createwallet.py34
-rwxr-xr-xtest/functional/wallet_descriptor.py32
-rwxr-xr-xtest/functional/wallet_fast_rescan.py3
-rwxr-xr-xtest/functional/wallet_fundrawtransaction.py169
-rwxr-xr-xtest/functional/wallet_hd.py10
-rwxr-xr-xtest/functional/wallet_import_rescan.py2
-rwxr-xr-xtest/functional/wallet_importdescriptors.py6
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py9
-rwxr-xr-xtest/functional/wallet_keypool.py14
-rwxr-xr-xtest/functional/wallet_keypool_topup.py6
-rwxr-xr-xtest/functional/wallet_labels.py4
-rwxr-xr-xtest/functional/wallet_listdescriptors.py2
-rwxr-xr-xtest/functional/wallet_listsinceblock.py9
-rwxr-xr-xtest/functional/wallet_migration.py53
-rwxr-xr-xtest/functional/wallet_multisig_descriptor_psbt.py4
-rwxr-xr-xtest/functional/wallet_orphanedreward.py5
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py6
-rwxr-xr-xtest/functional/wallet_send.py8
-rwxr-xr-xtest/functional/wallet_sendall.py18
-rwxr-xr-xtest/functional/wallet_signer.py20
-rwxr-xr-xtest/functional/wallet_taproot.py2
-rwxr-xr-xtest/functional/wallet_timelock.py2
-rwxr-xr-xtest/functional/wallet_watchonly.py4
-rwxr-xr-xtest/fuzz/test_runner.py22
-rwxr-xr-xtest/lint/lint-assertions.py10
-rwxr-xr-xtest/lint/lint-circular-dependencies.py2
-rwxr-xr-xtest/lint/lint-includes.py7
-rwxr-xr-xtest/lint/lint-locale-dependence.py2
-rwxr-xr-xtest/lint/lint-python-utf8-encoding.py2
-rwxr-xr-xtest/lint/lint-python.py15
-rwxr-xr-xtest/lint/run-lint-format-strings.py30
-rw-r--r--test/lint/spelling.ignore-words.txt1
-rw-r--r--test/sanitizer_suppressions/lsan3
-rw-r--r--test/sanitizer_suppressions/tsan5
-rw-r--r--test/sanitizer_suppressions/ubsan9
-rwxr-xr-xtest/util/test_runner.py5
789 files changed, 30754 insertions, 11419 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 2ae49be7d2..40db8321b2 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -47,6 +47,7 @@ container_depends_template: &CONTAINER_DEPENDS_TEMPLATE
cpu: 2
greedy: true
memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-containers
+ dockerfile: ci/test_imagefile # https://cirrus-ci.org/guide/docker-builder-vm/#dockerfile-as-a-ci-environment
depends_built_cache:
folder: "depends/built"
fingerprint_script: echo $CIRRUS_TASK_NAME $(git rev-parse HEAD:depends)
@@ -80,17 +81,18 @@ task:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
task:
- name: 'tidy [bookworm]'
+ name: 'tidy [lunar]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: debian:bookworm
cpu: 2
memory: 5G
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:lunar
+ FILE_ENV: "./ci/test/00_setup_env_native_tidy.sh"
# For faster CI feedback, immediately schedule the linters
<< : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_native_tidy.sh"
task:
name: "Win64 native [vs2022]"
@@ -191,38 +193,40 @@ task:
task:
name: 'ARM [unit tests, no functional tests] [bullseye]'
<< : *GLOBAL_TASK_TEMPLATE
- arm_container:
- image: debian:bullseye
- cpu: 2
- memory: 8G
+ container:
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: debian:bullseye
+ FILE_ENV: "./ci/test/00_setup_env_arm.sh"
+ << : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_arm.sh"
- QEMU_USER_CMD: "" # Disable qemu and run the test natively
task:
name: 'Win64 [unit tests, no gui tests, no boost::process, no functional tests] [jammy]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:jammy
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:jammy
+ FILE_ENV: "./ci/test/00_setup_env_win64.sh"
+ << : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_win64.sh"
task:
- name: '32-bit + dash [gui] [CentOS 8]'
+ name: '32-bit + dash [gui] [CentOS 9]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: quay.io/centos/centos:stream8
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: quay.io/centos/centos:stream9
+ FILE_ENV: "./ci/test/00_setup_env_i686_centos.sh"
# For faster CI feedback, immediately schedule one task that runs all tests
<< : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
PACKAGE_MANAGER_INSTALL: "yum install -y"
- FILE_ENV: "./ci/test/00_setup_env_i686_centos.sh"
task:
- name: '[previous releases, uses qt5 dev package and some depends packages, DEBUG] [unsigned char] [buster]'
+ name: '[previous releases, qt5 dev package and depends packages, DEBUG] [focal]'
previous_releases_cache:
folder: "releases"
<< : *GLOBAL_TASK_TEMPLATE
@@ -232,28 +236,31 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_qt5.sh"
task:
- name: '[TSan, depends, gui] [jammy]'
+ name: '[TSan, depends, gui] [lunar]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:jammy
- cpu: 6 # Increase CPU and Memory to avoid timeout
- memory: 24G
+ cpu: 4
+ memory: 16G # The default memory is too small, so double everything
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:lunar
+ FILE_ENV: "./ci/test/00_setup_env_native_tsan.sh"
+ << : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_native_tsan.sh"
task:
- name: '[MSan, depends] [focal]'
+ name: '[MSan, depends] [jammy]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:focal
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:jammy
+ FILE_ENV: "./ci/test/00_setup_env_native_msan.sh"
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_native_msan.sh"
MAKEJOBS: "-j4" # Avoid excessive memory use due to MSan
task:
- name: '[ASan + LSan + UBSan + integer, no depends, USDT] [jammy]'
+ name: '[ASan + LSan + UBSan + integer, no depends, USDT] [lunar]'
<< : *GLOBAL_TASK_TEMPLATE
# We can't use a 'container' for the USDT interface tests as the CirrusCI
# containers don't have privileges to hook into bitcoind. CirrusCI uses
@@ -261,8 +268,9 @@ task:
# Images can be found here: https://cloud.google.com/compute/docs/images/os-details
compute_engine_instance:
image_project: ubuntu-os-cloud
- image: family/ubuntu-2204-lts # when upgrading, check if we can drop "ADD_UNTRUSTED_BPFCC_PPA"
+ image: family/ubuntu-2304-amd64 # https://cirrus-ci.org/guide/custom-vms/#custom-compute-engine-vms
cpu: 4
+ disk: 100
memory: 12G
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
@@ -271,41 +279,48 @@ task:
MAKEJOBS: "-j4" # Avoid excessive memory use
task:
- name: '[fuzzer,address,undefined,integer, no depends] [jammy]'
+ name: '[fuzzer,address,undefined,integer, no depends] [lunar]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:jammy
cpu: 4 # Increase CPU and memory to avoid timeout
memory: 16G
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:lunar
+ FILE_ENV: "./ci/test/00_setup_env_native_fuzz.sh"
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_native_fuzz.sh"
task:
name: '[multiprocess, i686, DEBUG] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: ubuntu:focal
cpu: 4
- memory: 16G # The default memory is sometimes just a bit too small, so double everything
+ memory: 16G # The default memory is too small, so double everything
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:focal
+ FILE_ENV: "./ci/test/00_setup_env_i686_multiprocess.sh"
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_i686_multiprocess.sh"
task:
- name: '[no wallet, libbitcoinkernel] [buster]'
+ name: '[no wallet, libbitcoinkernel] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
- image: debian:buster
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:focal
+ FILE_ENV: "./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh"
+ << : *CREDITS_TEMPLATE
env:
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh"
task:
- name: 'macOS 10.15 [gui, no tests] [focal]'
+ name: 'macOS 11.0 [gui, no tests] [jammy]'
<< : *CONTAINER_DEPENDS_TEMPLATE
container:
- image: ubuntu:focal
+ docker_arguments:
+ CI_IMAGE_NAME_TAG: ubuntu:jammy
+ FILE_ENV: "./ci/test/00_setup_env_mac.sh"
+ << : *CREDITS_TEMPLATE
macos_sdk_cache:
folder: "depends/SDKs/$MACOS_SDK"
fingerprint_key: "$MACOS_SDK"
@@ -313,13 +328,12 @@ task:
env:
MACOS_SDK: "Xcode-12.2-12B45b-extracted-SDK-with-libcxx-headers"
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_mac.sh"
task:
name: 'macOS 13 native arm64 [gui, sqlite only] [no depends]'
macos_instance:
# Use latest image, but hardcode version to avoid silent upgrades (and breaks)
- image: ghcr.io/cirruslabs/macos-ventura-xcode:14.1 # https://cirrus-ci.org/guide/macOS
+ image: ghcr.io/cirruslabs/macos-ventura-xcode:14.3.1 # https://cirrus-ci.org/guide/macOS
<< : *BASE_TEMPLATE
check_clang_script:
- clang --version
@@ -331,19 +345,3 @@ task:
CI_USE_APT_INSTALL: "no"
PACKAGE_MANAGER_INSTALL: "echo" # Nothing to do
FILE_ENV: "./ci/test/00_setup_env_mac_native_arm64.sh"
-
-task:
- name: 'ARM64 Android APK [jammy]'
- << : *CONTAINER_DEPENDS_TEMPLATE
- container:
- image: ubuntu:jammy
- android_sdk_cache:
- folder: "depends/SDKs/android"
- fingerprint_key: "ANDROID_API_LEVEL=28 ANDROID_BUILD_TOOLS_VERSION=28.0.3 ANDROID_NDK_VERSION=23.2.8568313"
- depends_sources_cache:
- folder: "depends/sources"
- fingerprint_script: git rev-parse HEAD:depends/packages
- << : *MAIN_TEMPLATE
- env:
- << : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
- FILE_ENV: "./ci/test/00_setup_env_android.sh"
diff --git a/.python-version b/.python-version
index 36f601f10e..eee6392d5c 100644
--- a/.python-version
+++ b/.python-version
@@ -1 +1 @@
-3.7.16
+3.8.16
diff --git a/.style.yapf b/.style.yapf
index 69d8c6aee4..350ac63855 100644
--- a/.style.yapf
+++ b/.style.yapf
@@ -107,7 +107,7 @@ each_dict_entry_on_separate_line=True
i18n_comment=
# The i18n function call names. The presence of this function stops
-# reformattting on that line, because the string it has cannot be moved
+# reformatting on that line, because the string it has cannot be moved
# away from the i18n comment.
i18n_function_call=
diff --git a/autogen.sh b/autogen.sh
index de16260b56..69c892ffa0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -14,3 +14,16 @@ fi
command -v autoreconf >/dev/null || \
(echo "configuration failed, please install autoconf first" && exit 1)
autoreconf --install --force --warnings=all
+
+if expr "'$(build-aux/config.guess --timestamp)" \< "'$(depends/config.guess --timestamp)" > /dev/null; then
+ chmod ug+w build-aux/config.guess
+ chmod ug+w src/secp256k1/build-aux/config.guess
+ cp depends/config.guess build-aux
+ cp depends/config.guess src/secp256k1/build-aux
+fi
+if expr "'$(build-aux/config.sub --timestamp)" \< "'$(depends/config.sub --timestamp)" > /dev/null; then
+ chmod ug+w build-aux/config.sub
+ chmod ug+w src/secp256k1/build-aux/config.sub
+ cp depends/config.sub build-aux
+ cp depends/config.sub src/secp256k1/build-aux
+fi
diff --git a/build-aux/m4/l_filesystem.m4 b/build-aux/m4/l_filesystem.m4
deleted file mode 100644
index ca3a0cd41c..0000000000
--- a/build-aux/m4/l_filesystem.m4
+++ /dev/null
@@ -1,47 +0,0 @@
-dnl Copyright (c) 2022 The Bitcoin Core developers
-dnl Distributed under the MIT software license, see the accompanying
-dnl file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-# GCC 8.1 and earlier requires -lstdc++fs
-# Clang 8.0.0 (libc++) and earlier requires -lc++fs
-
-m4_define([_CHECK_FILESYSTEM_testbody], [[
- #include <filesystem>
-
- namespace fs = std::filesystem;
-
- int main() {
- (void)fs::current_path().root_name();
- return 0;
- }
-]])
-
-AC_DEFUN([CHECK_FILESYSTEM], [
-
- AC_LANG_PUSH(C++)
-
- AC_MSG_CHECKING([whether std::filesystem can be used without link library])
-
- AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_FILESYSTEM_testbody])],[
- AC_MSG_RESULT([yes])
- ],[
- AC_MSG_RESULT([no])
- SAVED_LIBS="$LIBS"
- LIBS="$SAVED_LIBS -lstdc++fs"
- AC_MSG_CHECKING([whether std::filesystem needs -lstdc++fs])
- AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_FILESYSTEM_testbody])],[
- AC_MSG_RESULT([yes])
- ],[
- AC_MSG_RESULT([no])
- AC_MSG_CHECKING([whether std::filesystem needs -lc++fs])
- LIBS="$SAVED_LIBS -lc++fs"
- AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_FILESYSTEM_testbody])],[
- AC_MSG_RESULT([yes])
- ],[
- AC_MSG_FAILURE([cannot figure out how to use std::filesystem])
- ])
- ])
- ])
-
- AC_LANG_POP
-])
diff --git a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in
index fc9d7cbed6..a5702a83ba 100644
--- a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in
+++ b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj.in
@@ -12,7 +12,7 @@
@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj">
diff --git a/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj b/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj
index 0d6358e0d0..20cdb7bb6e 100644
--- a/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj
+++ b/build_msvc/bitcoin-qt/bitcoin-qt.vcxproj
@@ -13,7 +13,7 @@
<ResourceCompile Include="..\..\src\qt\res\bitcoin-qt-res.rc" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj">
diff --git a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
index 4e9b4916a0..52585b98f9 100644
--- a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
+++ b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
@@ -12,7 +12,7 @@
<ClCompile Include="..\..\src\bitcoin-tx.cpp" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj">
diff --git a/build_msvc/bitcoin-util/bitcoin-util.vcxproj b/build_msvc/bitcoin-util/bitcoin-util.vcxproj
index 8a0964824b..4ea27fe439 100644
--- a/build_msvc/bitcoin-util/bitcoin-util.vcxproj
+++ b/build_msvc/bitcoin-util/bitcoin-util.vcxproj
@@ -12,7 +12,7 @@
<ClCompile Include="..\..\src\bitcoin-util.cpp" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj">
diff --git a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
index 2ac0be9814..56d88d6a44 100644
--- a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
+++ b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
@@ -15,7 +15,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj">
diff --git a/build_msvc/bitcoin.sln b/build_msvc/bitcoin.sln
index 2a1ccf58fe..0931bf5dfe 100644
--- a/build_msvc/bitcoin.sln
+++ b/build_msvc/bitcoin.sln
@@ -2,7 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.452
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoinconsensus", "libbitcoinconsensus\libbitcoinconsensus.vcxproj", "{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_consensus", "libbitcoin_consensus\libbitcoin_consensus.vcxproj", "{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoind", "bitcoind\bitcoind.vcxproj", "{D4513DDF-6013-44DC-ADCC-12EAF6D1F038}"
EndProject
diff --git a/build_msvc/bitcoin_config.h.in b/build_msvc/bitcoin_config.h.in
index 02d8fc41c2..1716647486 100644
--- a/build_msvc/bitcoin_config.h.in
+++ b/build_msvc/bitcoin_config.h.in
@@ -38,15 +38,12 @@
/* Define to 1 to enable SQLite wallet */
#define USE_SQLITE 1
-/* Define to 1 to enable ZMQ functions */
+/* Define this symbol to enable ZMQ functions */
#define ENABLE_ZMQ 1
/* define if external signer support is enabled (requires Boost::Process) */
#define ENABLE_EXTERNAL_SIGNER /**/
-/* Define this symbol if the consensus lib has been built */
-#define HAVE_CONSENSUS_LIB 1
-
/* Define to 1 if you have the declaration of `be16toh', and to 0 if you
don't. */
#define HAVE_DECL_BE16TOH 0
diff --git a/build_msvc/bitcoind/bitcoind.vcxproj b/build_msvc/bitcoind/bitcoind.vcxproj
index b1204d0d5d..bb61865e14 100644
--- a/build_msvc/bitcoind/bitcoind.vcxproj
+++ b/build_msvc/bitcoind/bitcoind.vcxproj
@@ -15,7 +15,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj">
diff --git a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
index 4cb0bdc902..95fdcdb79b 100644
--- a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
+++ b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
@@ -11,15 +11,6 @@
<ClCompile Include="..\..\src\arith_uint256.cpp" />
<ClCompile Include="..\..\src\consensus\merkle.cpp" />
<ClCompile Include="..\..\src\consensus\tx_check.cpp" />
- <ClCompile Include="..\..\src\crypto\aes.cpp" />
- <ClCompile Include="..\..\src\crypto\chacha20.cpp" />
- <ClCompile Include="..\..\src\crypto\hmac_sha256.cpp" />
- <ClCompile Include="..\..\src\crypto\hmac_sha512.cpp" />
- <ClCompile Include="..\..\src\crypto\ripemd160.cpp" />
- <ClCompile Include="..\..\src\crypto\sha1.cpp" />
- <ClCompile Include="..\..\src\crypto\sha256.cpp" />
- <ClCompile Include="..\..\src\crypto\sha256_sse4.cpp" />
- <ClCompile Include="..\..\src\crypto\sha512.cpp" />
<ClCompile Include="..\..\src\hash.cpp" />
<ClCompile Include="..\..\src\primitives\block.cpp" />
<ClCompile Include="..\..\src\primitives\transaction.cpp" />
diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
index 0b90f341a7..777515aa3a 100644
--- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj
+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
@@ -14,7 +14,8 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;ENABLE_MODULE_ELLSWIFT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <UndefinePreprocessorDefinitions>USE_ASM_X86_64;%(UndefinePreprocessorDefinitions)</UndefinePreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4146;4244;4267;4334</DisableSpecificWarnings>
</ClCompile>
diff --git a/build_msvc/libsecp256k1_config.h b/build_msvc/libsecp256k1_config.h
deleted file mode 100644
index 2b1a980e27..0000000000
--- a/build_msvc/libsecp256k1_config.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/**********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
-
-#ifndef BITCOIN_LIBSECP256K1_CONFIG_H
-#define BITCOIN_LIBSECP256K1_CONFIG_H
-
-#undef USE_ASM_X86_64
-
-#define ECMULT_GEN_PREC_BITS 4
-#define ECMULT_WINDOW_SIZE 15
-
-#endif // BITCOIN_LIBSECP256K1_CONFIG_H
diff --git a/build_msvc/libtest_util/libtest_util.vcxproj.in b/build_msvc/libtest_util/libtest_util.vcxproj.in
index b5e844010e..64cfa82dcc 100644
--- a/build_msvc/libtest_util/libtest_util.vcxproj.in
+++ b/build_msvc/libtest_util/libtest_util.vcxproj.in
@@ -8,6 +8,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<ItemGroup>
+ <ClCompile Include="..\..\src\wallet\test\util.cpp" />
@SOURCE_FILES@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py
index e02e3abdfa..9484f0cb89 100755
--- a/build_msvc/msvc-autogen.py
+++ b/build_msvc/msvc-autogen.py
@@ -111,7 +111,6 @@ def main():
set_properties(vcxproj_filename, '@SOURCE_FILES@\n', content)
parse_config_into_btc_config()
copyfile(os.path.join(SOURCE_DIR,'../build_msvc/bitcoin_config.h'), os.path.join(SOURCE_DIR, 'config/bitcoin-config.h'))
- copyfile(os.path.join(SOURCE_DIR,'../build_msvc/libsecp256k1_config.h'), os.path.join(SOURCE_DIR, 'secp256k1/src/libsecp256k1-config.h'))
if __name__ == '__main__':
main()
diff --git a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
index 3a2540d549..3776317fc7 100644
--- a/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
+++ b/build_msvc/test_bitcoin-qt/test_bitcoin-qt.vcxproj
@@ -10,13 +10,18 @@
<ItemGroup>
<ClCompile Include="..\..\src\init\bitcoin-qt.cpp" />
<ClCompile Include="..\..\src\test\util\setup_common.cpp" />
+ <ClCompile Include="..\..\src\wallet\test\util.cpp">
+ <ObjectFileName>$(IntDir)wallet_test_util.obj</ObjectFileName>
+ </ClCompile>
<ClCompile Include="..\..\src\qt\test\addressbooktests.cpp" />
<ClCompile Include="..\..\src\qt\test\apptests.cpp" />
<ClCompile Include="..\..\src\qt\test\optiontests.cpp" />
<ClCompile Include="..\..\src\qt\test\rpcnestedtests.cpp" />
<ClCompile Include="..\..\src\qt\test\test_main.cpp" />
<ClCompile Include="..\..\src\qt\test\uritests.cpp" />
- <ClCompile Include="..\..\src\qt\test\util.cpp" />
+ <ClCompile Include="..\..\src\qt\test\util.cpp">
+ <ObjectFileName>$(IntDir)qt_test_util.obj</ObjectFileName>
+ </ClCompile>
<ClCompile Include="..\..\src\qt\test\wallettests.cpp" />
<ClCompile Include="..\..\src\wallet\test\wallet_test_fixture.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_addressbooktests.cpp" />
@@ -27,7 +32,7 @@
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_wallettests.cpp" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj">
diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj
index 4182448ec3..c0c84fc6f1 100644
--- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj
+++ b/build_msvc/test_bitcoin/test_bitcoin.vcxproj
@@ -22,7 +22,7 @@
<ProjectReference Include="..\libminisketch\libminisketch.vcxproj">
<Project>{542007e3-be0d-4b0d-a6b0-aa8813e2558d}</Project>
</ProjectReference>
- <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <ProjectReference Include="..\libbitcoin_consensus\libbitcoin_consensus.vcxproj">
<Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj">
diff --git a/build_msvc/vcpkg.json b/build_msvc/vcpkg.json
index 86773d1fd3..3557269be0 100644
--- a/build_msvc/vcpkg.json
+++ b/build_msvc/vcpkg.json
@@ -13,5 +13,12 @@
"features": ["thread"]
},
"zeromq"
+ ],
+ "builtin-baseline": "f14984af3738e69f197bf0e647a8dca12de92996",
+ "overrides": [
+ {
+ "name": "libevent",
+ "version": "2.1.12#7"
+ }
]
}
diff --git a/ci/README.md b/ci/README.md
index de798607df..b4158d0183 100644
--- a/ci/README.md
+++ b/ci/README.md
@@ -14,16 +14,10 @@ testing compared to other parts of the codebase. If you want to keep the work tr
system in a virtual machine with a Linux operating system of your choice.
To allow for a wide range of tested environments, but also ensure reproducibility to some extent, the test stage
-requires `docker` to be installed. To install all requirements on Ubuntu, run
+requires `bash`, `docker`, and `python3` to be installed. To install all requirements on Ubuntu, run
```
-sudo apt install docker.io bash
-```
-
-To run the default test stage,
-
-```
-./ci/test_run_all.sh
+sudo apt install bash docker.io python3
```
To run the test stage with a specific configuration,
diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh
index f7147582dc..737cf3e2fb 100755
--- a/ci/lint/04_install.sh
+++ b/ci/lint/04_install.sh
@@ -35,6 +35,7 @@ fi
${CI_RETRY_EXE} pip3 install codespell==2.2.1
${CI_RETRY_EXE} pip3 install flake8==5.0.4
+${CI_RETRY_EXE} pip3 install lief==0.13.1
${CI_RETRY_EXE} pip3 install mypy==0.971
${CI_RETRY_EXE} pip3 install pyzmq==24.0.1
${CI_RETRY_EXE} pip3 install vulture==2.6
diff --git a/ci/lint/Dockerfile b/ci/lint/Dockerfile
index 03c20c7286..a0a4516480 100644
--- a/ci/lint/Dockerfile
+++ b/ci/lint/Dockerfile
@@ -5,7 +5,7 @@
# entire repo as docker context during build; if it lived elsewhere, it wouldn't be
# able to make back-references to pull in the install scripts. So here it lives.
-FROM python:3.7-buster
+FROM python:3.8-buster
ENV DEBIAN_FRONTEND=noninteractive
ENV LC_ALL=C.UTF-8
diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh
index 4a54f47b03..69fd05051e 100755
--- a/ci/test/00_setup_env.sh
+++ b/ci/test/00_setup_env.sh
@@ -6,6 +6,8 @@
export LC_ALL=C.UTF-8
+set -ex
+
# The root dir.
# The ci system copies this folder.
BASE_ROOT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../ >/dev/null 2>&1 && pwd )
@@ -37,7 +39,6 @@ export USE_BUSY_BOX=${USE_BUSY_BOX:-false}
export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true}
export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true}
export RUN_TIDY=${RUN_TIDY:-false}
-export RUN_SECURITY_TESTS=${RUN_SECURITY_TESTS:-false}
# By how much to scale the test_runner timeouts (option --timeout-factor).
# This is needed because some ci machines have slow CPU or disk, so sanitizers
# might be slow or a reindex might be waiting on disk IO.
@@ -45,8 +46,6 @@ export TEST_RUNNER_TIMEOUT_FACTOR=${TEST_RUNNER_TIMEOUT_FACTOR:-40}
export TEST_RUNNER_ENV=${TEST_RUNNER_ENV:-}
export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
-export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed}
-export CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG:-ubuntu:20.04}
# Randomize test order.
# See https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/utf_reference/rt_param_reference/random.html
export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1}
diff --git a/ci/test/00_setup_env_i686_centos.sh b/ci/test/00_setup_env_i686_centos.sh
index 8a931d44e5..606c28e252 100755
--- a/ci/test/00_setup_env_i686_centos.sh
+++ b/ci/test/00_setup_env_i686_centos.sh
@@ -8,11 +8,10 @@ export LC_ALL=C.UTF-8
export HOST=i686-pc-linux-gnu
export CONTAINER_NAME=ci_i686_centos
-export CI_IMAGE_NAME_TAG=quay.io/centos/centos:stream8
-export CI_BASE_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python38 python38-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison"
+export CI_IMAGE_NAME_TAG="quay.io/centos/centos:stream9"
+export CI_BASE_PACKAGES="gcc-c++ glibc-devel.x86_64 libstdc++-devel.x86_64 glibc-devel.i686 libstdc++-devel.i686 ccache libtool make git python3 python3-pip which patch lbzip2 xz procps-ng dash rsync coreutils bison util-linux"
export PIP_PACKAGES="pyzmq"
export GOAL="install"
-export NO_WERROR=1 # GCC 8
+export NO_WERROR=1 # Suppress error: #warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform [-Werror=cpp]
export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports"
export CONFIG_SHELL="/bin/dash"
-export TEST_RUNNER_ENV="LC_ALL=en_US.UTF-8"
diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh
index 9e3ea0d383..8ab4d54d31 100755
--- a/ci/test/00_setup_env_i686_multiprocess.sh
+++ b/ci/test/00_setup_env_i686_multiprocess.sh
@@ -12,6 +12,7 @@ export CI_IMAGE_NAME_TAG=ubuntu:20.04
export PACKAGES="cmake python3 llvm clang g++-multilib"
export DEP_OPTS="DEBUG=1 MULTIPROCESS=1"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-debug CC='clang -m32' CXX='clang++ -m32' LDFLAGS='--rtlib=compiler-rt -lgcc_s'"
+export BITCOIN_CONFIG="--enable-debug CC='clang -m32' CXX='clang++ -m32' \
+LDFLAGS='--rtlib=compiler-rt -lgcc_s' CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE'"
export TEST_RUNNER_ENV="BITCOIND=bitcoin-node"
export TEST_RUNNER_EXTRA="--nosandbox"
diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh
index fe42871c31..65c6119fcd 100755
--- a/ci/test/00_setup_env_mac.sh
+++ b/ci/test/00_setup_env_mac.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_macos_cross
-export CI_IMAGE_NAME_TAG=ubuntu:20.04 # Check that Focal can cross-compile to macos
+export CI_IMAGE_NAME_TAG=ubuntu:22.04
export HOST=x86_64-apple-darwin
export PACKAGES="cmake libz-dev libtinfo5 python3-setuptools xorriso"
export XCODE_VERSION=12.2
@@ -15,4 +15,7 @@ export XCODE_BUILD_ID=12B45b
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
-export BITCOIN_CONFIG="--with-gui --enable-reduce-exports"
+
+# False-positive warning is fixed with clang 17, remove this when that version
+# can be used.
+export BITCOIN_CONFIG="--with-gui --enable-reduce-exports LDFLAGS=-Wno-error=unused-command-line-argument"
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index bb3f6997f3..4de9511630 100755
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -8,19 +8,16 @@ export LC_ALL=C.UTF-8
# Only install BCC tracing packages in Cirrus CI.
if [[ "${CIRRUS_CI}" == "true" ]]; then
- # We install an up-to-date 'bpfcc-tools' package from an untrusted PPA.
- # This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages.
- # See the if-then in ci/test/04_install.sh too.
- export ADD_UNTRUSTED_BPFCC_PPA=true
export BPFCC_PACKAGE="bpfcc-tools"
else
- export ADD_UNTRUSTED_BPFCC_PPA=false
export BPFCC_PACKAGE=""
fi
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="systemtap-sdt-dev clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}"
-export CI_IMAGE_NAME_TAG=ubuntu:22.04
+export PACKAGES="systemtap-sdt-dev clang-16 llvm-16 libclang-rt-16-dev python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev ${BPFCC_PACKAGE}"
+export CI_IMAGE_NAME_TAG=ubuntu:23.04 # Version 23.04 will reach EOL in Jan 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
export NO_DEPENDS=1
export GOAL="install"
-export BITCOIN_CONFIG="--enable-c++20 --enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
+export BITCOIN_CONFIG="--enable-c++20 --enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 \
+CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' \
+--with-sanitizers=address,float-divide-by-zero,integer,undefined CC=clang-16 CXX=clang++-16"
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index a2d393bb5a..298eb11da3 100755
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -6,13 +6,14 @@
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="ubuntu:23.04" # Version 23.04 will reach EOL in Jan 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
export CONTAINER_NAME=ci_native_fuzz
-export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev"
+export PACKAGES="clang-16 llvm-16 libclang-rt-16-dev python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
export GOAL="install"
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,integer CC='clang -ftrivial-auto-var-init=pattern' CXX='clang++ -ftrivial-auto-var-init=pattern'"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,float-divide-by-zero,integer \
+CC='clang-16 -ftrivial-auto-var-init=pattern' CXX='clang++-16 -ftrivial-auto-var-init=pattern'"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_fuzz_with_msan.sh b/ci/test/00_setup_env_native_fuzz_with_msan.sh
index 7886f6efc9..1f9adc0682 100755
--- a/ci/test/00_setup_env_native_fuzz_with_msan.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_msan.sh
@@ -6,18 +6,18 @@
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="ubuntu:20.04"
-LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/build/"
+export CI_IMAGE_NAME_TAG="ubuntu:22.04"
+LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/cxx_build/"
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
-LIBCXX_FLAGS="-nostdinc++ -stdlib=libc++ -L${LIBCXX_DIR}lib -lc++abi -I${LIBCXX_DIR}include -I${LIBCXX_DIR}include/c++/v1 -lpthread -Wl,-rpath,${LIBCXX_DIR}lib -Wno-unused-command-line-argument"
+LIBCXX_FLAGS="-nostdinc++ -nostdlib++ -isystem ${LIBCXX_DIR}include/c++/v1 -L${LIBCXX_DIR}lib -Wl,-rpath,${LIBCXX_DIR}lib -lc++ -lc++abi -lpthread -Wno-unused-command-line-argument"
export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
export CONTAINER_NAME="ci_native_fuzz_msan"
-export PACKAGES="clang-12 llvm-12 cmake"
+export PACKAGES="cmake ninja-build"
# BDB generates false-positives and will be removed in future
-export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export DEP_OPTS="NO_BDB=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,memory --disable-hardening --with-asm=no CFLAGS='${MSAN_FLAGS}' CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export USE_MEMORY_SANITIZER="true"
export RUN_UNIT_TESTS="false"
export RUN_FUNCTIONAL_TESTS="false"
diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
index 75c10046b7..5fee10e37e 100755
--- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
@@ -6,15 +6,15 @@
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="debian:bookworm"
export CONTAINER_NAME=ci_native_fuzz_valgrind
-export PACKAGES="clang llvm python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev valgrind"
+export PACKAGES="clang llvm libclang-rt-dev python3 libevent-dev bsdmainutils libboost-dev libsqlite3-dev valgrind"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
export FUZZ_TESTS_CONFIG="--valgrind"
export GOAL="install"
-# Temporarily pin dwarf 4, until valgrind can understand clang's dwarf 5
+# Temporarily pin dwarf 4, until using Valgrind 3.20 or later
export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang CXX=clang++ CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_msan.sh b/ci/test/00_setup_env_native_msan.sh
index 1f9209bafb..34d60c6c4c 100755
--- a/ci/test/00_setup_env_native_msan.sh
+++ b/ci/test/00_setup_env_native_msan.sh
@@ -1,23 +1,23 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2020-2022 The Bitcoin Core developers
+# Copyright (c) 2020-2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="ubuntu:20.04"
-LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/build/"
+export CI_IMAGE_NAME_TAG="ubuntu:22.04"
+LIBCXX_DIR="${BASE_SCRATCH_DIR}/msan/cxx_build/"
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
-LIBCXX_FLAGS="-nostdinc++ -stdlib=libc++ -L${LIBCXX_DIR}lib -lc++abi -I${LIBCXX_DIR}include -I${LIBCXX_DIR}include/c++/v1 -lpthread -Wl,-rpath,${LIBCXX_DIR}lib -Wno-unused-command-line-argument"
+LIBCXX_FLAGS="-nostdinc++ -nostdlib++ -isystem ${LIBCXX_DIR}include/c++/v1 -L${LIBCXX_DIR}lib -Wl,-rpath,${LIBCXX_DIR}lib -lc++ -lc++abi -lpthread -Wno-unused-command-line-argument"
export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
export CONTAINER_NAME="ci_native_msan"
-export PACKAGES="clang-12 llvm-12 cmake"
+export PACKAGES="cmake ninja-build"
# BDB generates false-positives and will be removed in future
-export DEP_OPTS="NO_BDB=1 NO_QT=1 CC='clang' CXX='clang++' CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export DEP_OPTS="NO_BDB=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="install"
-export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
+export BITCOIN_CONFIG="--with-sanitizers=memory --disable-hardening --with-asm=no CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export USE_MEMORY_SANITIZER="true"
export RUN_FUNCTIONAL_TESTS="false"
export CCACHE_SIZE=250M
diff --git a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
index 06bc2401c5..8e3c935c6f 100755
--- a/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
+++ b/ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
@@ -7,11 +7,9 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_nowallet_libbitcoinkernel
-export CI_IMAGE_NAME_TAG=debian:buster
-# Use minimum supported python3.7 and clang-8, see doc/dependencies.md
-export PACKAGES="-t buster-backports python3-zmq clang-8 llvm-8 libc++abi-8-dev libc++-8-dev"
-export APPEND_APT_SOURCES_LIST="deb http://deb.debian.org/debian buster-backports main"
-export DEP_OPTS="NO_WALLET=1 CC=clang-8 CXX='clang++-8 -stdlib=libc++'"
+export CI_IMAGE_NAME_TAG="ubuntu:20.04"
+# Use minimum supported python3.8 and clang-10, see doc/dependencies.md
+export PACKAGES="python3-zmq clang-10 llvm-10 libc++abi-10-dev libc++-10-dev"
+export DEP_OPTS="NO_WALLET=1 CC=clang-10 CXX='clang++-10 -stdlib=libc++'"
export GOAL="install"
-export NO_WERROR=1
-export BITCOIN_CONFIG="--enable-reduce-exports CC=clang-8 CXX='clang++-8 -stdlib=libc++' --enable-experimental-util-chainstate --with-experimental-kernel-lib --enable-shared"
+export BITCOIN_CONFIG="--enable-reduce-exports --enable-experimental-util-chainstate --with-experimental-kernel-lib --enable-shared"
diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index 5cc0addd33..3a1d7808f1 100755
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -7,15 +7,15 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_qt5
-export CI_IMAGE_NAME_TAG=debian:buster
-# Use minimum supported python3.7 and gcc-8, see doc/dependencies.md
-export PACKAGES="gcc-8 g++-8 python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
-export DEP_OPTS="NO_QT=1 NO_UPNP=1 NO_NATPMP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1 CC=gcc-8 CXX=g++-8"
+export CI_IMAGE_NAME_TAG="ubuntu:20.04"
+# Use minimum supported python3.8 and gcc-9, see doc/dependencies.md
+export PACKAGES="gcc-9 g++-9 python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
+export DEP_OPTS="NO_QT=1 NO_UPNP=1 NO_NATPMP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1 CC=gcc-9 CXX=g++-9"
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
-export NO_WERROR=1
+export NO_WERROR=1 # -Werror=maybe-uninitialized
export DOWNLOAD_PREVIOUS_RELEASES="true"
-export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports \
---enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\" CC=gcc-8 CXX=g++-8"
+export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports --enable-debug \
+CFLAGS=\"-g0 -O2 -funsigned-char\" CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS=\"-g0 -O2 -funsigned-char\""
diff --git a/ci/test/00_setup_env_native_tidy.sh b/ci/test/00_setup_env_native_tidy.sh
index 994275f3dd..920180a274 100755
--- a/ci/test/00_setup_env_native_tidy.sh
+++ b/ci/test/00_setup_env_native_tidy.sh
@@ -1,19 +1,19 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2022 The Bitcoin Core developers
+# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="debian:bookworm"
+export CI_IMAGE_NAME_TAG="ubuntu:lunar" # Version 23.04 will reach EOL in Jan 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
export CONTAINER_NAME=ci_native_tidy
-export PACKAGES="clang-15 libclang-15-dev llvm-15-dev clang-tidy-15 bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev"
+export PACKAGES="clang-16 libclang-16-dev llvm-16-dev libomp-16-dev clang-tidy-16 jq bear cmake libevent-dev libboost-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev systemtap-sdt-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libqrencode-dev libsqlite3-dev libdb++-dev"
export NO_DEPENDS=1
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=false
export RUN_TIDY=true
export GOAL="install"
-export BITCOIN_CONFIG="CC=clang-15 CXX=clang++-15 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
+export BITCOIN_CONFIG="CC=clang-16 CXX=clang++-16 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0 -I/usr/lib/llvm-16/lib/clang/16/include'"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_tsan.sh b/ci/test/00_setup_env_native_tsan.sh
index 61bcd98f0a..8ebb1fa563 100755
--- a/ci/test/00_setup_env_native_tsan.sh
+++ b/ci/test/00_setup_env_native_tsan.sh
@@ -1,14 +1,14 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019-2022 The Bitcoin Core developers
+# Copyright (c) 2019-2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_tsan
-export CI_IMAGE_NAME_TAG=ubuntu:22.04
-export PACKAGES="clang-13 llvm-13 libc++abi-13-dev libc++-13-dev python3-zmq"
-export DEP_OPTS="CC=clang-13 CXX='clang++-13 -stdlib=libc++'"
+export CI_IMAGE_NAME_TAG=ubuntu:23.04 # Version 23.04 will reach EOL in Jan 2024, and can be replaced by "ubuntu:24.04" (or anything else that ships the wanted clang version).
+export PACKAGES="clang-16 llvm-16 libclang-rt-16-dev libc++abi-16-dev libc++-16-dev python3-zmq"
+export DEP_OPTS="CC=clang-16 CXX='clang++-16 -stdlib=libc++'"
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER -DDEBUG_LOCKCONTENTION' CXXFLAGS='-g' --with-sanitizers=thread"
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index 039a22b02e..97b85755ef 100755
--- a/ci/test/00_setup_env_native_valgrind.sh
+++ b/ci/test/00_setup_env_native_valgrind.sh
@@ -6,12 +6,12 @@
export LC_ALL=C.UTF-8
-export CI_IMAGE_NAME_TAG="ubuntu:22.04"
+export CI_IMAGE_NAME_TAG="debian:bookworm"
export CONTAINER_NAME=ci_native_valgrind
-export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
+export PACKAGES="valgrind clang llvm libclang-rt-dev python3-zmq libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
export USE_VALGRIND=1
export NO_DEPENDS=1
export TEST_RUNNER_EXTRA="--nosandbox --exclude feature_init,rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
export GOAL="install"
-# Temporarily pin dwarf 4, until valgrind can understand clang's dwarf 5
+# Temporarily pin dwarf 4, until using Valgrind 3.20 or later
export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang CXX=clang++ CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'" # TODO enable GUI
diff --git a/ci/test/01_base_install.sh b/ci/test/01_base_install.sh
index a050067ae4..76cde42161 100755
--- a/ci/test/01_base_install.sh
+++ b/ci/test/01_base_install.sh
@@ -6,35 +6,28 @@
export LC_ALL=C.UTF-8
-# This script is always run as root, and the functions can be removed and
-# replaced by a bash -c "command" directly, where needed.
-# For now, they are named aliases to aid review with --color-moved=dimmed-zebra.
-CI_EXEC_ROOT () { bash -c "$*"; }
-CI_EXEC() { bash -c "$*"; }
-export -f CI_EXEC_ROOT
-export -f CI_EXEC
+set -ex
+
+CFG_DONE="ci.base-install-done" # Use a global git setting to remember whether this script ran to avoid running it twice
+
+if [ "$(git config --global ${CFG_DONE})" == "true" ]; then
+ echo "Skip base install"
+ exit 0
+fi
if [ -n "$DPKG_ADD_ARCH" ]; then
- CI_EXEC_ROOT dpkg --add-architecture "$DPKG_ADD_ARCH"
+ dpkg --add-architecture "$DPKG_ADD_ARCH"
fi
if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then
- ${CI_RETRY_EXE} CI_EXEC_ROOT dnf -y install epel-release
- ${CI_RETRY_EXE} CI_EXEC_ROOT dnf -y --allowerasing install "$CI_BASE_PACKAGES" "$PACKAGES"
+ bash -c "dnf -y install epel-release"
+ bash -c "dnf -y --allowerasing install $CI_BASE_PACKAGES $PACKAGES"
elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
- if [[ "${ADD_UNTRUSTED_BPFCC_PPA}" == "true" ]]; then
- # Ubuntu 22.04 LTS and Debian 11 both have an outdated bpfcc-tools packages.
- # The iovisor PPA is outdated as well. The next Ubuntu and Debian releases will contain updated
- # packages. Meanwhile, use an untrusted PPA to install an up-to-date version of the bpfcc-tools
- # package.
- # TODO: drop this once we can use newer images in GCE
- CI_EXEC_ROOT add-apt-repository ppa:hadret/bpfcc
- fi
if [[ -n "${APPEND_APT_SOURCES_LIST}" ]]; then
- CI_EXEC_ROOT echo "${APPEND_APT_SOURCES_LIST}" \>\> /etc/apt/sources.list
+ echo "${APPEND_APT_SOURCES_LIST}" >> /etc/apt/sources.list
fi
- ${CI_RETRY_EXE} CI_EXEC_ROOT apt-get update
- ${CI_RETRY_EXE} CI_EXEC_ROOT apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$CI_BASE_PACKAGES"
+ ${CI_RETRY_EXE} apt-get update
+ ${CI_RETRY_EXE} bash -c "apt-get install --no-install-recommends --no-upgrade -y $PACKAGES $CI_BASE_PACKAGES"
fi
if [ -n "$PIP_PACKAGES" ]; then
@@ -44,29 +37,47 @@ if [ -n "$PIP_PACKAGES" ]; then
IN_GETOPT_BIN="$(brew --prefix gnu-getopt)/bin/getopt" ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
else
# shellcheck disable=SC2086
- ${CI_RETRY_EXE} CI_EXEC pip3 install --user $PIP_PACKAGES
+ ${CI_RETRY_EXE} pip3 install --user $PIP_PACKAGES
fi
fi
if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
- CI_EXEC_ROOT "update-alternatives --install /usr/bin/clang++ clang++ \$(which clang++-12) 100"
- CI_EXEC_ROOT "update-alternatives --install /usr/bin/clang clang \$(which clang-12) 100"
- CI_EXEC "mkdir -p ${BASE_SCRATCH_DIR}/msan/build/"
- CI_EXEC "git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-12.0.0 ${BASE_SCRATCH_DIR}/msan/llvm-project"
- CI_EXEC "cd ${BASE_SCRATCH_DIR}/msan/build/ && cmake -DLLVM_ENABLE_PROJECTS='libcxx;libcxxabi' -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_SANITIZER=MemoryWithOrigins -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_TARGETS_TO_BUILD=X86 ../llvm-project/llvm/"
- CI_EXEC "cd ${BASE_SCRATCH_DIR}/msan/build/ && make $MAKEJOBS cxx"
+ git clone --depth=1 https://github.com/llvm/llvm-project -b llvmorg-16.0.6 "${BASE_SCRATCH_DIR}"/msan/llvm-project
+
+ cmake -G Ninja -B "${BASE_SCRATCH_DIR}"/msan/clang_build/ -DLLVM_ENABLE_PROJECTS="clang" \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_TARGETS_TO_BUILD=Native \
+ -DLLVM_ENABLE_RUNTIMES="compiler-rt;libcxx;libcxxabi;libunwind" \
+ -S "${BASE_SCRATCH_DIR}"/msan/llvm-project/llvm
+
+ ninja -C "${BASE_SCRATCH_DIR}"/msan/clang_build/ "$MAKEJOBS"
+ ninja -C "${BASE_SCRATCH_DIR}"/msan/clang_build/ install-runtimes
+
+ update-alternatives --install /usr/bin/clang++ clang++ "${BASE_SCRATCH_DIR}"/msan/clang_build/bin/clang++ 100
+ update-alternatives --install /usr/bin/clang clang "${BASE_SCRATCH_DIR}"/msan/clang_build/bin/clang 100
+ update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer "${BASE_SCRATCH_DIR}"/msan/clang_build/bin/llvm-symbolizer 100
+
+ cmake -G Ninja -B "${BASE_SCRATCH_DIR}"/msan/cxx_build/ -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi' \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_USE_SANITIZER=MemoryWithOrigins \
+ -DCMAKE_C_COMPILER=clang \
+ -DCMAKE_CXX_COMPILER=clang++ \
+ -DLLVM_TARGETS_TO_BUILD=Native \
+ -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF \
+ -DLIBCXX_ENABLE_DEBUG_MODE=ON \
+ -DLIBCXX_ENABLE_ASSERTIONS=ON \
+ -S "${BASE_SCRATCH_DIR}"/msan/llvm-project/runtimes
+
+ ninja -C "${BASE_SCRATCH_DIR}"/msan/cxx_build/ "$MAKEJOBS"
fi
if [[ "${RUN_TIDY}" == "true" ]]; then
- if [ ! -d "${DIR_IWYU}" ]; then
- CI_EXEC "mkdir -p ${DIR_IWYU}/build/"
- CI_EXEC "git clone --depth=1 https://github.com/include-what-you-use/include-what-you-use -b clang_15 ${DIR_IWYU}/include-what-you-use"
- CI_EXEC "cd ${DIR_IWYU}/build && cmake -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-15 ../include-what-you-use"
- CI_EXEC_ROOT "cd ${DIR_IWYU}/build && make install $MAKEJOBS"
- fi
+ git clone --depth=1 https://github.com/include-what-you-use/include-what-you-use -b clang_16 "${DIR_IWYU}"/include-what-you-use
+ cmake -B "${DIR_IWYU}"/build/ -G 'Unix Makefiles' -DCMAKE_PREFIX_PATH=/usr/lib/llvm-16 -S "${DIR_IWYU}"/include-what-you-use
+ make -C "${DIR_IWYU}"/build/ install "$MAKEJOBS"
fi
-CI_EXEC mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources"
+mkdir -p "${DEPENDS_DIR}/SDKs" "${DEPENDS_DIR}/sdk-sources"
OSX_SDK_BASENAME="Xcode-${XCODE_VERSION}-${XCODE_BUILD_ID}-extracted-SDK-with-libcxx-headers"
@@ -74,17 +85,19 @@ if [ -n "$XCODE_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${OSX_SDK_BASENAME}" ]
OSX_SDK_FILENAME="${OSX_SDK_BASENAME}.tar.gz"
OSX_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${OSX_SDK_FILENAME}"
if [ ! -f "$OSX_SDK_PATH" ]; then
- CI_EXEC curl --location --fail "${SDK_URL}/${OSX_SDK_FILENAME}" -o "$OSX_SDK_PATH"
+ curl --location --fail "${SDK_URL}/${OSX_SDK_FILENAME}" -o "$OSX_SDK_PATH"
fi
- CI_EXEC tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH"
+ tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH"
fi
if [ -n "$ANDROID_HOME" ] && [ ! -d "$ANDROID_HOME" ]; then
ANDROID_TOOLS_PATH=${DEPENDS_DIR}/sdk-sources/android-tools.zip
if [ ! -f "$ANDROID_TOOLS_PATH" ]; then
- CI_EXEC curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH"
+ curl --location --fail "${ANDROID_TOOLS_URL}" -o "$ANDROID_TOOLS_PATH"
fi
- CI_EXEC mkdir -p "$ANDROID_HOME"
- CI_EXEC unzip -o "$ANDROID_TOOLS_PATH" -d "$ANDROID_HOME"
- CI_EXEC "yes | ${ANDROID_HOME}/cmdline-tools/bin/sdkmanager --sdk_root=\"${ANDROID_HOME}\" --install \"build-tools;${ANDROID_BUILD_TOOLS_VERSION}\" \"platform-tools\" \"platforms;android-${ANDROID_API_LEVEL}\" \"ndk;${ANDROID_NDK_VERSION}\""
+ mkdir -p "$ANDROID_HOME"
+ unzip -o "$ANDROID_TOOLS_PATH" -d "$ANDROID_HOME"
+ yes | "${ANDROID_HOME}"/cmdline-tools/bin/sdkmanager --sdk_root="${ANDROID_HOME}" --install "build-tools;${ANDROID_BUILD_TOOLS_VERSION}" "platform-tools" "platforms;android-${ANDROID_API_LEVEL}" "ndk;${ANDROID_NDK_VERSION}"
fi
+
+git config --global ${CFG_DONE} "true"
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
index b4d507cdbb..626461df03 100755
--- a/ci/test/04_install.sh
+++ b/ci/test/04_install.sh
@@ -18,7 +18,6 @@ export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=
export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan"
export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:halt_on_error=1:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan"
export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
-env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|LC_ALL|BOOST_TEST_RANDOM|DEBIAN_FRONTEND|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|PREVIOUS_RELEASES_DIR)' | tee /tmp/env
if [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
CI_CONTAINER_CAP="--cap-add SYS_PTRACE"
fi
@@ -27,12 +26,10 @@ export P_CI_DIR="$PWD"
export BINS_SCRATCH_DIR="${BASE_SCRATCH_DIR}/bins/"
if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
+ # Export all env vars to avoid missing some.
+ # Though, exclude those with newlines to avoid parsing problems.
+ python3 -c 'import os; [print(f"{key}={value}") for key, value in os.environ.items() if "\n" not in value and "HOME" not in key]' | tee /tmp/env
echo "Creating $CI_IMAGE_NAME_TAG container to run in"
- LOCAL_UID=$(id -u)
- LOCAL_GID=$(id -g)
-
- # the name isn't important, so long as we use the same UID
- LOCAL_USER=nonroot
DOCKER_BUILDKIT=1 ${CI_RETRY_EXE} docker build \
--file "${BASE_ROOT_DIR}/ci/test_imagefile" \
--build-arg "CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG}" \
@@ -45,7 +42,9 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
if [ -n "${RESTART_CI_DOCKER_BEFORE_RUN}" ] ; then
echo "Restart docker before run to stop and clear all containers started with --rm"
- systemctl restart docker
+ podman container stop --all # Similar to "systemctl restart docker"
+ echo "Prune all dangling images"
+ docker image prune --force
fi
# shellcheck disable=SC2086
@@ -59,66 +58,21 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
--name $CONTAINER_NAME \
$CONTAINER_NAME)
export CI_CONTAINER_ID
- export CI_EXEC_CMD_PREFIX_ROOT="docker exec -u 0 $CI_CONTAINER_ID"
- export CI_EXEC_CMD_PREFIX="docker exec -u $LOCAL_UID $CI_CONTAINER_ID"
- $CI_EXEC_CMD_PREFIX_ROOT rsync --archive --stats --human-readable /ci_base_install/ "${BASE_ROOT_DIR}"
- $CI_EXEC_CMD_PREFIX_ROOT rsync --archive --stats --human-readable /ro_base/ "$BASE_ROOT_DIR"
-
- # Create a non-root user inside the container which matches the local user.
- #
- # This prevents the root user in the container modifying the local file system permissions
- # on the mounted directories
- docker exec "$CI_CONTAINER_ID" useradd -u "$LOCAL_UID" -o -m "$LOCAL_USER"
- docker exec "$CI_CONTAINER_ID" groupmod -o -g "$LOCAL_GID" "$LOCAL_USER"
- docker exec "$CI_CONTAINER_ID" chown -R "$LOCAL_USER":"$LOCAL_USER" "${BASE_ROOT_DIR}"
+ export CI_EXEC_CMD_PREFIX="docker exec ${CI_CONTAINER_ID}"
else
echo "Running on host system without docker wrapper"
- "${BASE_ROOT_DIR}/ci/test/01_base_install.sh"
fi
CI_EXEC () {
$CI_EXEC_CMD_PREFIX bash -c "export PATH=${BINS_SCRATCH_DIR}:\$PATH && cd \"$P_CI_DIR\" && $*"
}
-CI_EXEC_ROOT () {
- $CI_EXEC_CMD_PREFIX_ROOT bash -c "export PATH=${BINS_SCRATCH_DIR}:\$PATH && cd \"$P_CI_DIR\" && $*"
-}
export -f CI_EXEC
-export -f CI_EXEC_ROOT
-
-CI_EXEC mkdir -p "${BINS_SCRATCH_DIR}"
-
-if [ "$CI_OS_NAME" == "macos" ]; then
- top -l 1 -s 0 | awk ' /PhysMem/ {print}'
- echo "Number of CPUs: $(sysctl -n hw.logicalcpu)"
-else
- CI_EXEC free -m -h
- CI_EXEC echo "Number of CPUs \(nproc\):" \$\(nproc\)
- CI_EXEC echo "$(lscpu | grep Endian)"
-fi
-CI_EXEC echo "Free disk space:"
-CI_EXEC df -h
-if [ "$RUN_FUZZ_TESTS" = "true" ]; then
- export DIR_FUZZ_IN=${DIR_QA_ASSETS}/fuzz_seed_corpus/
- if [ ! -d "$DIR_FUZZ_IN" ]; then
- CI_EXEC git clone --depth=1 https://github.com/bitcoin-core/qa-assets "${DIR_QA_ASSETS}"
- fi
-elif [ "$RUN_UNIT_TESTS" = "true" ] || [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
- export DIR_UNIT_TEST_DATA=${DIR_QA_ASSETS}/unit_test_data/
- if [ ! -d "$DIR_UNIT_TEST_DATA" ]; then
- CI_EXEC mkdir -p "$DIR_UNIT_TEST_DATA"
- CI_EXEC curl --location --fail https://github.com/bitcoin-core/qa-assets/raw/main/unit_test_data/script_assets_test.json -o "${DIR_UNIT_TEST_DATA}/script_assets_test.json"
- fi
-fi
+CI_EXEC rsync --archive --stats --human-readable /ci_base_install/ "${BASE_ROOT_DIR}" || echo "/ci_base_install/ missing"
+CI_EXEC "${BASE_ROOT_DIR}/ci/test/01_base_install.sh"
+CI_EXEC rsync --archive --stats --human-readable /ro_base/ "${BASE_ROOT_DIR}" || echo "Nothing to copy from ro_base"
+# Fixes permission issues when there is a container UID/GID mismatch with the owner
+# of the git source code directory.
+CI_EXEC git config --global --add safe.directory \"*\"
-CI_EXEC mkdir -p "${BASE_SCRATCH_DIR}/sanitizer-output/"
-
-if [ "$USE_BUSY_BOX" = "true" ]; then
- echo "Setup to use BusyBox utils"
- # tar excluded for now because it requires passing in the exact archive type in ./depends (fixed in later BusyBox version)
- # ar excluded for now because it does not recognize the -q option in ./depends (unknown if fixed)
- # shellcheck disable=SC1010
- CI_EXEC for util in \$\(busybox --list \| grep -v "^ar$" \| grep -v "^tar$" \)\; do ln -s \$\(command -v busybox\) "${BINS_SCRATCH_DIR}/\$util"\; done
- # Print BusyBox version
- CI_EXEC patch --help
-fi
+CI_EXEC mkdir -p "${BINS_SCRATCH_DIR}"
diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh
deleted file mode 100755
index 8e3153a20b..0000000000
--- a/ci/test/05_before_script.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-2022 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C.UTF-8
-
-# Make sure default datadir does not exist and is never read by creating a dummy file
-if [ "$CI_OS_NAME" == "macos" ]; then
- echo > "${HOME}/Library/Application Support/Bitcoin"
-else
- CI_EXEC echo \> \$HOME/.bitcoin
- CI_EXEC_ROOT echo \> \$HOME/.bitcoin
-fi
-
-if [ -z "$NO_DEPENDS" ]; then
- if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then
- # CentOS has problems building the depends if the config shell is not explicitly set
- # (i.e. for libevent a Makefile with an empty SHELL variable is generated, leading to
- # an error as the first command is executed)
- SHELL_OPTS="LC_ALL=en_US.UTF-8 CONFIG_SHELL=/bin/dash"
- else
- SHELL_OPTS="CONFIG_SHELL="
- fi
- CI_EXEC "$SHELL_OPTS" make "$MAKEJOBS" -C depends HOST="$HOST" "$DEP_OPTS" LOG=1
-fi
-if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then
- CI_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR"
-fi
diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh
deleted file mode 100755
index 5856d33d2d..0000000000
--- a/ci/test/06_script_a.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-2022 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C.UTF-8
-
-BITCOIN_CONFIG_ALL="--enable-suppress-external-warnings --disable-dependency-tracking"
-if [ -z "$NO_DEPENDS" ]; then
- BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} CONFIG_SITE=$DEPENDS_DIR/$HOST/share/config.site"
-fi
-if [ -z "$NO_WERROR" ]; then
- BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror"
-fi
-
-CI_EXEC "ccache --zero-stats --max-size=$CCACHE_SIZE"
-PRINT_CCACHE_STATISTICS="ccache --version | head -n 1 && ccache --show-stats"
-
-if [ -n "$ANDROID_TOOLS_URL" ]; then
- CI_EXEC make distclean || true
- CI_EXEC ./autogen.sh
- CI_EXEC ./configure "$BITCOIN_CONFIG_ALL" "$BITCOIN_CONFIG" || ( (CI_EXEC cat config.log) && false)
- CI_EXEC "make $MAKEJOBS && cd src/qt && ANDROID_HOME=${ANDROID_HOME} ANDROID_NDK_HOME=${ANDROID_NDK_HOME} make apk"
- CI_EXEC "${PRINT_CCACHE_STATISTICS}"
- exit 0
-fi
-
-BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --prefix=$BASE_OUTDIR"
-
-if [ -n "$CONFIG_SHELL" ]; then
- CI_EXEC "$CONFIG_SHELL" -c "./autogen.sh"
-else
- CI_EXEC ./autogen.sh
-fi
-
-CI_EXEC mkdir -p "${BASE_BUILD_DIR}"
-export P_CI_DIR="${BASE_BUILD_DIR}"
-
-CI_EXEC "${BASE_ROOT_DIR}/configure" --cache-file=config.cache "$BITCOIN_CONFIG_ALL" "$BITCOIN_CONFIG" || ( (CI_EXEC cat config.log) && false)
-
-CI_EXEC make distdir VERSION="$HOST"
-
-export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST"
-
-CI_EXEC ./configure --cache-file=../config.cache "$BITCOIN_CONFIG_ALL" "$BITCOIN_CONFIG" || ( (CI_EXEC cat config.log) && false)
-
-set -o errtrace
-trap 'CI_EXEC "cat ${BASE_SCRATCH_DIR}/sanitizer-output/* 2> /dev/null"' ERR
-
-if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
- # MemorySanitizer (MSAN) does not support tracking memory initialization done by
- # using the Linux getrandom syscall. Avoid using getrandom by undefining
- # HAVE_SYS_GETRANDOM. See https://github.com/google/sanitizers/issues/852 for
- # details.
- CI_EXEC 'grep -v HAVE_SYS_GETRANDOM src/config/bitcoin-config.h > src/config/bitcoin-config.h.tmp && mv src/config/bitcoin-config.h.tmp src/config/bitcoin-config.h'
-fi
-
-if [[ "${RUN_TIDY}" == "true" ]]; then
- MAYBE_BEAR="bear --config src/.bear-tidy-config"
- MAYBE_TOKEN="--"
-fi
-
-CI_EXEC "${MAYBE_BEAR}" "${MAYBE_TOKEN}" make "$MAKEJOBS" "$GOAL" || ( echo "Build failure. Verbose build follows." && CI_EXEC make "$GOAL" V=1 ; false )
-
-CI_EXEC "${PRINT_CCACHE_STATISTICS}"
-CI_EXEC du -sh "${DEPENDS_DIR}"/*/
-CI_EXEC du -sh "${PREVIOUS_RELEASES_DIR}"
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index e95a64186e..0b10ebd44b 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -6,98 +6,169 @@
export LC_ALL=C.UTF-8
+set -ex
+
+if [ "$CI_OS_NAME" == "macos" ]; then
+ top -l 1 -s 0 | awk ' /PhysMem/ {print}'
+ echo "Number of CPUs: $(sysctl -n hw.logicalcpu)"
+else
+ free -m -h
+ echo "Number of CPUs (nproc): $(nproc)"
+ lscpu | grep Endian
+fi
+echo "Free disk space:"
+df -h
+
+if [ "$RUN_FUZZ_TESTS" = "true" ]; then
+ export DIR_FUZZ_IN=${DIR_QA_ASSETS}/fuzz_seed_corpus/
+ if [ ! -d "$DIR_FUZZ_IN" ]; then
+ git clone --depth=1 https://github.com/bitcoin-core/qa-assets "${DIR_QA_ASSETS}"
+ fi
+ (
+ cd "${DIR_QA_ASSETS}"
+ echo "Using qa-assets repo from commit ..."
+ git log -1
+ )
+elif [ "$RUN_UNIT_TESTS" = "true" ] || [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
+ export DIR_UNIT_TEST_DATA=${DIR_QA_ASSETS}/unit_test_data/
+ if [ ! -d "$DIR_UNIT_TEST_DATA" ]; then
+ mkdir -p "$DIR_UNIT_TEST_DATA"
+ curl --location --fail https://github.com/bitcoin-core/qa-assets/raw/main/unit_test_data/script_assets_test.json -o "${DIR_UNIT_TEST_DATA}/script_assets_test.json"
+ fi
+fi
+
+mkdir -p "${BASE_SCRATCH_DIR}/sanitizer-output/"
+
+if [ "$USE_BUSY_BOX" = "true" ]; then
+ echo "Setup to use BusyBox utils"
+ # tar excluded for now because it requires passing in the exact archive type in ./depends (fixed in later BusyBox version)
+ # ar excluded for now because it does not recognize the -q option in ./depends (unknown if fixed)
+ for util in $(busybox --list | grep -v "^ar$" | grep -v "^tar$" ); do ln -s "$(command -v busybox)" "${BINS_SCRATCH_DIR}/$util"; done
+ # Print BusyBox version
+ patch --help
+fi
+
+# Make sure default datadir does not exist and is never read by creating a dummy file
+if [ "$CI_OS_NAME" == "macos" ]; then
+ echo > "${HOME}/Library/Application Support/Bitcoin"
+else
+ echo > "${HOME}/.bitcoin"
+fi
+
+if [ -z "$NO_DEPENDS" ]; then
+ if [[ $CI_IMAGE_NAME_TAG == *centos* ]]; then
+ SHELL_OPTS="CONFIG_SHELL=/bin/dash"
+ else
+ SHELL_OPTS="CONFIG_SHELL="
+ fi
+ bash -c "$SHELL_OPTS make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS LOG=1"
+fi
+if [ "$DOWNLOAD_PREVIOUS_RELEASES" = "true" ]; then
+ test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR"
+fi
+
+BITCOIN_CONFIG_ALL="--disable-dependency-tracking"
+if [ -z "$NO_DEPENDS" ]; then
+ BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} CONFIG_SITE=$DEPENDS_DIR/$HOST/share/config.site"
+fi
+if [ -z "$NO_WERROR" ]; then
+ BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-werror"
+fi
+
+ccache --zero-stats --max-size="${CCACHE_SIZE}"
+PRINT_CCACHE_STATISTICS="ccache --version | head -n 1 && ccache --show-stats"
+
+if [ -n "$ANDROID_TOOLS_URL" ]; then
+ make distclean || true
+ ./autogen.sh
+ bash -c "./configure $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || ( (cat config.log) && false)
+ make "${MAKEJOBS}" && cd src/qt && ANDROID_HOME=${ANDROID_HOME} ANDROID_NDK_HOME=${ANDROID_NDK_HOME} make apk
+ bash -c "${PRINT_CCACHE_STATISTICS}"
+ exit 0
+fi
+
+BITCOIN_CONFIG_ALL="${BITCOIN_CONFIG_ALL} --enable-external-signer --prefix=$BASE_OUTDIR"
+
+if [ -n "$CONFIG_SHELL" ]; then
+ "$CONFIG_SHELL" -c "./autogen.sh"
+else
+ ./autogen.sh
+fi
+
+mkdir -p "${BASE_BUILD_DIR}"
+cd "${BASE_BUILD_DIR}"
+
+bash -c "${BASE_ROOT_DIR}/configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || ( (cat config.log) && false)
+
+make distdir VERSION="$HOST"
+
+cd "${BASE_BUILD_DIR}/bitcoin-$HOST"
+
+bash -c "./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || ( (cat config.log) && false)
+
+if [[ "${RUN_TIDY}" == "true" ]]; then
+ MAYBE_BEAR="bear --config src/.bear-tidy-config"
+ MAYBE_TOKEN="--"
+fi
+
+bash -c "${MAYBE_BEAR} ${MAYBE_TOKEN} make $MAKEJOBS $GOAL" || ( echo "Build failure. Verbose build follows." && make "$GOAL" V=1 ; false )
+
+bash -c "${PRINT_CCACHE_STATISTICS}"
+du -sh "${DEPENDS_DIR}"/*/
+du -sh "${PREVIOUS_RELEASES_DIR}"
+
if [[ $HOST = *-mingw32 ]]; then
# Generate all binaries, so that they can be wrapped
- CI_EXEC make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1
- CI_EXEC make "$MAKEJOBS" -C src minisketch/test.exe VERBOSE=1
- CI_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh"
+ make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1
+ make "$MAKEJOBS" -C src minisketch/test.exe VERBOSE=1
+ "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh"
fi
if [ -n "$QEMU_USER_CMD" ]; then
# Generate all binaries, so that they can be wrapped
- CI_EXEC make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1
- CI_EXEC make "$MAKEJOBS" -C src minisketch/test VERBOSE=1
- CI_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-qemu.sh"
+ make "$MAKEJOBS" -C src/secp256k1 VERBOSE=1
+ make "$MAKEJOBS" -C src minisketch/test VERBOSE=1
+ "${BASE_ROOT_DIR}/ci/test/wrap-qemu.sh"
fi
if [ -n "$USE_VALGRIND" ]; then
- CI_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh"
+ "${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh"
fi
if [ "$RUN_UNIT_TESTS" = "true" ]; then
- CI_EXEC "${TEST_RUNNER_ENV}" DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" make "$MAKEJOBS" check VERBOSE=1
+ bash -c "${TEST_RUNNER_ENV} DIR_UNIT_TEST_DATA=${DIR_UNIT_TEST_DATA} LD_LIBRARY_PATH=${DEPENDS_DIR}/${HOST}/lib make $MAKEJOBS check VERBOSE=1"
fi
if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
- CI_EXEC "${TEST_RUNNER_ENV}" DIR_UNIT_TEST_DATA="${DIR_UNIT_TEST_DATA}" LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${BASE_OUTDIR}/bin/test_bitcoin" --catch_system_errors=no -l test_suite
+ bash -c "${TEST_RUNNER_ENV} DIR_UNIT_TEST_DATA=${DIR_UNIT_TEST_DATA} LD_LIBRARY_PATH=${DEPENDS_DIR}/${HOST}/lib ${BASE_OUTDIR}/bin/test_bitcoin --catch_system_errors=no -l test_suite"
fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
- CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" "${TEST_RUNNER_ENV}" test/functional/test_runner.py --ci "$MAKEJOBS" --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=99999999 --timeout-factor="${TEST_RUNNER_TIMEOUT_FACTOR}" "${TEST_RUNNER_EXTRA}" --quiet --failfast
+ bash -c "LD_LIBRARY_PATH=${DEPENDS_DIR}/${HOST}/lib ${TEST_RUNNER_ENV} test/functional/test_runner.py --ci $MAKEJOBS --tmpdirprefix ${BASE_SCRATCH_DIR}/test_runner/ --ansi --combinedlogslen=99999999 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA} --quiet --failfast"
fi
if [ "${RUN_TIDY}" = "true" ]; then
set -eo pipefail
- export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/src/"
- ( CI_EXEC run-clang-tidy-15 -quiet "${MAKEJOBS}" ) | grep -C5 "error"
- export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/"
- CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/iwyu_tool.py"\
- " src/common/init.cpp"\
- " src/common/url.cpp"\
- " src/compat"\
- " src/dbwrapper.cpp"\
- " src/init"\
- " src/kernel"\
- " src/node/chainstate.cpp"\
- " src/node/chainstatemanager_args.cpp"\
- " src/node/mempool_args.cpp"\
- " src/node/minisketchwrapper.cpp"\
- " src/node/utxo_snapshot.cpp"\
- " src/node/validation_cache_args.cpp"\
- " src/policy/feerate.cpp"\
- " src/policy/packages.cpp"\
- " src/policy/settings.cpp"\
- " src/primitives/transaction.cpp"\
- " src/random.cpp"\
- " src/rpc/fees.cpp"\
- " src/rpc/signmessage.cpp"\
- " src/test/fuzz/txorphan.cpp"\
- " src/test/fuzz/util/"\
- " src/test/util/coins.cpp"\
- " src/uint256.cpp"\
- " src/util/bip32.cpp"\
- " src/util/bytevectorhash.cpp"\
- " src/util/check.cpp"\
- " src/util/error.cpp"\
- " src/util/exception.cpp"\
- " src/util/getuniquepath.cpp"\
- " src/util/hasher.cpp"\
- " src/util/message.cpp"\
- " src/util/moneystr.cpp"\
- " src/util/serfloat.cpp"\
- " src/util/spanparsing.cpp"\
- " src/util/strencodings.cpp"\
- " src/util/string.cpp"\
- " src/util/syserror.cpp"\
- " src/util/threadinterrupt.cpp"\
- " src/zmq"\
- " -p . ${MAKEJOBS}"\
- " -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"\
- " |& tee /tmp/iwyu_ci.out"
- export P_CI_DIR="${BASE_ROOT_DIR}/src"
- CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/fix_includes.py --nosafe_headers < /tmp/iwyu_ci.out"
- CI_EXEC "git --no-pager diff"
-fi
-
-if [ "$RUN_SECURITY_TESTS" = "true" ]; then
- CI_EXEC make test-security-check
+ cd "${BASE_BUILD_DIR}/bitcoin-$HOST/src/"
+ ( run-clang-tidy-16 -quiet "${MAKEJOBS}" ) | grep -C5 "error"
+ # Filter out files by regex here, because regex may not be
+ # accepted in src/.bear-tidy-config
+ # Filter out:
+ # * qt qrc and moc generated files
+ # * secp256k1
+ jq 'map(select(.file | test("src/qt/qrc_.*\\.cpp$|/moc_.*\\.cpp$|src/secp256k1/src/") | not))' ../compile_commands.json > tmp.json
+ mv tmp.json ../compile_commands.json
+ cd "${BASE_BUILD_DIR}/bitcoin-$HOST/"
+ python3 "${DIR_IWYU}/include-what-you-use/iwyu_tool.py" \
+ -p . "${MAKEJOBS}" \
+ -- -Xiwyu --cxx17ns -Xiwyu --mapping_file="${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp" \
+ -Xiwyu --max_line_length=160 \
+ 2>&1 | tee /tmp/iwyu_ci.out
+ cd "${BASE_ROOT_DIR}/src"
+ python3 "${DIR_IWYU}/include-what-you-use/fix_includes.py" --nosafe_headers < /tmp/iwyu_ci.out
+ git --no-pager diff
fi
if [ "$RUN_FUZZ_TESTS" = "true" ]; then
- CI_EXEC LD_LIBRARY_PATH="${DEPENDS_DIR}/${HOST}/lib" test/fuzz/test_runner.py "${FUZZ_TESTS_CONFIG}" "$MAKEJOBS" -l DEBUG "${DIR_FUZZ_IN}"
-fi
-
-if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
- echo "Stop and remove CI container by ID"
- docker container kill "${CI_CONTAINER_ID}"
+ bash -c "LD_LIBRARY_PATH=${DEPENDS_DIR}/${HOST}/lib test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} $MAKEJOBS -l DEBUG ${DIR_FUZZ_IN} --empty_min_time=60"
fi
diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh
index 93b07aab1e..2284a2903b 100755
--- a/ci/test_run_all.sh
+++ b/ci/test_run_all.sh
@@ -8,6 +8,10 @@ export LC_ALL=C.UTF-8
set -o errexit; source ./ci/test/00_setup_env.sh
set -o errexit; source ./ci/test/04_install.sh
-set -o errexit; source ./ci/test/05_before_script.sh
-set -o errexit; source ./ci/test/06_script_a.sh
-set -o errexit; source ./ci/test/06_script_b.sh
+set -o errexit
+CI_EXEC "${BASE_ROOT_DIR}/ci/test/06_script_b.sh"
+
+if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
+ echo "Stop and remove CI container by ID"
+ docker container kill "${CI_CONTAINER_ID}"
+fi
diff --git a/configure.ac b/configure.ac
index cbe3dbcf19..f4368053a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.69])
-define(_CLIENT_VERSION_MAJOR, 24)
+define(_CLIENT_VERSION_MAJOR, 25)
define(_CLIENT_VERSION_MINOR, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 0)
@@ -70,11 +70,12 @@ else
fi
AC_PROG_CXX
-dnl By default, libtool for mingw refuses to link static libs into a dll for
-dnl fear of mixing pic/non-pic objects, and import/export complications. Since
-dnl we have those under control, re-enable that functionality.
+dnl libtool overrides
case $host in
*mingw*)
+ dnl By default, libtool for mingw refuses to link static libs into a dll for
+ dnl fear of mixing pic/non-pic objects, and import/export complications. Since
+ dnl we have those under control, re-enable that functionality.
lt_cv_deplibs_check_method="pass_all"
dnl Remove unwanted -DDLL_EXPORT from these variables.
@@ -83,6 +84,16 @@ case $host in
lt_cv_prog_compiler_pic="-DPIC"
lt_cv_prog_compiler_pic_CXX="-DPIC"
;;
+ *darwin*)
+ dnl Because it prints a verbose warning, lld fails the following check
+ dnl for "-Wl,-single_module" from libtool.m4:
+ dnl # If there is a non-empty error log, and "single_module"
+ dnl # appears in it, assume the flag caused a linker warning
+ dnl "-single_module" works fine on ld64 and lld, so just bypass the test.
+ dnl Failure to set this to "yes" causes libtool to use a very broken
+ dnl link-line for shared libs.
+ lt_cv_apple_cc_single_mod="yes"
+ ;;
esac
AC_ARG_WITH([seccomp],
@@ -104,9 +115,6 @@ else
AX_CXX_COMPILE_STDCXX([20], [noext], [mandatory])
fi
-dnl check if additional link flags are required for std::filesystem
-CHECK_FILESYSTEM
-
dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures
dnl that we get the same -std flags for both.
m4_ifdef([AC_PROG_OBJCXX],[
@@ -126,8 +134,8 @@ AC_PATH_TOOL([AR], [ar])
AC_PATH_TOOL([GCOV], [gcov])
AC_PATH_TOOL([LLVM_COV], [llvm-cov])
AC_PATH_PROG([LCOV], [lcov])
-dnl Python 3.7 is specified in .python-version and should be used if available, see doc/dependencies.md
-AC_PATH_PROGS([PYTHON], [python3.7 python3.8 python3.9 python3.10 python3.11 python3.12 python3 python])
+dnl Python 3.8 is specified in .python-version and should be used if available, see doc/dependencies.md
+AC_PATH_PROGS([PYTHON], [python3.8 python3.9 python3.10 python3.11 python3.12 python3 python])
AC_PATH_PROG([GENHTML], [genhtml])
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG([CCACHE], [ccache])
@@ -236,10 +244,10 @@ dnl May be useful if warnings from external headers clutter the build output
dnl too much, so that it becomes difficult to spot Bitcoin Core warnings
dnl or if they cause a build failure with --enable-werror.
AC_ARG_ENABLE([suppress-external-warnings],
- [AS_HELP_STRING([--enable-suppress-external-warnings],
- [Suppress warnings from external headers (default is no)])],
+ [AS_HELP_STRING([--disable-suppress-external-warnings],
+ [Do not suppress warnings from external headers (default is to suppress)])],
[suppress_external_warnings=$enableval],
- [suppress_external_warnings=no])
+ [suppress_external_warnings=yes])
AC_ARG_ENABLE([lcov],
[AS_HELP_STRING([--enable-lcov],
@@ -1000,6 +1008,7 @@ if test "$TARGET_OS" = "darwin"; then
AX_CHECK_LINK_FLAG([-Wl,-dead_strip], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-dead_strip"], [], [$LDFLAG_WERROR])
AX_CHECK_LINK_FLAG([-Wl,-dead_strip_dylibs], [CORE_LDFLAGS="$CORE_LDFLAGS -Wl,-dead_strip_dylibs"], [], [$LDFLAG_WERROR])
AX_CHECK_LINK_FLAG([-Wl,-bind_at_load], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-bind_at_load"], [], [$LDFLAG_WERROR])
+ AX_CHECK_LINK_FLAG([-Wl,-fixup_chains], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-fixup_chains"], [], [$LDFLAG_WERROR])
fi
AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h sys/select.h sys/prctl.h sys/sysctl.h vm/vm_param.h sys/vmmeter.h sys/resources.h])
@@ -1064,7 +1073,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
dnl Check for posix_fallocate
AC_MSG_CHECKING([for posix_fallocate])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- // same as in src/util/system.cpp
+ // same as in src/util/fs_helpers.cpp
#ifdef __linux__
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
@@ -1162,17 +1171,16 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <ctime>]],
)
dnl Check for different ways of gathering OS randomness
-AC_MSG_CHECKING([for Linux getrandom syscall])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>
- #include <sys/syscall.h>
- #include <linux/random.h>]],
- [[ syscall(SYS_getrandom, nullptr, 32, 0); ]])],
- [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_SYS_GETRANDOM], [1], [Define this symbol if the Linux getrandom system call is available]) ],
+AC_MSG_CHECKING([for Linux getrandom function])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <sys/random.h>]],
+ [[ getrandom(nullptr, 32, 0); ]])],
+ [ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETRANDOM], [1], [Define this symbol if the Linux getrandom function call is available]) ],
[ AC_MSG_RESULT([no])]
)
-AC_MSG_CHECKING([for getentropy via random.h])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <unistd.h>
+AC_MSG_CHECKING([for getentropy via sys/random.h])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/random.h>]],
[[ getentropy(nullptr, 32) ]])],
[ AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_GETENTROPY_RAND], [1], [Define this symbol if the BSD getentropy system call is available with sys/random.h]) ],
@@ -1401,7 +1409,9 @@ if test "$use_usdt" != "no"; then
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM(
[#include <sys/sdt.h>],
- [DTRACE_PROBE("context", "event");]
+ [DTRACE_PROBE(context, event);
+ int a, b, c, d, e, f, g;
+ DTRACE_PROBE7(context, event, a, b, c, d, e, f, g);]
)],
[AC_MSG_RESULT([yes]); AC_DEFINE([ENABLE_TRACING], [1], [Define to 1 to enable tracepoints for Userspace, Statically Defined Tracing])],
[AC_MSG_RESULT([no]); use_usdt=no;]
@@ -1482,10 +1492,6 @@ if test "$use_boost" = "yes"; then
AX_CHECK_PREPROC_FLAG([-DBOOST_NO_CXX98_FUNCTION_BASE], [BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_NO_CXX98_FUNCTION_BASE"], [], [$CXXFLAG_WERROR],
[AC_LANG_PROGRAM([[#include <boost/config.hpp>]])])
- if test "$enable_debug" = "yes" || test "$enable_fuzz" = "yes"; then
- BOOST_CPPFLAGS="$BOOST_CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE"
- fi
-
if test "$suppress_external_warnings" != "no"; then
BOOST_CPPFLAGS=SUPPRESS_WARNINGS($BOOST_CPPFLAGS)
fi
@@ -1622,12 +1628,9 @@ dnl ZMQ check
if test "$use_zmq" = "yes"; then
PKG_CHECK_MODULES([ZMQ], [libzmq >= 4],
- AC_DEFINE([ENABLE_ZMQ], [1], [Define to 1 to enable ZMQ functions]),
- [AC_DEFINE([ENABLE_ZMQ], [0], [Define to 1 to enable ZMQ functions])
- AC_MSG_WARN([libzmq version 4.x or greater not found, disabling])
+ AC_DEFINE([ENABLE_ZMQ], [1], [Define this symbol to enable ZMQ functions]),
+ [AC_MSG_WARN([libzmq version 4.x or greater not found, disabling])
use_zmq=no])
-else
- AC_DEFINE_UNQUOTED([ENABLE_ZMQ], [0], [Define to 1 to enable ZMQ functions])
fi
if test "$use_zmq" = "yes"; then
@@ -1639,6 +1642,8 @@ if test "$use_zmq" = "yes"; then
esac
fi
+AM_CONDITIONAL([ENABLE_ZMQ], [test "$use_zmq" = "yes"])
+
dnl libmultiprocess library check
libmultiprocess_found=no
@@ -1767,7 +1772,7 @@ else
use_upnp=yes
AC_DEFINE([USE_UPNP], [1], [Define to 1 if UPnP support should be compiled in.])
if test "$TARGET_OS" = "windows"; then
- MINIUPNPC_CPPFLAGS="$MINIUPNPC_CPPFLAGS -DSTATICLIB -DMINIUPNP_STATICLIB"
+ MINIUPNPC_CPPFLAGS="$MINIUPNPC_CPPFLAGS -DMINIUPNP_STATICLIB"
fi
else
AC_MSG_RESULT([no])
@@ -1833,8 +1838,6 @@ if test "$bitcoin_enable_qt" != "no"; then
fi
fi
-AM_CONDITIONAL([ENABLE_ZMQ], [test "$use_zmq" = "yes"])
-
AC_MSG_CHECKING([whether to build test_bitcoin])
if test "$use_tests" = "yes"; then
if test "$enable_fuzz" = "yes"; then
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 6cd022ef17..85f75f978a 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -10,7 +10,7 @@ Otherwise the exit status will be 1 and it will log which executables failed whi
import sys
from typing import List
-import lief #type:ignore
+import lief
def check_ELF_RELRO(binary) -> bool:
'''
@@ -158,13 +158,6 @@ def check_MACHO_NOUNDEFS(binary) -> bool:
'''
return binary.header.has(lief.MachO.HEADER_FLAGS.NOUNDEFS)
-def check_MACHO_LAZY_BINDINGS(binary) -> bool:
- '''
- Check for no lazy bindings.
- We don't use or check for MH_BINDATLOAD. See #18295.
- '''
- return binary.dyld_info.lazy_bind == (0,0)
-
def check_MACHO_Canary(binary) -> bool:
'''
Check for use of stack canary
@@ -214,7 +207,6 @@ BASE_PE = [
BASE_MACHO = [
('NOUNDEFS', check_MACHO_NOUNDEFS),
- ('LAZY_BINDINGS', check_MACHO_LAZY_BINDINGS),
('Canary', check_MACHO_Canary),
]
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index f26236dd59..d85912398d 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -13,7 +13,7 @@ Example usage:
import sys
from typing import List, Dict
-import lief #type:ignore
+import lief
# Debian 10 (Buster) EOL: 2024. https://wiki.debian.org/LTS
#
@@ -72,6 +72,25 @@ ELF_INTERPRETER_NAMES: Dict[lief.ELF.ARCH, Dict[lief.ENDIANNESS, str]] = {
},
}
+ELF_ABIS: Dict[lief.ELF.ARCH, Dict[lief.ENDIANNESS, List[int]]] = {
+ lief.ELF.ARCH.x86_64: {
+ lief.ENDIANNESS.LITTLE: [3,2,0],
+ },
+ lief.ELF.ARCH.ARM: {
+ lief.ENDIANNESS.LITTLE: [3,2,0],
+ },
+ lief.ELF.ARCH.AARCH64: {
+ lief.ENDIANNESS.LITTLE: [3,7,0],
+ },
+ lief.ELF.ARCH.PPC64: {
+ lief.ENDIANNESS.LITTLE: [3,10,0],
+ lief.ENDIANNESS.BIG: [3,2,0],
+ },
+ lief.ELF.ARCH.RISCV: {
+ lief.ENDIANNESS.LITTLE: [4,15,0],
+ },
+}
+
# Allowed NEEDED libraries
ELF_ALLOWED_LIBRARIES = {
# bitcoind and bitcoin-qt
@@ -213,7 +232,7 @@ def check_MACHO_libraries(binary) -> bool:
return ok
def check_MACHO_min_os(binary) -> bool:
- if binary.build_version.minos == [10,15,0]:
+ if binary.build_version.minos == [11,0,0]:
return True
return False
@@ -242,12 +261,19 @@ def check_ELF_interpreter(binary) -> bool:
return binary.concrete.interpreter == expected_interpreter
+def check_ELF_ABI(binary) -> bool:
+ expected_abi = ELF_ABIS[binary.header.machine_type][binary.abstract.header.endianness]
+ note = binary.concrete.get(lief.ELF.NOTE_TYPES.ABI_TAG)
+ assert note.details.abi == lief.ELF.NOTE_ABIS.LINUX
+ return note.details.version == expected_abi
+
CHECKS = {
lief.EXE_FORMATS.ELF: [
('IMPORTED_SYMBOLS', check_imported_symbols),
('EXPORTED_SYMBOLS', check_exported_symbols),
('LIBRARY_DEPENDENCIES', check_ELF_libraries),
('INTERPRETER_NAME', check_ELF_interpreter),
+ ('ABI', check_ELF_ABI),
],
lief.EXE_FORMATS.MACHO: [
('DYNAMIC_LIBRARIES', check_MACHO_libraries),
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index 54718fd7a1..90268740c6 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -5,7 +5,7 @@
'''
Test script for security-check.py
'''
-import lief #type:ignore
+import lief
import os
import subprocess
from typing import List
@@ -120,13 +120,13 @@ class TestSecurityChecks(unittest.TestCase):
if arch == lief.ARCHITECTURES.X86:
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-Wl,-allow_stack_execute','-fno-stack-protector']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS Canary PIE NX CONTROL_FLOW'))
+ (1, executable+': failed NOUNDEFS Canary PIE NX CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-Wl,-allow_stack_execute','-fstack-protector-all']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS PIE NX CONTROL_FLOW'))
+ (1, executable+': failed NOUNDEFS PIE NX CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-flat_namespace','-fstack-protector-all']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS PIE CONTROL_FLOW'))
+ (1, executable+': failed NOUNDEFS PIE CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-fstack-protector-all']),
- (1, executable+': failed LAZY_BINDINGS PIE CONTROL_FLOW'))
+ (1, executable+': failed PIE CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-bind_at_load','-fstack-protector-all']),
(1, executable+': failed PIE CONTROL_FLOW'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-no_pie','-Wl,-bind_at_load','-fstack-protector-all', '-fcf-protection=full']),
@@ -136,11 +136,9 @@ class TestSecurityChecks(unittest.TestCase):
else:
# arm64 darwin doesn't support non-PIE binaries, control flow or executable stacks
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fno-stack-protector']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS Canary'))
+ (1, executable+': failed NOUNDEFS Canary'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-flat_namespace','-fstack-protector-all']),
- (1, executable+': failed NOUNDEFS LAZY_BINDINGS'))
- self.assertEqual(call_security_check(cc, source, executable, ['-fstack-protector-all']),
- (1, executable+': failed LAZY_BINDINGS'))
+ (1, executable+': failed NOUNDEFS'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-bind_at_load','-fstack-protector-all']),
(0, ''))
diff --git a/contrib/devtools/test-symbol-check.py b/contrib/devtools/test-symbol-check.py
index e304880140..fe8a99739f 100755
--- a/contrib/devtools/test-symbol-check.py
+++ b/contrib/devtools/test-symbol-check.py
@@ -121,7 +121,7 @@ class TestSymbolChecks(unittest.TestCase):
}
''')
- self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,10.15', '-Wl,11.4']),
+ self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,11.0', '-Wl,11.4']),
(1, f'{executable}: failed SDK'))
def test_PE(self):
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index 08a6c72a95..e0bd15493f 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -188,9 +188,9 @@ make -C depends --jobs="$JOBS" HOST="$HOST" \
${SDK_PATH+SDK_PATH="$SDK_PATH"} \
x86_64_linux_CC=x86_64-linux-gnu-gcc \
x86_64_linux_CXX=x86_64-linux-gnu-g++ \
- x86_64_linux_AR=x86_64-linux-gnu-ar \
- x86_64_linux_RANLIB=x86_64-linux-gnu-ranlib \
- x86_64_linux_NM=x86_64-linux-gnu-nm \
+ x86_64_linux_AR=x86_64-linux-gnu-gcc-ar \
+ x86_64_linux_RANLIB=x86_64-linux-gnu-gcc-ranlib \
+ x86_64_linux_NM=x86_64-linux-gnu-gcc-nm \
x86_64_linux_STRIP=x86_64-linux-gnu-strip \
FORCE_USE_SYSTEM_CLANG=1
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 7c1550a8d1..1808eeffbe 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -11,7 +11,6 @@
(gnu packages commencement)
(gnu packages compression)
(gnu packages cross-base)
- (gnu packages curl)
(gnu packages file)
(gnu packages gawk)
(gnu packages gcc)
@@ -150,7 +149,7 @@ chain for " target " development."))
#:key
(base-gcc-for-libc base-gcc)
(base-kernel-headers base-linux-kernel-headers)
- (base-libc (hardened-glibc (make-glibc-without-werror glibc-2.27)))
+ (base-libc (hardened-glibc glibc-2.27))
(base-gcc (make-gcc-rpath-link (hardened-gcc base-gcc))))
"Convenience wrapper around MAKE-CROSS-TOOLCHAIN with default values
desirable for building Bitcoin Core release binaries."
@@ -208,35 +207,40 @@ chain for " target " development."))
(package-with-extra-patches lief
(search-our-patches "lief-fix-ppc64-nx-default.patch")))
-(define-public lief
+;; Our python-lief package can be removed once we are using
+;; guix 83bfdb409787cb2737e68b093a319b247b7858e6 or later.
+;; Note we currently use cmake-minimal.
+(define-public python-lief
(package
- (name "python-lief")
- (version "0.12.1")
- (source
- (origin
- (method git-fetch)
- (uri (git-reference
- (url "https://github.com/lief-project/LIEF.git")
- (commit version)))
- (file-name (git-file-name name version))
- (sha256
- (base32
- "1xzbh3bxy4rw1yamnx68da1v5s56ay4g081cyamv67256g0qy2i1"))))
- (build-system python-build-system)
- (arguments
- `(#:phases
- (modify-phases %standard-phases
- (add-after 'unpack 'parallel-jobs
- ;; build with multiple cores
- (lambda _
- (substitute* "setup.py" (("self.parallel if self.parallel else 1") (number->string (parallel-job-count)))))))))
- (native-inputs
- `(("cmake" ,cmake)))
- (home-page "https://github.com/lief-project/LIEF")
- (synopsis "Library to Instrument Executable Formats")
- (description "Python library to to provide a cross platform library which can
-parse, modify and abstract ELF, PE and MachO formats.")
- (license license:asl2.0)))
+ (name "python-lief")
+ (version "0.12.3")
+ (source (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/lief-project/LIEF")
+ (commit version)))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "11i6hqmcjh56y554kqhl61698n9v66j2qk1c1g63mv2w07h2z661"))))
+ (build-system python-build-system)
+ (native-inputs (list cmake-minimal))
+ (arguments
+ (list
+ #:tests? #f ;needs network
+ #:phases #~(modify-phases %standard-phases
+ (replace 'build
+ (lambda _
+ (invoke
+ "python" "setup.py" "--sdk" "build"
+ (string-append
+ "-j" (number->string (parallel-job-count)))))))))
+ (home-page "https://github.com/lief-project/LIEF")
+ (synopsis "Library to instrument executable formats")
+ (description
+ "@code{python-lief} is a cross platform library which can parse, modify
+and abstract ELF, PE and MachO formats.")
+ (license license:asl2.0)))
(define osslsigncode
(package
@@ -252,9 +256,6 @@ parse, modify and abstract ELF, PE and MachO formats.")
(build-system cmake-build-system)
(inputs
`(("openssl", openssl)))
- (arguments
- '(#:configure-flags
- (list "-DCMAKE_DISABLE_FIND_PACKAGE_CURL=TRUE")))
(home-page "https://github.com/mtrojnar/osslsigncode")
(synopsis "Authenticode signing and timestamping tool")
(description "osslsigncode is a small tool that implements part of the
@@ -530,15 +531,16 @@ and endian independent.")
inspecting signatures in Mach-O binaries.")
(license license:expat))))
-(define (make-glibc-without-werror glibc)
- (package-with-extra-configure-variable glibc "enable_werror" "no"))
-
;; https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html
+;; We don't use --disable-werror directly, as that would be passed through to bash,
+;; and cause it's build to fail.
(define (hardened-glibc glibc)
(package-with-extra-configure-variable (
- package-with-extra-configure-variable glibc
- "--enable-stack-protector" "all")
- "--enable-bind-now" "yes"))
+ package-with-extra-configure-variable (
+ package-with-extra-configure-variable glibc
+ "enable_werror" "no")
+ "--enable-stack-protector" "all")
+ "--enable-bind-now" "yes"))
(define-public glibc-2.27
(package
@@ -553,9 +555,7 @@ inspecting signatures in Mach-O binaries.")
(sha256
(base32
"0azpb9cvnbv25zg8019rqz48h8i2257ngyjg566dlnp74ivrs9vq"))
- (patches (search-our-patches "glibc-ldd-x86_64.patch"
- "glibc-versioned-locpath.patch"
- "glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch"
+ (patches (search-our-patches "glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch"
"glibc-2.27-fcommon.patch"
"glibc-2.27-guix-prefix.patch"))))))
@@ -592,11 +592,11 @@ inspecting signatures in Mach-O binaries.")
gcc-toolchain-10
(list gcc-toolchain-10 "static")
;; Scripting
- python-3
+ python-minimal ;; (3.9)
;; Git
git-minimal
;; Tests
- (fix-ppc64-nx-default lief))
+ (fix-ppc64-nx-default python-lief))
(let ((target (getenv "HOST")))
(cond ((string-suffix? "-mingw32" target)
;; Windows
@@ -608,5 +608,5 @@ inspecting signatures in Mach-O binaries.")
((string-contains target "-linux-")
(list (make-bitcoin-cross-toolchain target)))
((string-contains target "darwin")
- (list clang-toolchain-10 binutils cmake-minimal xorriso python-signapple))
+ (list clang-toolchain-11 binutils cmake-minimal xorriso python-signapple))
(else '())))))
diff --git a/contrib/guix/patches/gcc-broken-longjmp.patch b/contrib/guix/patches/gcc-broken-longjmp.patch
index 1cfc0918b0..56568813c0 100644
--- a/contrib/guix/patches/gcc-broken-longjmp.patch
+++ b/contrib/guix/patches/gcc-broken-longjmp.patch
@@ -29,6 +29,8 @@ Date: Wed May 5 22:48:51 2021 +0200
gcc/testsuite/
* gcc.c-torture/execute/20210505-1.c: New test.
+ This patch can be dropped when we are building with GCC 10.4.0 or later.
+
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 2f838840e96..06ad1b2274e 100644
--- a/gcc/config/i386/i386.c
diff --git a/contrib/guix/patches/glibc-2.27-fcommon.patch b/contrib/guix/patches/glibc-2.27-fcommon.patch
index f3baacab98..817aa85bb9 100644
--- a/contrib/guix/patches/glibc-2.27-fcommon.patch
+++ b/contrib/guix/patches/glibc-2.27-fcommon.patch
@@ -5,7 +5,7 @@ Date: Fri May 6 11:03:04 2022 +0100
build: use -fcommon to retain legacy behaviour with GCC 10
GCC 10 started using -fno-common by default, which causes issues with
- the powerpc builds using gibc 2.24. A patch was commited to glibc to fix
+ the powerpc builds using gibc 2.27. A patch was commited to glibc to fix
the issue, 18363b4f010da9ba459b13310b113ac0647c2fcc but is non-trvial
to backport, and was broken in at least one way, see the followup in
commit 7650321ce037302bfc2f026aa19e0213b8d02fe6.
@@ -17,6 +17,8 @@ Date: Fri May 6 11:03:04 2022 +0100
https://sourceware.org/git/?p=glibc.git;a=commit;h=18363b4f010da9ba459b13310b113ac0647c2fcc
https://sourceware.org/git/?p=glibc.git;a=commit;h=7650321ce037302bfc2f026aa19e0213b8d02fe6
+ This patch can be dropped when we are building with glibc 2.31+.
+
diff --git a/Makeconfig b/Makeconfig
index 86a71e5802..aa2166be60 100644
--- a/Makeconfig
diff --git a/contrib/guix/patches/glibc-2.27-guix-prefix.patch b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
index 6648bc6c05..dc515907ff 100644
--- a/contrib/guix/patches/glibc-2.27-guix-prefix.patch
+++ b/contrib/guix/patches/glibc-2.27-guix-prefix.patch
@@ -5,7 +5,7 @@ In order to be reproducible regardless of the architecture used to build
the package, map all guix store prefixes to something fixed, e.g. /usr.
We might be able to drop this in favour of using --with-nonshared-cflags
-when we being using newer versions of glibc.
+when we begin using newer versions of glibc.
--- a/Makeconfig
+++ b/Makeconfig
diff --git a/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch b/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch
index c0f8495c41..ab8ae9c023 100644
--- a/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch
+++ b/contrib/guix/patches/glibc-2.27-riscv64-Use-__has_include-to-include-asm-syscalls.h.patch
@@ -4,6 +4,8 @@ See also: http://lists.busybox.net/pipermail/buildroot/2020-July/590376.html.
https://sourceware.org/git/?p=glibc.git;a=commit;h=0b9c84906f653978fb8768c7ebd0ee14a47e662e
+This patch can be dropped when we are building with glibc 2.28+.
+
From 562c52cc81a4e456a62e6455feb32732049e9070 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Mon, 31 Dec 2018 09:26:42 -0800
diff --git a/contrib/guix/patches/glibc-ldd-x86_64.patch b/contrib/guix/patches/glibc-ldd-x86_64.patch
deleted file mode 100644
index a23b095caa..0000000000
--- a/contrib/guix/patches/glibc-ldd-x86_64.patch
+++ /dev/null
@@ -1,10 +0,0 @@
-By default, 'RTDLLIST' in 'ldd' refers to 'lib64/ld-linux-x86-64.so', whereas
-it's in 'lib/' for us. This patch fixes that.
-
---- a/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed
-+++ b/sysdeps/unix/sysv/linux/x86_64/ldd-rewrite.sed
-@@ -1,3 +1,3 @@
- /LD_TRACE_LOADED_OBJECTS=1/a\
- add_env="$add_env LD_LIBRARY_VERSION=\\$verify_out"
--s_^\(RTLDLIST=\)\(.*lib\)\(\|64\|x32\)\(/[^/]*\)\(-x86-64\|-x32\)\(\.so\.[0-9.]*\)[ ]*$_\1"\2\4\6 \264\4-x86-64\6 \2x32\4-x32\6"_
-+s_^\(RTLDLIST=\)\(.*lib\)\(\|64\|x32\)\(/[^/]*\)\(-x86-64\|-x32\)\(\.so\.[0-9.]*\)[ ]*$_\1"\2\4\6 \2\4-x86-64\6 \2x32\4-x32\6"_
diff --git a/contrib/guix/patches/glibc-versioned-locpath.patch b/contrib/guix/patches/glibc-versioned-locpath.patch
deleted file mode 100644
index bc7652127f..0000000000
--- a/contrib/guix/patches/glibc-versioned-locpath.patch
+++ /dev/null
@@ -1,240 +0,0 @@
-The format of locale data can be incompatible between libc versions, and
-loading incompatible data can lead to 'setlocale' returning EINVAL at best
-or triggering an assertion failure at worst. See
-https://lists.gnu.org/archive/html/guix-devel/2015-09/msg00717.html
-for background information.
-
-To address that, this patch changes libc to honor a new 'GUIX_LOCPATH'
-variable, and to look for locale data in version-specific sub-directories of
-that variable. So, if GUIX_LOCPATH=/foo:/bar, locale data is searched for in
-/foo/X.Y and /bar/X.Y, where X.Y is the libc version number.
-
-That way, a single 'GUIX_LOCPATH' setting can work even if different libc
-versions coexist on the system.
-
---- a/locale/newlocale.c
-+++ b/locale/newlocale.c
-@@ -30,6 +30,7 @@
- /* Lock for protecting global data. */
- __libc_rwlock_define (extern , __libc_setlocale_lock attribute_hidden)
-
-+extern error_t compute_locale_search_path (char **, size_t *);
-
- /* Use this when we come along an error. */
- #define ERROR_RETURN \
-@@ -48,7 +49,6 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
- __locale_t result_ptr;
- char *locale_path;
- size_t locale_path_len;
-- const char *locpath_var;
- int cnt;
- size_t names_len;
-
-@@ -102,17 +102,8 @@ __newlocale (int category_mask, const char *locale, __locale_t base)
- locale_path = NULL;
- locale_path_len = 0;
-
-- locpath_var = getenv ("LOCPATH");
-- if (locpath_var != NULL && locpath_var[0] != '\0')
-- {
-- if (__argz_create_sep (locpath_var, ':',
-- &locale_path, &locale_path_len) != 0)
-- return NULL;
--
-- if (__argz_add_sep (&locale_path, &locale_path_len,
-- _nl_default_locale_path, ':') != 0)
-- return NULL;
-- }
-+ if (compute_locale_search_path (&locale_path, &locale_path_len) != 0)
-+ return NULL;
-
- /* Get the names for the locales we are interested in. We either
- allow a composite name or a single name. */
-diff --git a/locale/setlocale.c b/locale/setlocale.c
-index ead030d..0c0e314 100644
---- a/locale/setlocale.c
-+++ b/locale/setlocale.c
-@@ -215,12 +215,65 @@ setdata (int category, struct __locale_data *data)
- }
- }
-
-+/* Return in *LOCALE_PATH and *LOCALE_PATH_LEN the locale data search path as
-+ a colon-separated list. Return ENOMEN on error, zero otherwise. */
-+error_t
-+compute_locale_search_path (char **locale_path, size_t *locale_path_len)
-+{
-+ char* guix_locpath_var = getenv ("GUIX_LOCPATH");
-+ char *locpath_var = getenv ("LOCPATH");
-+
-+ if (guix_locpath_var != NULL && guix_locpath_var[0] != '\0')
-+ {
-+ /* Entries in 'GUIX_LOCPATH' take precedence over 'LOCPATH'. These
-+ entries are systematically prefixed with "/X.Y" where "X.Y" is the
-+ libc version. */
-+ if (__argz_create_sep (guix_locpath_var, ':',
-+ locale_path, locale_path_len) != 0
-+ || __argz_suffix_entries (locale_path, locale_path_len,
-+ "/" VERSION) != 0)
-+ goto bail_out;
-+ }
-+
-+ if (locpath_var != NULL && locpath_var[0] != '\0')
-+ {
-+ char *reg_locale_path = NULL;
-+ size_t reg_locale_path_len = 0;
-+
-+ if (__argz_create_sep (locpath_var, ':',
-+ &reg_locale_path, &reg_locale_path_len) != 0)
-+ goto bail_out;
-+
-+ if (__argz_append (locale_path, locale_path_len,
-+ reg_locale_path, reg_locale_path_len) != 0)
-+ goto bail_out;
-+
-+ free (reg_locale_path);
-+ }
-+
-+ if (*locale_path != NULL)
-+ {
-+ /* Append the system default locale directory. */
-+ if (__argz_add_sep (locale_path, locale_path_len,
-+ _nl_default_locale_path, ':') != 0)
-+ goto bail_out;
-+ }
-+
-+ return 0;
-+
-+ bail_out:
-+ free (*locale_path);
-+ *locale_path = NULL;
-+ *locale_path_len = 0;
-+
-+ return ENOMEM;
-+}
-+
- char *
- setlocale (int category, const char *locale)
- {
- char *locale_path;
- size_t locale_path_len;
-- const char *locpath_var;
- char *composite;
-
- /* Sanity check for CATEGORY argument. */
-@@ -251,17 +304,10 @@ setlocale (int category, const char *locale)
- locale_path = NULL;
- locale_path_len = 0;
-
-- locpath_var = getenv ("LOCPATH");
-- if (locpath_var != NULL && locpath_var[0] != '\0')
-+ if (compute_locale_search_path (&locale_path, &locale_path_len) != 0)
- {
-- if (__argz_create_sep (locpath_var, ':',
-- &locale_path, &locale_path_len) != 0
-- || __argz_add_sep (&locale_path, &locale_path_len,
-- _nl_default_locale_path, ':') != 0)
-- {
-- __libc_rwlock_unlock (__libc_setlocale_lock);
-- return NULL;
-- }
-+ __libc_rwlock_unlock (__libc_setlocale_lock);
-+ return NULL;
- }
-
- if (category == LC_ALL)
-diff --git a/string/Makefile b/string/Makefile
-index 8424a61..f925503 100644
---- a/string/Makefile
-+++ b/string/Makefile
-@@ -38,7 +38,7 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \
- swab strfry memfrob memmem rawmemchr strchrnul \
- $(addprefix argz-,append count create ctsep next \
- delete extract insert stringify \
-- addsep replace) \
-+ addsep replace suffix) \
- envz basename \
- strcoll_l strxfrm_l string-inlines memrchr \
- xpg-strerror strerror_l
-diff --git a/string/argz-suffix.c b/string/argz-suffix.c
-new file mode 100644
-index 0000000..505b0f2
---- /dev/null
-+++ b/string/argz-suffix.c
-@@ -0,0 +1,56 @@
-+/* Copyright (C) 2015 Free Software Foundation, Inc.
-+ This file is part of the GNU C Library.
-+ Contributed by Ludovic Courtès <ludo@gnu.org>.
-+
-+ The GNU C Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Lesser General Public
-+ License as published by the Free Software Foundation; either
-+ version 2.1 of the License, or (at your option) any later version.
-+
-+ The GNU C Library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ Lesser General Public License for more details.
-+
-+ You should have received a copy of the GNU Lesser General Public
-+ License along with the GNU C Library; if not, see
-+ <http://www.gnu.org/licenses/>. */
-+
-+#include <argz.h>
-+#include <errno.h>
-+#include <stdlib.h>
-+#include <string.h>
-+
-+
-+error_t
-+__argz_suffix_entries (char **argz, size_t *argz_len, const char *suffix)
-+
-+{
-+ size_t suffix_len = strlen (suffix);
-+ size_t count = __argz_count (*argz, *argz_len);
-+ size_t new_argz_len = *argz_len + count * suffix_len;
-+ char *new_argz = malloc (new_argz_len);
-+
-+ if (new_argz)
-+ {
-+ char *p = new_argz, *entry;
-+
-+ for (entry = *argz;
-+ entry != NULL;
-+ entry = argz_next (*argz, *argz_len, entry))
-+ {
-+ p = stpcpy (p, entry);
-+ p = stpcpy (p, suffix);
-+ p++;
-+ }
-+
-+ free (*argz);
-+ *argz = new_argz;
-+ *argz_len = new_argz_len;
-+
-+ return 0;
-+ }
-+ else
-+ return ENOMEM;
-+}
-+weak_alias (__argz_suffix_entries, argz_suffix_entries)
-diff --git a/string/argz.h b/string/argz.h
-index bb62a31..d276a35 100644
---- a/string/argz.h
-+++ b/string/argz.h
-@@ -134,6 +134,16 @@ extern error_t argz_replace (char **__restrict __argz,
- const char *__restrict __str,
- const char *__restrict __with,
- unsigned int *__restrict __replace_count);
-+
-+/* Suffix each entry of ARGZ & ARGZ_LEN with SUFFIX. Return 0 on success,
-+ and ENOMEN if memory cannot be allocated. */
-+extern error_t __argz_suffix_entries (char **__restrict __argz,
-+ size_t *__restrict __argz_len,
-+ const char *__restrict __suffix);
-+extern error_t argz_suffix_entries (char **__restrict __argz,
-+ size_t *__restrict __argz_len,
-+ const char *__restrict __suffix);
-+
-
- /* Returns the next entry in ARGZ & ARGZ_LEN after ENTRY, or NULL if there
- are no more. If entry is NULL, then the first entry is returned. This
diff --git a/contrib/guix/patches/vmov-alignment.patch b/contrib/guix/patches/vmov-alignment.patch
index 072f76eafd..7976b864af 100644
--- a/contrib/guix/patches/vmov-alignment.patch
+++ b/contrib/guix/patches/vmov-alignment.patch
@@ -1,6 +1,7 @@
Description: Use unaligned VMOV instructions
Author: Stephen Kitt <skitt@debian.org>
Bug-Debian: https://bugs.debian.org/939559
+See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
Based on a patch originally by Claude Heiland-Allen <claude@mathr.co.uk>
diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service
index 93de353bb4..87da17f955 100644
--- a/contrib/init/bitcoind.service
+++ b/contrib/init/bitcoind.service
@@ -18,10 +18,11 @@ After=network-online.target
Wants=network-online.target
[Service]
-ExecStart=/usr/bin/bitcoind -daemonwait \
- -pid=/run/bitcoind/bitcoind.pid \
+ExecStart=/usr/bin/bitcoind -pid=/run/bitcoind/bitcoind.pid \
-conf=/etc/bitcoin/bitcoin.conf \
- -datadir=/var/lib/bitcoind
+ -datadir=/var/lib/bitcoind \
+ -startupnotify='systemd-notify --ready' \
+ -shutdownnotify='systemd-notify --stopping'
# Make sure the config directory is readable by the service user
PermissionsStartOnly=true
@@ -30,8 +31,10 @@ ExecStartPre=/bin/chgrp bitcoin /etc/bitcoin
# Process management
####################
-Type=forking
+Type=notify
+NotifyAccess=all
PIDFile=/run/bitcoind/bitcoind.pid
+
Restart=on-failure
TimeoutStartSec=infinity
TimeoutStopSec=600
diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md
index b0bbe96493..6db77cbbea 100644
--- a/contrib/seeds/README.md
+++ b/contrib/seeds/README.md
@@ -11,8 +11,10 @@ to addrman with).
The seeds compiled into the release are created from sipa's DNS seed and AS map
data. Run the following commands from the `/contrib/seeds` directory:
- curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt
- curl https://bitcoin.sipa.be/asmap-filled.dat > asmap-filled.dat
- python3 makeseeds.py -a asmap-filled.dat -s seeds_main.txt > nodes_main.txt
- cat nodes_main_manual.txt >> nodes_main.txt
- python3 generate-seeds.py . > ../../src/chainparamsseeds.h
+```
+curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt
+curl https://bitcoin.sipa.be/asmap-filled.dat > asmap-filled.dat
+python3 makeseeds.py -a asmap-filled.dat -s seeds_main.txt > nodes_main.txt
+cat nodes_main_manual.txt >> nodes_main.txt
+python3 generate-seeds.py . > ../../src/chainparamsseeds.h
+```
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index a6f435af0d..e921757802 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -3,7 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
-Script to generate list of seed nodes for chainparams.cpp.
+Script to generate list of seed nodes for kernel/chainparams.cpp.
This script expects two text files in the directory that is passed as an
argument:
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 23d38ee48d..af408c2df5 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -37,19 +37,26 @@ PATTERN_AGENT = re.compile(
r"0.19.(0|1|2|99)|"
r"0.20.(0|1|2|99)|"
r"0.21.(0|1|2|99)|"
- r"22.(0|99)|"
- r"23.(0|99)|"
- r"24.99"
+ r"22.(0|1|99)|"
+ r"23.(0|1|99)|"
+ r"24.(0|1|99)|"
+ r"25.99"
r")")
def parseline(line: str) -> Union[dict, None]:
""" Parses a line from `seeds_main.txt` into a dictionary of details for that line.
or `None`, if the line could not be parsed.
"""
+ if line.startswith('#'):
+ # Ignore line that starts with comment
+ return None
sline = line.split()
if len(sline) < 11:
# line too short to be valid, skip it.
return None
+ # Skip bad results.
+ if int(sline[1]) == 0:
+ return None
m = PATTERN_IPV4.match(sline[0])
sortkey = None
ip = None
@@ -83,9 +90,6 @@ def parseline(line: str) -> Union[dict, None]:
sortkey = ip
ipstr = m.group(1)
port = int(m.group(6))
- # Skip bad results.
- if sline[1] == 0:
- return None
# Extract uptime %.
uptime30 = float(sline[7][:-1])
# Extract Unix timestamp of last success.
diff --git a/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt
index f8572b26c7..100fe09685 100644
--- a/contrib/seeds/nodes_main.txt
+++ b/contrib/seeds/nodes_main.txt
@@ -1,857 +1,896 @@
-2.3.25.181:8333 # AS3215
-2.152.78.124:8333 # AS12430
-5.39.74.166:8333 # AS16276
-5.45.79.81:18332 # AS50673
-5.53.16.128:8333 # AS50923
-5.95.186.78:8333 # AS30722
+1.65.195.98:8333 # AS4760
+2.59.236.56:8333 # AS24904
+2.83.114.20:8333 # AS8657
+2.248.194.16:8333 # AS3301
+5.2.154.6:8333 # AS8708
+5.101.140.30:8333 # AS42831
5.128.87.126:8333 # AS31200
-5.133.65.82:8333 # AS15440
-5.146.20.229:8333 # AS3209
-5.180.41.119:8333 # AS18978
+5.144.21.49:8333 # AS15600
+5.172.132.104:8333 # AS15600
5.188.62.18:8333 # AS34665
-5.199.173.66:8333 # AS16125
-5.255.97.25:8333 # AS60404
-5.255.103.180:8333 # AS60404
-8.209.70.77:8333 # AS45102
+5.200.2.180:8333 # AS49544
+8.129.184.255:8333 # AS37963
8.209.105.138:8333 # AS45102
-18.162.208.153:48332 # AS16509
-23.175.0.200:8333 # AS395502
+12.34.98.148:8333 # AS7018
+14.199.102.151:8333 # AS9269
+18.27.79.17:8333 # AS3
+18.27.124.231:8333 # AS3
+18.216.249.151:8333 # AS16509
+23.88.155.58:8333 # AS10242
+23.93.101.158:8333 # AS46375
+23.109.156.76:8333 # AS7979
+23.175.0.220:8333 # AS395502
23.175.0.222:8333 # AS395502
-23.233.107.21:8333 # AS5645
-23.236.25.169:8333 # AS30029
-24.35.68.229:8333 # AS11404
-24.84.164.50:8333 # AS6327
-24.116.153.115:8333 # AS11492
-24.184.0.146:8333 # AS6128
-27.33.160.196:8333 # AS7545
+24.232.36.225:8333 # AS7303
27.124.108.19:8333 # AS58511
27.148.206.140:8333 # AS4134
-31.17.64.192:8333 # AS204028
-31.18.114.135:8333 # AS204028
+31.7.70.195:8333 # AS49666
+31.25.98.16:8333 # AS48635
31.41.23.249:8333 # AS31287
-31.42.176.138:8333 # AS43641
+31.47.102.92:8333 # AS8251
31.47.202.112:8333 # AS34385
-34.65.45.157:8333 # AS15169
-34.80.134.68:8333 # AS15169
+31.165.78.146:8333 # AS6730
+31.165.228.138:8333 # AS6730
+34.64.101.4:8333 # AS139070
+34.105.19.97:8333 # AS15169
+34.126.107.179:8333 # AS396982
34.126.115.35:8333 # AS396982
-37.1.204.231:8333 # AS50673
+35.245.186.117:8333 # AS15169
+37.15.60.144:8333 # AS12479
+37.16.105.63:8333 # AS20904
37.120.155.34:8333 # AS9009
-37.143.118.174:8333 # AS48926
+37.120.179.29:8333 # AS47147
+37.139.102.73:8333 # AS35816
37.193.227.16:8333 # AS31200
37.220.135.151:8333 # AS41206
-37.235.146.236:8333 # AS41268
-38.124.126.42:8333 # AS11550
+38.53.129.67:8333 # AS40237
+38.54.14.89:8333 # AS138915
38.141.134.140:8333 # AS174
38.145.151.150:8333 # AS40545
-40.115.137.28:8333 # AS8075
41.72.154.66:8333 # AS37153
-41.79.70.146:8333 # AS37349
-42.193.55.135:8333 # AS45090
-43.225.62.107:8333 # AS63953
+43.143.203.198:8333 # AS45090
+45.15.124.117:8333 # AS35913
45.43.97.103:8333 # AS26827
-45.85.48.58:8333 # AS208016
-45.126.26.229:8333 # AS45763
+45.44.213.116:8333 # AS54198
+45.58.187.101:8333 # AS46844
+45.79.192.236:8333 # AS63949
+45.81.241.97:8333 # AS30823
+45.83.220.102:8333 # AS39351
+45.83.241.46:8333 # AS206238
+45.87.106.57:8333 # AS39238
+45.129.38.5:8333 # AS49666
+45.130.20.177:8333 # AS3214
45.134.142.40:8333 # AS60068
-45.154.252.162:8333 # AS13335
-46.13.216.169:8333 # AS6855
+45.135.4.143:8333 # AS25596
+45.135.92.127:8333 # AS12555
+45.145.188.112:8333 # AS206805
46.23.87.218:8333 # AS51088
-46.40.127.164:8333 # AS43205
-46.48.126.58:8333 # AS12668
-46.59.13.35:8333 # AS8473
-46.72.238.17:8333 # AS12714
-46.128.141.184:8333 # AS16097
-46.146.248.89:8333 # AS9049
-46.165.221.209:9333 # AS28753
+46.32.50.98:8333 # AS39642
+46.32.78.17:8333 # AS48416
+46.59.40.91:8333 # AS8473
+46.138.246.77:8333 # AS8359
46.166.142.2:8333 # AS43350
+46.166.162.59:8333 # AS16125
46.175.178.3:8333 # AS28725
-47.36.144.51:8333 # AS20115
-47.180.49.158:8333 # AS5650
-49.228.131.133:2210 # AS133481
+46.188.15.6:8333 # AS39153
+46.188.30.118:8333 # AS39153
+46.223.223.216:8333 # AS51185
+46.226.18.135:8333 # AS52176
+47.88.86.79:8333 # AS45102
+47.148.7.69:8333 # AS5650
+47.198.223.60:8333 # AS5650
50.2.13.164:8333 # AS62904
-50.35.71.51:8333 # AS20055
+50.4.135.84:8333 # AS12083
+50.53.39.237:8333 # AS20055
50.53.250.162:8333 # AS20055
-51.68.36.57:8333 # AS16276
-51.138.4.135:30001 # AS8075
+50.68.121.44:8333 # AS6327
+50.117.132.178:8333 # AS577
51.154.62.103:8333 # AS15796
51.158.150.155:8333 # AS12876
+51.250.46.215:8333 # AS200350
54.176.63.16:8333 # AS16509
58.158.0.86:8333 # AS2519
-59.138.115.137:8333 # AS2516
-59.167.191.60:8333 # AS4739
60.205.205.119:8333 # AS37963
-60.234.122.245:8333 # AS9790
-60.240.210.155:8333 # AS7545
-61.239.91.250:8333 # AS9269
-62.74.143.11:8333 # AS3329
-62.138.162.12:8333 # AS20773
-62.169.74.233:8333 # AS2860
+61.74.99.193:8333 # AS4766
+61.92.59.104:8333 # AS9269
+62.122.173.171:8333 # AS50245
62.171.129.32:8333 # AS51167
-62.209.198.65:8333 # AS6855
-63.247.147.166:8333 # AS30221
-64.98.76.62:8333 # AS32133
+62.178.27.239:8333 # AS8412
+62.209.210.3:8333 # AS6855
+62.215.127.73:8333 # AS21050
+62.238.148.104:8333 # AS15435
+62.245.153.8:8333 # AS8767
+64.146.136.45:8333 # AS16713
+65.21.134.184:8333 # AS24940
+66.18.13.146:8333 # AS13767
+66.23.233.43:8333 # AS19318
+66.27.98.216:8333 # AS20001
66.29.129.218:8333 # AS22612
-66.96.235.28:8333 # AS63859
-66.130.120.52:8333 # AS5769
-66.198.209.243:8333 # AS33152
+66.38.94.13:8333 # AS11979
+66.45.141.46:8333 # AS11232
+66.58.243.215:8333 # AS8047
+66.114.33.49:8333 # AS23175
+66.198.211.167:8333 # AS10835
66.208.64.128:8333 # AS10352
-66.225.231.148:8333 # AS23352
-67.55.3.200:8333 # AS33139
-67.58.232.107:8333 # AS14051
-67.211.92.2:8333 # AS11711
-67.223.119.122:8333 # AS22612
-68.48.131.251:8333 # AS7922
-68.181.4.12:8333 # AS47
-69.14.185.9:8333 # AS12083
-69.54.29.193:8333 # AS12282
+66.219.196.170:8333 # AS29933
+67.210.228.203:8333 # AS7819
+68.183.75.251:8333 # AS14061
+68.194.125.140:8333 # AS6128
+68.199.120.17:8333 # AS6128
+69.4.94.226:8333 # AS36352
+69.8.175.201:8333 # AS21766
69.59.18.22:8333 # AS397444
-69.131.101.176:8333 # AS4181
-69.165.205.142:8833 # AS5645
+69.196.152.33:8333 # AS5645
69.228.219.124:8333 # AS7018
-70.59.123.25:8333 # AS209
-70.62.13.150:8333 # AS7843
-70.66.248.170:8333 # AS6327
-70.112.153.229:8333 # AS7843
+70.64.27.12:8333 # AS6327
70.160.240.132:8333 # AS22773
-70.190.177.204:8333 # AS22773
-71.28.189.239:8333 # AS398465
-71.234.125.198:8333 # AS1351
-72.74.123.179:8333 # AS701
-72.253.236.217:8333 # AS36149
-73.219.254.120:8333 # AS1351
+71.79.109.128:8333 # AS7843
+71.184.193.75:8333 # AS701
+72.15.59.173:8333 # AS21949
+72.48.253.168:8333 # AS7459
+72.207.171.210:8333 # AS22773
+73.117.132.138:8333 # AS7922
+73.212.226.59:8333 # AS7922
+74.76.151.110:8333 # AS7843
74.91.115.229:8333 # AS14586
74.118.137.119:8333 # AS20326
-74.195.166.100:8333 # AS19108
+74.213.175.108:8333 # AS21949
+74.213.251.239:8333 # AS14978
74.220.255.190:8333 # AS23175
-76.67.211.110:8333 # AS577
-76.169.163.14:8333 # AS20001
-77.32.121.162:8333 # AS35612
-77.53.135.74:8333 # AS45011
+74.221.189.109:8333 # AS26827
+75.83.203.225:8333 # AS20001
+75.172.52.186:8333 # AS209
+76.24.143.22:8333 # AS1351
+76.69.202.247:8333 # AS577
+76.73.198.242:8333 # AS12083
+76.119.248.240:8333 # AS1351
+77.20.48.144:8333 # AS3209
+77.22.152.239:8333 # AS204028
+77.37.224.222:8333 # AS42610
+77.48.196.234:8333 # AS16019
77.70.16.245:8333 # AS8717
-77.85.204.149:8333 # AS8866
-77.107.38.239:8333 # AS62183
-77.120.26.102:8333 # AS25229
77.162.190.90:8333 # AS1136
78.20.227.249:8333 # AS6848
78.21.167.8:8333 # AS6848
-78.27.139.13:8333 # AS6723
-78.90.91.220:8333 # AS8717
+78.35.147.203:8333 # AS8422
78.108.108.25:8333 # AS8251
-78.108.108.38:8333 # AS8251
-79.77.182.183:8333 # AS13285
-79.98.159.7:11333 # AS44065
-79.189.211.201:8333 # AS5617
-80.55.225.158:8333 # AS5617
-80.83.186.35:8333 # AS33891
-80.88.172.227:64264 # AS31263
-80.209.87.103:9333 # AS31027
+78.154.237.60:8333 # AS9155
+79.11.31.76:8333 # AS3269
+79.87.88.235:8333 # AS15557
+79.101.1.25:8333 # AS8400
+79.124.7.241:8333 # AS203380
+79.124.7.253:8333 # AS203380
+79.150.68.42:8333 # AS3352
+79.249.10.53:8333 # AS3320
+80.82.21.77:8333 # AS42927
+80.82.76.59:8333 # AS202425
+80.88.172.227:8333 # AS31263
+80.93.213.246:8333 # AS42910
+80.111.142.213:8333 # AS6830
+80.208.227.134:8333 # AS62282
+80.208.228.9:8333 # AS62282
+80.209.64.86:8333 # AS31027
80.229.28.60:8333 # AS2856
81.7.16.182:8333 # AS35366
-81.7.17.202:8333 # AS35366
81.19.10.2:8333 # AS24641
-81.88.221.190:8333 # AS39709
+81.162.196.43:8333 # AS34955
81.171.22.143:8333 # AS60781
+81.172.221.4:8333 # AS12430
81.224.44.164:8333 # AS3301
-81.224.160.81:8333 # AS3301
+81.245.96.36:8333 # AS5432
82.1.68.54:8333 # AS5089
-82.21.164.47:8333 # AS5089
-82.64.116.5:8333 # AS12322
82.66.10.11:8333 # AS12322
+82.66.211.31:8333 # AS12322
+82.71.4.154:8333 # AS13037
82.96.96.40:8333 # AS29686
82.116.50.101:8333 # AS30936
-82.129.68.62:8333 # AS48945
-82.136.99.122:8333 # AS8821
-82.154.24.209:8333 # AS8657
-82.197.215.125:8333 # AS25596
-83.128.132.91:8333 # AS15435
+82.136.98.249:8333 # AS8821
+82.195.237.253:8333 # AS1836
83.137.41.10:8333 # AS31394
-83.208.6.211:8333 # AS5610
+83.171.175.5:8333 # AS8767
83.208.193.242:8333 # AS5610
-83.222.138.85:8333 # AS31736
-83.240.124.68:8333 # AS31246
-83.243.191.199:8333 # AS41164
-84.9.5.211:8333 # AS5378
-84.28.57.90:8333 # AS6830
+83.233.76.165:8333 # AS29518
+83.240.89.196:8333 # AS31246
84.38.3.249:8333 # AS196691
-84.112.60.16:8333 # AS8412
-84.215.56.119:8333 # AS41164
-84.226.243.175:8333 # AS6730
-84.245.14.73:8333 # AS25596
-84.252.157.90:18333 # AS200590
+84.54.23.48:8333 # AS35913
+84.126.216.77:8333 # AS12430
+84.211.187.211:8333 # AS41164
+84.246.200.122:8333 # AS42455
84.255.244.61:8333 # AS34779
-85.23.24.123:8333 # AS16086
-85.52.185.29:8666 # AS12479
-85.58.120.201:8333 # AS12479
-85.93.96.18:8333 # AS29208
-85.165.8.197:8333 # AS2119
-85.173.165.66:8333 # AS12389
-85.184.143.105:8333 # AS39642
-85.191.74.103:8333 # AS39642
+85.165.42.115:8333 # AS2119
85.194.238.134:8333 # AS47605
-85.195.54.110:8333 # AS35706
-85.195.196.142:8333 # AS13030
-85.208.69.11:8333 # AS25091
85.208.69.21:8333 # AS25091
85.208.71.36:8333 # AS42275
-85.208.71.39:8333 # AS42275
+85.209.240.91:8333 # AS205581
85.214.118.71:8333 # AS6724
85.214.161.252:8333 # AS6724
-85.216.32.73:8333 # AS51185
-85.254.98.221:8333 # AS13194
-86.58.11.152:8333 # AS3212
+85.236.190.252:8333 # AS35032
+85.243.115.136:8333 # AS8657
+86.22.20.13:8333 # AS5089
+86.49.34.92:8333 # AS16019
86.95.8.249:8333 # AS1136
-86.100.26.188:8333 # AS39007
-86.106.143.143:55373 # AS9009
-86.124.145.184:8333 # AS8708
-86.133.251.239:8901 # AS2856
+86.104.228.10:8333 # AS31638
+86.104.228.23:8333 # AS31638
87.79.94.221:8333 # AS8422
-87.120.8.5:20008 # AS34224
-87.125.157.220:8333 # AS12430
-88.9.76.133:8333 # AS3352
-88.90.184.68:8333 # AS2119
-88.151.101.14:5000 # AS41075
-88.151.101.253:5000 # AS41075
-88.198.92.47:8333 # AS24940
+88.10.89.23:8333 # AS3352
+88.84.223.30:8333 # AS21453
+88.86.125.50:8333 # AS39392
+88.90.77.100:8333 # AS2119
+88.97.40.50:8333 # AS13037
+88.137.109.62:8333 # AS15557
+88.147.244.250:8333 # AS12389
88.208.115.70:8333 # AS29208
-88.210.15.24:8333 # AS212702
-88.212.45.166:8333 # AS42841
-89.102.206.238:8333 # AS16019
-89.103.111.34:8333 # AS16019
-89.114.143.113:8333 # AS12353
-89.134.62.74:8333 # AS21334
-89.152.8.231:8333 # AS2860
-89.161.26.78:8333 # AS39375
-89.207.131.19:8333 # AS49544
-89.248.193.229:8333 # AS49505
-90.3.48.62:8333 # AS3215
-90.146.121.97:8333 # AS12605
+88.212.53.246:8333 # AS42841
+89.35.142.168:8333 # AS34977
+89.78.111.197:8333 # AS6830
+89.117.59.129:8333 # AS1239
+89.147.108.200:8333 # AS44735
+89.163.132.180:8333 # AS24961
+89.165.232.242:8333 # AS48161
+89.216.21.96:8333 # AS31042
+90.50.172.182:8333 # AS3215
90.146.130.214:8333 # AS12605
-90.196.169.58:8333 # AS5607
-90.250.9.1:8333 # AS5378
+90.146.208.162:8333 # AS12605
+90.156.26.148:8333 # AS12741
+90.163.172.139:8333 # AS12479
+90.177.163.77:8333 # AS5610
+91.67.145.110:8333 # AS3209
91.93.194.154:8333 # AS34984
-91.126.40.109:8333 # AS35699
-91.204.99.178:8333 # AS20485
+91.123.182.164:8333 # AS51648
+91.123.183.219:8333 # AS51792
+91.135.0.187:8333 # AS12496
+91.147.232.98:8333 # AS5483
+91.184.168.249:8333 # AS9063
+91.193.237.116:8333 # AS42916
+91.199.41.45:8333 # AS6866
91.204.149.5:8333 # AS42765
-91.206.17.195:8333 # AS13259
-91.209.51.131:8333 # AS48239
91.215.91.254:8333 # AS48078
-92.91.27.60:8333 # AS15557
+91.219.25.232:8333 # AS50448
+91.237.88.218:8333 # AS56813
+92.27.150.46:8333 # AS13285
+92.27.150.47:8333 # AS13285
92.221.20.232:8333 # AS29695
-92.255.85.31:8333 # AS9002
-93.4.101.37:8333 # AS15557
-93.46.81.5:8333 # AS12874
-93.57.81.162:8333 # AS12874
-93.73.39.196:8333 # AS25229
-93.90.82.226:8333 # AS47626
+92.221.126.65:8333 # AS29695
+93.33.192.204:8333 # AS12874
+93.41.237.78:8333 # AS12874
93.95.88.13:8333 # AS35434
+93.95.227.125:8333 # AS44735
+93.103.13.1:8333 # AS34779
+93.115.86.239:8333 # AS3223
93.123.180.164:8333 # AS35539
-93.189.145.169:8333 # AS12555
-94.17.185.107:8333 # AS12709
-94.75.198.120:8333 # AS60781
-94.114.196.169:8333 # AS3209
-94.142.213.250:55544 # AS5524
+93.186.201.173:8333 # AS24961
+93.190.117.26:8333 # AS196881
+94.19.7.55:8333 # AS35807
+94.23.21.80:8333 # AS16276
+94.23.205.110:8333 # AS16276
+94.131.0.73:8333 # AS29632
+94.142.237.4:8333 # AS48926
94.154.159.99:8333 # AS62240
-94.158.246.183:8333 # AS39798
-94.239.145.32:8333 # AS5410
-95.31.12.22:8333 # AS8402
-95.31.196.15:8333 # AS3216
-95.110.133.223:8333 # AS31034
+94.202.50.200:8333 # AS15802
+94.231.253.18:8333 # AS35224
+95.42.140.142:8333 # AS8866
+95.67.18.100:8333 # AS34867
+95.70.238.176:8333 # AS12735
+95.83.73.31:8333 # AS8359
+95.90.128.3:8333 # AS204028
95.110.234.93:8333 # AS31034
95.161.12.45:8333 # AS39598
+95.172.62.167:8333 # AS201826
+95.179.128.87:8333 # AS20473
95.191.130.100:8333 # AS12389
-95.208.158.161:8333 # AS51185
-95.213.145.218:8333 # AS49505
95.214.53.154:8333 # AS201814
-95.214.53.160:8333 # AS201814
-96.44.156.199:8333 # AS8100
+96.3.53.254:8333 # AS11232
97.75.145.12:8333 # AS22709
+97.81.198.180:8333 # AS20115
+97.87.216.110:8333 # AS20115
+99.229.210.111:8333 # AS812
+99.246.87.2:8333 # AS812
+101.43.124.195:8333 # AS45090
102.132.192.141:8333 # AS37680
-103.14.245.250:8333 # AS24482
-103.85.38.205:8333 # AS134090
-103.88.92.78:8332 # AS17547
+103.21.3.89:8333 # AS38195
+103.35.121.72:8333 # AS9498
103.99.168.100:8333 # AS6939
103.99.168.140:8333 # AS6939
103.99.170.210:8333 # AS54415
103.99.170.220:8333 # AS54415
-103.100.44.70:8333 # AS10143
-103.178.236.27:8333 # AS49981
-103.209.12.144:8333 # AS58511
-104.59.147.15:8333 # AS7018
-104.129.171.121:8333 # AS174
-104.200.65.234:8333 # AS23033
+103.105.202.50:8333 # AS137764
104.238.220.199:8333 # AS23470
+104.243.33.165:8333 # AS23470
104.244.73.6:8333 # AS53667
-106.71.119.230:8333 # AS4804
-107.173.166.43:8333 # AS23352
-108.161.22.78:8333 # AS54154
-108.174.63.234:8333 # AS36352
+108.26.125.214:8333 # AS701
+109.86.60.33:8333 # AS13188
109.99.63.159:8333 # AS9050
-109.105.40.247:8333 # AS12570
-109.107.185.130:8333 # AS48282
-109.110.239.4:8333 # AS35432
-109.173.41.43:8333 # AS42610
+109.120.194.136:8333 # AS34569
+109.123.233.138:8333 # AS15685
+109.123.240.53:8333 # AS15685
+109.153.94.35:8333 # AS2856
+109.173.126.157:8333 # AS42610
+109.193.76.200:8333 # AS51185
+109.221.229.197:8333 # AS3215
109.236.90.117:8333 # AS49981
109.248.206.13:8333 # AS203493
-109.255.106.206:8333 # AS6830
111.90.140.23:8333 # AS45839
111.90.140.46:8333 # AS45839
-111.90.159.246:8333 # AS34309
-112.118.188.50:8333 # AS4760
-115.47.141.250:8885 # AS4134
+111.90.145.37:8333 # AS18106
+114.173.159.209:8333 # AS4713
116.58.171.67:8333 # AS2514
-118.92.107.108:8333 # AS9500
+119.31.179.202:8333 # AS17408
119.42.55.203:8333 # AS133159
-120.79.71.72:8333 # AS37963
-121.99.240.87:8333 # AS9790
+122.222.160.190:8333 # AS2519
123.60.213.192:8333 # AS55990
-124.156.158.100:8333 # AS132203
-124.222.123.238:8333 # AS45090
-125.178.6.116:8333 # AS3786
+124.197.54.113:8333 # AS9790
+125.168.140.108:8333 # AS4826
128.0.190.26:8333 # AS30764
128.65.194.136:8333 # AS29222
129.13.189.212:8333 # AS34878
-129.126.172.115:8333 # AS17547
-129.146.52.174:8333 # AS31898
-130.44.168.202:8333 # AS6079
-131.161.80.166:8333 # AS263694
+129.13.189.215:8333 # AS34878
+129.226.216.148:8333 # AS132203
131.188.40.191:8333 # AS680
+134.65.9.63:8333 # AS19653
+134.122.200.160:8333 # AS64050
134.195.185.52:8333 # AS13536
-135.134.238.47:8333 # AS4181
-135.180.218.58:8333 # AS46375
-135.181.215.237:8333 # AS24940
-136.29.109.180:8333 # AS19165
+135.19.253.101:8333 # AS5769
+136.29.109.58:8333 # AS19165
136.32.238.6:8333 # AS16591
-136.56.170.96:8333 # AS16591
-137.25.38.108:8333 # AS20115
+136.49.201.24:8333 # AS16591
137.226.34.46:8333 # AS680
-138.207.211.106:8333 # AS11776
+138.207.211.189:8333 # AS11776
139.130.41.82:8333 # AS1221
-139.153.255.107:8333 # AS786
-140.190.12.129:8333 # AS14828
+140.238.220.99:8333 # AS31898
142.54.181.218:8333 # AS32097
+142.166.19.23:8333 # AS855
+142.254.87.115:8333 # AS46375
143.177.229.149:8333 # AS50266
-143.178.64.10:8333 # AS50266
-144.24.245.183:8333 # AS31898
-144.126.130.178:8333 # AS40021
-146.4.124.129:8333 # AS3303
+144.2.101.21:8333 # AS3303
+144.24.236.64:8333 # AS31898
+145.40.51.52:8333 # AS49808
146.71.69.103:8333 # AS7782
-146.83.56.69:8333 # AS23140
-147.194.177.165:8333 # AS15128
-149.90.214.78:8333 # AS12353
-149.102.157.156:8333 # AS13768
-151.248.156.55:8333 # AS8821
-151.252.193.245:8333 # AS29582
-153.92.93.114:8333 # AS41998
-154.211.6.2:8333 # AS140224
-156.17.103.2:8088 # AS8970
+146.120.241.173:8333 # AS208515
+147.50.238.53:8333 # AS45265
+148.103.101.132:8333 # AS28118
+149.75.48.92:8333 # AS6079
+152.44.137.83:8333 # AS11404
+154.0.3.194:8333 # AS37680
+154.26.137.105:8333 # AS174
+154.26.154.73:8333 # AS1299
+154.57.5.11:8333 # AS200736
+155.4.55.21:8333 # AS8473
+156.146.137.142:8333 # AS1448
156.146.177.221:8333 # AS1448
-157.131.143.173:8333 # AS46375
-158.58.188.37:8333 # AS57497
-158.248.39.239:8333 # AS29695
-159.89.230.128:8333 # AS14061
+157.22.72.175:8333 # AS397379
+157.97.0.118:8333 # AS43571
+158.140.141.69:8333 # AS132132
+158.181.132.84:8333 # AS41750
+159.2.215.98:8333 # AS855
159.196.3.239:8333 # AS4764
159.224.189.250:8333 # AS13188
-160.72.51.154:8333 # AS46887
-161.29.236.55:8333 # AS4826
-161.97.119.166:8333 # AS51167
+160.80.12.16:8333 # AS137
+161.230.38.160:8333 # AS12353
161.246.11.230:8333 # AS9486
+162.0.210.152:8333 # AS22612
162.62.18.226:8333 # AS132203
-162.250.123.179:8333 # AS19318
-162.250.191.222:8333 # AS26832
162.254.118.20:8333 # AS6130
-163.172.81.70:8333 # AS12876
-164.90.47.8:8333 # AS53449
+163.158.168.181:8333 # AS15435
+165.173.19.33:8333 # AS132132
165.228.174.117:8333 # AS1221
-166.70.145.151:8333 # AS6315
-168.91.238.8:8333 # AS11039
-170.253.11.25:8333 # AS15704
-171.103.170.115:8333 # AS7470
-172.93.166.135:8333 # AS22653
-172.103.217.236:8333 # AS25668
+165.255.241.184:8333 # AS327693
+167.88.11.203:8333 # AS20278
+167.179.147.155:8333 # AS4764
+170.17.151.235:8333 # AS3303
+170.64.174.230:8333 # AS15108
+172.92.102.115:8333 # AS11404
172.105.21.216:8333 # AS63949
-172.112.153.95:8333 # AS20001
-173.3.218.91:8333 # AS6128
-173.12.119.133:8333 # AS7922
-173.34.127.181:8333 # AS812
-173.76.123.173:8333 # AS701
-173.176.198.68:8333 # AS5769
-173.208.152.218:8333 # AS32097
-173.241.227.243:8333 # AS19009
-173.246.27.7:8333 # AS1403
-173.255.240.205:8333 # AS63949
-174.30.47.15:8333 # AS209
-174.114.250.86:8333 # AS812
-174.138.35.229:8333 # AS14061
-174.142.191.136:8333 # AS32613
-176.10.143.190:8333 # AS8473
+172.111.176.244:8333 # AS46562
+172.255.98.108:8333 # AS7979
+173.82.5.202:8333 # AS35916
+173.181.35.50:8333 # AS395570
+173.212.253.137:8333 # AS51167
+173.235.73.87:8333 # AS11272
+174.30.29.85:8333 # AS209
+174.141.209.40:8333 # AS6461
+176.9.17.121:8333 # AS24940
+176.12.16.135:8333 # AS8717
176.74.136.237:8333 # AS35613
-176.118.220.29:8333 # AS60042
-176.126.116.7:8333 # AS20473
+176.74.139.120:8333 # AS35613
+176.122.122.134:8333 # AS50581
176.126.167.10:8333 # AS8449
+176.151.244.130:8333 # AS5410
+176.186.19.106:8333 # AS5410
176.212.185.153:8333 # AS9049
-176.235.209.186:8333 # AS34984
-177.81.236.117:8333 # AS28573
-177.89.205.70:8333 # AS28220
-178.48.168.12:8333 # AS21334
+177.142.146.193:8333 # AS4230
+178.21.118.178:8333 # AS49544
+178.61.141.198:8333 # AS21050
178.124.162.209:8333 # AS6697
+178.143.25.194:8333 # AS15962
+178.154.233.197:8333 # AS200350
178.159.98.133:8333 # AS202390
-178.196.89.209:8333 # AS3303
+178.232.186.191:8333 # AS41164
178.236.137.63:8333 # AS44843
-178.252.123.24:8333 # AS42893
-179.43.170.186:8333 # AS51852
-180.150.46.187:8333 # AS4764
-181.117.128.140:8333 # AS19037
-184.19.19.16:8333 # AS5650
-185.21.217.48:8333 # AS200052
+179.60.149.4:8333 # AS395839
+184.160.110.104:8333 # AS5769
+184.174.37.139:8333 # AS1239
+185.8.104.179:8333 # AS16125
+185.14.30.25:8333 # AS21100
185.25.48.184:8333 # AS61272
-185.31.136.246:8333 # AS47605
185.52.93.45:8333 # AS39449
185.64.116.15:8333 # AS31736
-185.68.249.91:8333 # AS51184
+185.69.105.117:8333 # AS6855
185.98.54.20:8333 # AS39572
185.107.83.55:8333 # AS43350
+185.132.109.122:8333 # AS38919
+185.135.81.50:8333 # AS57494
185.140.253.169:8333 # AS200735
-185.148.145.74:8333 # AS44901
+185.148.3.227:8333 # AS47605
+185.154.2.3:8333 # AS29119
+185.162.92.36:8333 # AS41722
+185.163.44.36:8333 # AS39798
185.165.170.19:8333 # AS3223
185.167.113.59:8333 # AS207054
-185.185.26.141:8111 # AS201206
-185.197.163.136:8333 # AS60144
+185.185.59.12:8333 # AS48614
+185.203.41.148:8333 # AS9009
185.209.12.76:8333 # AS212323
185.209.70.17:8333 # AS204568
-185.227.156.226:8333 # AS209846
+185.210.125.33:8333 # AS205671
185.233.189.210:8333 # AS61303
+185.238.131.19:8333 # AS206238
+185.239.220.210:8333 # AS61282
185.239.221.5:8333 # AS61282
-185.244.100.106:8333 # AS2586
-185.254.97.164:8333 # AS44486
-186.33.167.11:8333 # AS1299
-186.176.98.37:8333 # AS262197
+185.250.90.246:8333 # AS61955
186.249.217.25:8333 # AS7195
186.250.95.132:8333 # AS262967
-188.32.14.31:8334 # AS42610
188.35.167.14:8333 # AS34123
-188.68.45.143:8333 # AS47147
-188.117.200.212:8333 # AS25447
-188.138.88.14:8333 # AS20773
-188.151.237.158:8333 # AS1257
-188.154.236.49:8333 # AS6730
-189.123.177.128:8333 # AS4230
+188.68.53.44:8333 # AS47147
+188.120.255.115:8333 # AS29182
+189.6.195.111:8333 # AS28573
+190.2.130.44:8333 # AS49981
+190.13.122.89:8333 # AS33576
190.123.27.11:8333 # AS52468
190.145.127.254:8333 # AS14080
-192.69.53.77:8333 # AS11142
+191.220.156.64:8333 # AS8167
+192.31.136.90:8333 # AS54098
+192.69.53.43:8333 # AS11142
192.146.137.44:8333 # AS25376
-192.222.24.54:8333 # AS22646
-192.222.147.141:8333 # AS1403
-193.32.127.162:60969 # AS39351
-193.111.198.187:8111 # AS24961
-193.196.37.62:8333 # AS34878
-194.13.80.185:15430 # AS47147
-194.147.113.201:8333 # AS21232
-194.165.30.20:8333 # AS35162
-194.191.239.98:8333 # AS1836
-195.56.63.4:8333 # AS5483
-195.56.63.10:8333 # AS5483
-195.123.239.185:8333 # AS64010
-195.140.226.154:8333 # AS35614
-198.1.231.6:8333 # AS30236
-198.148.112.27:8333 # AS35916
-199.126.234.237:8333 # AS395570
-199.193.174.173:8333 # AS7992
+192.174.121.33:8333 # AS11492
+192.222.147.175:8333 # AS1403
+193.198.34.24:8333 # AS2108
+193.222.130.14:8333 # AS29208
+194.35.185.167:8333 # AS9063
+194.54.83.234:8333 # AS41018
+194.233.84.100:8333 # AS141995
+195.2.73.88:8333 # AS48282
+195.48.12.8:8333 # AS1836
+195.154.200.157:8333 # AS12876
+197.211.133.15:8333 # AS51265
+198.84.146.8:8333 # AS5645
+198.98.55.86:8333 # AS53667
199.247.7.208:8333 # AS20473
-200.122.181.46:8333 # AS3790
+200.116.154.131:8333 # AS13489
201.191.6.103:8333 # AS11830
-201.212.36.209:8333 # AS7303
201.221.234.200:8333 # AS27928
+202.47.225.242:8333 # AS9931
+202.107.219.130:8333 # AS4134
202.108.211.135:8333 # AS4837
-202.169.17.178:8333 # AS137549
-202.177.24.140:8333 # AS7479
-203.130.48.117:8885 # AS54994
-203.132.94.196:8333 # AS38195
+202.138.13.122:8333 # AS4826
+203.86.195.32:8333 # AS23655
+203.184.52.247:8333 # AS9790
+204.111.163.114:8333 # AS4922
205.178.41.124:8333 # AS11039
-206.72.201.228:8333 # AS19318
206.192.203.0:8333 # AS7029
-206.223.153.52:8333 # AS19214
-207.134.216.145:8334 # AS395570
-207.188.154.50:8333 # AS15704
207.229.46.80:8333 # AS852
+207.244.248.81:8333 # AS40021
207.255.193.47:8333 # AS11776
-208.104.92.74:8333 # AS14615
+208.59.133.63:8333 # AS11039
209.58.145.157:8333 # AS394380
-209.58.158.232:8335 # AS394380
-209.141.43.243:8333 # AS53667
-209.226.142.62:8333 # AS577
-209.237.127.227:8333 # AS1299
+209.97.189.249:8333 # AS14061
+209.177.138.245:8333 # AS7832
209.237.133.54:8333 # AS53859
-211.248.90.50:8333 # AS4766
-212.21.18.78:8333 # AS20485
+210.54.37.190:8333 # AS4648
+210.54.39.238:8333 # AS4648
212.34.225.118:8333 # AS44395
-212.51.146.137:8333 # AS13030
-212.227.211.87:8333 # AS8560
-213.0.69.76:8333 # AS3352
-213.5.36.58:8333 # AS49974
+212.41.9.30:8333 # AS49505
+212.51.132.176:8333 # AS13030
+212.69.60.77:8333 # AS12496
+212.86.32.106:8333 # AS15366
213.47.64.105:8333 # AS8412
-213.89.135.151:8333 # AS1257
213.141.154.201:8333 # AS12714
-213.159.198.45:8333 # AS8359
+213.142.148.169:8333 # AS6762
213.184.244.24:8333 # AS60280
-213.214.66.182:8333 # AS43205
-213.226.123.76:8333 # AS49943
+213.227.147.244:8333 # AS60781
+213.250.21.112:8333 # AS5603
216.146.251.8:8333 # AS54579
-216.186.238.14:8333 # AS12083
-217.5.150.114:8333 # AS3320
+216.232.157.104:8333 # AS395570
217.15.178.11:8333 # AS25534
-217.24.239.109:8333 # AS9063
-217.64.47.138:8333 # AS39324
-217.73.80.104:8333 # AS44291
-217.79.181.38:8333 # AS24961
+217.26.32.10:8333 # AS197312
+217.64.47.200:8333 # AS39324
+217.76.51.25:8333 # AS39597
217.92.55.246:8333 # AS3320
-217.113.121.169:8333 # AS8416
-217.115.116.250:8333 # AS30900
-217.155.244.170:8333 # AS13037
217.170.124.170:8333 # AS35401
-220.132.135.54:8333 # AS3462
-220.233.178.199:8333 # AS38195
-222.154.111.46:8333 # AS4648
-[2001:1620:510::2]:8333 # AS13030
-[2001:19f0:6001:39aa:5400:3ff:fef0:916]:8333 # AS20473
-[2001:19f0:8001:f71:5400:4ff:fe10:6a63]:8333 # AS20473
+217.180.221.162:8333 # AS30600
+217.180.238.137:8333 # AS30600
+220.84.232.46:8333 # AS4766
+220.133.39.61:8333 # AS3462
+220.233.91.182:8333 # AS38195
+[2001:19f0:1000:1db3:5400:4ff:fe56:5a8d]:8333 # AS20473
+[2001:19f0:5:24da:3eec:efff:feb9:f36e]:8333 # AS20473
+[2001:19f0:5:24da::]:8333 # AS20473
+[2001:19f0:5:4535:3eec:efff:feb9:87e4]:8333 # AS20473
+[2001:19f0:5:4535::]:8333 # AS20473
[2001:1bc0:c1::2000]:8333 # AS29686
-[2001:1c02:11e:3500:df25:6321:8260:d9be]:8333 # AS6830
-[2001:41d0:1004:1b79::]:8339 # AS16276
+[2001:1c04:4008:6300:8a5f:2678:114b:a660]:8333 # AS6830
[2001:41d0:203:3739::]:8333 # AS16276
-[2001:41d0:203:aacc::]:8333 # AS16276
+[2001:41d0:203:8f49::]:8333 # AS16276
[2001:41d0:203:bb0a::]:8333 # AS16276
[2001:41d0:2:bf8f::]:8333 # AS16276
-[2001:41d0:303:6586::]:8333 # AS16276
-[2001:41d0:602:4493::]:8333 # AS16276
-[2001:41d0:8:b9d8::1]:8333 # AS16276
+[2001:41d0:303:de8b::]:8333 # AS16276
+[2001:41d0:403:3d61::]:8333 # AS16276
+[2001:41d0:405:9600::]:8333 # AS16276
+[2001:41d0:8:ed7f::1]:8333 # AS16276
[2001:41d0:a:69a2::1]:8333 # AS16276
[2001:41f0::62:6974:636f:696e]:8333 # AS6830
-[2001:44b8:256:5d11:216:3eff:fe39:d5d4]:8333 # AS4739
[2001:470:1b62::]:8333 # AS6939
-[2001:470:1f07:803:20c:29ff:fe2d:5879]:8333 # AS6939
+[2001:470:1f05:43b:2831:8530:7179:5864]:8333 # AS6939
+[2001:470:1f09:b14::11]:8333 # AS6939
[2001:470:1f15:106:e2d5:5eff:fe42:7ae5]:8333 # AS6939
-[2001:470:1f15:c43::11]:8333 # AS6939
-[2001:470:26:472::b7c]:8333 # AS6939
+[2001:470:1f1b:365:aa20:66ff:fe3f:1909]:8333 # AS6939
+[2001:470:1f1b:5a6:216:3eff:fe24:1162]:8333 # AS6939
+[2001:470:6a7c::]:8333 # AS6939
[2001:470:75e9:1::10]:8333 # AS6939
-[2001:470:de5a::ec]:9333 # AS6939
-[2001:4ba0:babe:584::1]:8333 # AS24961
+[2001:470:8ca0:2:4e72:b9ff:fe56:f8b8]:8333 # AS6939
+[2001:470:dbc7:0:1010::100]:8333 # AS6939
+[2001:4ba0:cafe:14cc::1]:8333 # AS24961
[2001:4ba0:ffff:24::1]:8333 # AS24961
[2001:4dd0:3564:0:30b7:1d7b:6fec:4c5c]:8333 # AS8422
[2001:4dd0:3564:0:88e:b4ff:2ad0:699b]:8333 # AS8422
[2001:4dd0:3564:0:9c1c:cc31:9fe8:5505]:8333 # AS8422
[2001:4dd0:3564:0:a0c4:d41f:4c4:1bb0]:8333 # AS8422
-[2001:4dd0:3564:0:fd76:c1d3:1854:5bd9]:8333 # AS8422
[2001:4dd0:3564:1::7676:8090]:8333 # AS8422
[2001:4dd0:3564:1:b977:bd71:4612:8e40]:8333 # AS8422
[2001:4dd0:af0e:3564::69:1]:8333 # AS8422
[2001:4dd0:af0e:3564::69:90]:8333 # AS8422
-[2001:4de8:b1b2:1:0:dead:beef:7]:8333 # AS29208
+[2001:560:441f:1::4]:8333 # AS18530
[2001:638:a000:4140::ffff:191]:8333 # AS680
-[2001:678:acc:42::]:8333 # AS60404
+[2001:67c:25dc:91::2]:8333 # AS41018
[2001:67c:26b4:ff00::44]:8333 # AS25376
[2001:67c:2db8:6::36]:8333 # AS39798
-[2001:7c0:2310:0:f816:3eff:fe0d:4ab6]:8333 # AS34878
[2001:7c0:2310:0:f816:3eff:fe6c:4f58]:8333 # AS34878
-[2001:861:3246:a10::40]:8333 # AS5410
-[2001:b07:2e6:38d7:ba27:ebff:fe60:3dc1]:8333 # AS12874
+[2001:861:3242:8420::40]:8333 # AS5410
+[2001:8b0:1301:1000::60]:8333 # AS20712
+[2001:b030:2422::208d]:8333 # AS3462
+[2001:b07:2ef:6e4a:3d:974e:784a:684b]:8333 # AS12874
+[2001:b07:5d32:b142:8f77:3c7d:a2fd:ed2e]:8333 # AS12874
[2001:b07:6461:7811:489:d2da:e07:1af7]:8333 # AS12874
-[2001:b07:ac9:442b:79d6:bbbe:b37c:a783]:8333 # AS12874
+[2001:b07:646b:8074:32e8:9243:a337:e60a]:8333 # AS12874
+[2001:b07:646b:8074:4cc6:79a5:3af7:7132]:8333 # AS12874
+[2001:b07:ad4:ca4b:7dd5:8471:50c3:5363]:8333 # AS12874
+[2001:bc8:1201:71a:2e59:e5ff:fe42:52f4]:8333 # AS12876
[2001:bc8:1600:0:208:a2ff:fe0c:8a2e]:8333 # AS12876
[2001:bc8:323c:ff:a634:384f:1849:f4bc]:8333 # AS12876
[2001:bc8:323c:ff:d217:c2ff:fe07:2cd9]:8333 # AS12876
-[2001:bc8:3bec:100::1]:8333 # AS12876
-[2002:2f5b:a5f9::2f5b:a5f9]:8885 # AS6939
-[2003:cb:8713:6102:aaa1:59ff:fe57:7779]:8333 # AS3320
-[2003:e0:370e:1400::5]:8333 # AS3320
-[2003:f6:3f10:6700:4c9f:7620:8324:d4a7]:8333 # AS3320
-[2400:2410:cea2:d00:41bc:c9ea:861b:51ee]:8333 # AS17676
-[2400:2411:a3e1:4900:2568:684b:e99:7120]:8333 # AS17676
-[2400:2411:a3e1:4900:2987:b88f:61e0:84fa]:8333 # AS17676
-[2400:3b00:20:c:bacb:29ff:feab:8886]:8333 # AS18229
+[2001:bc8:700:2b14::1]:8333 # AS12876
+[2001:bc8:700:8d16::1]:8333 # AS12876
+[2001:e68:5400:58d0:bd15:ea8c:5b20:7523]:8333 # AS4788
+[2400:2411:a3e1:4900:7298:f550:67e7:b99b]:8333 # AS17676
+[2400:8901::f03c:93ff:fe2b:5c0b]:8333 # AS63949
+[2400:8901::f03c:93ff:fe5a:685c]:8333 # AS63949
[2401:b140:1::100:210]:8333 # AS54415
[2401:b140:1::100:220]:8333 # AS54415
-[2401:b140::42:100]:8333 # AS6939
-[2401:b140::44:130]:8333 # AS6939
[2401:d002:3902:700:d72c:5e22:4e95:389d]:8333 # AS38195
-[2404:4408:6752:c000::1999]:8333 # AS9790
-[2404:7a85:4161:2b00:49a1:427a:fac:3409]:8333 # AS2518
-[2405:9800:b972:ab58:c05:e938:267e:271]:8333 # AS45430
+[2404:4408:63a4:a01::250]:8333 # AS9790
+[2406:3400:216:8b00:211:32ff:feca:336b]:8333 # AS10143
+[2406:8c00:0:3422:133:18:228:108]:8333 # AS24282
[2406:da11:169:b03:32b5:f901:9f7c:3e4b]:8333 # AS16509
-[2406:da14:335:b601:ceb7:b4fc:a855:f3a5]:8333 # AS16509
+[2406:da18:9f1:f301:7d2e:c256:c112:f2be]:8333 # AS16509
+[2406:da18:9f1:f303:c1c9:c569:b799:2057]:8333 # AS16509
+[2406:da1e:a4e:8a00:20db:dd8d:3670:28f0]:8333 # AS16509
[2406:da1e:a4e:8a03:2aad:496b:768d:e497]:8333 # AS16509
-[2407:8800:bc61:2202:a0c6:107:502b:4e3b]:8333 # AS7545
-[2409:10:ca20:1df0:224:e8ff:fe1f:60d9]:8333 # AS55391
-[2600:1700:22f1:641f:e8:39c8:eb1d:a1eb]:8333 # AS7018
-[2600:1700:9c5d:ed0::38]:8333 # AS7018
-[2600:1700:9c5d:ed0:d0d6:1d9:5cc2:ab47]:8333 # AS7018
-[2600:1702:1ce0:4010::40]:8333 # AS7018
-[2600:1f14:40e:e301:d155:aa3a:77be:960e]:8333 # AS16509
-[2600:1f16:a08:b901:1afa:ef4e:4ce7:2ba4]:8333 # AS16509
-[2600:1f1c:2d3:2403:5bac:3fc6:6513:7a63]:8333 # AS16509
+[2407:3640:2107:1278::1]:8333 # AS141995
+[2407:3640:3010:4012::1]:8333 # AS141995
+[2407:8800:bc61:2202:d63d:7eff:fe6c:dc36]:8333 # AS7545
+[2600:1700:5c5b:b0:aaa1:59ff:fe5f:615a]:8333 # AS7018
+[2600:1700:ec7b:5730::48]:8333 # AS7018
+[2600:1900:4000:4cc4:0:1::]:8333 # AS15169
+[2600:1900:4000:4cc4:0:2::]:8333 # AS15169
+[2600:1900:4000:4cc4:0:3::]:8333 # AS15169
+[2600:1900:4000:4cc4::]:8333 # AS15169
+[2600:1900:4030:a25e::]:8333 # AS15169
+[2600:1f14:40e:e301:afdd:ad00:e568:d220]:8333 # AS16509
+[2600:1f1c:2d3:2400:f15e:2f2a:760d:a33d]:8333 # AS16509
[2600:2104:1003:c5ab:dc5e:90ff:fe18:1d08]:8333 # AS11404
[2600:3c00::f03c:92ff:fe92:2745]:8333 # AS63949
[2600:3c00::f03c:92ff:fecf:61b6]:8333 # AS63949
-[2600:3c00::f03c:93ff:feb3:1b6]:8333 # AS63949
[2600:3c00:e002:2e32::1:14]:8333 # AS63949
+[2600:3c01::f03c:93ff:fe2a:5266]:8333 # AS63949
+[2600:3c01::f03c:93ff:fe74:5f59]:8333 # AS63949
+[2600:3c01::f03c:93ff:fee6:2146]:8333 # AS63949
[2600:3c02::f03c:92ff:fe5d:9fb]:8333 # AS63949
-[2600:4040:2854:5e00:c6e9:84ff:fe46:ee8]:8666 # AS13786
-[2600:6c54:7100:1ad1:bddf:550e:91be:f9e1]:8333 # AS20115
+[2600:4040:2004:3201:459f:8fe8:444d:baf1]:8333 # AS13786
+[2600:4040:4541:4900:4e1:b58a:8438:450e]:8333 # AS13786
+[2600:6c54:7100:1ad1:c92e:36d:651:bd18]:8333 # AS20115
+[2600:8801:2f80:477::141c]:8333 # AS22773
+[2600:8801:8d00:3eb0:20c:29ff:fec3:d799]:8333 # AS22773
[2600:8805:2400:14e:12dd:b1ff:fef2:3013]:8333 # AS22773
-[2601:184:300:bde:3c29:8e94:1ba8:fde3]:8333 # AS7922
-[2601:18c:8080:300f:219:d1ff:fe75:dc2f]:8333 # AS7922
-[2601:18d:4600:43f1:20e7:b3ff:fecf:a99]:8333 # AS7922
-[2601:18d:8701:c290::3330]:8333 # AS7922
-[2601:246:4d7f:9e28:f321:36ca:7a71:c687]:8333 # AS7922
-[2601:640:c201:960d:86eb:f27d:66a2:f2c1]:8333 # AS7922
-[2602:241:75d1:2b90::7840]:8333 # AS46375
-[2602:ffb8::208:72:57:200]:8333 # AS2914
+[2601:184:300:156c:ba4c:30:9da:6c06]:8333 # AS7922
+[2601:346:d7f:fff7:18c6:4856:ef75:744c]:8333 # AS7922
+[2601:405:4a00:876:c8d3:f081:2ce8:ba8e]:8333 # AS7922
+[2602:24c:b8f:cd90::7840]:8333 # AS46375
+[2602:fec3:0:1::69]:8333 # AS62563
+[2602:ff16:1:0:1:412:0:1]:8333 # AS29802
+[2603:3001:2618:c000:2ec1:df1f:a463:9119]:8333 # AS7922
+[2603:3003:11b:e100:20c:29ff:fe38:bbc0]:8333 # AS7922
[2603:3004:6a1:3800:851f:584d:7aba:affb]:8333 # AS7922
-[2603:3004:6a1:3800::4402]:8333 # AS7922
-[2603:3004:70d:1400:8532:2900:ce6f:acdf]:8333 # AS7922
-[2603:3004:745:900:f0d7:556a:a8c:ced5]:8333 # AS7922
-[2603:6080:c000:5d8a::104f]:8333 # AS7843
-[2603:8000:d100:8991:cc29:ccff:fe42:300c]:8333 # AS7843
+[2603:3004:6a1:3800::7bba]:8333 # AS7922
+[2603:3004:6a1:3800::f667]:8333 # AS7922
+[2603:3024:1606:1400::29ec]:8333 # AS7922
+[2603:3024:18ee:8000:20e:c4ff:fed1:ef15]:8333 # AS7922
+[2603:6000:a400:9300::2000]:8333 # AS7843
+[2603:6010:7001:4830::2:1]:8333 # AS7843
[2603:8080:1f07:6fdd:7de2:d969:78c9:b7ea]:8333 # AS7843
-[2603:8080:7300:531::13ea]:8333 # AS7843
-[2603:80a0:703:40f8::38]:8333 # AS7843
-[2604:180:f3::218]:8333 # AS3842
-[2604:3d08:0:5:d941:4b03:a093:131b]:8333 # AS6327
-[2604:7c00:120:4b::eb24]:8333 # AS174
-[2604:a00:21:3043:bf6a:535e:dfeb:5b7b]:8333 # AS19318
-[2604:a880:400:d0::1ce7:4001]:8333 # AS14061
-[2604:a880:400:d0::1d44:e001]:8333 # AS14061
+[2603:8080:d600:1800:7ce1:74a2:6a8a:4643]:8333 # AS7843
+[2603:8081:6c00:306e:215:5dff:fe02:150a]:8333 # AS7843
+[2604:3d09:7182:8700:bba9:cde6:5b37:a8df]:8333 # AS6327
+[2604:4080:1036:80b1::3be]:8333 # AS11404
+[2604:a00:3:1223:216:3eff:fe27:76e0]:8333 # AS19318
[2604:a880:400:d0::261f:6001]:8333 # AS14061
-[2604:a880:400:d1::7e2:e001]:8333 # AS14061
-[2604:a880:4:1d0::14:3000]:8333 # AS14061
+[2604:a880:4:1d0::13e:f000]:8333 # AS14061
+[2604:a880:4:1d0::17a:7000]:8333 # AS14061
+[2604:a880:4:1d0::c1:3000]:8333 # AS14061
[2604:a880:4:1d0::e5:b000]:8333 # AS14061
+[2605:4a80:a302:7940:7254:1ed4:90d7:4f39]:8333 # AS11232
+[2605:4a80:a302:7940::2]:8333 # AS11232
[2605:6400:30:f220::]:8333 # AS53667
-[2605:6f80:0:7:fc1b:ccff:fe8a:d822]:8333 # AS53340
-[2605:a140:2076:8253::1]:8333 # AS40021
-[2605:a140:3007:1287::1]:8333 # AS40021
+[2605:a140:3010:4014::1]:8333 # AS40021
[2605:ae00:203::203]:8333 # AS7819
+[2605:b40:14d0:5b00:7988:eb8:6bb6:66e2]:8333 # AS174
[2605:c000:2a0a:1::102]:8333 # AS7393
-[2607:1a00:1:d::11:7c4d]:8333 # AS22653
-[2607:5300:203:1214::]:8333 # AS16276
+[2607:5300:61:854::1]:8333 # AS16276
[2607:9280:b:73b:250:56ff:fe14:25b5]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe21:9c2f]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe21:bf32]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe33:4d1b]:8333 # AS395502
[2607:9280:b:73b:250:56ff:fe3d:401]:8333 # AS395502
-[2607:f2c0:e1c2:69:12c3:7bff:fe4d:9431]:8333 # AS5645
-[2607:f2c0:e1c2:69:ecb2:6e88:9f33:5057]:8333 # AS5645
-[2620:6:2003:105:2d8:61ff:fe0f:853]:8333 # AS25682
[2620:6e:a000:1:42:42:42:42]:8333 # AS397444
-[2620:a6:2000:1::3:d570]:8333 # AS27566
-[2620:a6:2000:1::5:162a]:8333 # AS27566
-[2620:a6:2000:1::5:1631]:8333 # AS27566
-[2620:a6:2000:1::c:e634]:8333 # AS27566
-[2800:40:33:8ab:a0e7:b215:fc83:5c31]:8333 # AS16814
-[2800:bf0:149:f4b:f8df:8d7d:801b:e25e]:8333 # AS27947
-[2804:14c:198:80d5:7603:41d1:d3fc:e797]:8333 # AS28573
-[2804:14d:ae81:827b:99a8:1e3f:6db2:29db]:8333 # AS4230
-[2804:d57:5537:4800:3e7c:3fff:fe7b:80aa]:8333 # AS8167
-[2a00:12e0:101:99:20c:29ff:fe29:d03f]:8333 # AS6798
-[2a00:1328:e101:c00::163]:8333 # AS31078
+[2620:a6:2000:1:1:0:5:1601]:8333 # AS27566
+[2620:a6:2000:1:2:0:9:900b]:8333 # AS27566
+[2620:a6:2000:1:2:0:b:300e]:8333 # AS27566
+[2800:150:11d:d2f:bdac:7807:2f5:4aa0]:8333 # AS22047
+[2803:9800:a007:82ba:650b:82b8:8377:d0]:8333 # AS19037
+[2804:14c:155:45e0:1e86:15a3:efd9:7287]:8333 # AS28573
+[2804:14c:657d:4030:28b4:eff:fe9b:8894]:8333 # AS28573
+[2804:14d:1087:9434::1002]:8333 # AS4230
+[2804:954:24:2:b390:d83b:358a:db53]:8333 # AS263073
+[2804:d57:554d:de00:3e7c:3fff:fe7b:80aa]:8333 # AS8167
+[2a00:1028:838c:563a:fd25:87b6:5a54:811]:8333 # AS5610
+[2a00:1298:8001::6542]:8333 # AS5578
[2a00:1398:4:2a03:215:5dff:fed6:1033]:8333 # AS34878
[2a00:1398:4:2a03::bc03]:8333 # AS34878
-[2a00:1630:10:1003:0:b19:b00b:babe]:8333 # AS49544
[2a00:1768:2001:27::ef6a]:8333 # AS43350
-[2a00:1828:a004:2::666]:8333 # AS34240
-[2a00:1c10:2:709::217]:22220 # AS50300
[2a00:1f40:5001:108:5d17:7703:b0f5:4133]:8333 # AS42864
[2a00:23c5:fe80:7301:d6ae:52ff:fed5:56a5]:8333 # AS2856
-[2a00:23c6:5c91:5808:c05a:4dff:fe65:9d69]:8333 # AS2856
-[2a00:6020:1bfa:d400:20c:29ff:fe61:4a4c]:8333 # AS60294
-[2a00:6020:b482:9200:491a:358c:d8f7:1da]:8333 # AS60294
+[2a00:6020:13dc:bc00:5559:258:27d:b52b]:8333 # AS60294
+[2a00:6020:4503:3700:20c:29ff:fe61:4a4c]:8333 # AS60294
+[2a00:6020:b434:eb00:dea6:32ff:fe0d:a5c0]:8333 # AS60294
[2a00:6020:b489:2000:5054:ff:fefc:5ed8]:8333 # AS60294
+[2a00:7c80:0:10c::2]:8333 # AS49981
[2a00:7c80:0:25::e37a]:8333 # AS49981
-[2a00:7c80:0:71::8]:8333 # AS49981
[2a00:8a60:e012:a00::21]:8333 # AS680
-[2a00:ae40:240e:3200::3]:8333 # AS50923
+[2a00:bbe0:cc:0:5a11:22ff:feb4:8f5c]:8333 # AS47605
[2a00:bbe0:cc:0:62a4:4cff:fe23:7510]:8333 # AS47605
-[2a00:ca8:a1f:3025:f949:e442:c940:13e8]:8333 # AS30764
-[2a00:d4e0:2:d002:4467:31e0:6fa5:b3ef]:8333 # AS15600
+[2a00:ca8:a15:9a5b:8b42:a886:7d48:7a21]:8333 # AS30764
+[2a00:ca8:a1f:f9b7:cb55:5766:524b:acaa]:8333 # AS30764
+[2a00:d4e0:ff:fc02:5e55:4a7c:b83b:e5a1]:8333 # AS15600
+[2a00:d520:9:9300:420b:544e:8019:6d3a]:8333 # AS15600
+[2a00:d880:5:c2::d329]:8333 # AS198203
[2a00:ee2:1200:1900:8d3:d2ff:feb1:bc58]:8333 # AS5603
-[2a01:238:420f:9200:fa5a:1a4b:1e6a:fadf]:8333 # AS6724
-[2a01:238:4389:c400:3b26:d94e:38d5:44ef]:8333 # AS6724
-[2a01:490:16:301::2]:8333 # AS8251
-[2a01:4b00:807c:3100:cda1:c6a:2bad:2418]:8333 # AS56478
-[2a01:4f8:141:2254::2]:8333 # AS24940
[2a01:4f8:173:230a::2]:8333 # AS24940
-[2a01:4f8:190:91c4::2]:8333 # AS24940
[2a01:4f8:200:7222::2]:8333 # AS24940
[2a01:4f8:202:3e6::2]:8333 # AS24940
[2a01:4f8:221:44d7::2]:8333 # AS24940
[2a01:4f8:231:915::2]:8333 # AS24940
-[2a01:4f9:2a:1ce0::2]:8333 # AS24940
+[2a01:4f8:261:2bcd::2]:8333 # AS24940
+[2a01:4f8:261:3cae::2]:8333 # AS24940
+[2a01:4f8:261:420c::2]:8333 # AS24940
[2a01:4f9:2b:29a::2]:8333 # AS24940
-[2a01:4f9:4a:31de::2]:8333 # AS24940
-[2a01:5200:6c:6162:7a61:746b:6f2e:736b]:8333 # AS6855
-[2a01:6380:fffe:73:10fb:d012:8581:b4d7]:8333 # AS25540
+[2a01:4f9:3a:2dd2::2]:8333 # AS24940
[2a01:7a7:2:2804:ae1f:6bff:fe9d:6c94]:8333 # AS20773
-[2a01:7c8:aaac:89:5054:ff:feb7:f5cb]:8333 # AS20857
+[2a01:7c8:aac2:180:5054:ff:fe56:8d10]:8333 # AS20857
[2a01:7c8:aac9:c9:5054:ff:fedf:ff95]:8333 # AS20857
-[2a01:7c8:d001:1c1:5054:ff:feee:3e1a]:8333 # AS20857
-[2a01:7c8:d009:2aa:5054:ff:fe1b:a196]:11520 # AS20857
-[2a01:7c8:fffa:50e:ddfe:c924:ca0a:cbab]:8333 # AS20857
-[2a01:7e00::f03c:93ff:fe59:66dc]:8333 # AS63949
-[2a01:7e01::f03c:93ff:fe3b:bb5b]:8333 # AS63949
+[2a01:7e01::f03c:93ff:fe49:2f5b]:8333 # AS63949
+[2a01:8740:1:753::e5cb]:8333 # AS57344
[2a01:8740:1:ffc5::8c6a]:8333 # AS57344
-[2a01:9f40:a000::100]:8333 # AS42908
-[2a01:cb00:d3d:7700:227:eff:fe28:c565]:8333 # AS3215
-[2a01:e0a:20:7350:919c:b1c3:8b83:adf9]:8333 # AS12322
+[2a01:cb00:b63:c000:227:eff:fe28:c565]:8333 # AS3215
+[2a01:cb19:688:e900:aa60:b6ff:fe29:bbae]:8333 # AS3215
+[2a01:e0a:163:c0b0:9da5:1690:a12b:bede]:8333 # AS12322
+[2a01:e0a:282:67b0:b4f4:aaff:fe7c:44a6]:8333 # AS12322
[2a01:e0a:301:7010:b87d:e14b:cea9:b998]:8333 # AS12322
-[2a01:e0a:48b:2d10:94f2:4d5c:ca5f:bf49]:8333 # AS12322
-[2a01:e0a:530:a0a0:f465:af5:be1b:9075]:8333 # AS12322
-[2a01:e0a:aa7:c8c0:9679:affa:b6e5:efc7]:8333 # AS12322
+[2a01:e0a:320:39a0:325a:3aff:fe02:3180]:8333 # AS12322
+[2a01:e0a:351:9fb0:6bf2:95d6:b7bd:b846]:8333 # AS12322
+[2a01:e0a:5fa:a0a0:ca1f:66ff:fece:b8a2]:8333 # AS12322
+[2a01:e0a:83d:dd30:3676:5d8e:8a6f:115a]:8333 # AS12322
+[2a01:e0a:9e9:c240:7b44:f32a:6ec0:a8af]:8333 # AS12322
+[2a01:e0a:b5:7f50:c257:a55b:4846:97e1]:8333 # AS12322
[2a01:e11:100c:70:cbc8:9e31:4b77:1626]:8333 # AS12322
-[2a01:e34:ee78:3060:230:48ff:fe81:f1c6]:8333 # AS12322
-[2a02:1210:14a9:6700:a00:27ff:fe4e:82b6]:8333 # AS3303
-[2a02:1210:4639:f00:10a7:e965:509a:7a4a]:8333 # AS3303
-[2a02:1210:7c92:5100:211:32ff:feae:152d]:8333 # AS3303
-[2a02:1210:86bf:f100:3178:d700:d44d:6bb1]:8333 # AS3303
-[2a02:1210:9487:a200:edc1:93a4:945:9a92]:8333 # AS3303
+[2a02:1210:2cdf:4600:2bc:e03e:43e8:4718]:8333 # AS3303
+[2a02:1210:86bf:f100:a9ac:d041:1f8e:6925]:8333 # AS3303
+[2a02:1210:94c3:3400:d8c3:743c:90f6:a48a]:8333 # AS3303
+[2a02:168:2000:96::12]:8333 # AS13030
[2a02:168:420b:a::20]:8333 # AS13030
-[2a02:168:6328:0:4a21:bff:fe26:38c3]:8333 # AS13030
[2a02:168:676e:0:e65f:1ff:fe09:3591]:8333 # AS13030
-[2a02:1748:f39f:5872:dead:beef:b1ac:c0fe]:8333 # AS51184
+[2a02:1748:f39f:5872:216:3eff:fe21:266]:8333 # AS51184
[2a02:180:1:1::517:10b6]:8333 # AS35366
-[2a02:2168:a379:d100:96de:80ff:fea3:fd00]:8333 # AS42610
[2a02:2780:9000:70::7]:8333 # AS35434
[2a02:2780:9000:70::f]:8333 # AS35434
[2a02:2780::e01a]:8333 # AS35434
-[2a02:2e02:3900:5400:a099:e1ff:feb6:d0e]:8333 # AS12479
-[2a02:2f05:660e:8b00::1]:8333 # AS48571
-[2a02:58:97:7d20::60]:8333 # AS25596
-[2a02:6d40:3073:c01:dea6:32ff:fe44:4b25]:8333 # AS42652
+[2a02:2f05:6008:ce00::1]:8333 # AS48571
+[2a02:390:9000:0:aaa1:59ff:fe43:b57b]:8333 # AS12496
+[2a02:578:85ce:1600:1e1b:dff:fee3:774b]:8333 # AS9031
+[2a02:768:f92b:db46:5e46:772b:71d:29b7]:8333 # AS44489
[2a02:7a01::91:228:45:130]:8333 # AS16019
+[2a02:7b40:50d0:e386::1]:8333 # AS62282
+[2a02:7b40:50d1:e35b::1]:8333 # AS62282
[2a02:7b40:5928:89::1]:8333 # AS62282
-[2a02:7b40:c3b5:f583::1]:8333 # AS62282
-[2a02:8308:8087:aa00:9ea8:1b2:ef98:56bf]:8333 # AS16019
+[2a02:7b40:b945:344d::1]:8333 # AS62282
+[2a02:7b40:d418:6d9a::1]:8333 # AS62282
+[2a02:8070:b84:6ae0:f9c6:fbb9:1c41:81aa]:8333 # AS51185
+[2a02:8070:f186:38e0::d5a6]:8333 # AS51185
+[2a02:8084:103:6810:1e69:7aff:fea2:1acc]:8333 # AS6830
+[2a02:8308:8081:f300:3b8:7ec0:2837:1b57]:8333 # AS16019
+[2a02:8388:e302:7980:6f85:a0b3:4b4d:8b0f]:8333 # AS8412
+[2a02:8388:e5c3:4a80:201:2eff:fe82:b3cc]:8333 # AS8412
[2a02:842a:1df:8a01:1e1b:dff:fe0b:236d]:8333 # AS15557
+[2a02:a210:28be:5f80::111]:8333 # AS6830
+[2a02:a44b:5cf9:1:b62e:99ff:fe49:d492]:8333 # AS1136
[2a02:a44d:14d6:1:2c0:8ff:fe8f:b3b2]:8333 # AS1136
[2a02:a45a:94cd:f00d::1]:8333 # AS1136
-[2a02:a45f:3b9d:30::3]:8333 # AS1136
-[2a02:a467:7833:1:7285:c2ff:fe2c:21e9]:8333 # AS1136
-[2a02:aa14:2380:b300:4040:be88:8b01:d38]:8333 # AS6830
+[2a02:a45f:3b9d:31::199]:8333 # AS1136
+[2a02:a464:3d6b::1:2]:8333 # AS1136
+[2a02:a46c:7f8e:1:35bf:3aeb:137c:1d35]:8333 # AS1136
+[2a02:a46d:36f:1:20d:b9ff:fe4e:6398]:8333 # AS1136
+[2a02:c205:2021:4216::1]:8333 # AS51167
[2a02:c206:2044:9826::1]:8333 # AS51167
-[2a02:c206:2082:1246::1]:8333 # AS51167
-[2a02:c206:3008:2368::1]:8333 # AS51167
-[2a02:c207:0:4971::1]:5332 # AS51167
+[2a02:c206:2075:3351::1]:8333 # AS51167
+[2a02:c207:0:3829::1]:8333 # AS51167
[2a02:c207:2014:4199::1]:8333 # AS51167
-[2a02:c207:2024:6115::1]:8333 # AS51167
+[2a02:c207:2014:8757::1]:8333 # AS51167
[2a02:c207:2026:6682::1]:8333 # AS51167
+[2a02:c207:2034:7358::1]:8333 # AS51167
[2a02:c207:3002:7468::1]:8333 # AS51167
+[2a02:c207:3008:4592::1]:8333 # AS51167
+[2a02:cb43:4000::178]:8333 # AS33891
+[2a02:e5e:1:10::27]:8333 # AS25057
[2a02:e98:20:1504::1]:8333 # AS24641
-[2a03:4000:6:416c::43]:8333 # AS47147
-[2a03:4000:6:f814:548b:17ff:fe31:b64a]:8333 # AS47147
+[2a03:4000:28:68:7411:53ff:fe4c:21d]:8333 # AS47147
+[2a03:4000:65:fdc:3462:66ff:fe05:ec5c]:8333 # AS47147
[2a03:6000:870:0:46:23:87:218]:8333 # AS51088
[2a03:94e0:ffff:185:243:218:0:19]:8333 # AS56655
[2a03:b0c0:1:e0::397:6001]:8333 # AS14061
-[2a03:b0c0:2:f0::163:3001]:8333 # AS14061
-[2a03:b0c0:2:f0::18a:d001]:8333 # AS14061
-[2a03:b0c0:3:d0::f3e:2001]:8333 # AS14061
-[2a03:e2c0:1347::2]:8333 # AS50113
-[2a03:ec0:0:928::701:701]:8333 # AS199669
-[2a04:52c0:103:c455::1]:8334 # AS60404
-[2a04:52c0:3007:200::2000]:8333 # AS60404
+[2a03:b0c0:1:e0::794:9001]:8333 # AS14061
+[2a03:b0c0:2:f0::288:c001]:8333 # AS14061
+[2a03:b0c0:2:f0::30c:1]:8333 # AS14061
+[2a03:b0c0:3:d0::e3b:5001]:8333 # AS14061
+[2a03:cfc0:8000:7::5fd6:3557]:8333 # AS201814
+[2a04:2180:dc05:2::3b]:8333 # AS61272
+[2a04:2180:ffff:fffe::d]:8333 # AS61272
+[2a04:52c0:103:c455::1]:8333 # AS60404
[2a04:bc40:1dc3:8d::2:1001]:8333 # AS35277
-[2a05:1500:702:0:1c00:40ff:fe00:c]:8333 # AS48635
-[2a05:3580:d101:3700::]:8333 # AS20764
-[2a05:3580:db0b:1600:c489:76ed:313d:b33]:8333 # AS20764
-[2a05:d014:a55:4001:8127:afa7:daf9:d91b]:8333 # AS16509
-[2a05:d014:a55:4001:f6ab:dd5e:4039:b46c]:8333 # AS16509
-[2a05:d014:a55:4003:6523:50a1:152:e88c]:8333 # AS16509
-[2a05:d01a:b7b:3c01:8bf7:ae14:afb3:33ae]:8333 # AS16509
+[2a05:3580:dc0b:1600:def4:5a62:de42:324a]:8333 # AS20764
+[2a05:d014:a55:4000:8dde:69f:4ac7:b26]:8333 # AS16509
+[2a05:d016:98f:5201:6be0:a4de:80c7:32d5]:8333 # AS16509
+[2a05:d018:a75:6c03:75b:2c73:8caa:414b]:8333 # AS16509
[2a05:f480:1800:697:5400:2ff:feb6:c36d]:8333 # AS20473
[2a06:e040:7603:2918:c6ef:464e:9fe5:73ec]:8333 # AS198507
-[2a07:abc4::1:946]:8333 # AS62000
+[2a07:abc4::89:234:180:194]:8333 # AS62000
+[2a07:d884::127e]:8333 # AS6762
+[2a09:2681:1010:10::5]:8333 # AS61282
[2a09:2681:102::210]:8333 # AS61282
-[2a0a:c801:1:7::183]:8333 # AS39798
-[2a0c:5a80:1210:a800:6af7:28ff:fee5:6b3a]:8333 # AS57269
-[2a0d:5600:24:a8e::a91e]:55373 # AS9009
-[2a0d:7c40:3000:b04::2]:8333 # AS54290
+[2a0b:f300:2:6::2]:8333 # AS62240
[2a0d:8340:24::2]:8333 # AS50113
-[2a0f:df00:0:2010::162]:8333 # AS41281
-[2a10:3781:16b9:1:fe3f:dbff:fe04:2d4c]:8333 # AS206238
-[2a10:3781:84b:1:b123:6306:943a:f09b]:8333 # AS206238
+[2a0e:8f02:21d1:144::101]:8333 # AS20473
+[2a0e:b780::55d1:f05b]:8333 # AS205581
+[2a10:3781:2c19::1]:8333 # AS206238
[2a10:d200:1:33:a6bf:1ff:fe6a:46a9]:8333 # AS212323
-[2c0f:f4c0:2202:20b0:261c:4ff:fe14:daa0]:8333 # AS327693
-[2c0f:f8f0:da51:0:70c3:eea9:9717:9579]:8333 # AS30844
+[2a12:8e40:5668:e40a::1]:8333 # AS34465
+[2a12:8e40:5668:e40b::1]:8333 # AS34465
+[2a12:8e40:5668:e40c::1]:8333 # AS34465
+[2a12:8e40:5668:e40d::1]:8333 # AS34465
+[2a12:8e40:5668:e40e::1]:8333 # AS34465
+[2a12:8e40:5668:e40f::1]:8333 # AS34465
+[2a12:8e40:5668:e410::1]:8333 # AS34465
+[2a12:8e40:5668:e411::1]:8333 # AS34465
+[2a12:8e40:5668:e412::1]:8333 # AS34465
+[2a12:8e40:5668:e417::1]:8333 # AS34465
+[2c0f:f8f0:da51:0:3a45:fc57:5e30:2593]:8333 # AS30844
-# manually updated 2022-08 for minimal torv3 bootstrap support
+# manually updated 2023-04 for minimal torv3 bootstrap support
+
+2bqghnldu6mcug4pikzprwhtjjnsyederctvci6klcwzepnjd46ikjyd.onion:8333
+4lr3w2iyyl5u5l6tosizclykf5v3smqroqdn2i4h3kq6pfbbjb2xytad.onion:8333
5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
+5sbmcl4m5api5tqafi4gcckrn3y52sz5mskxf3t6iw4bp7erwiptrgqd.onion:8333
+776aegl7tfhg6oiqqy76jnwrwbvcytsx2qegcgh2mjqujll4376ohlid.onion:8333
+77mdte42srl42shdh2mhtjr7nf7dmedqrw6bkcdekhdvmnld6ojyyiad.onion:8333
+azbpsh4arqlm6442wfimy7qr65bmha2zhgjg7wbaji6vvaug53hur2qd.onion:8333
b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
-fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333
+bsqbtcparrfihlwolt4xgjbf4cgqckvrvsfyvy6vhiqrnh4w6ghixoid.onion:8333
+bsqbtctulf2g4jtjsdfgl2ed7qs6zz5wqx27qnyiik7laockryvszqqd.onion:8333
+cwi3ekrwhig47dhhzfenr5hbvckj7fzaojygvazi2lucsenwbzwoyiqd.onion:8333
+devinbtcmwkuitvxl3tfi5of4zau46ymeannkjv6fpnylkgf3q5fa3id.onion:8333
+devinbtctu7uctl7hly2juu3thbgeivfnvw3ckj3phy6nyvpnx66yeyd.onion:8333
+devinbtcyk643iruzfpaxw3on2jket7rbjmwygm42dmdyub3ietrbmid.onion:8333
+dtql5vci4iaml4anmueftqr7bfgzqlauzfy4rc2tfgulldd3ekyijjyd.onion:8333
+emzybtc25oddoa2prol2znpz2axnrg6k77xwgirmhv7igoiucddsxiad.onion:8333
+emzybtc3ewh7zihpkdvuwlgxrhzcxy2p5fvjggp7ngjbxcytxvt4rjid.onion:8333
+emzybtc454ewbviqnmgtgx3rgublsgkk23r4onbhidcv36wremue4kqd.onion:8333
+emzybtc5bnpb2o6gh54oquiox54o4r7yn4a2wiiwzrjonlouaibm2zid.onion:8333
fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333
-gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333
-ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333
-itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333
+hanvo3hzqbhcqm5vahhi5a3czxxdwc7vt56p5gr7bifcvelaqurv6iid.onion:8333
+hz7oqntvj4adrwtqappcgaxfribg5u4rvfkpwlo3xup5fcuyvylkxlqd.onion:8333
+ityrxhidvjnjnf6imzyuqqnkkwridjnebkbokx25so3suq3fzezmksid.onion:8333
+jto2jfbsxhb6yvhcrrjddrgbakte6tgsy3c3z3prss64gndgvovvosyd.onion:8333
+k7nb3r7hxi5exvr4xmvnilhfw6hei7sw4rwz2t6onh4py6wbora6tuyd.onion:8333
kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion:8333
+l7kw3vjs4cf5mnuejjgqcxrw6wwsjmabllq3h3amy4f5q33d6cgo2kyd.onion:8333
m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333
+mowb2qwpjgs2a6q3yj3xa7nxklfssul4w7ynonyycw3uyopfu3x6ujad.onion:8333
mwmfluek4au6mxxpw6fy7sjhkm65bdfc7izc7lpz3trewfdghyrzsbid.onion:8333
-rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333
+rfqmn3qe36uaptkxhdvi74p4hyrzhir6vhmzb2hqryxodig4gue2zbyd.onion:8333
+rsgwtnousfc7zyg4qsm3gvczjx7cihh2njyjbjl3qvcj3xg7wmvhddqd.onion:8333
+s2d52bbttuwcl3pdrwzhxpmhtxn3jg23havjqg5eygwhtiw6lgyelpqd.onion:8333
+upvthy74hgvgbqi6w3zd2mlchoi5tvvw7b5hpmmhcddd5fnnwrixneid.onion:8333
+who3qs4eqlqzoxhqqgan4mg54ua5uz3mk4lj33ag53ei4orvnznrjbad.onion:8333
+wizbit5555bsslwv4ctronnsgk5vh2w2pdx7v7eyuivlyuoteejk7lid.onion:8333
+yrmedr35tt4wqfnwgilltxh5bnukeukxjpgg3jzmmsyld5lgsn5amvyd.onion:8333
-# manually updated 2022-08 for minimal i2p bootstrap support
+# manually updated 2023-04 for minimal i2p bootstrap support
255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
-2el6enckmfyiwbfcwsygkwksovtynzsigmyv3bzyk7j7qqahooua.b32.i2p:0
3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
-3tns2oov4tnllntotazy6umzkq4fhkco3iu5rnkxtu3pbfzxda7q.b32.i2p:0
4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
-52v6uo6crlrlhzphslyiqblirux6olgsaa45ixih7sq5np4jujaa.b32.i2p:0
6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
-7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0
a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
-bddbsmkas3z6fakorbkfjhv77i4hv6rysyjsvrdjukxolfghc23q.b32.i2p:0
bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
-di2zq6fr3fegf2jdcd7hdwyql4umr462gonsns2nxz5qg5vz4bka.b32.i2p:0
+du5kydummi23bjfp6bd7owsvrijgt7zhvxmz5h5f5spcioeoetwq.b32.i2p:0
e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0
ejlnngarmhqvune74ko7kk55xtgbz5i5ncs4vmnvjpy3l7y63xaa.b32.i2p:0
-g47cqoppu26pr4n2cfaioqx7lbdi7mea7yqhlrkdz3wjwxjxdh2a.b32.i2p:0
-h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p:0
+fhzlp3xroabohnmjonu5iqazwhlbbwh5cpujvw2azcu3srqdceja.b32.i2p:0
+fx6np3oheacr3t7gluftrqo2qxldbbatgw4hepp7ulb4j5ry57ca.b32.i2p:0
+gehtac45oaghz54ypyopim64mql7oad2bqclla74l6tfeolzmodq.b32.i2p:0
hhfi4yqkg2twqiwezrfksftjjofbyx3ojkmlnfmcwntgnrjjhkya.b32.i2p:0
-hpiibrflqkbrcshfhmrtwfyeb7mds7a3obzwrgarejevddzamvsq.b32.i2p:0
-i4pyhsfdq4247dunel7paatdaq5gusi2hnybp2yf5wxwdnrgxaqq.b32.i2p:0
-iw6tgpmbdykffceku5da6nzf2bmz66fvp5fpcvemfu3df6aq6pga.b32.i2p:0
-jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0
jz3s4eurm5vzjresf4mwo7oni4bk36daolwxh4iqtewakylgkxmq.b32.i2p:0
liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0
-ljsquuu3y4xje6l32p32inn6r2y6ull6oocgup6jtjrohrqxbz6a.b32.i2p:0
lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0
lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0
m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0
m6v454xd6p3bt5swujgmveklsp7lzbkqlqqfc2p36cjlwv5dbucq.b32.i2p:0
mlgeizrroynuhpxbzeosajt5u4ddcvynxfmcbm6kwjpaufilxigq.b32.i2p:0
+o6t4fr5ayfadzieutstgwcllvwxeuzjlxmzsmpj3hpkvefhzfaea.b32.i2p:0
ofubxr2ir7u2guzjwyrvujicivzmvinwa36nuzlrg7tnsmebal7a.b32.i2p:0
-okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0
oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0
+pohfcrfc7prn4bvn4xstw6nt3e7hjmb7kuj4djtsfqsskwhmhnna.b32.i2p:0
qd6jlsevsexww3wefpqs7iglxb3f63y4e6ydulfzrvwflpicmdqa.b32.i2p:0
-qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0
+rfjkzdzv4cwpxo6hzuncicvuyui76wxqx3a23lynq72ktwqs7aja.b32.i2p:0
rizfinyses2r3or4iubs5wx66gdy6mpf73w7uobfacm2l5cral3q.b32.i2p:0
-s5hhjtmlg53bko3nwwskas7xgsmeqzy6thtsj5aa64djyrljgqaq.b32.i2p:0
sedndhv5vpcgdmykyi5st4yqhdxl3hpdtglta4do435wupahhx6q.b32.i2p:0
-tsl4dlpu2id252b6crbdnblruct664se6f2iw35fuqwa3te7wcoq.b32.i2p:0
tugq6wa2ls2bv27pr2iy3da3k5ow3fzefbcvjcr22uc7w5vmevja.b32.i2p:0
usztavbib756k5vqggzgkyswoj6mttihjvp3c2pa642t2mb4pvsa.b32.i2p:0
vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0
wjrul5jwwb4vqdmkkrjbmly7osj6amecdpsac5xvaoqrti4nb3ha.b32.i2p:0
-wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0
wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0
-xlqndzjoe5nr2nsxo6xwibh44ghyz4jfqevu62xykvemextpmjbq.b32.i2p:0
+xfkarmvk43vfkfvhkehy7ioj2b6wtfdlezvmlakblz3q4r7mccfq.b32.i2p:0
yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0
zdoabsg7ugzothyawodjhq54nvlofa746rxfkxpnjzj6nukmha6a.b32.i2p:0
zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p:0
zysrlpii5ftrzivfcyhdrwpeyyqddbrdefnfu5q6otk5gtugmh2a.b32.i2p:0
-# manually added 2022-01 for minimal cjdns bootstrap support
+# manually updated 2023-04 for minimal cjdns bootstrap support
[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333
+[fcdc:73ae:b1a9:1bf8:d4c2:811:a4c7:c34e]:8333
diff --git a/contrib/seeds/nodes_main_manual.txt b/contrib/seeds/nodes_main_manual.txt
index 286448d95d..91a64c6e51 100644
--- a/contrib/seeds/nodes_main_manual.txt
+++ b/contrib/seeds/nodes_main_manual.txt
@@ -1,78 +1,95 @@
-# manually updated 2022-08 for minimal torv3 bootstrap support
+# manually updated 2023-04 for minimal torv3 bootstrap support
+
+2bqghnldu6mcug4pikzprwhtjjnsyederctvci6klcwzepnjd46ikjyd.onion:8333
+4lr3w2iyyl5u5l6tosizclykf5v3smqroqdn2i4h3kq6pfbbjb2xytad.onion:8333
5g72ppm3krkorsfopcm2bi7wlv4ohhs4u4mlseymasn7g7zhdcyjpfid.onion:8333
+5sbmcl4m5api5tqafi4gcckrn3y52sz5mskxf3t6iw4bp7erwiptrgqd.onion:8333
+776aegl7tfhg6oiqqy76jnwrwbvcytsx2qegcgh2mjqujll4376ohlid.onion:8333
+77mdte42srl42shdh2mhtjr7nf7dmedqrw6bkcdekhdvmnld6ojyyiad.onion:8333
+azbpsh4arqlm6442wfimy7qr65bmha2zhgjg7wbaji6vvaug53hur2qd.onion:8333
b64xcbleqmwgq2u46bh4hegnlrzzvxntyzbmucn3zt7cssm7y4ubv3id.onion:8333
-fjdyxicpm4o42xmedlwl3uvk5gmqdfs5j37wir52327vncjzvtpfv7yd.onion:8333
+bsqbtcparrfihlwolt4xgjbf4cgqckvrvsfyvy6vhiqrnh4w6ghixoid.onion:8333
+bsqbtctulf2g4jtjsdfgl2ed7qs6zz5wqx27qnyiik7laockryvszqqd.onion:8333
+cwi3ekrwhig47dhhzfenr5hbvckj7fzaojygvazi2lucsenwbzwoyiqd.onion:8333
+devinbtcmwkuitvxl3tfi5of4zau46ymeannkjv6fpnylkgf3q5fa3id.onion:8333
+devinbtctu7uctl7hly2juu3thbgeivfnvw3ckj3phy6nyvpnx66yeyd.onion:8333
+devinbtcyk643iruzfpaxw3on2jket7rbjmwygm42dmdyub3ietrbmid.onion:8333
+dtql5vci4iaml4anmueftqr7bfgzqlauzfy4rc2tfgulldd3ekyijjyd.onion:8333
+emzybtc25oddoa2prol2znpz2axnrg6k77xwgirmhv7igoiucddsxiad.onion:8333
+emzybtc3ewh7zihpkdvuwlgxrhzcxy2p5fvjggp7ngjbxcytxvt4rjid.onion:8333
+emzybtc454ewbviqnmgtgx3rgublsgkk23r4onbhidcv36wremue4kqd.onion:8333
+emzybtc5bnpb2o6gh54oquiox54o4r7yn4a2wiiwzrjonlouaibm2zid.onion:8333
fpz6r5ppsakkwypjcglz6gcnwt7ytfhxskkfhzu62tnylcknh3eq6pad.onion:8333
-gxo5anvfnffnftfy5frkgvplq3rpga2ie3tcblo2vl754fvnhgorn5yd.onion:8333
-ifdu5qvbofrt4ekui2iyb3kbcyzcsglazhx2hn4wfskkrx2v24qxriid.onion:8333
-itz3oxsihs62muvknc237xabl5f6w6rfznfhbpayrslv2j2ubels47yd.onion:8333
+hanvo3hzqbhcqm5vahhi5a3czxxdwc7vt56p5gr7bifcvelaqurv6iid.onion:8333
+hz7oqntvj4adrwtqappcgaxfribg5u4rvfkpwlo3xup5fcuyvylkxlqd.onion:8333
+ityrxhidvjnjnf6imzyuqqnkkwridjnebkbokx25so3suq3fzezmksid.onion:8333
+jto2jfbsxhb6yvhcrrjddrgbakte6tgsy3c3z3prss64gndgvovvosyd.onion:8333
+k7nb3r7hxi5exvr4xmvnilhfw6hei7sw4rwz2t6onh4py6wbora6tuyd.onion:8333
kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion:8333
+l7kw3vjs4cf5mnuejjgqcxrw6wwsjmabllq3h3amy4f5q33d6cgo2kyd.onion:8333
m7cbpjolo662uel7rpaid46as2otcj44vvwg3gccodnvaeuwbm3anbyd.onion:8333
+mowb2qwpjgs2a6q3yj3xa7nxklfssul4w7ynonyycw3uyopfu3x6ujad.onion:8333
mwmfluek4au6mxxpw6fy7sjhkm65bdfc7izc7lpz3trewfdghyrzsbid.onion:8333
-rp7k2go3s5lyj3fnj6zn62ktarlrsft2ohlsxkyd7v3e3idqyptvread.onion:8333
+rfqmn3qe36uaptkxhdvi74p4hyrzhir6vhmzb2hqryxodig4gue2zbyd.onion:8333
+rsgwtnousfc7zyg4qsm3gvczjx7cihh2njyjbjl3qvcj3xg7wmvhddqd.onion:8333
+s2d52bbttuwcl3pdrwzhxpmhtxn3jg23havjqg5eygwhtiw6lgyelpqd.onion:8333
+upvthy74hgvgbqi6w3zd2mlchoi5tvvw7b5hpmmhcddd5fnnwrixneid.onion:8333
+who3qs4eqlqzoxhqqgan4mg54ua5uz3mk4lj33ag53ei4orvnznrjbad.onion:8333
+wizbit5555bsslwv4ctronnsgk5vh2w2pdx7v7eyuivlyuoteejk7lid.onion:8333
+yrmedr35tt4wqfnwgilltxh5bnukeukxjpgg3jzmmsyld5lgsn5amvyd.onion:8333
-# manually updated 2022-08 for minimal i2p bootstrap support
+# manually updated 2023-04 for minimal i2p bootstrap support
255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p:0
27yrtht5b5bzom2w5ajb27najuqvuydtzb7bavlak25wkufec5mq.b32.i2p:0
-2el6enckmfyiwbfcwsygkwksovtynzsigmyv3bzyk7j7qqahooua.b32.i2p:0
3gocb7wc4zvbmmebktet7gujccuux4ifk3kqilnxnj5wpdpqx2hq.b32.i2p:0
-3tns2oov4tnllntotazy6umzkq4fhkco3iu5rnkxtu3pbfzxda7q.b32.i2p:0
4fcc23wt3hyjk3csfzcdyjz5pcwg5dzhdqgma6bch2qyiakcbboa.b32.i2p:0
4osyqeknhx5qf3a73jeimexwclmt42cju6xdp7icja4ixxguu2hq.b32.i2p:0
4umsi4nlmgyp4rckosg4vegd2ysljvid47zu7pqsollkaszcbpqq.b32.i2p:0
-52v6uo6crlrlhzphslyiqblirux6olgsaa45ixih7sq5np4jujaa.b32.i2p:0
6j2ezegd3e2e2x3o3pox335f5vxfthrrigkdrbgfbdjchm5h4awa.b32.i2p:0
6n36ljyr55szci5ygidmxqer64qr24f4qmnymnbvgehz7qinxnla.b32.i2p:0
72yjs6mvlby3ky6mgpvvlemmwq5pfcznrzd34jkhclgrishqdxva.b32.i2p:0
-7r4ri53lby2i3xqbgpw3idvhzeku7ubhftlf72ldqkg5kde6dauq.b32.i2p:0
a5qsnv3maw77mlmmzlcglu6twje6ttctd3fhpbfwcbpmewx6fczq.b32.i2p:0
aovep2pco7v2k4rheofrgytbgk23eg22dczpsjqgqtxcqqvmxk6a.b32.i2p:0
-bddbsmkas3z6fakorbkfjhv77i4hv6rysyjsvrdjukxolfghc23q.b32.i2p:0
bitcoi656nll5hu6u7ddzrmzysdtwtnzcnrjd4rfdqbeey7dmn5a.b32.i2p:0
brifkruhlkgrj65hffybrjrjqcgdgqs2r7siizb5b2232nruik3a.b32.i2p:0
c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p:0
day3hgxyrtwjslt54sikevbhxxs4qzo7d6vi72ipmscqtq3qmijq.b32.i2p:0
-di2zq6fr3fegf2jdcd7hdwyql4umr462gonsns2nxz5qg5vz4bka.b32.i2p:0
+du5kydummi23bjfp6bd7owsvrijgt7zhvxmz5h5f5spcioeoetwq.b32.i2p:0
e55k6wu46rzp4pg5pk5npgbr3zz45bc3ihtzu2xcye5vwnzdy7pq.b32.i2p:0
eciohu5nq7vsvwjjc52epskuk75d24iccgzmhbzrwonw6lx4gdva.b32.i2p:0
ejlnngarmhqvune74ko7kk55xtgbz5i5ncs4vmnvjpy3l7y63xaa.b32.i2p:0
-g47cqoppu26pr4n2cfaioqx7lbdi7mea7yqhlrkdz3wjwxjxdh2a.b32.i2p:0
-h3r6bkn46qxftwja53pxiykntegfyfjqtnzbm6iv6r5mungmqgmq.b32.i2p:0
+fhzlp3xroabohnmjonu5iqazwhlbbwh5cpujvw2azcu3srqdceja.b32.i2p:0
+fx6np3oheacr3t7gluftrqo2qxldbbatgw4hepp7ulb4j5ry57ca.b32.i2p:0
+gehtac45oaghz54ypyopim64mql7oad2bqclla74l6tfeolzmodq.b32.i2p:0
hhfi4yqkg2twqiwezrfksftjjofbyx3ojkmlnfmcwntgnrjjhkya.b32.i2p:0
-hpiibrflqkbrcshfhmrtwfyeb7mds7a3obzwrgarejevddzamvsq.b32.i2p:0
-i4pyhsfdq4247dunel7paatdaq5gusi2hnybp2yf5wxwdnrgxaqq.b32.i2p:0
-iw6tgpmbdykffceku5da6nzf2bmz66fvp5fpcvemfu3df6aq6pga.b32.i2p:0
-jkfuajo4ayvo2rbv5qdj443q6adqmnormbhsf2f7rlp5t24xomda.b32.i2p:0
jz3s4eurm5vzjresf4mwo7oni4bk36daolwxh4iqtewakylgkxmq.b32.i2p:0
liu75cvktv4icbctg72w7nxbk4eibt7wamizfdii4omz7gcke5vq.b32.i2p:0
-ljsquuu3y4xje6l32p32inn6r2y6ull6oocgup6jtjrohrqxbz6a.b32.i2p:0
lrah7acdsgopybg43shadwwiv6igezaw64i6jb5muqdg7dmhj3la.b32.i2p:0
lzuu6mjtu7vd55d2biphicihufipoa7vyym6xfnkmmlra3tiziia.b32.i2p:0
m6bpynxkv2ktwxkg6p2gyudjfhdupb6kuzabeqdnckkdkf4kxjla.b32.i2p:0
m6v454xd6p3bt5swujgmveklsp7lzbkqlqqfc2p36cjlwv5dbucq.b32.i2p:0
mlgeizrroynuhpxbzeosajt5u4ddcvynxfmcbm6kwjpaufilxigq.b32.i2p:0
+o6t4fr5ayfadzieutstgwcllvwxeuzjlxmzsmpj3hpkvefhzfaea.b32.i2p:0
ofubxr2ir7u2guzjwyrvujicivzmvinwa36nuzlrg7tnsmebal7a.b32.i2p:0
-okfxeoh6itu4f5f43dhbzvkqwfrvm5c66lj6lvjj4q2b35i4pk4q.b32.i2p:0
oz2ia3flpm3du2tyusulrn7h7e2eo3juzkrmn34bvnrlcrugv7ia.b32.i2p:0
+pohfcrfc7prn4bvn4xstw6nt3e7hjmb7kuj4djtsfqsskwhmhnna.b32.i2p:0
qd6jlsevsexww3wefpqs7iglxb3f63y4e6ydulfzrvwflpicmdqa.b32.i2p:0
-qddg7myylinn4tw6kdjmmp6fsyetkosnrbp2gsjx77tmkqyqv6ua.b32.i2p:0
+rfjkzdzv4cwpxo6hzuncicvuyui76wxqx3a23lynq72ktwqs7aja.b32.i2p:0
rizfinyses2r3or4iubs5wx66gdy6mpf73w7uobfacm2l5cral3q.b32.i2p:0
-s5hhjtmlg53bko3nwwskas7xgsmeqzy6thtsj5aa64djyrljgqaq.b32.i2p:0
sedndhv5vpcgdmykyi5st4yqhdxl3hpdtglta4do435wupahhx6q.b32.i2p:0
-tsl4dlpu2id252b6crbdnblruct664se6f2iw35fuqwa3te7wcoq.b32.i2p:0
tugq6wa2ls2bv27pr2iy3da3k5ow3fzefbcvjcr22uc7w5vmevja.b32.i2p:0
usztavbib756k5vqggzgkyswoj6mttihjvp3c2pa642t2mb4pvsa.b32.i2p:0
vgu6llqbyjphml25umd5ztvyxrxuplz2g74fzbx75g3kkaetoyiq.b32.i2p:0
wjrul5jwwb4vqdmkkrjbmly7osj6amecdpsac5xvaoqrti4nb3ha.b32.i2p:0
-wvktcp7hy4l6immhi5cxyz2dlsbhhvtcmskjemrnqehacnoap23q.b32.i2p:0
wwbw7nqr3ahkqv62cuqfwgtneekvvpnuc4i4f6yo7tpoqjswvcwa.b32.i2p:0
-xlqndzjoe5nr2nsxo6xwibh44ghyz4jfqevu62xykvemextpmjbq.b32.i2p:0
+xfkarmvk43vfkfvhkehy7ioj2b6wtfdlezvmlakblz3q4r7mccfq.b32.i2p:0
yc4xwin5ujenvcr6ynwkz7lnmmq3nmzxvfguele6ovqqpxgjvonq.b32.i2p:0
zdoabsg7ugzothyawodjhq54nvlofa746rxfkxpnjzj6nukmha6a.b32.i2p:0
zsxwyo6qcn3chqzwxnseusqgsnuw3maqnztkiypyfxtya4snkoka.b32.i2p:0
zysrlpii5ftrzivfcyhdrwpeyyqddbrdefnfu5q6otk5gtugmh2a.b32.i2p:0
-# manually added 2022-01 for minimal cjdns bootstrap support
+# manually updated 2023-04 for minimal cjdns bootstrap support
[fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa]:8333
[fcc7:be49:ccd1:dc91:3125:f0da:457d:8ce]:8333
+[fcdc:73ae:b1a9:1bf8:d4c2:811:a4c7:c34e]:8333
diff --git a/contrib/tracing/mempool_monitor.py b/contrib/tracing/mempool_monitor.py
index 9d427d4632..afb5e60372 100755
--- a/contrib/tracing/mempool_monitor.py
+++ b/contrib/tracing/mempool_monitor.py
@@ -27,7 +27,7 @@ PROGRAM = """
struct added_event
{
u8 hash[HASH_LENGTH];
- u64 vsize;
+ s32 vsize;
s64 fee;
};
@@ -35,7 +35,7 @@ struct removed_event
{
u8 hash[HASH_LENGTH];
char reason[MAX_REMOVAL_REASON_LENGTH];
- u64 vsize;
+ s32 vsize;
s64 fee;
u64 entry_time;
};
@@ -49,11 +49,11 @@ struct rejected_event
struct replaced_event
{
u8 replaced_hash[HASH_LENGTH];
- u64 replaced_vsize;
+ s32 replaced_vsize;
s64 replaced_fee;
u64 replaced_entry_time;
u8 replacement_hash[HASH_LENGTH];
- u64 replacement_vsize;
+ s32 replacement_vsize;
s64 replacement_fee;
};
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
index 9a8edba445..faba1f6ae6 100644
--- a/contrib/valgrind.supp
+++ b/contrib/valgrind.supp
@@ -13,19 +13,8 @@
#
# Note that suppressions may depend on OS and/or library versions.
# Tested on:
-# * aarch64 (Ubuntu 22.04 system libs, clang, without gui)
-# * x86_64 (Ubuntu 22.04 system libs, clang, without gui)
-{
- Suppress libstdc++ warning - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65434
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:malloc
- obj:*/libstdc++.*
- fun:call_init.part.0
- fun:call_init
- fun:_dl_init
- obj:*/ld-*.so
-}
+# * aarch64 (Debian Bookworm system libs, clang, without gui)
+# * x86_64 (Debian Bookworm system libs, clang, without gui)
{
Suppress libdb warning - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=662917
Memcheck:Cond
@@ -71,12 +60,6 @@
fun:_Z8ShutdownR11NodeContext
}
{
- Ignore GUI warning
- Memcheck:Leak
- ...
- obj:/usr/lib64/libgdk-3.so.0.2404.7
-}
-{
Suppress leveldb leak
Memcheck:Leak
match-leak-kinds: reachable
diff --git a/contrib/verify-binaries/README.md b/contrib/verify-binaries/README.md
new file mode 100644
index 0000000000..04d683e69b
--- /dev/null
+++ b/contrib/verify-binaries/README.md
@@ -0,0 +1,88 @@
+### Verify Binaries
+
+#### Preparation
+
+As of Bitcoin Core v22.0, releases are signed by a number of public keys on the basis
+of the [guix.sigs repository](https://github.com/bitcoin-core/guix.sigs/). When
+verifying binary downloads, you (the end user) decide which of these public keys you
+trust and then use that trust model to evaluate the signature on a file that contains
+hashes of the release binaries. The downloaded binaries are then hashed and compared to
+the signed checksum file.
+
+First, you have to figure out which public keys to recognize. Browse the [list of frequent
+builder-keys](https://github.com/bitcoin-core/guix.sigs/tree/main/builder-keys) and
+decide which of these keys you would like to trust. For each key you want to trust, you
+must obtain that key for your local GPG installation.
+
+You can obtain these keys by
+ - through a browser using a key server (e.g. keyserver.ubuntu.com),
+ - manually using the `gpg --keyserver <url> --recv-keys <key>` command, or
+ - you can run the packaged `verify.py --import-keys ...` script to
+ have it automatically retrieve unrecognized keys.
+
+#### Usage
+
+This script attempts to download the checksum file (`SHA256SUMS`) and corresponding
+signature file `SHA256SUMS.asc` from https://bitcoincore.org and https://bitcoin.org.
+
+It first checks if the checksum file is valid based upon a plurality of signatures, and
+then downloads the release files specified in the checksum file, and checks if the
+hashes of the release files are as expected.
+
+If we encounter pubkeys in the signature file that we do not recognize, the script
+can prompt the user as to whether they'd like to download the pubkeys. To enable
+this behavior, use the `--import-keys` flag.
+
+The script returns 0 if everything passes the checks. It returns 1 if either the
+signature check or the hash check doesn't pass. An exit code of >2 indicates an error.
+
+See the `Config` object for various options.
+
+#### Examples
+
+Validate releases with default settings:
+```sh
+./contrib/verify-binaries/verify.py pub 22.0
+./contrib/verify-binaries/verify.py pub 22.0-rc3
+```
+
+Get JSON output and don't prompt for user input (no auto key import):
+
+```sh
+./contrib/verify-binaries/verify.py --json pub 22.0-x86
+```
+
+Rely only on local GPG state and manually specified keys, while requiring a
+threshold of at least 10 trusted signatures:
+```sh
+./contrib/verify-binaries/verify.py \
+ --trusted-keys 74E2DEF5D77260B98BC19438099BAD163C70FBFA,9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C \
+ --min-good-sigs 10 pub 22.0-x86
+```
+
+If you only want to download the binaries for a certain platform, add the corresponding suffix, e.g.:
+
+```sh
+./contrib/verify-binaries/verify.py pub 24.0.1-darwin
+./contrib/verify-binaries/verify.py pub 23.1-rc1-win64
+```
+
+If you do not want to keep the downloaded binaries, specify the cleanup option.
+
+```sh
+./contrib/verify-binaries/verify.py pub --cleanup 22.0
+```
+
+Use the bin subcommand to verify all files listed in a local checksum file
+
+```sh
+./contrib/verify-binaries/verify.py bin SHA256SUMS
+```
+
+Verify only a subset of the files listed in a local checksum file
+
+```sh
+./contrib/verify-binaries/verify.py bin ~/Downloads/SHA256SUMS \
+ ~/Downloads/bitcoin-24.0.1-x86_64-linux-gnu.tar.gz \
+ ~/Downloads/bitcoin-24.0.1-arm-linux-gnueabihf.tar.gz
+```
diff --git a/contrib/verify-binaries/test.py b/contrib/verify-binaries/test.py
new file mode 100755
index 0000000000..22d718ece3
--- /dev/null
+++ b/contrib/verify-binaries/test.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+
+import json
+import sys
+import subprocess
+from pathlib import Path
+
+
+def main():
+ """Tests ordered roughly from faster to slower."""
+ expect_code(run_verify("", "pub", '0.32'), 4, "Nonexistent version should fail")
+ expect_code(run_verify("", "pub", '0.32.awefa.12f9h'), 11, "Malformed version should fail")
+ expect_code(run_verify('--min-good-sigs 20', "pub", "22.0"), 9, "--min-good-sigs 20 should fail")
+
+ print("- testing verification (22.0)", flush=True)
+ _220 = run_verify("--json", "pub", "22.0")
+ try:
+ result = json.loads(_220.stdout.decode())
+ except Exception:
+ print("failed on 22.0 --json:")
+ print_process_failure(_220)
+ raise
+
+ expect_code(_220, 0, "22.0 should succeed")
+ v = result['verified_binaries']
+ assert result['good_trusted_sigs']
+ assert v['bitcoin-22.0-aarch64-linux-gnu.tar.gz'] == 'ac718fed08570a81b3587587872ad85a25173afa5f9fbbd0c03ba4d1714cfa3e'
+ assert v['bitcoin-22.0-osx64.tar.gz'] == '2744d199c3343b2d94faffdfb2c94d75a630ba27301a70e47b0ad30a7e0155e9'
+ assert v['bitcoin-22.0-x86_64-linux-gnu.tar.gz'] == '59ebd25dd82a51638b7a6bb914586201e67db67b919b2a1ff08925a7936d1b16'
+
+
+def run_verify(global_args: str, command: str, command_args: str) -> subprocess.CompletedProcess:
+ maybe_here = Path.cwd() / 'verify.py'
+ path = maybe_here if maybe_here.exists() else Path.cwd() / 'contrib' / 'verify-binaries' / 'verify.py'
+
+ if command == "pub":
+ command += " --cleanup"
+
+ return subprocess.run(
+ f"{path} {global_args} {command} {command_args}",
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+
+
+def expect_code(completed: subprocess.CompletedProcess, expected_code: int, msg: str):
+ if completed.returncode != expected_code:
+ print(f"{msg!r} failed: got code {completed.returncode}, expected {expected_code}")
+ print_process_failure(completed)
+ sys.exit(1)
+ else:
+ print(f"✓ {msg!r} passed")
+
+
+def print_process_failure(completed: subprocess.CompletedProcess):
+ print(f"stdout:\n{completed.stdout.decode()}")
+ print(f"stderr:\n{completed.stderr.decode()}")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/verify-binaries/verify.py b/contrib/verify-binaries/verify.py
new file mode 100755
index 0000000000..d0749f503f
--- /dev/null
+++ b/contrib/verify-binaries/verify.py
@@ -0,0 +1,713 @@
+#!/usr/bin/env python3
+# 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.
+"""Script for verifying Bitcoin Core release binaries.
+
+This script attempts to download the sum file SHA256SUMS and corresponding
+signature file SHA256SUMS.asc from bitcoincore.org and bitcoin.org and
+compares them.
+
+The sum-signature file is signed by a number of builder keys. This script
+ensures that there is a minimum threshold of signatures from pubkeys that
+we trust. This trust is articulated on the basis of configuration options
+here, but by default is based upon local GPG trust settings.
+
+The builder keys are available in the guix.sigs repo:
+
+ https://github.com/bitcoin-core/guix.sigs/tree/main/builder-keys
+
+If a minimum good, trusted signature threshold is met on the sum file, we then
+download the files specified in SHA256SUMS, and check if the hashes of these
+files match those that are specified. The script returns 0 if everything passes
+the checks. It returns 1 if either the signature check or the hash check
+doesn't pass. If an error occurs the return value is >= 2.
+
+Logging output goes to stderr and final binary verification data goes to stdout.
+
+JSON output can by obtained by setting env BINVERIFY_JSON=1.
+"""
+import argparse
+import difflib
+import json
+import logging
+import os
+import subprocess
+import typing as t
+import re
+import sys
+import shutil
+import tempfile
+import textwrap
+import urllib.request
+import urllib.error
+import enum
+from hashlib import sha256
+from pathlib import PurePath, Path
+
+# The primary host; this will fail if we can't retrieve files from here.
+HOST1 = "https://bitcoincore.org"
+HOST2 = "https://bitcoin.org"
+VERSIONPREFIX = "bitcoin-core-"
+SUMS_FILENAME = 'SHA256SUMS'
+SIGNATUREFILENAME = f"{SUMS_FILENAME}.asc"
+
+
+class ReturnCode(enum.IntEnum):
+ SUCCESS = 0
+ INTEGRITY_FAILURE = 1
+ FILE_GET_FAILED = 4
+ FILE_MISSING_FROM_ONE_HOST = 5
+ FILES_NOT_EQUAL = 6
+ NO_BINARIES_MATCH = 7
+ NOT_ENOUGH_GOOD_SIGS = 9
+ BINARY_DOWNLOAD_FAILED = 10
+ BAD_VERSION = 11
+
+
+def set_up_logger(is_verbose: bool = True) -> logging.Logger:
+ """Set up a logger that writes to stderr."""
+ log = logging.getLogger(__name__)
+ log.setLevel(logging.INFO if is_verbose else logging.WARNING)
+ console = logging.StreamHandler(sys.stderr) # log to stderr
+ console.setLevel(logging.DEBUG)
+ formatter = logging.Formatter('[%(levelname)s] %(message)s')
+ console.setFormatter(formatter)
+ log.addHandler(console)
+ return log
+
+
+log = set_up_logger()
+
+
+def indent(output: str) -> str:
+ return textwrap.indent(output, ' ')
+
+
+def bool_from_env(key, default=False) -> bool:
+ if key not in os.environ:
+ return default
+ raw = os.environ[key]
+
+ if raw.lower() in ('1', 'true'):
+ return True
+ elif raw.lower() in ('0', 'false'):
+ return False
+ raise ValueError(f"Unrecognized environment value {key}={raw!r}")
+
+
+VERSION_FORMAT = "<major>.<minor>[.<patch>][-rc[0-9]][-platform]"
+VERSION_EXAMPLE = "22.0-x86_64 or 23.1-rc1-darwin"
+
+def parse_version_string(version_str):
+ parts = version_str.split('-')
+ version_base = parts[0]
+ version_rc = ""
+ version_os = ""
+ if len(parts) == 2: # "<version>-rcN" or "version-platform"
+ if "rc" in parts[1]:
+ version_rc = parts[1]
+ else:
+ version_os = parts[1]
+ elif len(parts) == 3: # "<version>-rcN-platform"
+ version_rc = parts[1]
+ version_os = parts[2]
+
+ return version_base, version_rc, version_os
+
+
+def download_with_wget(remote_file, local_file):
+ result = subprocess.run(['wget', '-O', local_file, remote_file],
+ stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+ return result.returncode == 0, result.stdout.decode().rstrip()
+
+
+def download_lines_with_urllib(url) -> t.Tuple[bool, t.List[str]]:
+ """Get (success, text lines of a file) over HTTP."""
+ try:
+ return (True, [
+ line.strip().decode() for line in urllib.request.urlopen(url).readlines()])
+ except urllib.error.HTTPError as e:
+ log.warning(f"HTTP request to {url} failed (HTTPError): {e}")
+ except Exception as e:
+ log.warning(f"HTTP request to {url} failed ({e})")
+ return (False, [])
+
+
+def verify_with_gpg(
+ filename,
+ signature_filename,
+ output_filename: t.Optional[str] = None
+) -> t.Tuple[int, str]:
+ with tempfile.NamedTemporaryFile() as status_file:
+ args = [
+ 'gpg', '--yes', '--verify', '--verify-options', 'show-primary-uid-only', "--status-file", status_file.name,
+ '--output', output_filename if output_filename else '', signature_filename, filename]
+
+ env = dict(os.environ, LANGUAGE='en')
+ result = subprocess.run(args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=env)
+
+ gpg_data = status_file.read().decode().rstrip()
+
+ log.debug(f'Result from GPG ({result.returncode}): {result.stdout.decode()}')
+ log.debug(f"{gpg_data}")
+ return result.returncode, gpg_data
+
+
+def remove_files(filenames):
+ for filename in filenames:
+ os.remove(filename)
+
+
+class SigData:
+ """GPG signature data as parsed from GPG stdout."""
+ def __init__(self):
+ self.key = None
+ self.name = ""
+ self.trusted = False
+ self.status = ""
+
+ def __bool__(self):
+ return self.key is not None
+
+ def __repr__(self):
+ return (
+ "SigData(%r, %r, trusted=%s, status=%r)" %
+ (self.key, self.name, self.trusted, self.status))
+
+
+def parse_gpg_result(
+ output: t.List[str]
+) -> t.Tuple[t.List[SigData], t.List[SigData], t.List[SigData]]:
+ """Returns good, unknown, and bad signatures from GPG stdout."""
+ good_sigs: t.List[SigData] = []
+ unknown_sigs: t.List[SigData] = []
+ bad_sigs: t.List[SigData] = []
+ total_resolved_sigs = 0
+
+ # Ensure that all lines we match on include a prefix that prevents malicious input
+ # from fooling the parser.
+ def line_begins_with(patt: str, line: str) -> t.Optional[re.Match]:
+ return re.match(r'^(\[GNUPG:\])\s+' + patt, line)
+
+ curr_sigs = unknown_sigs
+ curr_sigdata = SigData()
+
+ for line in output:
+ if line_begins_with(r"NEWSIG(?:\s|$)", line):
+ total_resolved_sigs += 1
+ if curr_sigdata:
+ curr_sigs.append(curr_sigdata)
+ curr_sigdata = SigData()
+ newsig_split = line.split()
+ if len(newsig_split) == 3:
+ curr_sigdata.name = newsig_split[2]
+
+ elif line_begins_with(r"GOODSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = good_sigs
+
+ elif line_begins_with(r"EXPKEYSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = good_sigs
+ curr_sigdata.status = "expired"
+
+ elif line_begins_with(r"REVKEYSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = good_sigs
+ curr_sigdata.status = "revoked"
+
+ elif line_begins_with(r"BADSIG(?:\s|$)", line):
+ curr_sigdata.key, curr_sigdata.name = line.split(maxsplit=3)[2:4]
+ curr_sigs = bad_sigs
+
+ elif line_begins_with(r"ERRSIG(?:\s|$)", line):
+ curr_sigdata.key, _, _, _, _, _ = line.split()[2:8]
+ curr_sigs = unknown_sigs
+
+ elif line_begins_with(r"TRUST_(UNDEFINED|NEVER)(?:\s|$)", line):
+ curr_sigdata.trusted = False
+
+ elif line_begins_with(r"TRUST_(MARGINAL|FULLY|ULTIMATE)(?:\s|$)", line):
+ curr_sigdata.trusted = True
+
+ # The last one won't have been added, so add it now
+ assert curr_sigdata
+ curr_sigs.append(curr_sigdata)
+
+ all_found = len(good_sigs + bad_sigs + unknown_sigs)
+ if all_found != total_resolved_sigs:
+ raise RuntimeError(
+ f"failed to evaluate all signatures: found {all_found} "
+ f"but expected {total_resolved_sigs}")
+
+ return (good_sigs, unknown_sigs, bad_sigs)
+
+
+def files_are_equal(filename1, filename2):
+ with open(filename1, 'rb') as file1:
+ contents1 = file1.read()
+ with open(filename2, 'rb') as file2:
+ contents2 = file2.read()
+ eq = contents1 == contents2
+
+ if not eq:
+ with open(filename1, 'r', encoding='utf-8') as f1, \
+ open(filename2, 'r', encoding='utf-8') as f2:
+ f1lines = f1.readlines()
+ f2lines = f2.readlines()
+
+ diff = indent(
+ ''.join(difflib.unified_diff(f1lines, f2lines)))
+ log.warning(f"found diff in files ({filename1}, {filename2}):\n{diff}\n")
+
+ return eq
+
+
+def get_files_from_hosts_and_compare(
+ hosts: t.List[str], path: str, filename: str, require_all: bool = False
+) -> ReturnCode:
+ """
+ Retrieve the same file from a number of hosts and ensure they have the same contents.
+ The first host given will be treated as the "primary" host, and is required to succeed.
+
+ Args:
+ filename: for writing the file locally.
+ """
+ assert len(hosts) > 1
+ primary_host = hosts[0]
+ other_hosts = hosts[1:]
+ got_files = []
+
+ def join_url(host: str) -> str:
+ return host.rstrip('/') + '/' + path.lstrip('/')
+
+ url = join_url(primary_host)
+ success, output = download_with_wget(url, filename)
+ if not success:
+ log.error(
+ f"couldn't fetch file ({url}). "
+ "Have you specified the version number in the following format?\n"
+ f"{VERSION_FORMAT} "
+ f"(example: {VERSION_EXAMPLE})\n"
+ f"wget output:\n{indent(output)}")
+ return ReturnCode.FILE_GET_FAILED
+ else:
+ log.info(f"got file {url} as {filename}")
+ got_files.append(filename)
+
+ for i, host in enumerate(other_hosts):
+ url = join_url(host)
+ fname = filename + f'.{i + 2}'
+ success, output = download_with_wget(url, fname)
+
+ if require_all and not success:
+ log.error(
+ f"{host} failed to provide file ({url}), but {primary_host} did?\n"
+ f"wget output:\n{indent(output)}")
+ return ReturnCode.FILE_MISSING_FROM_ONE_HOST
+ elif not success:
+ log.warning(
+ f"{host} failed to provide file ({url}). "
+ f"Continuing based solely upon {primary_host}.")
+ else:
+ log.info(f"got file {url} as {fname}")
+ got_files.append(fname)
+
+ for i, got_file in enumerate(got_files):
+ if got_file == got_files[-1]:
+ break # break on last file, nothing after it to compare to
+
+ compare_to = got_files[i + 1]
+ if not files_are_equal(got_file, compare_to):
+ log.error(f"files not equal: {got_file} and {compare_to}")
+ return ReturnCode.FILES_NOT_EQUAL
+
+ return ReturnCode.SUCCESS
+
+
+def check_multisig(sums_file: str, sigfilename: str, args: argparse.Namespace) -> t.Tuple[int, str, t.List[SigData], t.List[SigData], t.List[SigData]]:
+ # check signature
+ #
+ # We don't write output to a file because this command will almost certainly
+ # fail with GPG exit code '2' (and so not writing to --output) because of the
+ # likely presence of multiple untrusted signatures.
+ retval, output = verify_with_gpg(sums_file, sigfilename)
+
+ if args.verbose:
+ log.info(f"gpg output:\n{indent(output)}")
+
+ good, unknown, bad = parse_gpg_result(output.splitlines())
+
+ if unknown and args.import_keys:
+ # Retrieve unknown keys and then try GPG again.
+ for unsig in unknown:
+ if prompt_yn(f" ? Retrieve key {unsig.key} ({unsig.name})? (y/N) "):
+ ran = subprocess.run(
+ ["gpg", "--keyserver", args.keyserver, "--recv-keys", unsig.key])
+
+ if ran.returncode != 0:
+ log.warning(f"failed to retrieve key {unsig.key}")
+
+ # Reparse the GPG output now that we have more keys
+ retval, output = verify_with_gpg(sums_file, sigfilename)
+ good, unknown, bad = parse_gpg_result(output.splitlines())
+
+ return retval, output, good, unknown, bad
+
+
+def prompt_yn(prompt) -> bool:
+ """Return true if the user inputs 'y'."""
+ got = ''
+ while got not in ['y', 'n']:
+ got = input(prompt).lower()
+ return got == 'y'
+
+def verify_shasums_signature(
+ signature_file_path: str, sums_file_path: str, args: argparse.Namespace
+) -> t.Tuple[
+ ReturnCode, t.List[SigData], t.List[SigData], t.List[SigData], t.List[SigData]
+]:
+ min_good_sigs = args.min_good_sigs
+ gpg_allowed_codes = [0, 2] # 2 is returned when untrusted signatures are present.
+
+ gpg_retval, gpg_output, good, unknown, bad = check_multisig(sums_file_path, signature_file_path, args)
+
+ if gpg_retval not in gpg_allowed_codes:
+ if gpg_retval == 1:
+ log.critical(f"Bad signature (code: {gpg_retval}).")
+ else:
+ log.critical(f"unexpected GPG exit code ({gpg_retval})")
+
+ log.error(f"gpg output:\n{indent(gpg_output)}")
+ return (ReturnCode.INTEGRITY_FAILURE, [], [], [], [])
+
+ # Decide which keys we trust, though not "trust" in the GPG sense, but rather
+ # which pubkeys convince us that this sums file is legitimate. In other words,
+ # which pubkeys within the Bitcoin community do we trust for the purposes of
+ # binary verification?
+ trusted_keys = set()
+ if args.trusted_keys:
+ trusted_keys |= set(args.trusted_keys.split(','))
+
+ # Tally signatures and make sure we have enough goods to fulfill
+ # our threshold.
+ good_trusted = [sig for sig in good if sig.trusted or sig.key in trusted_keys]
+ good_untrusted = [sig for sig in good if sig not in good_trusted]
+ num_trusted = len(good_trusted) + len(good_untrusted)
+ log.info(f"got {num_trusted} good signatures")
+
+ if num_trusted < min_good_sigs:
+ log.info("Maybe you need to import "
+ f"(`gpg --keyserver {args.keyserver} --recv-keys <key-id>`) "
+ "some of the following keys: ")
+ log.info('')
+ for sig in unknown:
+ log.info(f" {sig.key} ({sig.name})")
+ log.info('')
+ log.error(
+ "not enough trusted sigs to meet threshold "
+ f"({num_trusted} vs. {min_good_sigs})")
+
+ return (ReturnCode.NOT_ENOUGH_GOOD_SIGS, [], [], [], [])
+
+ for sig in good_trusted:
+ log.info(f"GOOD SIGNATURE: {sig}")
+
+ for sig in good_untrusted:
+ log.info(f"GOOD SIGNATURE (untrusted): {sig}")
+
+ for sig in [sig for sig in good if sig.status == 'expired']:
+ log.warning(f"key {sig.key} for {sig.name} is expired")
+
+ for sig in bad:
+ log.warning(f"BAD SIGNATURE: {sig}")
+
+ for sig in unknown:
+ log.warning(f"UNKNOWN SIGNATURE: {sig}")
+
+ return (ReturnCode.SUCCESS, good_trusted, good_untrusted, unknown, bad)
+
+
+def parse_sums_file(sums_file_path: str, filename_filter: t.List[str]) -> t.List[t.List[str]]:
+ # extract hashes/filenames of binaries to verify from hash file;
+ # each line has the following format: "<hash> <binary_filename>"
+ with open(sums_file_path, 'r', encoding='utf8') as hash_file:
+ return [line.split()[:2] for line in hash_file if len(filename_filter) == 0 or any(f in line for f in filename_filter)]
+
+
+def verify_binary_hashes(hashes_to_verify: t.List[t.List[str]]) -> t.Tuple[ReturnCode, t.Dict[str, str]]:
+ offending_files = []
+ files_to_hashes = {}
+
+ for hash_expected, binary_filename in hashes_to_verify:
+ with open(binary_filename, 'rb') as binary_file:
+ hash_calculated = sha256(binary_file.read()).hexdigest()
+ if hash_calculated != hash_expected:
+ offending_files.append(binary_filename)
+ else:
+ files_to_hashes[binary_filename] = hash_calculated
+
+ if offending_files:
+ joined_files = '\n'.join(offending_files)
+ log.critical(
+ "Hashes don't match.\n"
+ f"Offending files:\n{joined_files}")
+ return (ReturnCode.INTEGRITY_FAILURE, files_to_hashes)
+
+ return (ReturnCode.SUCCESS, files_to_hashes)
+
+
+def verify_published_handler(args: argparse.Namespace) -> ReturnCode:
+ WORKINGDIR = Path(tempfile.gettempdir()) / f"bitcoin_verify_binaries.{args.version}"
+
+ def cleanup():
+ log.info("cleaning up files")
+ os.chdir(Path.home())
+ shutil.rmtree(WORKINGDIR)
+
+ # determine remote dir dependent on provided version string
+ try:
+ version_base, version_rc, os_filter = parse_version_string(args.version)
+ version_tuple = [int(i) for i in version_base.split('.')]
+ except Exception as e:
+ log.debug(e)
+ log.error(f"unable to parse version; expected format is {VERSION_FORMAT}")
+ log.error(f" e.g. {VERSION_EXAMPLE}")
+ return ReturnCode.BAD_VERSION
+
+ remote_dir = f"/bin/{VERSIONPREFIX}{version_base}/"
+ if version_rc:
+ remote_dir += f"test.{version_rc}/"
+ remote_sigs_path = remote_dir + SIGNATUREFILENAME
+ remote_sums_path = remote_dir + SUMS_FILENAME
+
+ # create working directory
+ os.makedirs(WORKINGDIR, exist_ok=True)
+ os.chdir(WORKINGDIR)
+
+ hosts = [HOST1, HOST2]
+
+ got_sig_status = get_files_from_hosts_and_compare(
+ hosts, remote_sigs_path, SIGNATUREFILENAME, args.require_all_hosts)
+ if got_sig_status != ReturnCode.SUCCESS:
+ return got_sig_status
+
+ # Multi-sig verification is available after 22.0.
+ if version_tuple[0] < 22:
+ log.error("Version too old - single sig not supported. Use a previous "
+ "version of this script from the repo.")
+ return ReturnCode.BAD_VERSION
+
+ got_sums_status = get_files_from_hosts_and_compare(
+ hosts, remote_sums_path, SUMS_FILENAME, args.require_all_hosts)
+ if got_sums_status != ReturnCode.SUCCESS:
+ return got_sums_status
+
+ # Verify the signature on the SHA256SUMS file
+ sigs_status, good_trusted, good_untrusted, unknown, bad = verify_shasums_signature(SIGNATUREFILENAME, SUMS_FILENAME, args)
+ if sigs_status != ReturnCode.SUCCESS:
+ if sigs_status == ReturnCode.INTEGRITY_FAILURE:
+ cleanup()
+ return sigs_status
+
+ # Extract hashes and filenames
+ hashes_to_verify = parse_sums_file(SUMS_FILENAME, [os_filter])
+ if not hashes_to_verify:
+ log.error("no files matched the platform specified")
+ return ReturnCode.NO_BINARIES_MATCH
+
+ # remove binaries that are known not to be hosted by bitcoincore.org
+ fragments_to_remove = ['-unsigned', '-debug', '-codesignatures']
+ for fragment in fragments_to_remove:
+ nobinaries = [i for i in hashes_to_verify if fragment in i[1]]
+ if nobinaries:
+ remove_str = ', '.join(i[1] for i in nobinaries)
+ log.info(
+ f"removing *{fragment} binaries ({remove_str}) from verification "
+ f"since {HOST1} does not host *{fragment} binaries")
+ hashes_to_verify = [i for i in hashes_to_verify if fragment not in i[1]]
+
+ # download binaries
+ for _, binary_filename in hashes_to_verify:
+ log.info(f"downloading {binary_filename} to {WORKINGDIR}")
+ success, output = download_with_wget(
+ HOST1 + remote_dir + binary_filename, binary_filename)
+
+ if not success:
+ log.error(
+ f"failed to download {binary_filename}\n"
+ f"wget output:\n{indent(output)}")
+ return ReturnCode.BINARY_DOWNLOAD_FAILED
+
+ # verify hashes
+ hashes_status, files_to_hashes = verify_binary_hashes(hashes_to_verify)
+ if hashes_status != ReturnCode.SUCCESS:
+ return hashes_status
+
+
+ if args.cleanup:
+ cleanup()
+ else:
+ log.info(f"did not clean up {WORKINGDIR}")
+
+ if args.json:
+ output = {
+ 'good_trusted_sigs': [str(s) for s in good_trusted],
+ 'good_untrusted_sigs': [str(s) for s in good_untrusted],
+ 'unknown_sigs': [str(s) for s in unknown],
+ 'bad_sigs': [str(s) for s in bad],
+ 'verified_binaries': files_to_hashes,
+ }
+ print(json.dumps(output, indent=2))
+ else:
+ for filename in files_to_hashes:
+ print(f"VERIFIED: {filename}")
+
+ return ReturnCode.SUCCESS
+
+
+def verify_binaries_handler(args: argparse.Namespace) -> ReturnCode:
+ binary_to_basename = {}
+ for file in args.binary:
+ binary_to_basename[PurePath(file).name] = file
+
+ sums_sig_path = None
+ if args.sums_sig_file:
+ sums_sig_path = Path(args.sums_sig_file)
+ else:
+ log.info(f"No signature file specified, assuming it is {args.sums_file}.asc")
+ sums_sig_path = Path(args.sums_file).with_suffix(".asc")
+
+ # Verify the signature on the SHA256SUMS file
+ sigs_status, good_trusted, good_untrusted, unknown, bad = verify_shasums_signature(str(sums_sig_path), args.sums_file, args)
+ if sigs_status != ReturnCode.SUCCESS:
+ return sigs_status
+
+ # Extract hashes and filenames
+ hashes_to_verify = parse_sums_file(args.sums_file, [k for k, n in binary_to_basename.items()])
+ if not hashes_to_verify:
+ log.error(f"No files in {args.sums_file} match the specified binaries")
+ return ReturnCode.NO_BINARIES_MATCH
+
+ # Make sure all files are accounted for
+ sums_file_path = Path(args.sums_file)
+ missing_files = []
+ files_to_hash = []
+ if len(binary_to_basename) > 0:
+ for file_hash, file in hashes_to_verify:
+ files_to_hash.append([file_hash, binary_to_basename[file]])
+ del binary_to_basename[file]
+ if len(binary_to_basename) > 0:
+ log.error(f"Not all specified binaries are in {args.sums_file}")
+ return ReturnCode.NO_BINARIES_MATCH
+ else:
+ log.info(f"No binaries specified, assuming all files specified in {args.sums_file} are located relatively")
+ for file_hash, file in hashes_to_verify:
+ file_path = Path(sums_file_path.parent.joinpath(file))
+ if file_path.exists():
+ files_to_hash.append([file_hash, str(file_path)])
+ else:
+ missing_files.append(file)
+
+ # verify hashes
+ hashes_status, files_to_hashes = verify_binary_hashes(files_to_hash)
+ if hashes_status != ReturnCode.SUCCESS:
+ return hashes_status
+
+ if args.json:
+ output = {
+ 'good_trusted_sigs': [str(s) for s in good_trusted],
+ 'good_untrusted_sigs': [str(s) for s in good_untrusted],
+ 'unknown_sigs': [str(s) for s in unknown],
+ 'bad_sigs': [str(s) for s in bad],
+ 'verified_binaries': files_to_hashes,
+ "missing_binaries": missing_files,
+ }
+ print(json.dumps(output, indent=2))
+ else:
+ for filename in files_to_hashes:
+ print(f"VERIFIED: {filename}")
+ for filename in missing_files:
+ print(f"MISSING: {filename}")
+
+ return ReturnCode.SUCCESS
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '-v', '--verbose', action='store_true',
+ default=bool_from_env('BINVERIFY_VERBOSE'),
+ )
+ parser.add_argument(
+ '-q', '--quiet', action='store_true',
+ default=bool_from_env('BINVERIFY_QUIET'),
+ )
+ parser.add_argument(
+ '--import-keys', action='store_true',
+ default=bool_from_env('BINVERIFY_IMPORTKEYS'),
+ help='if specified, ask to import each unknown builder key'
+ )
+ parser.add_argument(
+ '--min-good-sigs', type=int, action='store', nargs='?',
+ default=int(os.environ.get('BINVERIFY_MIN_GOOD_SIGS', 3)),
+ help=(
+ 'The minimum number of good signatures to require successful termination.'),
+ )
+ parser.add_argument(
+ '--keyserver', action='store', nargs='?',
+ default=os.environ.get('BINVERIFY_KEYSERVER', 'hkps://keys.openpgp.org'),
+ help='which keyserver to use',
+ )
+ parser.add_argument(
+ '--trusted-keys', action='store', nargs='?',
+ default=os.environ.get('BINVERIFY_TRUSTED_KEYS', ''),
+ help='A list of trusted signer GPG keys, separated by commas. Not "trusted keys" in the GPG sense.',
+ )
+ parser.add_argument(
+ '--json', action='store_true',
+ default=bool_from_env('BINVERIFY_JSON'),
+ help='If set, output the result as JSON',
+ )
+
+ subparsers = parser.add_subparsers(title="Commands", required=True, dest="command")
+
+ pub_parser = subparsers.add_parser("pub", help="Verify a published release.")
+ pub_parser.set_defaults(func=verify_published_handler)
+ pub_parser.add_argument(
+ 'version', type=str, help=(
+ f'version of the bitcoin release to download; of the format '
+ f'{VERSION_FORMAT}. Example: {VERSION_EXAMPLE}')
+ )
+ pub_parser.add_argument(
+ '--cleanup', action='store_true',
+ default=bool_from_env('BINVERIFY_CLEANUP'),
+ help='if specified, clean up files afterwards'
+ )
+ pub_parser.add_argument(
+ '--require-all-hosts', action='store_true',
+ default=bool_from_env('BINVERIFY_REQUIRE_ALL_HOSTS'),
+ help=(
+ f'If set, require all hosts ({HOST1}, {HOST2}) to provide signatures. '
+ '(Sometimes bitcoin.org lags behind bitcoincore.org.)')
+ )
+
+ bin_parser = subparsers.add_parser("bin", help="Verify local binaries.")
+ bin_parser.set_defaults(func=verify_binaries_handler)
+ bin_parser.add_argument("--sums-sig-file", "-s", help="Path to the SHA256SUMS.asc file to verify")
+ bin_parser.add_argument("sums_file", help="Path to the SHA256SUMS file to verify")
+ bin_parser.add_argument(
+ "binary", nargs="*",
+ help="Path to a binary distribution file to verify. Can be specified multiple times for multiple files to verify."
+ )
+
+ args = parser.parse_args()
+ if args.quiet:
+ log.setLevel(logging.WARNING)
+
+ return args.func(args)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 94daf28b15..f25486776f 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -2,3 +2,4 @@ E777299FC265DD04793070EB944D35F9AC3DB76A
D1DBF2C4B96F2DEBF4C16654410108112E7EA81F
152812300785C96444D3334D17565732E08E5E41
6B002C6EA3F91B1B0DF0C9BC8F617F1200A6D25C
+4D1B3D5ECBA1A7E05371EEBE46800E30FC748A66
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index f301964280..a1fe78a643 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -178,7 +178,20 @@ def main():
allow_unclean = current_commit in unclean_merge_allowed
if len(parents) == 2 and check_merge and not allow_unclean:
current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit]).decode('utf8').splitlines()[0]
- recreated_tree = subprocess.check_output([GIT, "merge-tree", parents[0], parents[1]]).decode('utf8').splitlines()[0]
+
+ # This merge-tree functionality requires git >= 2.38. The
+ # --write-tree option was added in order to opt-in to the new
+ # behavior. Older versions of git will not recognize the option and
+ # will instead exit with code 128.
+ try:
+ recreated_tree = subprocess.check_output([GIT, "merge-tree", "--write-tree", parents[0], parents[1]]).decode('utf8').splitlines()[0]
+ except subprocess.CalledProcessError as e:
+ if e.returncode == 128:
+ print("git v2.38+ is required for this functionality.", file=sys.stderr)
+ sys.exit(1)
+ else:
+ raise e
+
if current_tree != recreated_tree:
print("Merge commit {} is not clean".format(current_commit), file=sys.stderr)
subprocess.call([GIT, 'diff', recreated_tree, current_tree])
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
deleted file mode 100644
index ab831eea28..0000000000
--- a/contrib/verifybinaries/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-### Verify Binaries
-
-#### Usage:
-
-This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
-
-It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file.
-
-The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
-
-
-```sh
-./verify.py bitcoin-core-0.11.2
-./verify.py bitcoin-core-0.12.0
-./verify.py bitcoin-core-0.13.0-rc3
-```
-
-If you only want to download the binaries of certain platform, add the corresponding suffix, e.g.:
-
-```sh
-./verify.py bitcoin-core-0.11.2-osx
-./verify.py 0.12.0-linux
-./verify.py bitcoin-core-0.13.0-rc3-win64
-```
-
-If you do not want to keep the downloaded binaries, specify anything as the second parameter.
-
-```sh
-./verify.py bitcoin-core-0.13.0 delete
-```
diff --git a/contrib/verifybinaries/verify.py b/contrib/verifybinaries/verify.py
deleted file mode 100755
index b5e4f1318b..0000000000
--- a/contrib/verifybinaries/verify.py
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env python3
-# 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.
-"""Script for verifying Bitcoin Core release binaries
-
-This script attempts to download the signature file SHA256SUMS.asc from
-bitcoincore.org and bitcoin.org and compares them.
-It first checks if the signature passes, and then downloads the files
-specified in the file, and checks if the hashes of these files match those
-that are specified in the signature file.
-The script returns 0 if everything passes the checks. It returns 1 if either
-the signature check or the hash check doesn't pass. If an error occurs the
-return value is >= 2.
-"""
-from hashlib import sha256
-import os
-import subprocess
-import sys
-from textwrap import indent
-
-WORKINGDIR = "/tmp/bitcoin_verify_binaries"
-HASHFILE = "hashes.tmp"
-HOST1 = "https://bitcoincore.org"
-HOST2 = "https://bitcoin.org"
-VERSIONPREFIX = "bitcoin-core-"
-SIGNATUREFILENAME = "SHA256SUMS.asc"
-
-
-def parse_version_string(version_str):
- if version_str.startswith(VERSIONPREFIX): # remove version prefix
- version_str = version_str[len(VERSIONPREFIX):]
-
- parts = version_str.split('-')
- version_base = parts[0]
- version_rc = ""
- version_os = ""
- if len(parts) == 2: # "<version>-rcN" or "version-platform"
- if "rc" in parts[1]:
- version_rc = parts[1]
- else:
- version_os = parts[1]
- elif len(parts) == 3: # "<version>-rcN-platform"
- version_rc = parts[1]
- version_os = parts[2]
-
- return version_base, version_rc, version_os
-
-
-def download_with_wget(remote_file, local_file=None):
- if local_file:
- wget_args = ['wget', '-O', local_file, remote_file]
- else:
- # use timestamping mechanism if local filename is not explicitly set
- wget_args = ['wget', '-N', remote_file]
-
- result = subprocess.run(wget_args,
- stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
- return result.returncode == 0, result.stdout.decode().rstrip()
-
-
-def files_are_equal(filename1, filename2):
- with open(filename1, 'rb') as file1:
- contents1 = file1.read()
- with open(filename2, 'rb') as file2:
- contents2 = file2.read()
- return contents1 == contents2
-
-
-def verify_with_gpg(signature_filename, output_filename):
- result = subprocess.run(['gpg', '--yes', '--decrypt', '--output',
- output_filename, signature_filename],
- stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
- return result.returncode, result.stdout.decode().rstrip()
-
-
-def remove_files(filenames):
- for filename in filenames:
- os.remove(filename)
-
-
-def main(args):
- # sanity check
- if len(args) < 1:
- print("Error: need to specify a version on the command line")
- return 3
-
- # determine remote dir dependent on provided version string
- version_base, version_rc, os_filter = parse_version_string(args[0])
- remote_dir = f"/bin/{VERSIONPREFIX}{version_base}/"
- if version_rc:
- remote_dir += f"test.{version_rc}/"
- remote_sigfile = remote_dir + SIGNATUREFILENAME
-
- # create working directory
- os.makedirs(WORKINGDIR, exist_ok=True)
- os.chdir(WORKINGDIR)
-
- # fetch first signature file
- sigfile1 = SIGNATUREFILENAME
- success, output = download_with_wget(HOST1 + remote_sigfile, sigfile1)
- if not success:
- print("Error: couldn't fetch signature file. "
- "Have you specified the version number in the following format?")
- print(f"[{VERSIONPREFIX}]<version>[-rc[0-9]][-platform] "
- f"(example: {VERSIONPREFIX}0.21.0-rc3-osx)")
- print("wget output:")
- print(indent(output, '\t'))
- return 4
-
- # fetch second signature file
- sigfile2 = SIGNATUREFILENAME + ".2"
- success, output = download_with_wget(HOST2 + remote_sigfile, sigfile2)
- if not success:
- print("bitcoin.org failed to provide signature file, "
- "but bitcoincore.org did?")
- print("wget output:")
- print(indent(output, '\t'))
- remove_files([sigfile1])
- return 5
-
- # ensure that both signature files are equal
- if not files_are_equal(sigfile1, sigfile2):
- print("bitcoin.org and bitcoincore.org signature files were not equal?")
- print(f"See files {WORKINGDIR}/{sigfile1} and {WORKINGDIR}/{sigfile2}")
- return 6
-
- # check signature and extract data into file
- retval, output = verify_with_gpg(sigfile1, HASHFILE)
- if retval != 0:
- if retval == 1:
- print("Bad signature.")
- elif retval == 2:
- print("gpg error. Do you have the Bitcoin Core binary release "
- "signing key installed?")
- print("gpg output:")
- print(indent(output, '\t'))
- remove_files([sigfile1, sigfile2, HASHFILE])
- return 1
-
- # extract hashes/filenames of binaries to verify from hash file;
- # each line has the following format: "<hash> <binary_filename>"
- with open(HASHFILE, 'r', encoding='utf8') as hash_file:
- hashes_to_verify = [
- line.split()[:2] for line in hash_file if os_filter in line]
- remove_files([HASHFILE])
- if not hashes_to_verify:
- print("error: no files matched the platform specified")
- return 7
-
- # download binaries
- for _, binary_filename in hashes_to_verify:
- print(f"Downloading {binary_filename}")
- download_with_wget(HOST1 + remote_dir + binary_filename)
-
- # verify hashes
- offending_files = []
- for hash_expected, binary_filename in hashes_to_verify:
- with open(binary_filename, 'rb') as binary_file:
- hash_calculated = sha256(binary_file.read()).hexdigest()
- if hash_calculated != hash_expected:
- offending_files.append(binary_filename)
- if offending_files:
- print("Hashes don't match.")
- print("Offending files:")
- print('\n'.join(offending_files))
- return 1
- verified_binaries = [entry[1] for entry in hashes_to_verify]
-
- # clean up files if desired
- if len(args) >= 2:
- print("Clean up the binaries")
- remove_files([sigfile1, sigfile2] + verified_binaries)
- else:
- print(f"Keep the binaries in {WORKINGDIR}")
-
- print("Verified hashes of")
- print('\n'.join(verified_binaries))
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/depends/Makefile b/depends/Makefile
index 27bf804c6b..3169117633 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -45,6 +45,7 @@ NO_USDT ?=
NO_NATPMP ?=
MULTIPROCESS ?=
LTO ?=
+NO_HARDEN ?=
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
C_STANDARD ?= c11
@@ -146,8 +147,8 @@ include packages/packages.mk
# 2. Before including packages/*.mk (excluding packages/packages.mk), since
# they rely on the build_id variables
#
-build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
-$(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(host_AR)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
+build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
+$(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(host_AR)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
boost_packages_$(NO_BOOST) = $(boost_packages)
@@ -253,6 +254,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@no_natpmp@|$(NO_NATPMP)|' \
-e 's|@multiprocess@|$(MULTIPROCESS)|' \
-e 's|@lto@|$(LTO)|' \
+ -e 's|@no_harden@|$(NO_HARDEN)|' \
-e 's|@debug@|$(DEBUG)|' \
$< > $@
touch $@
diff --git a/depends/README.md b/depends/README.md
index 11abbbd90d..8bf751ab30 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -15,6 +15,7 @@ For example:
**Bitcoin Core's `configure` script by default will ignore the depends output.** In
order for it to pick up libraries, tools, and settings from the depends build,
you must set the `CONFIG_SITE` environment variable to point to a `config.site` settings file.
+Make sure that `CONFIG_SITE` is an absolute path.
In the above example, a file named `depends/x86_64-w64-mingw32/share/config.site` will be
created. To use it during compilation:
@@ -107,7 +108,8 @@ The following can be set when running make: `make FOO=bar`
- `NO_BDB`: Don't download/build/cache BerkeleyDB
- `NO_SQLITE`: Don't download/build/cache SQLite
- `NO_UPNP`: Don't download/build/cache packages needed for enabling UPnP
-- `NO_NATPMP`: Don't download/build/cache packages needed for enabling NAT-PMP</dd>
+- `NO_NATPMP`: Don't download/build/cache packages needed for enabling NAT-PMP
+- `NO_USDT`: Don't download/build/cache packages needed for enabling USDT tracepoints
- `ALLOW_HOST_PACKAGES`: Packages that are missed in dependencies (due to `NO_*` option or
build script logic) are searched for among the host system packages using
`pkg-config`. It allows building with packages of other (newer) versions
@@ -122,6 +124,7 @@ The following can be set when running make: `make FOO=bar`
resides in the `depends` directory, and the log file is printed out automatically in case
of build error. After successful build log files are moved along with package archives
- `LTO`: Use LTO when building packages.
+- `NO_HARDEN=1`: Don't use hardening options when building packages
If some packages are not built, for example `make NO_WALLET=1`, the appropriate
options will be passed to bitcoin's configure. In this case, `--disable-wallet`.
diff --git a/depends/config.guess b/depends/config.guess
index dc0a6b2997..69188da73d 100755
--- a/depends/config.guess
+++ b/depends/config.guess
@@ -1,12 +1,14 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2021 Free Software Foundation, Inc.
+# Copyright 1992-2023 Free Software Foundation, Inc.
-timestamp='2021-05-24'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2023-01-01'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -32,7 +34,15 @@ timestamp='2021-05-24'
# Please send patches to <config-patches@gnu.org>.
-me=$(echo "$0" | sed -e 's,.*/,,')
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
@@ -50,7 +60,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -84,6 +94,9 @@ if test $# != 0; then
exit 1
fi
+# Just in case it came from the environment.
+GUESS=
+
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
@@ -102,8 +115,8 @@ set_cc_for_build() {
# prevent multiple calls if $tmp is already set
test "$tmp" && return 0
: "${TMPDIR=/tmp}"
- # shellcheck disable=SC2039
- { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test -n "$tmp" && test -d "$tmp" ; } ||
+ # shellcheck disable=SC2039,SC3028
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
@@ -112,7 +125,7 @@ set_cc_for_build() {
,,) echo "int x;" > "$dummy.c"
for driver in cc gcc c89 c99 ; do
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$driver"
+ CC_FOR_BUILD=$driver
break
fi
done
@@ -131,10 +144,10 @@ if test -f /.attbin/uname ; then
PATH=$PATH:/.attbin ; export PATH
fi
-UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
-UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
-UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
-UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case $UNAME_SYSTEM in
Linux|GNU|GNU/*)
@@ -157,7 +170,8 @@ Linux|GNU|GNU/*)
#endif
#endif
EOF
- eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')"
+ cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ eval "$cc_set_libc"
# Second heuristic to detect musl libc.
if [ "$LIBC" = unknown ] &&
@@ -188,10 +202,10 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
#
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
- UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
/usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
- echo unknown))
+ echo unknown)`
case $UNAME_MACHINE_ARCH in
aarch64eb) machine=aarch64_be-unknown ;;
armeb) machine=armeb-unknown ;;
@@ -200,11 +214,11 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
earmv*)
- arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,')
- endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p')
- machine="${arch}${endian}"-unknown
+ arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine=${arch}${endian}-unknown
;;
- *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ *) machine=$UNAME_MACHINE_ARCH-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently (or will in the future) and ABI.
@@ -232,7 +246,7 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
case $UNAME_MACHINE_ARCH in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
- abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
+ abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
;;
esac
# The OS release
@@ -245,76 +259,76 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
release='-gnu'
;;
*)
- release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2)
+ release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "$machine-${os}${release}${abi-}"
- exit ;;
+ GUESS=$machine-${os}${release}${abi-}
+ ;;
*:Bitrig:*:*)
- UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
- echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
- exit ;;
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+ ;;
*:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
- echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
- exit ;;
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+ ;;
*:SecBSD:*:*)
- UNAME_MACHINE_ARCH=$(arch | sed 's/SecBSD.//')
- echo "$UNAME_MACHINE_ARCH"-unknown-secbsd"$UNAME_RELEASE"
- exit ;;
+ UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+ ;;
*:LibertyBSD:*:*)
- UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
- echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
- exit ;;
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+ ;;
*:MidnightBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+ ;;
*:ekkoBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+ ;;
*:SolidBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+ ;;
*:OS108:*:*)
- echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+ ;;
macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+ ;;
*:MirBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+ ;;
*:Sortix:*:*)
- echo "$UNAME_MACHINE"-unknown-sortix
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-sortix
+ ;;
*:Twizzler:*:*)
- echo "$UNAME_MACHINE"-unknown-twizzler
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-twizzler
+ ;;
*:Redox:*:*)
- echo "$UNAME_MACHINE"-unknown-redox
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-redox
+ ;;
mips:OSF1:*.*)
- echo mips-dec-osf1
- exit ;;
+ GUESS=mips-dec-osf1
+ ;;
alpha:OSF1:*:*)
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
trap '' 0
case $UNAME_RELEASE in
*4.0)
- UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
;;
*5.*)
- UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
# OSF/1 and Tru64 systems produced since 1995. I hope that
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
- ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1)
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case $ALPHA_CPU_TYPE in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
@@ -352,65 +366,69 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
- exit ;;
+ OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+ ;;
Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit ;;
+ GUESS=m68k-unknown-sysv4
+ ;;
*:[Aa]miga[Oo][Ss]:*:*)
- echo "$UNAME_MACHINE"-unknown-amigaos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-amigaos
+ ;;
*:[Mm]orph[Oo][Ss]:*:*)
- echo "$UNAME_MACHINE"-unknown-morphos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-morphos
+ ;;
*:OS/390:*:*)
- echo i370-ibm-openedition
- exit ;;
+ GUESS=i370-ibm-openedition
+ ;;
*:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
+ GUESS=s390-ibm-zvmoe
+ ;;
*:OS400:*:*)
- echo powerpc-ibm-os400
- exit ;;
+ GUESS=powerpc-ibm-os400
+ ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix"$UNAME_RELEASE"
- exit ;;
+ GUESS=arm-acorn-riscix$UNAME_RELEASE
+ ;;
arm*:riscos:*:*|arm*:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
+ GUESS=arm-unknown-riscos
+ ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit ;;
+ GUESS=hppa1.1-hitachi-hiuxmpp
+ ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "$( (/bin/universe) 2>/dev/null)" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit ;;
+ case `(/bin/universe) 2>/dev/null` in
+ att) GUESS=pyramid-pyramid-sysv3 ;;
+ *) GUESS=pyramid-pyramid-bsd ;;
+ esac
+ ;;
NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit ;;
+ GUESS=pyramid-pyramid-svr4
+ ;;
DRS?6000:unix:4.0:6*)
- echo sparc-icl-nx6
- exit ;;
+ GUESS=sparc-icl-nx6
+ ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
- case $(/usr/bin/uname -p) in
- sparc) echo sparc-icl-nx7; exit ;;
- esac ;;
+ case `/usr/bin/uname -p` in
+ sparc) GUESS=sparc-icl-nx7 ;;
+ esac
+ ;;
s390x:SunOS:*:*)
- echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+ ;;
sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-hal-solaris2$SUN_REL
+ ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris2$SUN_REL
+ ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
- echo i386-pc-auroraux"$UNAME_RELEASE"
- exit ;;
+ GUESS=i386-pc-auroraux$UNAME_RELEASE
+ ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
set_cc_for_build
SUN_ARCH=i386
@@ -419,47 +437,50 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
# This test works for both compilers.
if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH=x86_64
fi
fi
- echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+ ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris3$SUN_REL
+ ;;
sun4*:SunOS:*:*)
- case $(/usr/bin/arch -k) in
+ case `/usr/bin/arch -k` in
Series*|S4*)
- UNAME_RELEASE=$(uname -v)
+ UNAME_RELEASE=`uname -v`
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+ GUESS=sparc-sun-sunos$SUN_REL
+ ;;
sun3*:SunOS:*:*)
- echo m68k-sun-sunos"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
+ ;;
sun*:*:4.2BSD:*)
- UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
- case $(/bin/arch) in
+ case `/bin/arch` in
sun3)
- echo m68k-sun-sunos"$UNAME_RELEASE"
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
;;
sun4)
- echo sparc-sun-sunos"$UNAME_RELEASE"
+ GUESS=sparc-sun-sunos$UNAME_RELEASE
;;
esac
- exit ;;
+ ;;
aushp:SunOS:*:*)
- echo sparc-auspex-sunos"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-auspex-sunos$UNAME_RELEASE
+ ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
@@ -469,41 +490,41 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-milan-mint$UNAME_RELEASE
+ ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-hades-mint$UNAME_RELEASE
+ ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-unknown-mint$UNAME_RELEASE
+ ;;
m68k:machten:*:*)
- echo m68k-apple-machten"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-apple-machten$UNAME_RELEASE
+ ;;
powerpc:machten:*:*)
- echo powerpc-apple-machten"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-apple-machten$UNAME_RELEASE
+ ;;
RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit ;;
+ GUESS=mips-dec-mach_bsd4.3
+ ;;
RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-dec-ultrix$UNAME_RELEASE
+ ;;
VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix"$UNAME_RELEASE"
- exit ;;
+ GUESS=vax-dec-ultrix$UNAME_RELEASE
+ ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix"$UNAME_RELEASE"
- exit ;;
+ GUESS=clipper-intergraph-clix$UNAME_RELEASE
+ ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
@@ -528,78 +549,79 @@ case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
}
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
- dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
- SYSTEM_NAME=$("$dummy" "$dummyarg") &&
+ dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-mips-riscos$UNAME_RELEASE
+ ;;
Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit ;;
+ GUESS=powerpc-motorola-powermax
+ ;;
Motorola:*:4.3:PL8-*)
- echo powerpc-harris-powermax
- exit ;;
+ GUESS=powerpc-harris-powermax
+ ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
- echo powerpc-harris-powermax
- exit ;;
+ GUESS=powerpc-harris-powermax
+ ;;
Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit ;;
+ GUESS=powerpc-harris-powerunix
+ ;;
m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit ;;
+ GUESS=m88k-harris-cxux7
+ ;;
m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit ;;
+ GUESS=m88k-motorola-sysv4
+ ;;
m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit ;;
+ GUESS=m88k-motorola-sysv3
+ ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=$(/usr/bin/uname -p)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
then
if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
test "$TARGET_BINARY_INTERFACE"x = x
then
- echo m88k-dg-dgux"$UNAME_RELEASE"
+ GUESS=m88k-dg-dgux$UNAME_RELEASE
else
- echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
fi
else
- echo i586-dg-dgux"$UNAME_RELEASE"
+ GUESS=i586-dg-dgux$UNAME_RELEASE
fi
- exit ;;
+ ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit ;;
+ GUESS=m88k-dolphin-sysv3
+ ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit ;;
+ GUESS=m88k-motorola-sysv3
+ ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit ;;
+ GUESS=m88k-tektronix-sysv3
+ ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit ;;
+ GUESS=m68k-tektronix-bsd
+ ;;
*:IRIX*:*:*)
- echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
- exit ;;
+ IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+ GUESS=mips-sgi-irix$IRIX_REL
+ ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX '
+ GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
- echo i386-ibm-aix
- exit ;;
+ GUESS=i386-ibm-aix
+ ;;
ia64:AIX:*:*)
if test -x /usr/bin/oslevel ; then
- IBM_REV=$(/usr/bin/oslevel)
+ IBM_REV=`/usr/bin/oslevel`
else
- IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
fi
- echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
- exit ;;
+ GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+ ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
set_cc_for_build
@@ -614,63 +636,63 @@ EOF
exit(0);
}
EOF
- if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy")
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
then
- echo "$SYSTEM_NAME"
+ GUESS=$SYSTEM_NAME
else
- echo rs6000-ibm-aix3.2.5
+ GUESS=rs6000-ibm-aix3.2.5
fi
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
+ GUESS=rs6000-ibm-aix3.2.4
else
- echo rs6000-ibm-aix3.2
+ GUESS=rs6000-ibm-aix3.2
fi
- exit ;;
+ ;;
*:AIX:*:[4567])
- IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }')
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
if test -x /usr/bin/lslpp ; then
- IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
- awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
else
- IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
fi
- echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
- exit ;;
+ GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+ ;;
*:AIX:*:*)
- echo rs6000-ibm-aix
- exit ;;
+ GUESS=rs6000-ibm-aix
+ ;;
ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
- echo romp-ibm-bsd4.4
- exit ;;
+ GUESS=romp-ibm-bsd4.4
+ ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
+ GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to
+ ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
- echo rs6000-bull-bosx
- exit ;;
+ GUESS=rs6000-bull-bosx
+ ;;
DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit ;;
+ GUESS=m68k-bull-sysv3
+ ;;
9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit ;;
+ GUESS=m68k-hp-bsd
+ ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit ;;
+ GUESS=m68k-hp-bsd4.4
+ ;;
9000/[34678]??:HP-UX:*:*)
- HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
case $UNAME_MACHINE in
9000/31?) HP_ARCH=m68000 ;;
9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
if test -x /usr/bin/getconf; then
- sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 2>/dev/null)
- sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null)
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case $sc_cpu_version in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
@@ -717,7 +739,7 @@ EOF
exit (0);
}
EOF
- (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=$("$dummy")
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
@@ -742,12 +764,12 @@ EOF
HP_ARCH=hppa64
fi
fi
- echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
- exit ;;
+ GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+ ;;
ia64:HP-UX:*:*)
- HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
- echo ia64-hp-hpux"$HPUX_REV"
- exit ;;
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ GUESS=ia64-hp-hpux$HPUX_REV
+ ;;
3050*:HI-UX:*:*)
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
@@ -775,38 +797,38 @@ EOF
exit (0);
}
EOF
- $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo unknown-hitachi-hiuxwe2
- exit ;;
+ GUESS=unknown-hitachi-hiuxwe2
+ ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
- echo hppa1.1-hp-bsd
- exit ;;
+ GUESS=hppa1.1-hp-bsd
+ ;;
9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit ;;
+ GUESS=hppa1.0-hp-bsd
+ ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit ;;
+ GUESS=hppa1.0-hp-mpeix
+ ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
- echo hppa1.1-hp-osf
- exit ;;
+ GUESS=hppa1.1-hp-osf
+ ;;
hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit ;;
+ GUESS=hppa1.0-hp-osf
+ ;;
i*86:OSF1:*:*)
if test -x /usr/sbin/sysversion ; then
- echo "$UNAME_MACHINE"-unknown-osf1mk
+ GUESS=$UNAME_MACHINE-unknown-osf1mk
else
- echo "$UNAME_MACHINE"-unknown-osf1
+ GUESS=$UNAME_MACHINE-unknown-osf1
fi
- exit ;;
+ ;;
parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit ;;
+ GUESS=hppa1.1-hp-lites
+ ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit ;;
+ GUESS=c1-convex-bsd
+ ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
@@ -814,17 +836,18 @@ EOF
fi
exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit ;;
+ GUESS=c34-convex-bsd
+ ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit ;;
+ GUESS=c38-convex-bsd
+ ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit ;;
+ GUESS=c4-convex-bsd
+ ;;
CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=ymp-cray-unicos$CRAY_REL
+ ;;
CRAY*[A-Z]90:*:*:*)
echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
@@ -832,114 +855,135 @@ EOF
-e 's/\.[^.]*$/.X/'
exit ;;
CRAY*TS:*:*:*)
- echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=t90-cray-unicos$CRAY_REL
+ ;;
CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=alphaev5-cray-unicosmk$CRAY_REL
+ ;;
CRAY*SV1:*:*:*)
- echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=sv1-cray-unicos$CRAY_REL
+ ;;
*:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=craynv-cray-unicosmp$CRAY_REL
+ ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
- FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
- FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
- FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+ ;;
sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+ ;;
*:BSD/OS:*:*)
- echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+ ;;
arm:FreeBSD:*:*)
- UNAME_PROCESSOR=$(uname -p)
+ UNAME_PROCESSOR=`uname -p`
set_cc_for_build
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
else
- echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
fi
- exit ;;
+ ;;
*:FreeBSD:*:*)
- UNAME_PROCESSOR=$(/usr/bin/uname -p)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
case $UNAME_PROCESSOR in
amd64)
UNAME_PROCESSOR=x86_64 ;;
i386)
UNAME_PROCESSOR=i586 ;;
esac
- echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
- exit ;;
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+ ;;
i*:CYGWIN*:*)
- echo "$UNAME_MACHINE"-pc-cygwin
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-cygwin
+ ;;
*:MINGW64*:*)
- echo "$UNAME_MACHINE"-pc-mingw64
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-mingw64
+ ;;
*:MINGW*:*)
- echo "$UNAME_MACHINE"-pc-mingw32
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-mingw32
+ ;;
*:MSYS*:*)
- echo "$UNAME_MACHINE"-pc-msys
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-msys
+ ;;
i*:PW*:*)
- echo "$UNAME_MACHINE"-pc-pw32
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-pw32
+ ;;
+ *:SerenityOS:*:*)
+ GUESS=$UNAME_MACHINE-pc-serenity
+ ;;
*:Interix*:*)
case $UNAME_MACHINE in
x86)
- echo i586-pc-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=i586-pc-interix$UNAME_RELEASE
+ ;;
authenticamd | genuineintel | EM64T)
- echo x86_64-unknown-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=x86_64-unknown-interix$UNAME_RELEASE
+ ;;
IA64)
- echo ia64-unknown-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=ia64-unknown-interix$UNAME_RELEASE
+ ;;
esac ;;
i*:UWIN*:*)
- echo "$UNAME_MACHINE"-pc-uwin
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-uwin
+ ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-pc-cygwin
- exit ;;
+ GUESS=x86_64-pc-cygwin
+ ;;
prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=powerpcle-unknown-solaris2$SUN_REL
+ ;;
*:GNU:*:*)
# the GNU system
- echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')"
- exit ;;
+ GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+ GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+ ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
- exit ;;
+ GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+ ;;
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+ ;;
+ *:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+ ;;
*:Minix:*:*)
- echo "$UNAME_MACHINE"-unknown-minix
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-minix
+ ;;
aarch64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
alpha:Linux:*:*)
- case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null) in
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -950,63 +994,63 @@ EOF
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
- arc:Linux:*:* | arceb:Linux:*:* | arc64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
arm*:Linux:*:*)
set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
else
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
fi
fi
- exit ;;
+ ;;
avr32*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
cris:Linux:*:*)
- echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
crisv32:Linux:*:*)
- echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
e2k:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
frv:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
hexagon:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
i*86:Linux:*:*)
- echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+ ;;
ia64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
k1om:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
- loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
m32r*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
m68*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
mips:Linux:*:* | mips64:Linux:*:*)
set_cc_for_build
IS_GLIBC=0
@@ -1051,138 +1095,150 @@ EOF
#endif
#endif
EOF
- eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
+ cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+ eval "$cc_set_vars"
test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
mips64el:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
openrisc*:Linux:*:*)
- echo or1k-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=or1k-unknown-linux-$LIBC
+ ;;
or32:Linux:*:* | or1k*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
padre:Linux:*:*)
- echo sparc-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=sparc-unknown-linux-$LIBC
+ ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=hppa64-unknown-linux-$LIBC
+ ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
- case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
- PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
- PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
- *) echo hppa-unknown-linux-"$LIBC" ;;
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+ PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+ *) GUESS=hppa-unknown-linux-$LIBC ;;
esac
- exit ;;
+ ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc64-unknown-linux-$LIBC
+ ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc-unknown-linux-$LIBC
+ ;;
ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc64le-unknown-linux-$LIBC
+ ;;
ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpcle-unknown-linux-$LIBC
+ ;;
riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
s390:Linux:*:* | s390x:Linux:*:*)
- echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+ ;;
sh64*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
sh*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
tile*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
vax:Linux:*:*)
- echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+ ;;
x86_64:Linux:*:*)
set_cc_for_build
+ CPU=$UNAME_MACHINE
LIBCABI=$LIBC
if test "$CC_FOR_BUILD" != no_compiler_found; then
- if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_X32 >/dev/null
- then
- LIBCABI="$LIBC"x32
- fi
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __i386__
+ ABI=x86
+ #else
+ #ifdef __ILP32__
+ ABI=x32
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ x86) CPU=i686 ;;
+ x32) LIBCABI=${LIBC}x32 ;;
+ esac
fi
- echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
- exit ;;
+ GUESS=$CPU-pc-linux-$LIBCABI
+ ;;
xtensa*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
- echo i386-sequent-sysv4
- exit ;;
+ GUESS=i386-sequent-sysv4
+ ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
- echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+ ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
- echo "$UNAME_MACHINE"-pc-os2-emx
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-os2-emx
+ ;;
i*86:XTS-300:*:STOP)
- echo "$UNAME_MACHINE"-unknown-stop
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-stop
+ ;;
i*86:atheos:*:*)
- echo "$UNAME_MACHINE"-unknown-atheos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-atheos
+ ;;
i*86:syllable:*:*)
- echo "$UNAME_MACHINE"-pc-syllable
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-syllable
+ ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
- echo i386-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=i386-unknown-lynxos$UNAME_RELEASE
+ ;;
i*86:*DOS:*:*)
- echo "$UNAME_MACHINE"-pc-msdosdjgpp
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+ ;;
i*86:*:4.*:*)
- UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
+ UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
else
- echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
fi
- exit ;;
+ ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
- case $(/bin/uname -X | grep "^Machine") in
+ case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
- echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
- UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
- echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL
elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
&& UNAME_MACHINE=i586
@@ -1190,11 +1246,11 @@ EOF
&& UNAME_MACHINE=i686
(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
- echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
else
- echo "$UNAME_MACHINE"-pc-sysv32
+ GUESS=$UNAME_MACHINE-pc-sysv32
fi
- exit ;;
+ ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1202,37 +1258,37 @@ EOF
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build.
- echo i586-pc-msdosdjgpp
- exit ;;
+ GUESS=i586-pc-msdosdjgpp
+ ;;
Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit ;;
+ GUESS=i386-pc-mach3
+ ;;
paragon:*:*:*)
- echo i860-intel-osf1
- exit ;;
+ GUESS=i860-intel-osf1
+ ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4
fi
- exit ;;
+ ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
- echo m68010-convergent-sysv
- exit ;;
+ GUESS=m68010-convergent-sysv
+ ;;
mc68k:UNIX:SYSTEM5:3.51m)
- echo m68k-convergent-sysv
- exit ;;
+ GUESS=m68k-convergent-sysv
+ ;;
M680?0:D-NIX:5.3:*)
- echo m68k-diab-dnix
- exit ;;
+ GUESS=m68k-diab-dnix
+ ;;
M68*:*:R3V[5678]*:*)
test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
- && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1243,7 +1299,7 @@ EOF
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
- && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1251,118 +1307,121 @@ EOF
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+ ;;
mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit ;;
+ GUESS=m68k-atari-sysv4
+ ;;
TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+ ;;
rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+ ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
- echo powerpc-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+ ;;
SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-dde-sysv$UNAME_RELEASE
+ ;;
RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
+ GUESS=mips-sni-sysv4
+ ;;
RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
+ GUESS=mips-sni-sysv4
+ ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=$( (uname -p) 2>/dev/null)
- echo "$UNAME_MACHINE"-sni-sysv4
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ GUESS=$UNAME_MACHINE-sni-sysv4
else
- echo ns32k-sni-sysv
+ GUESS=ns32k-sni-sysv
fi
- exit ;;
+ ;;
PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
# says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit ;;
+ GUESS=i586-unisys-sysv4
+ ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <hewes@openmarket.com>.
# How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit ;;
+ GUESS=hppa1.1-stratus-sysv4
+ ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit ;;
+ GUESS=i860-stratus-sysv4
+ ;;
i*86:VOS:*:*)
# From Paul.Green@stratus.com.
- echo "$UNAME_MACHINE"-stratus-vos
- exit ;;
+ GUESS=$UNAME_MACHINE-stratus-vos
+ ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
- echo hppa1.1-stratus-vos
- exit ;;
+ GUESS=hppa1.1-stratus-vos
+ ;;
mc68*:A/UX:*:*)
- echo m68k-apple-aux"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-apple-aux$UNAME_RELEASE
+ ;;
news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit ;;
+ GUESS=mips-sony-newsos6
+ ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if test -d /usr/nec; then
- echo mips-nec-sysv"$UNAME_RELEASE"
+ GUESS=mips-nec-sysv$UNAME_RELEASE
else
- echo mips-unknown-sysv"$UNAME_RELEASE"
+ GUESS=mips-unknown-sysv$UNAME_RELEASE
fi
- exit ;;
+ ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit ;;
+ GUESS=powerpc-be-beos
+ ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit ;;
+ GUESS=powerpc-apple-beos
+ ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit ;;
+ GUESS=i586-pc-beos
+ ;;
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
- echo i586-pc-haiku
- exit ;;
- x86_64:Haiku:*:*)
- echo x86_64-unknown-haiku
- exit ;;
+ GUESS=i586-pc-haiku
+ ;;
+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC
+ GUESS=powerpc-apple-haiku
+ ;;
+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
+ GUESS=$UNAME_MACHINE-unknown-haiku
+ ;;
SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx4-nec-superux$UNAME_RELEASE
+ ;;
SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx5-nec-superux$UNAME_RELEASE
+ ;;
SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx6-nec-superux$UNAME_RELEASE
+ ;;
SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx7-nec-superux$UNAME_RELEASE
+ ;;
SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx8-nec-superux$UNAME_RELEASE
+ ;;
SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx8r-nec-superux$UNAME_RELEASE
+ ;;
SX-ACE:SUPER-UX:*:*)
- echo sxace-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sxace-nec-superux$UNAME_RELEASE
+ ;;
Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+ ;;
*:Rhapsody:*:*)
- echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+ ;;
arm64:Darwin:*:*)
- echo aarch64-apple-darwin"$UNAME_RELEASE"
- exit ;;
+ GUESS=aarch64-apple-darwin$UNAME_RELEASE
+ ;;
*:Darwin:*:*)
- UNAME_PROCESSOR=$(uname -p)
+ UNAME_PROCESSOR=`uname -p`
case $UNAME_PROCESSOR in
unknown) UNAME_PROCESSOR=powerpc ;;
esac
@@ -1396,43 +1455,43 @@ EOF
# uname -m returns i386 or x86_64
UNAME_PROCESSOR=$UNAME_MACHINE
fi
- echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+ ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=$(uname -p)
+ UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
- echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+ ;;
*:QNX:*:4*)
- echo i386-pc-qnx
- exit ;;
+ GUESS=i386-pc-qnx
+ ;;
NEO-*:NONSTOP_KERNEL:*:*)
- echo neo-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=neo-tandem-nsk$UNAME_RELEASE
+ ;;
NSE-*:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nse-tandem-nsk$UNAME_RELEASE
+ ;;
NSR-*:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsr-tandem-nsk$UNAME_RELEASE
+ ;;
NSV-*:NONSTOP_KERNEL:*:*)
- echo nsv-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsv-tandem-nsk$UNAME_RELEASE
+ ;;
NSX-*:NONSTOP_KERNEL:*:*)
- echo nsx-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsx-tandem-nsk$UNAME_RELEASE
+ ;;
*:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit ;;
+ GUESS=mips-compaq-nonstopux
+ ;;
BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit ;;
+ GUESS=bs2000-siemens-sysv
+ ;;
DS/*:UNIX_System_V:*:*)
- echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+ ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
@@ -1440,64 +1499,75 @@ EOF
if test "${cputype-}" = 386; then
UNAME_MACHINE=i386
elif test "x${cputype-}" != x; then
- UNAME_MACHINE="$cputype"
+ UNAME_MACHINE=$cputype
fi
- echo "$UNAME_MACHINE"-unknown-plan9
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-plan9
+ ;;
*:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit ;;
+ GUESS=pdp10-unknown-tops10
+ ;;
*:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit ;;
+ GUESS=pdp10-unknown-tenex
+ ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit ;;
+ GUESS=pdp10-dec-tops20
+ ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit ;;
+ GUESS=pdp10-xkl-tops20
+ ;;
*:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit ;;
+ GUESS=pdp10-unknown-tops20
+ ;;
*:ITS:*:*)
- echo pdp10-unknown-its
- exit ;;
+ GUESS=pdp10-unknown-its
+ ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-sei-seiux$UNAME_RELEASE
+ ;;
*:DragonFly:*:*)
- echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')"
- exit ;;
+ DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+ ;;
*:*VMS:*:*)
- UNAME_MACHINE=$( (uname -p) 2>/dev/null)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
case $UNAME_MACHINE in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
+ A*) GUESS=alpha-dec-vms ;;
+ I*) GUESS=ia64-dec-vms ;;
+ V*) GUESS=vax-dec-vms ;;
esac ;;
*:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
+ GUESS=i386-pc-xenix
+ ;;
i*86:skyos:*:*)
- echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')"
- exit ;;
+ SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+ GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+ ;;
i*86:rdos:*:*)
- echo "$UNAME_MACHINE"-pc-rdos
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-rdos
+ ;;
+ i*86:Fiwix:*:*)
+ GUESS=$UNAME_MACHINE-pc-fiwix
+ ;;
*:AROS:*:*)
- echo "$UNAME_MACHINE"-unknown-aros
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-aros
+ ;;
x86_64:VMkernel:*:*)
- echo "$UNAME_MACHINE"-unknown-esx
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-esx
+ ;;
amd64:Isilon\ OneFS:*:*)
- echo x86_64-unknown-onefs
- exit ;;
+ GUESS=x86_64-unknown-onefs
+ ;;
*:Unleashed:*:*)
- echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+ ;;
esac
+# Do we have a guess based on uname results?
+if test "x$GUESS" != x; then
+ echo "$GUESS"
+ exit
+fi
+
# No uname command or uname output not recognized.
set_cc_for_build
cat > "$dummy.c" <<EOF
@@ -1537,7 +1607,7 @@ main ()
#define __ARCHITECTURE__ "m68k"
#endif
int version;
- version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null);
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
if (version < 4)
printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
else
@@ -1629,7 +1699,7 @@ main ()
}
EOF
-$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
{ echo "$SYSTEM_NAME"; exit; }
# Apollos put the system type in the environment.
@@ -1659,9 +1729,11 @@ and
https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
EOF
-year=$(echo $timestamp | sed 's,-.*,,')
+our_year=`echo $timestamp | sed 's,-.*,,'`
+thisyear=`date +%Y`
# shellcheck disable=SC2003
-if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
+script_age=`expr "$thisyear" - "$our_year"`
+if test "$script_age" -lt 3 ; then
cat >&2 <<EOF
If $0 has already been updated, send the following data and any
@@ -1670,20 +1742,20 @@ provide the necessary information to handle your system.
config.guess timestamp = $timestamp
-uname -m = $( (uname -m) 2>/dev/null || echo unknown)
-uname -r = $( (uname -r) 2>/dev/null || echo unknown)
-uname -s = $( (uname -s) 2>/dev/null || echo unknown)
-uname -v = $( (uname -v) 2>/dev/null || echo unknown)
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
-/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)
-/bin/uname -X = $( (/bin/uname -X) 2>/dev/null)
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
-hostinfo = $( (hostinfo) 2>/dev/null)
-/bin/universe = $( (/bin/universe) 2>/dev/null)
-/usr/bin/arch -k = $( (/usr/bin/arch -k) 2>/dev/null)
-/bin/arch = $( (/bin/arch) 2>/dev/null)
-/usr/bin/oslevel = $( (/usr/bin/oslevel) 2>/dev/null)
-/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
UNAME_MACHINE = "$UNAME_MACHINE"
UNAME_RELEASE = "$UNAME_RELEASE"
diff --git a/depends/config.site.in b/depends/config.site.in
index 8f6849214d..05c2ccbac1 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -82,6 +82,10 @@ if test -z "$enable_lto" && test -n "@lto@"; then
enable_lto=yes
fi
+if test -z "$enable_hardening" && test -n "@no_harden@"; then
+ enable_hardening=no
+fi
+
PKG_CONFIG="$(which pkg-config) --static"
PKG_CONFIG_PATH="${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig"
diff --git a/depends/config.sub b/depends/config.sub
index 7384e9198b..de4259e404 100755
--- a/depends/config.sub
+++ b/depends/config.sub
@@ -1,12 +1,14 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2021 Free Software Foundation, Inc.
+# Copyright 1992-2023 Free Software Foundation, Inc.
-timestamp='2021-04-30'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2023-01-21'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -50,7 +52,14 @@ timestamp='2021-04-30'
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
-me=$(echo "$0" | sed -e 's,.*/,,')
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
@@ -67,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2021 Free Software Foundation, Inc.
+Copyright 1992-2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -112,9 +121,11 @@ esac
# Split fields of configuration type
# shellcheck disable=SC2162
+saved_IFS=$IFS
IFS="-" read field1 field2 field3 field4 <<EOF
$1
EOF
+IFS=$saved_IFS
# Separate into logical components for further validation
case $1 in
@@ -134,7 +145,7 @@ case $1 in
nto-qnx* | linux-* | uclinux-uclibc* \
| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
- | storm-chaos* | os2-emx* | rtmk-nova*)
+ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-*)
basic_machine=$field1
basic_os=$maybe_os
;;
@@ -163,6 +174,10 @@ case $1 in
basic_machine=$field1
basic_os=$field2
;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
# Manufacturers
dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
@@ -769,22 +784,22 @@ case $basic_machine in
vendor=hp
;;
i*86v32)
- cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
basic_os=sysv32
;;
i*86v4*)
- cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
basic_os=sysv4
;;
i*86v)
- cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
basic_os=sysv
;;
i*86sol2)
- cpu=$(echo "$1" | sed -e 's/86.*/86/')
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
basic_os=solaris2
;;
@@ -917,14 +932,16 @@ case $basic_machine in
;;
leon-*|leon[3-9]-*)
cpu=sparc
- vendor=$(echo "$basic_machine" | sed 's/-.*//')
+ vendor=`echo "$basic_machine" | sed 's/-.*//'`
;;
*-*)
# shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read cpu vendor <<EOF
$basic_machine
EOF
+ IFS=$saved_IFS
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
@@ -1003,6 +1020,11 @@ case $cpu-$vendor in
;;
# Here we normalize CPU types with a missing or matching vendor
+ armh-unknown | armh-alt)
+ cpu=armv7l
+ vendor=alt
+ basic_os=${basic_os:-linux-gnueabihf}
+ ;;
dpx20-unknown | dpx20-bull)
cpu=rs6000
vendor=bull
@@ -1053,7 +1075,7 @@ case $cpu-$vendor in
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
cpu=i586
;;
- pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
cpu=i686
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
@@ -1084,7 +1106,7 @@ case $cpu-$vendor in
cpu=mipsisa64sb1el
;;
sh5e[lb]-*)
- cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
+ cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
;;
spur-*)
cpu=spur
@@ -1102,9 +1124,9 @@ case $cpu-$vendor in
cpu=x86_64
;;
xscale-* | xscalee[bl]-*)
- cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
+ cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
- arm64-*)
+ arm64-* | aarch64le-*)
cpu=aarch64
;;
@@ -1165,7 +1187,7 @@ case $cpu-$vendor in
| alphapca5[67] | alpha64pca5[67] \
| am33_2.0 \
| amdgcn \
- | arc | arceb | arc64 \
+ | arc | arceb | arc32 | arc64 \
| arm | arm[lb]e | arme[lb] | armv* \
| avr | avr32 \
| asmjs \
@@ -1185,7 +1207,7 @@ case $cpu-$vendor in
| k1om \
| le32 | le64 \
| lm32 \
- | loongarch32 | loongarch64 | loongarchx32 \
+ | loongarch32 | loongarch64 \
| m32c | m32r | m32rle \
| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
@@ -1287,35 +1309,41 @@ esac
if test x$basic_os != x
then
-# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
# set os.
case $basic_os in
gnu/linux*)
kernel=linux
- os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
+ os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
;;
os2-emx)
kernel=os2
- os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
+ os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
;;
nto-qnx*)
kernel=nto
- os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
+ os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
;;
*-*)
# shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read kernel os <<EOF
$basic_os
EOF
+ IFS=$saved_IFS
;;
# Default OS when just kernel was specified
nto*)
kernel=nto
- os=$(echo $basic_os | sed -e 's|nto|qnx|')
+ os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
;;
linux*)
kernel=linux
- os=$(echo $basic_os | sed -e 's|linux|gnu|')
+ os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
+ ;;
+ managarm*)
+ kernel=managarm
+ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
;;
*)
kernel=
@@ -1336,7 +1364,7 @@ case $os in
os=cnk
;;
solaris1 | solaris1.*)
- os=$(echo $os | sed -e 's|solaris1|sunos4|')
+ os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
;;
solaris)
os=solaris2
@@ -1365,7 +1393,7 @@ case $os in
os=sco3.2v4
;;
sco3.2.[4-9]*)
- os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
+ os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
;;
sco*v* | scout)
# Don't match below
@@ -1395,7 +1423,7 @@ case $os in
os=lynxos
;;
mac[0-9]*)
- os=$(echo "$os" | sed -e 's|mac|macos|')
+ os=`echo "$os" | sed -e 's|mac|macos|'`
;;
opened*)
os=openedition
@@ -1404,10 +1432,10 @@ case $os in
os=os400
;;
sunos5*)
- os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
;;
sunos6*)
- os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
;;
wince*)
os=wince
@@ -1441,7 +1469,7 @@ case $os in
;;
# Preserve the version number of sinix5.
sinix5.*)
- os=$(echo $os | sed -e 's|sinix|sysv|')
+ os=`echo "$os" | sed -e 's|sinix|sysv|'`
;;
sinix*)
os=sysv4
@@ -1688,7 +1716,7 @@ fi
# Now, validate our (potentially fixed-up) OS.
case $os in
# Sometimes we do "kernel-libc", so those need to count as OSes.
- musl* | newlib* | uclibc*)
+ musl* | newlib* | relibc* | uclibc*)
;;
# Likewise for "kernel-abi"
eabi* | gnueabi*)
@@ -1729,7 +1757,8 @@ case $os in
| skyos* | haiku* | rdos* | toppers* | drops* | es* \
| onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
| midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
- | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
+ | fiwix* | mlibc* )
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1737,6 +1766,9 @@ case $os in
;;
none)
;;
+ kernel* )
+ # Restricted further below
+ ;;
*)
echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
exit 1
@@ -1746,16 +1778,27 @@ esac
# As a final step for OS-related things, validate the OS-kernel combination
# (given a valid OS), if there is a kernel.
case $kernel-$os in
- linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+ linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
+ | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* )
;;
uclinux-uclibc* )
;;
- -dietlibc* | -newlib* | -musl* | -uclibc* )
+ managarm-mlibc* | managarm-kernel* )
+ ;;
+ -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* )
# These are just libc implementations, not actual OSes, and thus
# require a kernel.
echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
exit 1
;;
+ -kernel* )
+ echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ *-kernel* )
+ echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2
+ exit 1
+ ;;
kfreebsd*-gnu* | kopensolaris*-gnu*)
;;
vxworks-simlinux | vxworks-simwindows | vxworks-spe)
diff --git a/depends/funcs.mk b/depends/funcs.mk
index f0bbf4a168..987be4e611 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -176,7 +176,7 @@ $(1)_cmake=env CC="$$($(1)_cc)" \
CXX="$$($(1)_cxx)" \
CXXFLAGS="$$($(1)_cppflags) $$($(1)_cxxflags)" \
LDFLAGS="$$($(1)_ldflags)" \
- cmake -DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" $$($(1)_cmake_opts)
+ cmake -DCMAKE_INSTALL_PREFIX:PATH="$$($($(1)_type)_prefix)" $$($(1)_config_opts)
ifeq ($($(1)_type),build)
$(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH="$$($($(1)_type)_prefix)/lib"
else
diff --git a/depends/gen_id b/depends/gen_id
index 7caf8d764d..3341310e46 100755
--- a/depends/gen_id
+++ b/depends/gen_id
@@ -2,7 +2,7 @@
# Usage: env [ CC=... ] [ C_STANDARD=...] [ CXX=... ] [CXX_STANDARD=...] \
# [ AR=... ] [ RANLIB=... ] [ STRIP=... ] [ DEBUG=... ] \
-# [ LTO=... ] ./build-id [ID_SALT]...
+# [ LTO=... ] [ NO_HARDEN=... ] ./build-id [ID_SALT]...
#
# Prints to stdout a SHA256 hash representing the current toolset, used by
# depends/Makefile as a build id for caching purposes (detecting when the
@@ -70,6 +70,10 @@
echo "LTO=${LTO}"
echo "END LTO"
+ echo "BEGIN NO_HARDEN"
+ echo "NO_HARDEN=${NO_HARDEN}"
+ echo "END NO_HARDEN"
+
echo "END ALL"
) | if [ -n "$DEBUG" ] && command -v tee > /dev/null 2>&1; then
# When debugging and `tee` is available, output the preimage to stderr
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index 8fcea35d98..fa6d6d4b8b 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -1,4 +1,4 @@
-OSX_MIN_VERSION=10.15
+OSX_MIN_VERSION=11.0
OSX_SDK_VERSION=11.0
XCODE_VERSION=12.2
XCODE_BUILD_ID=12B45b
@@ -19,7 +19,6 @@ clang_prog=$(build_prefix)/bin/clang
clangxx_prog=$(clang_prog)++
llvm_config_prog=$(build_prefix)/bin/llvm-config
-clang_resource_dir=$(build_prefix)/lib/clang/$(native_clang_version)
else
# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's
# system
@@ -37,7 +36,6 @@ clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang")
clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++")
llvm_config_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v llvm-config")
-clang_resource_dir=$(shell clang -print-resource-dir)
llvm_lib_dir=$(shell $(llvm_config_prog) --libdir)
endif
@@ -63,54 +61,33 @@ $(foreach TOOL,$(cctools_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/$$(
# Explicitly point to our binaries (e.g. cctools) so that they are
# ensured to be found and preferred over other possibilities.
#
-# -stdlib=libc++ -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1
+# -isysroot$(OSX_SDK) -nostdlibinc
#
-# Forces clang to use the libc++ headers from our SDK and completely
-# forget about the libc++ headers from the standard directories
+# Disable default include paths built into the compiler as well as
+# those normally included for libc and libc++. The only path that
+# remains implicitly is the clang resource dir.
#
-# -Xclang -*system<path_a> \
-# -Xclang -*system<path_b> \
-# -Xclang -*system<path_c> ...
+# -iwithsysroot / -iframeworkwithsysroot
#
-# Adds path_a, path_b, and path_c to the bottom of clang's list of
-# include search paths. This is used to explicitly specify the list of
-# system include search paths and its ordering, rather than rely on
-# clang's autodetection routine. This routine has been shown to:
-# 1. Fail to pickup libc++ headers in $SYSROOT/usr/include/c++/v1
-# when clang was built manually (see: https://github.com/bitcoin/bitcoin/pull/17919#issuecomment-656785034)
-# 2. Fail to pickup C headers in $SYSROOT/usr/include when
-# C_INCLUDE_DIRS was specified at configure time (see: https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9)
-#
-# Talking directly to cc1 with -Xclang here grants us access to specify
-# more granular categories for these system include search paths, and we
-# can use the correct categories that these search paths would have been
-# placed in if the autodetection routine had worked correctly. (see:
-# https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9#the-treatment)
-#
-# Furthermore, it places these search paths after any "non-Xclang"
-# specified search paths. This prevents any additional clang options or
-# environment variables from coming after or in between these system
-# include search paths, as that would be wrong in general but would also
-# break #include_next's.
+# Adds the desired paths from the SDK
#
+
darwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
-u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
-u LIBRARY_PATH \
$(clang_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
-B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
- -isysroot$(OSX_SDK) \
- -Xclang -internal-externc-isystem$(clang_resource_dir)/include \
- -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include
+ -isysroot$(OSX_SDK) -nostdlibinc \
+ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks
+
darwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
-u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
-u LIBRARY_PATH \
$(clangxx_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
-B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
- -isysroot$(OSX_SDK) \
- -stdlib=libc++ \
- -stdlib++-isystem$(OSX_SDK)/usr/include/c++/v1 \
- -Xclang -internal-externc-isystem$(clang_resource_dir)/include \
- -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include
+ -isysroot$(OSX_SDK) -nostdlibinc \
+ -iwithsysroot/usr/include/c++/v1 \
+ -iwithsysroot/usr/include -iframeworkwithsysroot/System/Library/Frameworks
darwin_CFLAGS=-pipe -std=$(C_STANDARD)
darwin_CXXFLAGS=-pipe -std=$(CXX_STANDARD)
diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk
index 635d3d16da..0e2496174e 100644
--- a/depends/hosts/linux.mk
+++ b/depends/hosts/linux.mk
@@ -17,7 +17,7 @@ linux_release_CXXFLAGS=$(linux_release_CFLAGS)
linux_debug_CFLAGS=-O1
linux_debug_CXXFLAGS=$(linux_debug_CFLAGS)
-linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_LIBCPP_DEBUG=1
+linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_LIBCPP_ENABLE_ASSERTIONS=1
ifeq (86,$(findstring 86,$(build_arch)))
i686_linux_CC=gcc -m32
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index d607336059..9f5a925015 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -14,7 +14,7 @@ $(package)_config_opts_freebsd=--with-pic
$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
-$(package)_cflags+=-Wno-error=implicit-function-declaration -Wno-error=format-security
+$(package)_cflags+=-Wno-error=implicit-function-declaration -Wno-error=format-security -Wno-error=implicit-int
$(package)_cppflags_freebsd=-D_XOPEN_SOURCE=600 -D__BSD_VISIBLE=1
$(package)_cppflags_netbsd=-D_XOPEN_SOURCE=600
$(package)_cppflags_openbsd=-D_XOPEN_SOURCE=600
diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk
index c8b2fc33d5..444acfe36d 100644
--- a/depends/packages/fontconfig.mk
+++ b/depends/packages/fontconfig.mk
@@ -9,6 +9,7 @@ $(package)_patches=gperf_header_regen.patch
define $(package)_set_vars
$(package)_config_opts=--disable-docs --disable-static --disable-libxml2 --disable-iconv
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
+ $(package)_cflags += -Wno-implicit-function-declaration
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk
index 8374f2a103..9650f77db9 100644
--- a/depends/packages/libevent.mk
+++ b/depends/packages/libevent.mk
@@ -16,8 +16,11 @@ define $(package)_set_vars
$(package)_config_opts_netbsd=--with-pic
$(package)_config_opts_openbsd=--with-pic
$(package)_config_opts_android=--with-pic
- $(package)_cppflags+=-D_FORTIFY_SOURCE=3
$(package)_cppflags_mingw32=-D_WIN32_WINNT=0x0601
+
+ ifeq ($(NO_HARDEN),)
+ $(package)_cppflags+=-D_FORTIFY_SOURCE=3
+ endif
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/libmultiprocess.mk b/depends/packages/libmultiprocess.mk
index 6da5693b3f..765d649377 100644
--- a/depends/packages/libmultiprocess.mk
+++ b/depends/packages/libmultiprocess.mk
@@ -10,8 +10,8 @@ endif
define $(package)_set_vars :=
ifneq ($(host),$(build))
-$(package)_cmake_opts := -DCAPNP_EXECUTABLE="$$(native_capnp_prefixbin)/capnp"
-$(package)_cmake_opts += -DCAPNPC_CXX_EXECUTABLE="$$(native_capnp_prefixbin)/capnpc-c++"
+$(package)_config_opts := -DCAPNP_EXECUTABLE="$$(native_capnp_prefixbin)/capnp"
+$(package)_config_opts += -DCAPNPC_CXX_EXECUTABLE="$$(native_capnp_prefixbin)/capnpc-c++"
endif
endef
diff --git a/depends/packages/native_clang.mk b/depends/packages/native_clang.mk
index f2712294ab..109796c0e6 100644
--- a/depends/packages/native_clang.mk
+++ b/depends/packages/native_clang.mk
@@ -1,18 +1,14 @@
package=native_clang
-$(package)_version=10.0.1
+$(package)_version=11.1.0
$(package)_download_path=https://github.com/llvm/llvm-project/releases/download/llvmorg-$($(package)_version)
ifneq (,$(findstring aarch64,$(BUILD)))
$(package)_file_name=clang+llvm-$($(package)_version)-aarch64-linux-gnu.tar.xz
-$(package)_sha256_hash=90dc69a4758ca15cd0ffa45d07fbf5bf4309d47d2c7745a9f0735ecffde9c31f
+$(package)_sha256_hash=18df38247af3fba0e0e2991fb00d7e3cf3560b4d3509233a14af699ef0039e1c
else
$(package)_file_name=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-16.04.tar.xz
-$(package)_sha256_hash=48b83ef827ac2c213d5b64f5ad7ed082c8bcb712b46644e0dc5045c6f462c231
+$(package)_sha256_hash=c691a558967fb7709fb81e0ed80d1f775f4502810236aa968b4406526b43bee1
endif
-define $(package)_preprocess_cmds
- rm -f $($(package)_extract_dir)/lib/libc++abi.so*
-endef
-
define $(package)_stage_cmds
mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_version)/include && \
mkdir -p $($(package)_staging_prefix_dir)/bin && \
diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk
index d1687883bc..2afd95d7c4 100644
--- a/depends/packages/qrencode.mk
+++ b/depends/packages/qrencode.mk
@@ -1,15 +1,16 @@
package=qrencode
-$(package)_version=3.4.4
+$(package)_version=4.1.1
$(package)_download_path=https://fukuchi.org/works/qrencode/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5
+$(package)_sha256_hash=e455d9732f8041cf5b9c388e345a641fd15707860f928e94507b1961256a6923
define $(package)_set_vars
-$(package)_config_opts=--disable-shared --without-tools --without-tests --disable-sdltest
+$(package)_config_opts=--disable-shared --without-tools --without-tests --without-png
$(package)_config_opts += --disable-gprof --disable-gcov --disable-mudflap
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_android=--with-pic
+$(package)_cflags += -Wno-int-conversion -Wno-implicit-function-declaration
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index 2f7ddf6a5f..136ce32579 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -161,9 +161,15 @@ $(package)_config_opts_linux += -dbus-runtime
ifneq ($(LTO),)
$(package)_config_opts_linux += -ltcg
endif
-$(package)_config_opts_linux += -platform linux-g++ -xplatform bitcoin-linux-g++
-ifneq (,$(findstring -stdlib=libc++,$($(1)_cxx)))
-$(package)_config_opts_x86_64_linux = -xplatform linux-clang-libc++
+
+ifneq (,$(findstring clang,$($(package)_cxx)))
+ ifneq (,$(findstring -stdlib=libc++,$($(package)_cxx)))
+ $(package)_config_opts_linux += -platform linux-clang-libc++ -xplatform linux-clang-libc++
+ else
+ $(package)_config_opts_linux += -platform linux-clang -xplatform linux-clang
+ endif
+else
+ $(package)_config_opts_linux += -platform linux-g++ -xplatform bitcoin-linux-g++
endif
$(package)_config_opts_mingw32 = -no-opengl
diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md
index ab5db58cdd..6cbb6ebd72 100644
--- a/doc/JSON-RPC-interface.md
+++ b/doc/JSON-RPC-interface.md
@@ -5,6 +5,41 @@ The headless daemon `bitcoind` has the JSON-RPC API enabled by default, the GUI
option. In the GUI it is possible to execute RPC methods in the Debug Console
Dialog.
+## Endpoints
+
+There are two JSON-RPC endpoints on the server:
+
+1. `/`
+2. `/wallet/<walletname>/`
+
+### `/` endpoint
+
+This endpoint is always active.
+It can always service non-wallet requests and can service wallet requests when
+exactly one wallet is loaded.
+
+### `/wallet/<walletname>/` endpoint
+
+This endpoint is only activated when the wallet component has been compiled in.
+It can service both wallet and non-wallet requests.
+It MUST be used for wallet requests when two or more wallets are loaded.
+
+This is the endpoint used by bitcoin-cli when a `-rpcwallet=` parameter is passed in.
+
+Best practice would dictate using the `/wallet/<walletname>/` endpoint for ALL
+requests when multiple wallets are in use.
+
+### Examples
+
+```sh
+# Get block count from the / endpoint when rpcuser=alice and rpcport=38332
+$ curl --user alice --data-binary '{"jsonrpc": "1.0", "id": "0", "method": "getblockcount", "params": []}' -H 'content-type: text/plain;' localhost:38332/
+
+# Get balance from the /wallet/walletname endpoint when rpcuser=alice, rpcport=38332 and rpcwallet=desc-wallet
+$ curl --user alice --data-binary '{"jsonrpc": "1.0", "id": "0", "method": "getbalance", "params": []}' -H 'content-type: text/plain;' localhost:38332/wallet/desc-wallet
+
+```
+
## Parameter passing
The JSON-RPC server supports both _by-position_ and _by-name_ [parameter
diff --git a/doc/bips.md b/doc/bips.md
index 1d5c91b8bd..94213f8048 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -1,4 +1,4 @@
-BIPs that are implemented by Bitcoin Core (up-to-date up to **v24.0**):
+BIPs that are implemented by Bitcoin Core:
* [`BIP 9`](https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki): The changes allowing multiple soft-forks to be deployed in parallel have been implemented since **v0.12.1** ([PR #7575](https://github.com/bitcoin/bitcoin/pull/7575))
* [`BIP 11`](https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki): Multisig outputs are standard since **v0.6.0** ([PR #669](https://github.com/bitcoin/bitcoin/pull/669)).
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index 255995a517..96ee714341 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,6 +1,6 @@
# OpenBSD Build Guide
-**Updated for OpenBSD [7.1](https://www.openbsd.org/71.html)**
+**Updated for OpenBSD [7.3](https://www.openbsd.org/73.html)**
This guide describes how to build bitcoind, command-line utilities, and GUI on OpenBSD.
@@ -80,10 +80,6 @@ export AUTOMAKE_VERSION=1.16
### 1. Configuration
-Note that external signer support is currently not available on OpenBSD, since
-the used header-only library Boost.Process fails to compile (certain system
-calls and preprocessor defines like `waitid()` and `WEXITED` are missing).
-
There are many ways to configure Bitcoin Core, here are a few common examples:
##### Descriptor Wallet and GUI:
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 0960ae1577..3633d4f811 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -4,16 +4,6 @@ Some notes on how to build Bitcoin Core in Unix.
(For BSD specific instructions, see `build-*bsd.md` in this directory.)
-Note
----------------------
-Always use absolute paths to configure and compile Bitcoin Core and the dependencies.
-For example, when specifying the path of the dependency:
-
- ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX
-
-Here BDB_PREFIX must be an absolute path - it is defined using $(pwd) which ensures
-the usage of the absolute path.
-
To Build
---------------------
@@ -24,12 +14,11 @@ make # use "-j N" for N parallel jobs
make install # optional
```
-This will build bitcoin-qt as well, if the dependencies are met.
-
-See [dependencies.md](dependencies.md) for a complete overview.
+See below for instructions on how to [install the dependencies on popular Linux
+distributions](#linux-distribution-specific-instructions), or the
+[dependencies](#dependencies) section for a complete overview.
-Memory Requirements
---------------------
+## Memory Requirements
C++ compilers are memory-hungry. It is recommended to have at least 1.5 GB of
memory available when compiling Bitcoin Core. On systems with less, gcc can be
@@ -57,7 +46,7 @@ Build requirements:
sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils python3
-Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies:
+Now, you can either build from self-compiled [depends](#dependencies) or install the required dependencies:
sudo apt-get install libevent-dev libboost-dev
@@ -65,7 +54,7 @@ SQLite is required for the descriptor wallet:
sudo apt install libsqlite3-dev
-Berkeley DB is required for the legacy wallet. Ubuntu and Debian have their own `libdb-dev` and `libdb++-dev` packages,
+Berkeley DB is only required for the legacy wallet. Ubuntu and Debian have their own `libdb-dev` and `libdb++-dev` packages,
but these will install Berkeley DB 5.1 or later. This will break binary wallet compatibility with the distributed
executables, which are based on BerkeleyDB 4.8. If you do not care about wallet compatibility, pass
`--with-incompatible-bdb` to configure. Otherwise, you can build Berkeley DB [yourself](#berkeley-db).
@@ -114,7 +103,7 @@ Build requirements:
sudo dnf install gcc-c++ libtool make autoconf automake python3
-Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies:
+Now, you can either build from self-compiled [depends](#dependencies) or install the required dependencies:
sudo dnf install libevent-devel boost-devel
@@ -126,7 +115,7 @@ Berkeley DB is required for the legacy wallet:
sudo dnf install libdb4-devel libdb4-cxx-devel
-Newer Fedora releases, since Fedora 33, have only `libdb-devel` and `libdb-cxx-devel` packages, but these will install
+Berkeley DB is only required for the legacy wallet. Newer Fedora releases have only `libdb-devel` and `libdb-cxx-devel` packages, but these will install
Berkeley DB 5.3 or later. This will break binary wallet compatibility with the distributed executables, which
are based on Berkeley DB 4.8. If you do not care about wallet compatibility,
pass `--with-incompatible-bdb` to configure. Otherwise, you can build Berkeley DB [yourself](#berkeley-db).
@@ -166,27 +155,13 @@ libqrencode (optional) can be installed with:
Once these are installed, they will be found by configure and a bitcoin-qt executable will be
built by default.
-Notes
------
-The release is built with GCC and then "strip bitcoind" to strip the debug
-symbols, which reduces the executable size by about 90%.
+## Dependencies
-miniupnpc
----------
+See [dependencies.md](dependencies.md) for a complete overview, and
+[depends](/depends/README.md) on how to compile them yourself, if you wish to
+not use the packages of your Linux distribution.
-[miniupnpc](https://miniupnp.tuxfamily.org) may be used for UPnP port mapping. It can be downloaded from [here](
-https://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and
-turned off by default.
-
-libnatpmp
----------
-
-[libnatpmp](https://miniupnp.tuxfamily.org/libnatpmp.html) may be used for NAT-PMP port mapping. It can be downloaded
-from [here](https://miniupnp.tuxfamily.org/files/). NAT-PMP support is compiled in and
-turned off by default.
-
-Berkeley DB
------------
+### Berkeley DB
The legacy wallet uses Berkeley DB. To ensure backwards compatibility it is
recommended to use Berkeley DB 4.8. If you have to build it yourself, and don't
@@ -205,53 +180,9 @@ export BDB_PREFIX="/path/to/bitcoin/depends/x86_64-pc-linux-gnu"
BDB_CFLAGS="-I${BDB_PREFIX}/include"
```
-**Note**: You only need Berkeley DB if the legacy wallet is enabled (see [*Disable-wallet mode*](#disable-wallet-mode)).
-
-Security
---------
-To help make your Bitcoin Core installation more secure by making certain attacks impossible to
-exploit even if a vulnerability is found, binaries are hardened by default.
-This can be disabled with:
-
-Hardening Flags:
+**Note**: Make sure that `BDB_PREFIX` is an absolute path.
- ./configure --enable-hardening
- ./configure --disable-hardening
-
-
-Hardening enables the following features:
-* _Position Independent Executable_: Build position independent code to take advantage of Address Space Layout Randomization
- offered by some kernels. Attackers who can cause execution of code at an arbitrary memory
- location are thwarted if they don't know where anything useful is located.
- The stack and heap are randomly located by default, but this allows the code section to be
- randomly located as well.
-
- On an AMD64 processor where a library was not compiled with -fPIC, this will cause an error
- such as: "relocation R_X86_64_32 against `......' can not be used when making a shared object;"
-
- To test that you have built PIE executable, install scanelf, part of paxutils, and use:
-
- scanelf -e ./bitcoin
-
- The output should contain:
-
- TYPE
- ET_DYN
-
-* _Non-executable Stack_: If the stack is executable then trivial stack-based buffer overflow exploits are possible if
- vulnerable buffers are found. By default, Bitcoin Core should be built with a non-executable stack,
- but if one of the libraries it uses asks for an executable stack or someone makes a mistake
- and uses a compiler extension which requires an executable stack, it will silently build an
- executable without the non-executable stack protection.
-
- To verify that the stack is non-executable after compiling use:
- `scanelf -e ./bitcoin`
-
- The output should contain:
- STK/REL/PTL
- RW- R-- RW-
-
- The STK RW- means that the stack is readable and writeable but not executable.
+**Note**: You only need Berkeley DB if the legacy wallet is enabled (see [*Disable-wallet mode*](#disable-wallet-mode)).
Disable-wallet mode
--------------------
diff --git a/doc/cjdns.md b/doc/cjdns.md
index b69564729f..031cd1978b 100644
--- a/doc/cjdns.md
+++ b/doc/cjdns.md
@@ -112,5 +112,4 @@ There are several ways to see your CJDNS address in Bitcoin Core:
To see which CJDNS peers your node is connected to, use `bitcoin-cli -netinfo 4`
or the `getpeerinfo` RPC (i.e. `bitcoin-cli getpeerinfo`).
-To see which CJDNS addresses your node knows, use the `getnodeaddresses 0 cjdns`
-RPC.
+You can use the `getnodeaddresses` RPC to fetch a number of CJDNS peers known to your node; run `bitcoin-cli help getnodeaddresses` for details.
diff --git a/doc/dependencies.md b/doc/dependencies.md
index a9ca5b3e7a..804f796abe 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -8,9 +8,9 @@ You can find installation instructions in the `build-*.md` file for your platfor
| --- | --- |
| [Autoconf](https://www.gnu.org/software/autoconf/) | [2.69](https://github.com/bitcoin/bitcoin/pull/17769) |
| [Automake](https://www.gnu.org/software/automake/) | [1.13](https://github.com/bitcoin/bitcoin/pull/18290) |
-| [Clang](https://clang.llvm.org) | [8.0](https://github.com/bitcoin/bitcoin/pull/24164) |
-| [GCC](https://gcc.gnu.org) | [8.1](https://github.com/bitcoin/bitcoin/pull/23060) |
-| [Python](https://www.python.org) (tests) | [3.7](https://github.com/bitcoin/bitcoin/pull/26226) |
+| [Clang](https://clang.llvm.org) | [10.0](https://github.com/bitcoin/bitcoin/pull/27682) |
+| [GCC](https://gcc.gnu.org) | [9.1](https://github.com/bitcoin/bitcoin/pull/27662) |
+| [Python](https://www.python.org) (scripts, tests) | [3.8](https://github.com/bitcoin/bitcoin/pull/27483) |
| [systemtap](https://sourceware.org/systemtap/) ([tracing](tracing.md))| N/A |
## Required
@@ -20,7 +20,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| [Boost](../depends/packages/boost.mk) | [link](https://www.boost.org/users/download/) | [1.81.0](https://github.com/bitcoin/bitcoin/pull/26557) | [1.64.0](https://github.com/bitcoin/bitcoin/pull/22320) | No |
| [libevent](../depends/packages/libevent.mk) | [link](https://github.com/libevent/libevent/releases) | [2.1.12-stable](https://github.com/bitcoin/bitcoin/pull/21991) | [2.1.8](https://github.com/bitcoin/bitcoin/pull/24681) | No |
| glibc | [link](https://www.gnu.org/software/libc/) | N/A | [2.27](https://github.com/bitcoin/bitcoin/pull/27029) | Yes |
-| Linux Kernel | [link](https://www.kernel.org/) | N/A | 3.2.0 | Yes |
+| Linux Kernel | [link](https://www.kernel.org/) | N/A | [3.17.0](https://github.com/bitcoin/bitcoin/pull/27699) | Yes |
## Optional
@@ -29,7 +29,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| --- | --- | --- | --- | --- |
| [Fontconfig](../depends/packages/fontconfig.mk) | [link](https://www.freedesktop.org/wiki/Software/fontconfig/) | [2.12.6](https://github.com/bitcoin/bitcoin/pull/23495) | 2.6 | Yes |
| [FreeType](../depends/packages/freetype.mk) | [link](https://freetype.org) | [2.11.0](https://github.com/bitcoin/bitcoin/commit/01544dd78ccc0b0474571da854e27adef97137fb) | 2.3.0 | Yes |
-| [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [3.4.4](https://github.com/bitcoin/bitcoin/pull/6373) | | No |
+| [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [4.1.1](https://github.com/bitcoin/bitcoin/pull/27312) | | No |
| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.5](https://github.com/bitcoin/bitcoin/pull/25719) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
### Networking
@@ -47,4 +47,4 @@ You can find installation instructions in the `build-*.md` file for your platfor
| Dependency | Releases | Version used | Minimum required | Runtime |
| --- | --- | --- | --- | --- |
| [Berkeley DB](../depends/packages/bdb.mk) (legacy wallet) | [link](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.30 | 4.8.x | No |
-| [SQLite](../depends/packages/sqlite.mk) | [link](https://sqlite.org) | [3.32.1](https://github.com/bitcoin/bitcoin/pull/19077) | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | No |
+| [SQLite](../depends/packages/sqlite.mk) | [link](https://sqlite.org) | [3.38.5](https://github.com/bitcoin/bitcoin/pull/25378) | [3.7.17](https://github.com/bitcoin/bitcoin/pull/19077) | No |
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index ceaba8cb99..fca72914a3 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -111,8 +111,8 @@ code.
- `static_assert` is preferred over `assert` where possible. Generally; compile-time checking is preferred over run-time checking.
- Use a named cast or functional cast, not a C-Style cast. When casting
between integer types, use functional casts such as `int(x)` or `int{x}`
- instead of `(int) x`. When casting between more complex types, use static_cast.
- Use reinterpret_cast and const_cast as appropriate.
+ instead of `(int) x`. When casting between more complex types, use `static_cast`.
+ Use `reinterpret_cast` and `const_cast` as appropriate.
For function calls a namespace should be specified explicitly, unless such functions have been declared within it.
Otherwise, [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl), also known as ADL, could be
@@ -217,13 +217,11 @@ apt install clang-tidy bear clang
Then, pass clang as compiler to configure, and use bear to produce the `compile_commands.json`:
```sh
-./autogen.sh && ./configure CC=clang CXX=clang++ --enable-suppress-external-warnings
+./autogen.sh && ./configure CC=clang CXX=clang++
make clean && bear --config src/.bear-tidy-config -- make -j $(nproc)
```
-The output is denoised of errors from external dependencies and includes with
-`--enable-suppress-external-warnings` and `--config src/.bear-tidy-config`. Both
-options may be omitted to view the full list of errors.
+The output is denoised of errors from external dependencies.
To run clang-tidy on all source files:
diff --git a/doc/i2p.md b/doc/i2p.md
index 0432136554..cfff426617 100644
--- a/doc/i2p.md
+++ b/doc/i2p.md
@@ -109,8 +109,7 @@ incoming I2P connections (`-i2pacceptincoming`):
To see which I2P peers your node is connected to, use `bitcoin-cli -netinfo 4`
or the `getpeerinfo` RPC (e.g. `bitcoin-cli getpeerinfo`).
-To see which I2P addresses your node knows, use the `getnodeaddresses 0 i2p`
-RPC.
+You can use the `getnodeaddresses` RPC to fetch a number of I2P peers known to your node; run `bitcoin-cli help getnodeaddresses` for details.
## Compatibility
diff --git a/doc/policy/packages.md b/doc/policy/packages.md
index 274854ddf9..2a5758318a 100644
--- a/doc/policy/packages.md
+++ b/doc/policy/packages.md
@@ -80,24 +80,37 @@ test accepts):
If any transactions in the package are already in the mempool, they are not submitted again
("deduplicated") and are thus excluded from this calculation.
-To meet the two feerate requirements of a mempool, i.e., the pre-configured minimum relay feerate
-(`-minrelaytxfee`) and the dynamic mempool minimum feerate, the total package feerate is used instead
-of the individual feerate. The individual transactions are allowed to be below the feerate
-requirements if the package meets the feerate requirements. For example, the parent(s) in the
-package can pay no fees but be paid for by the child.
-
-*Rationale*: This can be thought of as "CPFP within a package," solving the issue of a parent not
-meeting minimum fees on its own. This would allow contracting applications to adjust their fees at
-broadcast time instead of overshooting or risking becoming stuck or pinned.
-
-*Rationale*: It would be incorrect to use the fees of transactions that are already in the mempool, as
-we do not want a transaction's fees to be double-counted.
+To meet the dynamic mempool minimum feerate, i.e., the feerate determined by the transactions
+evicted when the mempool reaches capacity (not the static minimum relay feerate), the total package
+feerate instead of individual feerate can be used. For example, if the mempool minimum feerate is
+5sat/vB and a 1sat/vB parent transaction has a high-feerate child, it may be accepted if
+submitted as a package.
+
+*Rationale*: This can be thought of as "CPFP within a package," solving the issue of a presigned
+transaction (i.e. in which a replacement transaction with a higher fee cannot be signed) being
+rejected from the mempool when transaction volume is high and the mempool minimum feerate rises.
+
+Note: Package feerate cannot be used to meet the minimum relay feerate (`-minrelaytxfee`)
+requirement. For example, if the mempool minimum feerate is 5sat/vB and the minimum relay feerate is
+set to 5satvB, a 1sat/vB parent transaction with a high-feerate child will not be accepted, even if
+submitted as a package.
+
+*Rationale*: Avoid situations in which the mempool contains non-bumped transactions below min relay
+feerate (which we consider to have pay 0 fees and thus receiving free relay). While package
+submission would ensure these transactions are bumped at the time of entry, it is not guaranteed
+that the transaction will always be bumped. For example, a later transaction could replace the
+fee-bumping child without still bumping the parent. These no-longer-bumped transactions should be
+removed during a replacement, but we do not have a DoS-resistant way of removing them or enforcing a
+limit on their quantity. Instead, prevent their entry into the mempool.
Implementation Note: Transactions within a package are always validated individually first, and
package validation is used for the transactions that failed. Since package feerate is only
calculated using transactions that are not in the mempool, this implementation detail affects the
outcome of package validation.
+*Rationale*: It would be incorrect to use the fees of transactions that are already in the mempool, as
+we do not want a transaction's fees to be double-counted.
+
*Rationale*: Packages are intended for incentive-compatible fee-bumping: transaction B is a
"legitimate" fee-bump for transaction A only if B is a descendant of A and has a *higher* feerate
than A. We want to prevent "parents pay for children" behavior; fees of parents should not help
diff --git a/doc/reduce-memory.md b/doc/reduce-memory.md
index 25205258b8..dbe88d45f3 100644
--- a/doc/reduce-memory.md
+++ b/doc/reduce-memory.md
@@ -43,7 +43,7 @@ threads take up 8MiB for the thread stack on a 64-bit system, and 4MiB in a
## Linux specific
-By default, since glibc `2.10`, the C library will create up to two heap arenas per core. This is known to cause excessive memory usage in some scenarios. To avoid this make a script that sets `MALLOC_ARENA_MAX` before starting bitcoind:
+By default, glibc will create up to two heap arenas per core. This is known to cause excessive memory usage in some scenarios. To avoid this make a script that sets `MALLOC_ARENA_MAX` before starting bitcoind:
```bash
#!/usr/bin/env bash
diff --git a/doc/release-note-26194.md b/doc/release-note-26194.md
deleted file mode 100644
index b72dbf9a23..0000000000
--- a/doc/release-note-26194.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Add `next_index` in `listdescriptors` RPC
------------------
-
-- Added a new `next_index` field in the response in `listdescriptors` to have the same format as `importdescriptors`
diff --git a/doc/release-notes-19762.md b/doc/release-notes-19762.md
deleted file mode 100644
index 4dc45fb2c8..0000000000
--- a/doc/release-notes-19762.md
+++ /dev/null
@@ -1,19 +0,0 @@
-JSON-RPC
----
-
-All JSON-RPC methods accept a new [named
-parameter](JSON-RPC-interface.md#parameter-passing) called `args` that can
-contain positional parameter values. This is a convenience to allow some
-parameter values to be passed by name without having to name every value. The
-python test framework and `bitcoin-cli` tool both take advantage of this, so
-for example:
-
-```sh
-bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=1
-```
-
-Can now be shortened to:
-
-```sh
-bitcoin-cli -named createwallet mywallet load_on_startup=1
-```
diff --git a/doc/release-notes-22087.md b/doc/release-notes-22087.md
deleted file mode 100644
index 8d7fd242b2..0000000000
--- a/doc/release-notes-22087.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Updated settings
-----------------
-
-- Ports specified in `-port` and `-rpcport` options are now validated at startup. Values that previously worked and were considered valid can now result in errors. (#22087)
diff --git a/doc/release-notes-23395.md b/doc/release-notes-23395.md
deleted file mode 100644
index b9d7d9409c..0000000000
--- a/doc/release-notes-23395.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Notable changes
-===============
-
-New settings
-------------
-
-- The `shutdownnotify` option is used to specify a command to execute synchronously
-before Bitcoin Core has begun its shutdown sequence. (#23395)
diff --git a/doc/release-notes-25158.md b/doc/release-notes-25158.md
new file mode 100644
index 0000000000..ce8ab53ddd
--- /dev/null
+++ b/doc/release-notes-25158.md
@@ -0,0 +1,6 @@
+RPC Wallet
+----------
+
+- The `gettransaction`, `listtransactions`, `listsinceblock` RPCs now return
+ the `abandoned` field for all transactions. Previously, the "abandoned" field
+ was only returned for sent transactions. (#25158) \ No newline at end of file
diff --git a/doc/release-notes-25375.md b/doc/release-notes-25375.md
deleted file mode 100644
index 504a2644f4..0000000000
--- a/doc/release-notes-25375.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Updated RPCs
---------
-
-The `minconf` option, which allows a user to specify the minimum number
-of confirmations a UTXO being spent has, and the `maxconf` option,
-which allows specifying the maximum number of confirmations, have been
-added to the following RPCs:
-- `fundrawtransaction`
-- `send`
-- `walletcreatefundedpsbt`
-- `sendall`
diff --git a/doc/release-notes-25412.md b/doc/release-notes-25412.md
deleted file mode 100644
index b11fe73d45..0000000000
--- a/doc/release-notes-25412.md
+++ /dev/null
@@ -1,5 +0,0 @@
-New REST endpoint
------------------
-
-- A new `/rest/deploymentinfo` endpoint has been added for fetching various
- state info regarding deployments of consensus changes. (#25412)
diff --git a/doc/release-notes-25574.md b/doc/release-notes-25574.md
deleted file mode 100644
index 312a99d95b..0000000000
--- a/doc/release-notes-25574.md
+++ /dev/null
@@ -1,13 +0,0 @@
-Updated settings
-----------------
-
-If the `-checkblocks` or `-checklevel` options are explicitly provided by the
-user, but the verification checks cannot be completed due to an insufficient
-dbcache, Bitcoin Core will now return an error at startup. (#25574)
-
-RPC
----
-The `-verifychain` RPC will now return `false` if the checks didn't fail,
-but couldn't be completed at the desired depth and level. This could be due
-to missing data while pruning, due to an insufficient dbcache or due to
-the node being shutdown before the call could finish. (#25574)
diff --git a/doc/release-notes-25730.md b/doc/release-notes-25730.md
deleted file mode 100644
index 33393cf314..0000000000
--- a/doc/release-notes-25730.md
+++ /dev/null
@@ -1,6 +0,0 @@
-RPC Wallet
-----------
-
-- RPC `listunspent` now has a new argument `include_immature_coinbase`
- to include coinbase UTXOs that don't meet the minimum spendability
- depth requirement (which before were silently skipped). (#25730) \ No newline at end of file
diff --git a/doc/release-notes-25934.md b/doc/release-notes-25934.md
deleted file mode 100644
index b4f1ae0d3c..0000000000
--- a/doc/release-notes-25934.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Low-level changes
-=================
-
-RPC
----
-
-- RPC `listsinceblock` now accepts an optional `label` argument
- to fetch incoming transactions having the specified label. (#25934) \ No newline at end of file
diff --git a/doc/release-notes-25943.md b/doc/release-notes-25943.md
deleted file mode 100644
index 81b0a48b5d..0000000000
--- a/doc/release-notes-25943.md
+++ /dev/null
@@ -1,4 +0,0 @@
-New RPC Argument
---------
-- `sendrawtransaction` has a new, optional argument, `maxburnamount` with a default value of `0`. Any transaction containing an unspendable output with a value greater than `maxburnamount` will not be submitted. At present, the outputs deemed unspendable are those with scripts that begin with an `OP_RETURN` code (known as 'datacarriers'), scripts that exceed the maximum script size, and scripts that contain invalid opcodes.
-
diff --git a/doc/release-notes-25957.md b/doc/release-notes-25957.md
deleted file mode 100644
index c71afa2c2e..0000000000
--- a/doc/release-notes-25957.md
+++ /dev/null
@@ -1,9 +0,0 @@
-Wallet
-------
-
-- Rescans for descriptor wallets are now significantly faster if compact
- block filters (BIP158) are available. Since those are not constructed
- by default, the configuration option "-blockfilterindex=1" has to be
- provided to take advantage of the optimization. This improves the
- performance of the RPC calls `rescanblockchain`, `importdescriptors`
- and `restorewallet`. (#25957)
diff --git a/doc/release-notes-26076.md b/doc/release-notes-26076.md
new file mode 100644
index 0000000000..f95e4be0e3
--- /dev/null
+++ b/doc/release-notes-26076.md
@@ -0,0 +1,13 @@
+RPC
+---
+
+- The `listdescriptors`, `decodepsbt` and similar RPC methods now show `h` rather than apostrophe (`'`) to indicate
+ hardened derivation. This does not apply when using the `private` parameter, which
+ matches the marker used when descriptor was generated or imported. Newly created
+ wallets use `h`. This change makes it easier to handle descriptor strings manually.
+ E.g. the `importdescriptors` RPC call is easiest to use `h` as the marker: `'["desc": ".../0h/..."]'`.
+ With this change `listdescriptors` will use `h`, so you can copy-paste the result,
+ without having to add escape characters or switch `'` to 'h' manually.
+ Note that this changes the descriptor checksum.
+ For legacy wallets the `hdkeypath` field in `getaddressinfo` is unchanged,
+ nor is the serialization format of wallet dumps. (#26076)
diff --git a/doc/release-notes-26094.md b/doc/release-notes-26094.md
new file mode 100644
index 0000000000..ba73f2707e
--- /dev/null
+++ b/doc/release-notes-26094.md
@@ -0,0 +1,6 @@
+- The `getbalances` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
+ hash and height at the time the balances were calculated. This result shouldn't be cached because importing new keys could invalidate it.
+- The `gettransaction` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
+ hash and height at the time the transaction information was generated.
+- The `getwalletinfo` RPC now returns a `lastprocessedblock` JSON object which contains the wallet's last processed block
+ hash and height at the time the wallet information was generated. \ No newline at end of file
diff --git a/doc/release-notes-26213.md b/doc/release-notes-26213.md
deleted file mode 100644
index e78d718ca9..0000000000
--- a/doc/release-notes-26213.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Low-level changes
-=================
-
-- Previously `setban`, `addpeeraddress`, `walletcreatefundedpsbt`, methods
- allowed non-boolean and non-null values to be passed as boolean parameters.
- Any string, number, array, or object value that was passed would be treated
- as false. After this change, passing any value except `true`, `false`, or
- `null` now triggers a JSON value is not of expected type error. (#26213)
diff --git a/doc/release-notes-26265.md b/doc/release-notes-26265.md
deleted file mode 100644
index ca2313d956..0000000000
--- a/doc/release-notes-26265.md
+++ /dev/null
@@ -1,6 +0,0 @@
-P2P and network changes
----------
-
-- Transactions of non-witness size 65 and above are now allowed by mempool
- and relay policy. This is to better reflect the actual afforded protections
- against CVE-2017-12842 and open up additional use-cases of smaller transaction sizes. (#26265)
diff --git a/doc/release-notes-26471.md b/doc/release-notes-26471.md
deleted file mode 100644
index 2cb74804ca..0000000000
--- a/doc/release-notes-26471.md
+++ /dev/null
@@ -1,13 +0,0 @@
-Updated settings
-----------------
-
-- Setting `-blocksonly` will now reduce the maximum mempool memory
- to 5MB (users may still use `-maxmempool` to override). Previously,
- the default 300MB would be used, leading to unexpected memory usage
- for users running with `-blocksonly` expecting it to eliminate
- mempool memory usage.
-
- As unused mempool memory is shared with dbcache, this also reduces
- the dbcache size for users running with `-blocksonly`, potentially
- impacting performance.
-
diff --git a/doc/release-notes-26485.md b/doc/release-notes-26485.md
new file mode 100644
index 0000000000..c8df3d22fb
--- /dev/null
+++ b/doc/release-notes-26485.md
@@ -0,0 +1,16 @@
+JSON-RPC
+---
+
+For RPC methods which accept `options` parameters ((`importmulti`, `listunspent`, `fundrawtransaction`, `bumpfee`, `send`, `sendall`, `walletcreatefundedpsbt`, `simulaterawtransaction`), it is now possible to pass the options as named parameters without the need for a nested object. (#26485)
+
+This means it is possible make calls like:
+
+```sh
+src/bitcoin-cli -named bumpfee txid fee_rate=100
+```
+
+instead of
+
+```sh
+src/bitcoin-cli -named bumpfee txid options='{"fee_rate": 100}'
+```
diff --git a/doc/release-notes-26618.md b/doc/release-notes-26618.md
deleted file mode 100644
index 9d1ef3bd2e..0000000000
--- a/doc/release-notes-26618.md
+++ /dev/null
@@ -1,4 +0,0 @@
-RPC Wallet
-----------
-
-- RPC `unloadwallet` now fails if a rescan is in progress. (#26618)
diff --git a/doc/release-notes-26628.md b/doc/release-notes-26628.md
deleted file mode 100644
index 48a07c1e81..0000000000
--- a/doc/release-notes-26628.md
+++ /dev/null
@@ -1,4 +0,0 @@
-JSON-RPC
----
-
-The JSON-RPC server now rejects requests where a parameter is specified multiple times with the same name, instead of silently overwriting earlier parameter values with later ones. (#26628)
diff --git a/doc/release-notes-26646.md b/doc/release-notes-26646.md
deleted file mode 100644
index 7f94505a01..0000000000
--- a/doc/release-notes-26646.md
+++ /dev/null
@@ -1,8 +0,0 @@
-JSON-RPC
---------
-
-The `testmempoolaccept` RPC now returns 2 additional results within the "fees" result:
-"effective-feerate" is the feerate including fees and sizes of transactions validated together if
-package validation was used, and also includes any modified fees from prioritisetransaction. The
-"effective-includes" result lists the wtxids of transactions whose modified fees and sizes were used
-in the effective-feerate (#26646).
diff --git a/doc/release-notes-26896.md b/doc/release-notes-26896.md
deleted file mode 100644
index ff4ab44e27..0000000000
--- a/doc/release-notes-26896.md
+++ /dev/null
@@ -1,7 +0,0 @@
-Build System
-------------
-
-The --enable-upnp-default and --enable-natpmp-default options
-have been removed. If you want to use port mapping, you can
-configure it using a .conf file, or by passing the relevant
-options at runtime. \ No newline at end of file
diff --git a/doc/release-notes-26899.md b/doc/release-notes-26899.md
deleted file mode 100644
index ceb9ec2f7a..0000000000
--- a/doc/release-notes-26899.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Updated settings
-----------------
-
-- Setting `-maxconnections=0` will now disable `-dnsseed`
- and `-listen` (users may still set them to override). \ No newline at end of file
diff --git a/doc/release-notes-27037.md b/doc/release-notes-27037.md
deleted file mode 100644
index ee30e64010..0000000000
--- a/doc/release-notes-27037.md
+++ /dev/null
@@ -1,5 +0,0 @@
-RPC
----
-
-- `decodescript` may now infer a Miniscript descriptor under P2WSH context if it is not lacking
- information.
diff --git a/doc/release-notes-27068.md b/doc/release-notes-27068.md
deleted file mode 100644
index 3f5c5dba37..0000000000
--- a/doc/release-notes-27068.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Wallet
-------
-
-- Wallet passphrases may now contain null characters.
- Prior to this change, only characters up to the first
- null character were recognized and accepted. (#27068) \ No newline at end of file
diff --git a/doc/release-notes-27302.md b/doc/release-notes-27302.md
new file mode 100644
index 0000000000..e67a6c8b06
--- /dev/null
+++ b/doc/release-notes-27302.md
@@ -0,0 +1,4 @@
+Configuration
+---
+
+- `bitcoind` and `bitcoin-qt` will now raise an error on startup if a datadir that is being used contains a bitcoin.conf file that will be ignored, which can happen when a datadir= line is used in a bitcoin.conf file. The error message is just a diagnostic intended to prevent accidental misconfiguration, and it can be disabled to restore the previous behavior of using the datadir while ignoring the bitcoin.conf contained in it.
diff --git a/doc/release-notes-27501.md b/doc/release-notes-27501.md
new file mode 100644
index 0000000000..386a00fb34
--- /dev/null
+++ b/doc/release-notes-27501.md
@@ -0,0 +1,3 @@
+- A new `getprioritisedtransactions` RPC has been added. It returns a map of all fee deltas created by the
+ user with prioritisetransaction, indexed by txid. The map also indicates whether each transaction is
+ present in the mempool.
diff --git a/doc/release-notes-27632.md b/doc/release-notes-27632.md
new file mode 100644
index 0000000000..d588247c85
--- /dev/null
+++ b/doc/release-notes-27632.md
@@ -0,0 +1,5 @@
+Updated settings
+----------------
+
+- Passing an invalid `-debug`, `-debugexclude`, or `-loglevel` logging configuration
+ option now raises an error, rather than logging an easily missed warning. (#27632)
diff --git a/doc/release-notes-27757.md b/doc/release-notes-27757.md
new file mode 100644
index 0000000000..fb6aaa01a5
--- /dev/null
+++ b/doc/release-notes-27757.md
@@ -0,0 +1,8 @@
+Wallet
+------
+
+- The `deprecatedrpc=walletwarningfield` configuration option has been removed.
+ The `createwallet`, `loadwallet`, `restorewallet` and `unloadwallet` RPCs no
+ longer return the "warning" string field. The same information is provided
+ through the "warnings" field added in v25.0, which returns a JSON array of
+ strings. The "warning" string field was deprecated also in v25.0. (#27757)
diff --git a/doc/release-notes-empty-template.md b/doc/release-notes-empty-template.md
index 4cd2314308..887104548b 100644
--- a/doc/release-notes-empty-template.md
+++ b/doc/release-notes-empty-template.md
@@ -36,7 +36,7 @@ Compatibility
==============
Bitcoin Core is supported and extensively tested on operating systems
-using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+using the Linux kernel, macOS 11.0+, and Windows 7 and newer. Bitcoin
Core should also work on most other Unix-like systems but is not as
frequently tested on them. It is not recommended to use Bitcoin Core on
unsupported systems.
diff --git a/doc/release-notes/release-notes-23.2.md b/doc/release-notes/release-notes-23.2.md
new file mode 100644
index 0000000000..2d6354ae5d
--- /dev/null
+++ b/doc/release-notes/release-notes-23.2.md
@@ -0,0 +1,72 @@
+23.2 Release Notes
+==================
+
+Bitcoin Core version 23.2 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-23.2/>
+
+This release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+### P2P
+
+- #26909 net: prevent peers.dat corruptions by only serializing once
+- #27608 p2p: Avoid prematurely clearing download state for other peers
+- #27610 Improve performance of p2p inv to send queues
+
+### Build system
+
+- #25436 build: suppress array-bounds errors in libxkbcommon
+- #25763 bdb: disable Werror for format-security
+- #26944 depends: fix systemtap download URL
+- #27462 depends: fix compiling bdb with clang-16 on aarch64
+
+### Miscellaneous
+
+- #25444 ci: macOS task imrovements
+- #26388 ci: Use macos-ventura-xcode:14.1 image for "macOS native" task
+- #26924 refactor: Add missing includes to fix gcc-13 compile error
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Anthony Towns
+- Hennadii Stepanov
+- MacroFake
+- Martin Zumsande
+- Michael Ford
+- Suhas Daftuar
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/). \ No newline at end of file
diff --git a/doc/release-notes/release-notes-24.1.md b/doc/release-notes/release-notes-24.1.md
new file mode 100644
index 0000000000..f46434cc43
--- /dev/null
+++ b/doc/release-notes/release-notes-24.1.md
@@ -0,0 +1,99 @@
+24.1 Release Notes
+==================
+
+Bitcoin Core version 24.1 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-24.1/>
+
+This release includes various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+### P2P
+
+- #26878 I2P network optimizations
+- #26909 net: prevent peers.dat corruptions by only serializing once
+- #27608 p2p: Avoid prematurely clearing download state for other peers
+- #27610 Improve performance of p2p inv to send queues
+
+### RPC and other APIs
+
+- #26515 rpc: Require NodeStateStats object in getpeerinfo
+- #27279 doc: fix/improve warning helps in {create,load,unload,restore}wallet
+- #27468 rest: avoid segfault for invalid URI
+
+### Build System
+
+- #26944 depends: fix systemtap download URL
+- #27462 depends: fix compiling bdb with clang-16 on aarch64
+
+### Wallet
+
+- #26595 wallet: be able to specify a wallet name and passphrase to migratewallet
+- #26675 wallet: For feebump, ignore abandoned descendant spends
+- #26679 wallet: Skip rescanning if wallet is more recent than tip
+- #26761 wallet: fully migrate address book entries for watchonly/solvable wallets
+- #27053 wallet: reuse change dest when re-creating TX with avoidpartialspends
+- #27080 wallet: Zero out wallet master key upon locking so it doesn't persist in memory
+- #27473 wallet: Properly handle "unknown" Address Type
+
+### GUI changes
+
+- gui#687 Load PSBTs using istreambuf_iterator rather than istream_iterator
+- gui#704 Correctly limit overview transaction list
+
+### Miscellaneous
+
+- #26880 ci: replace Intel macOS CI job
+- #26924 refactor: Add missing includes to fix gcc-13 compile error
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Andrew Chow
+- Anthony Towns
+- Hennadii Stepanov
+- John Moffett
+- Jon Atack
+- Marco Falke
+- Martin Zumsande
+- Matthew Zipkin
+- Michael Ford
+- pablomartin4btc
+- Sebastian Falbesoner
+- Suhas Daftuar
+- Thomas Nguyen
+- Vasil Dimov
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/). \ No newline at end of file
diff --git a/doc/release-notes/release-notes-25.0.md b/doc/release-notes/release-notes-25.0.md
new file mode 100644
index 0000000000..919cb3b2f3
--- /dev/null
+++ b/doc/release-notes/release-notes-25.0.md
@@ -0,0 +1,340 @@
+25.0 Release Notes
+==================
+
+Bitcoin Core version 25.0 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-25.0/>
+
+This release includes new features, various bug fixes and performance
+improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at GitHub:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.15+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+Notable changes
+===============
+
+P2P and network changes
+-----------------------
+
+- Transactions of non-witness size 65 bytes and above are now allowed by mempool
+ and relay policy. This is to better reflect the actual afforded protections
+ against CVE-2017-12842 and open up additional use-cases of smaller transaction sizes. (#26265)
+
+New RPCs
+--------
+
+- The scanblocks RPC returns the relevant blockhashes from a set of descriptors by
+ scanning all blockfilters in the given range. It can be used in combination with
+ the getblockheader and rescanblockchain RPCs to achieve fast wallet rescans. Note
+ that this functionality can only be used if a compact block filter index
+ (-blockfilterindex=1) has been constructed by the node. (#23549)
+
+Updated RPCs
+------------
+
+- All JSON-RPC methods accept a new [named
+ parameter](https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md#parameter-passing) called `args` that can
+ contain positional parameter values. This is a convenience to allow some
+ parameter values to be passed by name without having to name every value. The
+ python test framework and `bitcoin-cli` tool both take advantage of this, so
+ for example:
+
+```sh
+bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=1
+```
+
+Can now be shortened to:
+
+```sh
+bitcoin-cli -named createwallet mywallet load_on_startup=1
+```
+
+- The `verifychain` RPC will now return `false` if the checks didn't fail,
+ but couldn't be completed at the desired depth and level. This could be due
+ to missing data while pruning, due to an insufficient dbcache or due to
+ the node being shutdown before the call could finish. (#25574)
+
+- `sendrawtransaction` has a new, optional argument, `maxburnamount` with a default value of `0`.
+ Any transaction containing an unspendable output with a value greater than `maxburnamount` will
+ not be submitted. At present, the outputs deemed unspendable are those with scripts that begin
+ with an `OP_RETURN` code (known as 'datacarriers'), scripts that exceed the maximum script size,
+ and scripts that contain invalid opcodes.
+
+- The `testmempoolaccept` RPC now returns 2 additional results within the "fees" result:
+ "effective-feerate" is the feerate including fees and sizes of transactions validated together if
+ package validation was used, and also includes any modified fees from prioritisetransaction. The
+ "effective-includes" result lists the wtxids of transactions whose modified fees and sizes were used
+ in the effective-feerate (#26646).
+
+- `decodescript` may now infer a Miniscript descriptor under P2WSH context if it is not lacking
+ information. (#27037)
+
+- `finalizepsbt` is now able to finalize a transaction with inputs spending Miniscript-compatible
+ P2WSH scripts. (#24149)
+
+Changes to wallet related RPCs can be found in the Wallet section below.
+
+Build System
+------------
+
+- The `--enable-upnp-default` and `--enable-natpmp-default` options
+ have been removed. If you want to use port mapping, you can
+ configure it using a .conf file, or by passing the relevant
+ options at runtime. (#26896)
+
+Updated settings
+----------------
+
+- If the `-checkblocks` or `-checklevel` options are explicitly provided by the
+user, but the verification checks cannot be completed due to an insufficient
+dbcache, Bitcoin Core will now return an error at startup. (#25574)
+
+- Ports specified in `-port` and `-rpcport` options are now validated at startup.
+ Values that previously worked and were considered valid can now result in errors. (#22087)
+
+- Setting `-blocksonly` will now reduce the maximum mempool memory
+ to 5MB (users may still use `-maxmempool` to override). Previously,
+ the default 300MB would be used, leading to unexpected memory usage
+ for users running with `-blocksonly` expecting it to eliminate
+ mempool memory usage.
+
+ As unused mempool memory is shared with dbcache, this also reduces
+ the dbcache size for users running with `-blocksonly`, potentially
+ impacting performance.
+- Setting `-maxconnections=0` will now disable `-dnsseed`
+ and `-listen` (users may still set them to override).
+
+Changes to GUI or wallet related settings can be found in the GUI or Wallet section below.
+
+New settings
+------------
+
+- The `shutdownnotify` option is used to specify a command to execute synchronously
+before Bitcoin Core has begun its shutdown sequence. (#23395)
+
+
+Wallet
+------
+
+- The `minconf` option, which allows a user to specify the minimum number
+of confirmations a UTXO being spent has, and the `maxconf` option,
+which allows specifying the maximum number of confirmations, have been
+added to the following RPCs in #25375:
+ - `fundrawtransaction`
+ - `send`
+ - `walletcreatefundedpsbt`
+ - `sendall`
+
+- Added a new `next_index` field in the response in `listdescriptors` to
+ have the same format as `importdescriptors` (#26194)
+
+- RPC `listunspent` now has a new argument `include_immature_coinbase`
+ to include coinbase UTXOs that don't meet the minimum spendability
+ depth requirement (which before were silently skipped). (#25730)
+
+- Rescans for descriptor wallets are now significantly faster if compact
+ block filters (BIP158) are available. Since those are not constructed
+ by default, the configuration option "-blockfilterindex=1" has to be
+ provided to take advantage of the optimization. This improves the
+ performance of the RPC calls `rescanblockchain`, `importdescriptors`
+ and `restorewallet`. (#25957)
+
+- RPC `unloadwallet` now fails if a rescan is in progress. (#26618)
+
+- Wallet passphrases may now contain null characters.
+ Prior to this change, only characters up to the first
+ null character were recognized and accepted. (#27068)
+
+- Address Purposes strings are now restricted to the currently known values of "send",
+ "receive", and "refund". Wallets that have unrecognized purpose strings will have
+ loading warnings, and the `listlabels` RPC will raise an error if an unrecognized purpose
+ is requested. (#27217)
+
+- In the `createwallet`, `loadwallet`, `unloadwallet`, and `restorewallet` RPCs, the
+ "warning" string field is deprecated in favor of a "warnings" field that
+ returns a JSON array of strings to better handle multiple warning messages and
+ for consistency with other wallet RPCs. The "warning" field will be fully
+ removed from these RPCs in v26. It can be temporarily re-enabled during the
+ deprecation period by launching bitcoind with the configuration option
+ `-deprecatedrpc=walletwarningfield`. (#27279)
+
+- Descriptor wallets can now spend coins sent to P2WSH Miniscript descriptors. (#24149)
+
+GUI changes
+-----------
+
+- The "Mask values" is a persistent option now. (gui#701)
+- The "Mask values" option affects the "Transaction" view now, in addition to the
+ "Overview" one. (gui#708)
+
+REST
+----
+
+- A new `/rest/deploymentinfo` endpoint has been added for fetching various
+ state info regarding deployments of consensus changes. (#25412)
+
+Binary verification
+----
+
+- The binary verification script has been updated. In previous releases it
+ would verify that the binaries had been signed with a single "release key".
+ In this release and moving forward it will verify that the binaries are
+ signed by a _threshold of trusted keys_. For more details and
+ examples, see:
+ https://github.com/bitcoin/bitcoin/blob/master/contrib/verify-binaries/README.md
+ (#27358)
+
+Low-level changes
+=================
+
+RPC
+---
+
+- The JSON-RPC server now rejects requests where a parameter is specified multiple
+ times with the same name, instead of silently overwriting earlier parameter values
+ with later ones. (#26628)
+- RPC `listsinceblock` now accepts an optional `label` argument
+ to fetch incoming transactions having the specified label. (#25934)
+- Previously `setban`, `addpeeraddress`, `walletcreatefundedpsbt`, methods
+ allowed non-boolean and non-null values to be passed as boolean parameters.
+ Any string, number, array, or object value that was passed would be treated
+ as false. After this change, passing any value except `true`, `false`, or
+ `null` now triggers a JSON value is not of expected type error. (#26213)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 0xb10c
+- 721217.xyz
+- @RandyMcMillan
+- amadeuszpawlik
+- Amiti Uttarwar
+- Andrew Chow
+- Andrew Toth
+- Anthony Towns
+- Antoine Poinsot
+- Aurèle Oulès
+- Ben Woosley
+- Bitcoin Hodler
+- brunoerg
+- Bushstar
+- Carl Dong
+- Chris Geihsler
+- Cory Fields
+- David Gumberg
+- dergoegge
+- Dhruv Mehta
+- Dimitris Tsapakidis
+- dougEfish
+- Douglas Chimento
+- ekzyis
+- Elichai Turkel
+- Ethan Heilman
+- Fabian Jahr
+- FractalEncrypt
+- furszy
+- Gleb Naumenko
+- glozow
+- Greg Sanders
+- Hennadii Stepanov
+- hernanmarino
+- ishaanam
+- ismaelsadeeq
+- James O'Beirne
+- jdjkelly@gmail.com
+- Jeff Ruane
+- Jeffrey Czyz
+- Jeremy Rubin
+- Jesse Barton
+- João Barbosa
+- JoaoAJMatos
+- John Moffett
+- Jon Atack
+- Jonas Schnelli
+- jonatack
+- Joshua Kelly
+- josibake
+- Juan Pablo Civile
+- kdmukai
+- klementtan
+- Kolby ML
+- kouloumos
+- Kristaps Kaupe
+- laanwj
+- Larry Ruane
+- Leonardo Araujo
+- Leonardo Lazzaro
+- Luke Dashjr
+- MacroFake
+- MarcoFalke
+- Martin Leitner-Ankerl
+- Martin Zumsande
+- Matt Whitlock
+- Matthew Zipkin
+- Michael Ford
+- Miles Liu
+- mruddy
+- Murray Nesbitt
+- muxator
+- omahs
+- pablomartin4btc
+- Pasta
+- Pieter Wuille
+- Pttn
+- Randall Naar
+- Riahiamirreza
+- roconnor-blockstream
+- Russell O'Connor
+- Ryan Ofsky
+- S3RK
+- Sebastian Falbesoner
+- Seibart Nedor
+- sinetek
+- Sjors Provoost
+- Skuli Dulfari
+- SomberNight
+- Stacie Waleyko
+- stickies-v
+- stratospher
+- Suhas Daftuar
+- Suriyaa Sundararuban
+- TheCharlatan
+- Vasil Dimov
+- Vasil Stoyanov
+- virtu
+- w0xlt
+- willcl-ark
+- yancy
+- Yusuf Sahin HAMZA
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/). \ No newline at end of file
diff --git a/doc/release-process.md b/doc/release-process.md
index f1fd72f8ac..930110922c 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -29,7 +29,7 @@ Release Process
#### Before branch-off
* Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example.
-* Update the following variables in [`src/chainparams.cpp`](/src/chainparams.cpp) for mainnet, testnet, and signet:
+* Update the following variables in [`src/kernel/chainparams.cpp`](/src/kernel/chainparams.cpp) for mainnet, testnet, and signet:
- `m_assumed_blockchain_size` and `m_assumed_chain_state_size` with the current size plus some overhead (see
[this](#how-to-calculate-assumed-blockchain-and-chain-state-size) for information on how to calculate them).
- The following updates should be reviewed with `reindex-chainstate` and `assumevalid=0` to catch any defect
@@ -60,6 +60,8 @@ Release Process
- Create a pinned meta-issue for testing the release candidate (see [this issue](https://github.com/bitcoin/bitcoin/issues/17079) for an example) and provide a link to it in the release announcements where useful.
- Translations on Transifex
- Change the auto-update URL for the new major version's resource away from `master` and to the branch, e.g. `https://raw.githubusercontent.com/bitcoin/bitcoin/<branch>/src/qt/locale/bitcoin_en.xlf`. Do not forget this or it will keep tracking the translations on master instead, drifting away from the specific major release.
+- Prune inputs from the qa-assets repo (See [pruning
+ inputs](https://github.com/bitcoin-core/qa-assets#pruning-inputs)).
#### Before final release
@@ -98,7 +100,7 @@ Generate the change log. As this is a huge amount of work to do manually, there
Generate list of authors:
- git log --format='- %aN' v(current version, e.g. 0.20.0)..v(new version, e.g. 0.20.1) | sort -fiu
+ git log --format='- %aN' v(current version, e.g. 24.0)..v(new version, e.g. 24.1) | sort -fiu
### Setup and perform Guix builds
@@ -107,7 +109,7 @@ Checkout the Bitcoin Core version you'd like to build:
```sh
pushd ./bitcoin
SIGNER='(your builder key, ie bluematt, sipa, etc)'
-VERSION='(new version without v-prefix, e.g. 0.20.0)'
+VERSION='(new version without v-prefix, e.g. 24.0)'
git fetch origin "v${VERSION}"
git checkout "v${VERSION}"
popd
@@ -282,7 +284,7 @@ cat "$VERSION"/*/all.SHA256SUMS.asc > SHA256SUMS.asc
- Push the flatpak to flathub, e.g. https://github.com/flathub/org.bitcoincore.bitcoin-qt/pull/2
- - Push the snap, see https://github.com/bitcoin-core/packaging/blob/master/snap/build.md
+ - Push the snap, see https://github.com/bitcoin-core/packaging/blob/main/snap/local/build.md
- This repo
diff --git a/doc/tor.md b/doc/tor.md
index 08d031d084..65aa3ece02 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -2,9 +2,7 @@
It is possible to run Bitcoin Core as a Tor onion service, and connect to such services.
-The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on port 9150. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly
-configure Tor.
-
+The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on port 9150.
## Compatibility
- Starting with version 22.0, Bitcoin Core only supports Tor version 3 hidden
@@ -27,8 +25,7 @@ CLI `-addrinfo` returns the number of addresses known to your node per
network. This can be useful to see how many onion peers your node knows,
e.g. for `-onlynet=onion`.
-To fetch a number of onion addresses that your node knows, for example seven
-addresses, use the `getnodeaddresses 7 onion` RPC.
+You can use the `getnodeaddresses` RPC to fetch a number of onion peers known to your node; run `bitcoin-cli help getnodeaddresses` for details.
## 1. Run Bitcoin Core behind a Tor proxy
@@ -92,19 +89,13 @@ out by default (if not, add them):
ControlPort 9051
CookieAuthentication 1
CookieAuthFileGroupReadable 1
+DataDirectoryGroupReadable 1
```
Add or uncomment those, save, and restart Tor (usually `systemctl restart tor`
or `sudo systemctl restart tor` on most systemd-based systems, including recent
Debian and Ubuntu, or just restart the computer).
-On some systems (such as Arch Linux), you may also need to add the following
-line:
-
-```
-DataDirectoryGroupReadable 1
-```
-
### Authentication
Connecting to Tor's control socket API requires one of two authentication
diff --git a/doc/tracing.md b/doc/tracing.md
index d26cf52fc3..0e3414205a 100644
--- a/doc/tracing.md
+++ b/doc/tracing.md
@@ -220,7 +220,7 @@ about the transaction.
Arguments passed:
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
-2. Transaction virtual size as `uint64`
+2. Transaction virtual size as `int32`
3. Transaction fee as `int64`
#### Tracepoint `mempool:removed`
@@ -231,7 +231,7 @@ about the transaction.
Arguments passed:
1. Transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
2. Removal reason as `pointer to C-style String` (max. length 9 characters)
-3. Transaction virtual size as `uint64`
+3. Transaction virtual size as `int32`
4. Transaction fee as `int64`
5. Transaction mempool entry time (epoch) as `uint64`
@@ -242,11 +242,11 @@ Passes information about the replaced and replacement transactions.
Arguments passed:
1. Replaced transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
-2. Replaced transaction virtual size as `uint64`
+2. Replaced transaction virtual size as `int32`
3. Replaced transaction fee as `int64`
4. Replaced transaction mempool entry time (epoch) as `uint64`
5. Replacement transaction ID (hash) as `pointer to unsigned chars` (i.e. 32 bytes in little-endian)
-6. Replacement transaction virtual size as `uint64`
+6. Replacement transaction virtual size as `int32`
7. Replacement transaction fee as `int64`
Note: In cases where a single replacement transaction replaces multiple
diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in
index 053359e0a8..b4e6f6a150 100644
--- a/share/qt/Info.plist.in
+++ b/share/qt/Info.plist.in
@@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>LSMinimumSystemVersion</key>
- <string>10.15.0</string>
+ <string>11</string>
<key>LSArchitecturePriority</key>
<array>
diff --git a/src/.clang-tidy b/src/.clang-tidy
index b2c1b49588..39566c0cb7 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -5,10 +5,11 @@ bugprone-use-after-move,
misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
-performance-for-range-copy,
-performance-move-const-arg,
-performance-no-automatic-move,
-performance-unnecessary-copy-initialization,
+performance-*,
+-performance-inefficient-string-concatenation,
+-performance-no-int-to-ptr,
+-performance-noexcept-move-constructor,
+-performance-unnecessary-value-param,
readability-const-return-type,
readability-redundant-declaration,
readability-redundant-string-init,
diff --git a/src/Makefile.am b/src/Makefile.am
index 53c809c901..b4ff556eb6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -133,6 +133,7 @@ BITCOIN_CORE_H = \
checkqueue.h \
clientversion.h \
coins.h \
+ common/args.h \
common/bloom.h \
common/init.h \
common/run_command.h \
@@ -142,6 +143,8 @@ BITCOIN_CORE_H = \
compat/compat.h \
compat/cpuid.h \
compat/endian.h \
+ common/settings.h \
+ common/system.h \
compressor.h \
consensus/consensus.h \
consensus/tx_check.h \
@@ -154,7 +157,6 @@ BITCOIN_CORE_H = \
deploymentstatus.h \
external_signer.h \
flatfile.h \
- fs.h \
headerssync.h \
httprpc.h \
httpserver.h \
@@ -186,6 +188,7 @@ BITCOIN_CORE_H = \
kernel/mempool_limits.h \
kernel/mempool_options.h \
kernel/mempool_persist.h \
+ kernel/notifications_interface.h \
kernel/validation_cache_sizes.h \
key.h \
key_io.h \
@@ -214,9 +217,11 @@ BITCOIN_CORE_H = \
node/database_args.h \
node/eviction.h \
node/interface_ui.h \
+ node/kernel_notifications.h \
node/mempool_args.h \
node/mempool_persist_args.h \
node/miner.h \
+ node/mini_miner.h \
node/minisketchwrapper.h \
node/psbt.h \
node/transaction.h \
@@ -261,6 +266,7 @@ BITCOIN_CORE_H = \
shutdown.h \
signet.h \
streams.h \
+ support/allocators/pool.h \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
support/cleanse.h \
@@ -275,20 +281,26 @@ BITCOIN_CORE_H = \
txorphanage.h \
txrequest.h \
undo.h \
+ util/any.h \
util/asmap.h \
+ util/batchpriority.h \
util/bip32.h \
util/bitdeque.h \
util/bytevectorhash.h \
+ util/chaintype.h \
util/check.h \
util/epochguard.h \
util/error.h \
util/exception.h \
util/fastrange.h \
util/fees.h \
+ util/fs.h \
+ util/fs_helpers.h \
util/getuniquepath.h \
util/golombrice.h \
util/hash_type.h \
util/hasher.h \
+ util/insert.h \
util/macros.h \
util/message.h \
util/moneystr.h \
@@ -298,13 +310,11 @@ BITCOIN_CORE_H = \
util/readwritefile.h \
util/result.h \
util/serfloat.h \
- util/settings.h \
util/sock.h \
util/spanparsing.h \
util/string.h \
util/syscall_sandbox.h \
util/syserror.h \
- util/system.h \
util/thread.h \
util/threadinterrupt.h \
util/threadnames.h \
@@ -328,7 +338,6 @@ BITCOIN_CORE_H = \
wallet/external_signer_scriptpubkeyman.h \
wallet/feebumper.h \
wallet/fees.h \
- wallet/ismine.h \
wallet/load.h \
wallet/receive.h \
wallet/rpc/util.h \
@@ -338,6 +347,7 @@ BITCOIN_CORE_H = \
wallet/spend.h \
wallet/sqlite.h \
wallet/transaction.h \
+ wallet/types.h \
wallet/wallet.h \
wallet/walletdb.h \
wallet/wallettool.h \
@@ -353,7 +363,7 @@ BITCOIN_CORE_H = \
obj/build.h: FORCE
@$(MKDIR_P) $(builddir)/obj
- @$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \
+ $(AM_V_GEN) $(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \
"$(abs_top_srcdir)"
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
@@ -403,9 +413,11 @@ libbitcoin_node_a_SOURCES = \
node/eviction.cpp \
node/interface_ui.cpp \
node/interfaces.cpp \
+ node/kernel_notifications.cpp \
node/mempool_args.cpp \
node/mempool_persist_args.cpp \
node/miner.cpp \
+ node/mini_miner.cpp \
node/minisketchwrapper.cpp \
node/psbt.cpp \
node/transaction.cpp \
@@ -645,10 +657,14 @@ libbitcoin_common_a_SOURCES = \
bech32.cpp \
chainparams.cpp \
coins.cpp \
+ common/args.cpp \
common/bloom.cpp \
+ common/config.cpp \
common/init.cpp \
common/interfaces.cpp \
common/run_command.cpp \
+ common/settings.cpp \
+ common/system.cpp \
compressor.cpp \
core_read.cpp \
core_write.cpp \
@@ -694,29 +710,30 @@ libbitcoin_util_a_SOURCES = \
support/lockedpool.cpp \
chainparamsbase.cpp \
clientversion.cpp \
- fs.cpp \
logging.cpp \
random.cpp \
randomenv.cpp \
support/cleanse.cpp \
sync.cpp \
util/asmap.cpp \
+ util/batchpriority.cpp \
util/bip32.cpp \
util/bytevectorhash.cpp \
+ util/chaintype.cpp \
util/check.cpp \
util/error.cpp \
util/exception.cpp \
util/fees.cpp \
+ util/fs.cpp \
+ util/fs_helpers.cpp \
util/getuniquepath.cpp \
util/hasher.cpp \
util/sock.cpp \
util/syserror.cpp \
- util/system.cpp \
util/message.cpp \
util/moneystr.cpp \
util/rbf.cpp \
util/readwritefile.cpp \
- util/settings.cpp \
util/thread.cpp \
util/threadinterrupt.cpp \
util/threadnames.cpp \
@@ -895,8 +912,6 @@ libbitcoinkernel_la_SOURCES = \
kernel/bitcoinkernel.cpp \
arith_uint256.cpp \
chain.cpp \
- chainparamsbase.cpp \
- chainparams.cpp \
clientversion.cpp \
coins.cpp \
compressor.cpp \
@@ -908,7 +923,6 @@ libbitcoinkernel_la_SOURCES = \
deploymentinfo.cpp \
deploymentstatus.cpp \
flatfile.cpp \
- fs.cpp \
hash.cpp \
kernel/chain.cpp \
kernel/checks.cpp \
@@ -949,19 +963,21 @@ libbitcoinkernel_la_SOURCES = \
txdb.cpp \
txmempool.cpp \
uint256.cpp \
+ util/batchpriority.cpp \
+ util/chaintype.cpp \
util/check.cpp \
util/exception.cpp \
+ util/fs.cpp \
+ util/fs_helpers.cpp \
util/getuniquepath.cpp \
util/hasher.cpp \
util/moneystr.cpp \
util/rbf.cpp \
util/serfloat.cpp \
- util/settings.cpp \
util/strencodings.cpp \
util/string.cpp \
util/syscall_sandbox.cpp \
util/syserror.cpp \
- util/system.cpp \
util/thread.cpp \
util/threadnames.cpp \
util/time.cpp \
@@ -1037,7 +1053,7 @@ clean-local:
-rm -rf test/__pycache__
.rc.o:
- @test -f $(WINDRES)
+ @test -f $(WINDRES) || (echo "windres $(WINDRES) not found, but is required to compile windows resource files"; exit 1)
## FIXME: How to get the appropriate modulename_CPPFLAGS in here?
$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@
@@ -1092,12 +1108,11 @@ endif
%.raw.h: %.raw
@$(MKDIR_P) $(@D)
- @{ \
+ $(AM_V_GEN) { \
echo "static unsigned const char $(*F)_raw[] = {" && \
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
echo "};"; \
} > "$@.new" && mv -f "$@.new" "$@"
- @echo "Generated $@"
include Makefile.minisketch.include
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index f1e4e706a1..10c8389c80 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -18,6 +18,7 @@ bench_bench_bitcoin_SOURCES = \
bench/bench.cpp \
bench/bench.h \
bench/bench_bitcoin.cpp \
+ bench/bip324_ecdh.cpp \
bench/block_assemble.cpp \
bench/ccoins_caching.cpp \
bench/chacha20.cpp \
@@ -29,6 +30,7 @@ bench_bench_bitcoin_SOURCES = \
bench/data.h \
bench/descriptors.cpp \
bench/duplicate_inputs.cpp \
+ bench/ellswift.cpp \
bench/examples.cpp \
bench/gcs_filter.cpp \
bench/hashpadding.cpp \
@@ -42,10 +44,12 @@ bench_bench_bitcoin_SOURCES = \
bench/nanobench.h \
bench/peer_eviction.cpp \
bench/poly1305.cpp \
+ bench/pool.cpp \
bench/prevector.cpp \
bench/rollingbloom.cpp \
bench/rpc_blockchain.cpp \
bench/rpc_mempool.cpp \
+ bench/streams_findbyte.cpp \
bench/strencodings.cpp \
bench/util_time.cpp \
bench/verify_script.cpp
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 602a118259..7852d1a2fa 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -371,13 +371,13 @@ translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCO
@rm -f $(srcdir)/qt/locale/bitcoin_en.xlf.old
$(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM)
- @test -f $(RCC)
+ @test -f $(RCC) || (echo "rcc $(RCC) not found, but is required for generating qrc cpp files"; exit 1)
@cp -f $< $(@D)/temp_$(<F)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin_locale --format-version 1 $(@D)/temp_$(<F) > $@
@rm $(@D)/temp_$(<F)
$(QT_QRC_CPP): $(QT_QRC) $(QT_FORMS_H) $(QT_RES_FONTS) $(QT_RES_ICONS) $(QT_RES_ANIMATION)
- @test -f $(RCC)
+ @test -f $(RCC) || (echo "rcc $(RCC) not found, but is required for generating qrc cpp files"; exit 1)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(RCC) -name bitcoin --format-version 1 $< > $@
CLEAN_QT = $(nodist_qt_libbitcoinqt_a_SOURCES) $(QT_QM) $(QT_FORMS_H) qt/*.gcda qt/*.gcno qt/temp_bitcoin_locale.qrc
@@ -404,7 +404,7 @@ bitcoin_qt_apk: FORCE
cd qt/android && ./gradlew build
ui_%.h: %.ui
- @test -f $(UIC)
+ @test -f $(UIC) || (echo "uic $(UIC) not found, but is required for generating ui headers"; exit 1)
@$(MKDIR_P) $(@D)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false)
@@ -415,6 +415,6 @@ moc_%.cpp: %.h
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< > $@
%.qm: %.ts
- @test -f $(LRELEASE)
+ @test -f $(LRELEASE) || (echo "lrelease $(LRELEASE) not found, but is required for generating translations"; exit 1)
@$(MKDIR_P) $(@D)
$(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index a39b0abd9d..224f1fe301 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -106,6 +106,7 @@ BITCOIN_TESTS =\
test/merkle_tests.cpp \
test/merkleblock_tests.cpp \
test/miner_tests.cpp \
+ test/miniminer_tests.cpp \
test/miniscript_tests.cpp \
test/minisketch_tests.cpp \
test/multisig_tests.cpp \
@@ -116,6 +117,7 @@ BITCOIN_TESTS =\
test/pmt_tests.cpp \
test/policy_fee_tests.cpp \
test/policyestimator_tests.cpp \
+ test/pool_tests.cpp \
test/pow_tests.cpp \
test/prevector_tests.cpp \
test/raii_event_tests.cpp \
@@ -192,7 +194,9 @@ BITCOIN_TESTS += wallet/test/db_tests.cpp
endif
FUZZ_WALLET_SRC = \
+ wallet/test/fuzz/coincontrol.cpp \
wallet/test/fuzz/coinselection.cpp \
+ wallet/test/fuzz/fees.cpp \
wallet/test/fuzz/parse_iso8601.cpp
if USE_SQLITE
@@ -272,6 +276,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/flatfile.cpp \
test/fuzz/float.cpp \
test/fuzz/golomb_rice.cpp \
+ test/fuzz/headerssync.cpp \
test/fuzz/hex.cpp \
test/fuzz/http_request.cpp \
test/fuzz/i2p.cpp \
@@ -285,6 +290,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/message.cpp \
test/fuzz/miniscript.cpp \
test/fuzz/minisketch.cpp \
+ test/fuzz/mini_miner.cpp \
test/fuzz/muhash.cpp \
test/fuzz/multiplication_overflow.cpp \
test/fuzz/net.cpp \
@@ -300,6 +306,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/partially_downloaded_block.cpp \
test/fuzz/policy_estimator.cpp \
test/fuzz/policy_estimator_io.cpp \
+ test/fuzz/poolresource.cpp \
test/fuzz/pow.cpp \
test/fuzz/prevector.cpp \
test/fuzz/primitives_transaction.cpp \
@@ -341,6 +348,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/txorphan.cpp \
test/fuzz/txrequest.cpp \
test/fuzz/utxo_snapshot.cpp \
+ test/fuzz/utxo_total_supply.cpp \
test/fuzz/validation_load_mempool.cpp \
test/fuzz/versionbits.cpp
endif # ENABLE_FUZZ_BINARY
@@ -418,10 +426,9 @@ endif
%.json.h: %.json
@$(MKDIR_P) $(@D)
- @{ \
+ $(AM_V_GEN) { \
echo "namespace json_tests{" && \
echo "static unsigned const char $(*F)[] = {" && \
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
echo "};};"; \
} > "$@.new" && mv -f "$@.new" "$@"
- @echo "Generated $@"
diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include
index aefefe789a..11b93ad13e 100644
--- a/src/Makefile.test_util.include
+++ b/src/Makefile.test_util.include
@@ -15,6 +15,7 @@ TEST_UTIL_H = \
test/util/logging.h \
test/util/mining.h \
test/util/net.h \
+ test/util/poolresourcetester.h \
test/util/random.h \
test/util/script.h \
test/util/setup_common.h \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 9ae8244d1c..cb1c49050e 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -8,8 +8,9 @@
#include <addrman.h>
#include <chainparams.h>
#include <clientversion.h>
+#include <common/args.h>
+#include <common/settings.h>
#include <cstdint>
-#include <fs.h>
#include <hash.h>
#include <logging.h>
#include <logging/timer.h>
@@ -19,8 +20,8 @@
#include <streams.h>
#include <tinyformat.h>
#include <univalue.h>
-#include <util/settings.h>
-#include <util/system.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/translation.h>
namespace {
@@ -131,7 +132,7 @@ CBanDB::CBanDB(fs::path ban_list_path)
bool CBanDB::Write(const banmap_t& banSet)
{
std::vector<std::string> errors;
- if (util::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
+ if (common::WriteSettings(m_banlist_json, {{JSON_KEY, BanMapToJson(banSet)}}, errors)) {
return true;
}
@@ -151,10 +152,10 @@ bool CBanDB::Read(banmap_t& banSet)
return false;
}
- std::map<std::string, util::SettingsValue> settings;
+ std::map<std::string, common::SettingsValue> settings;
std::vector<std::string> errors;
- if (!util::ReadSettings(m_banlist_json, settings, errors)) {
+ if (!common::ReadSettings(m_banlist_json, settings, errors)) {
for (const auto& err : errors) {
LogPrintf("Cannot load banlist %s: %s\n", fs::PathToString(m_banlist_json), err);
}
@@ -182,10 +183,10 @@ void ReadFromStream(AddrMan& addr, CDataStream& ssPeers)
DeserializeDB(ssPeers, addr, false);
}
-std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
+util::Result<std::unique_ptr<AddrMan>> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args)
{
auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
- addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ auto addrman{std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman)};
const auto start{SteadyClock::now()};
const auto path_addr{args.GetDataDirNet() / "peers.dat"};
@@ -199,19 +200,18 @@ std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, con
DumpPeerAddresses(args, *addrman);
} catch (const InvalidAddrManVersionError&) {
if (!RenameOver(path_addr, (fs::path)path_addr + ".bak")) {
- addrman = nullptr;
- return strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."));
+ return util::Error{strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."))};
}
// Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
LogPrintf("Creating new peers.dat because the file version was not compatible (%s). Original backed up to peers.dat.bak\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const std::exception& e) {
- addrman = nullptr;
- return strprintf(_("Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start."),
- e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr)));
+ return util::Error{strprintf(_("Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start."),
+ e.what(), PACKAGE_BUGREPORT, fs::quoted(fs::PathToString(path_addr)))};
}
- return std::nullopt;
+ return {std::move(addrman)}; // std::move should be unneccessary but is temporarily needed to work around clang bug
+ // (https://github.com/bitcoin/bitcoin/pull/25977#issuecomment-1561270092)
}
void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors)
diff --git a/src/addrdb.h b/src/addrdb.h
index 627ef3ac3c..0037495d18 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_ADDRDB_H
#define BITCOIN_ADDRDB_H
-#include <fs.h>
-#include <net_types.h> // For banmap_t
-#include <univalue.h>
+#include <net_types.h>
+#include <util/fs.h>
+#include <util/result.h>
-#include <optional>
+#include <memory>
#include <vector>
class ArgsManager;
@@ -18,7 +18,6 @@ class AddrMan;
class CAddress;
class CDataStream;
class NetGroupManager;
-struct bilingual_str;
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr);
/** Only used by tests. */
@@ -49,7 +48,7 @@ public:
};
/** Returns an error string on failure */
-std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman);
+util::Result<std::unique_ptr<AddrMan>> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args);
/**
* Dump the anchor IP address database (anchors.dat)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index f5ca9a5c34..cdfd079fcd 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -58,9 +58,9 @@ int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGr
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
-int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) const
+int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int bucket) const
{
- uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << nBucket << GetKey()).GetCheapHash();
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << (fNew ? uint8_t{'N'} : uint8_t{'K'}) << bucket << GetKey()).GetCheapHash();
return hash1 % ADDRMAN_BUCKET_SIZE;
}
@@ -714,72 +714,98 @@ void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds
}
}
-std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::optional<Network> network) const
{
AssertLockHeld(cs);
if (vRandom.empty()) return {};
- if (newOnly && nNew == 0) return {};
-
- // Use a 50% chance for choosing between tried and new table entries.
- if (!newOnly &&
- (nTried > 0 && (nNew == 0 || insecure_rand.randbool() == 0))) {
- // use a tried node
- double fChanceFactor = 1.0;
- while (1) {
- // Pick a tried bucket, and an initial position in that bucket.
- int nKBucket = insecure_rand.randrange(ADDRMAN_TRIED_BUCKET_COUNT);
- int nKBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
- // Iterate over the positions of that bucket, starting at the initial one,
- // and looping around.
- int i;
- for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
- if (vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
- }
- // If the bucket is entirely empty, start over with a (likely) different one.
- if (i == ADDRMAN_BUCKET_SIZE) continue;
- // Find the entry to return.
- int nId = vvTried[nKBucket][(nKBucketPos + i) % ADDRMAN_BUCKET_SIZE];
- const auto it_found{mapInfo.find(nId)};
- assert(it_found != mapInfo.end());
- const AddrInfo& info{it_found->second};
- // With probability GetChance() * fChanceFactor, return the entry.
- if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
- LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToStringAddrPort());
- return {info, info.m_last_try};
- }
- // Otherwise start over with a (likely) different bucket, and increased chance factor.
- fChanceFactor *= 1.2;
- }
+ size_t new_count = nNew;
+ size_t tried_count = nTried;
+
+ if (network.has_value()) {
+ auto it = m_network_counts.find(*network);
+ if (it == m_network_counts.end()) return {};
+
+ auto counts = it->second;
+ new_count = counts.n_new;
+ tried_count = counts.n_tried;
+ }
+
+ if (new_only && new_count == 0) return {};
+ if (new_count + tried_count == 0) return {};
+
+ // Decide if we are going to search the new or tried table
+ // If either option is viable, use a 50% chance to choose
+ bool search_tried;
+ if (new_only || tried_count == 0) {
+ search_tried = false;
+ } else if (new_count == 0) {
+ search_tried = true;
} else {
- // use a new node
- double fChanceFactor = 1.0;
- while (1) {
- // Pick a new bucket, and an initial position in that bucket.
- int nUBucket = insecure_rand.randrange(ADDRMAN_NEW_BUCKET_COUNT);
- int nUBucketPos = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
- // Iterate over the positions of that bucket, starting at the initial one,
- // and looping around.
- int i;
- for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
- if (vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE] != -1) break;
- }
- // If the bucket is entirely empty, start over with a (likely) different one.
- if (i == ADDRMAN_BUCKET_SIZE) continue;
- // Find the entry to return.
- int nId = vvNew[nUBucket][(nUBucketPos + i) % ADDRMAN_BUCKET_SIZE];
- const auto it_found{mapInfo.find(nId)};
- assert(it_found != mapInfo.end());
- const AddrInfo& info{it_found->second};
- // With probability GetChance() * fChanceFactor, return the entry.
- if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
- LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToStringAddrPort());
- return {info, info.m_last_try};
+ search_tried = insecure_rand.randbool();
+ }
+
+ const int bucket_count{search_tried ? ADDRMAN_TRIED_BUCKET_COUNT : ADDRMAN_NEW_BUCKET_COUNT};
+
+ // Loop through the addrman table until we find an appropriate entry
+ double chance_factor = 1.0;
+ while (1) {
+ // Pick a bucket, and an initial position in that bucket.
+ int bucket = insecure_rand.randrange(bucket_count);
+ int initial_position = insecure_rand.randrange(ADDRMAN_BUCKET_SIZE);
+
+ // Iterate over the positions of that bucket, starting at the initial one,
+ // and looping around.
+ int i;
+ for (i = 0; i < ADDRMAN_BUCKET_SIZE; ++i) {
+ int position = (initial_position + i) % ADDRMAN_BUCKET_SIZE;
+ int node_id = GetEntry(search_tried, bucket, position);
+ if (node_id != -1) {
+ if (network.has_value()) {
+ const auto it{mapInfo.find(node_id)};
+ assert(it != mapInfo.end());
+ const auto info{it->second};
+ if (info.GetNetwork() == *network) break;
+ } else {
+ break;
+ }
}
- // Otherwise start over with a (likely) different bucket, and increased chance factor.
- fChanceFactor *= 1.2;
}
+
+ // If the bucket is entirely empty, start over with a (likely) different one.
+ if (i == ADDRMAN_BUCKET_SIZE) continue;
+
+ // Find the entry to return.
+ int position = (initial_position + i) % ADDRMAN_BUCKET_SIZE;
+ int nId = GetEntry(search_tried, bucket, position);
+ const auto it_found{mapInfo.find(nId)};
+ assert(it_found != mapInfo.end());
+ const AddrInfo& info{it_found->second};
+
+ // With probability GetChance() * chance_factor, return the entry.
+ if (insecure_rand.randbits(30) < chance_factor * info.GetChance() * (1 << 30)) {
+ LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");
+ return {info, info.m_last_try};
+ }
+
+ // Otherwise start over with a (likely) different bucket, and increased chance factor.
+ chance_factor *= 1.2;
+ }
+}
+
+int AddrManImpl::GetEntry(bool use_tried, size_t bucket, size_t position) const
+{
+ AssertLockHeld(cs);
+
+ assert(position < ADDRMAN_BUCKET_SIZE);
+
+ if (use_tried) {
+ assert(bucket < ADDRMAN_TRIED_BUCKET_COUNT);
+ return vvTried[bucket][position];
+ } else {
+ assert(bucket < ADDRMAN_NEW_BUCKET_COUNT);
+ return vvNew[bucket][position];
}
}
@@ -1164,11 +1190,11 @@ std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision()
return ret;
}
-std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, std::optional<Network> network) const
{
LOCK(cs);
Check();
- auto addrRet = Select_(newOnly);
+ auto addrRet = Select_(new_only, network);
Check();
return addrRet;
}
@@ -1262,9 +1288,9 @@ std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision()
return m_impl->SelectTriedCollision();
}
-std::pair<CAddress, NodeSeconds> AddrMan::Select(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, std::optional<Network> network) const
{
- return m_impl->Select(newOnly);
+ return m_impl->Select(new_only, network);
}
std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
diff --git a/src/addrman.h b/src/addrman.h
index 4985fc764c..6284b80a52 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -146,11 +146,14 @@ public:
/**
* Choose an address to connect to.
*
- * @param[in] newOnly Whether to only select addresses from the new table.
+ * @param[in] new_only Whether to only select addresses from the new table. Passing `true` returns
+ * an address from the new table or an empty pair. Passing `false` will return an
+ * address from either the new or tried table (it does not guarantee a tried entry).
+ * @param[in] network Select only addresses of this network (nullopt = all)
* @return CAddress The record for the selected peer.
* seconds The last time we attempted to connect to that peer.
*/
- std::pair<CAddress, NodeSeconds> Select(bool newOnly = false) const;
+ std::pair<CAddress, NodeSeconds> Select(bool new_only = false, std::optional<Network> network = std::nullopt) const;
/**
* Return all or many randomly selected addresses, optionally by network.
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 94fe81aca9..7aead2812b 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -90,7 +90,7 @@ public:
}
//! Calculate in which position of a bucket to store this entry.
- int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
+ int GetBucketPosition(const uint256 &nKey, bool fNew, int bucket) const;
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(NodeSeconds now = Now<NodeSeconds>()) const;
@@ -127,7 +127,7 @@ public:
std::pair<CAddress, NodeSeconds> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
- std::pair<CAddress, NodeSeconds> Select(bool newOnly) const
+ std::pair<CAddress, NodeSeconds> Select(bool new_only, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
@@ -251,7 +251,13 @@ private:
void Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
- std::pair<CAddress, NodeSeconds> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::pair<CAddress, NodeSeconds> Select_(bool new_only, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
+ /** Helper to generalize looking up an addrman entry from either table.
+ *
+ * @return int The nid of the entry or -1 if the addrman position is empty.
+ * */
+ int GetEntry(bool use_tried, size_t bucket, size_t position) const EXCLUSIVE_LOCKS_REQUIRED(cs);
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/attributes.h b/src/attributes.h
index 9957bcd84b..a4603b0270 100644
--- a/src/attributes.h
+++ b/src/attributes.h
@@ -16,4 +16,12 @@
# define LIFETIMEBOUND
#endif
+#if defined(__GNUC__)
+# define ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+# define ALWAYS_INLINE __forceinline
+#else
+# error No known always_inline attribute for this platform.
+#endif
+
#endif // BITCOIN_ATTRIBUTES_H
diff --git a/src/banman.cpp b/src/banman.cpp
index ece949d997..a96b7e3c53 100644
--- a/src/banman.cpp
+++ b/src/banman.cpp
@@ -5,10 +5,11 @@
#include <banman.h>
+#include <common/system.h>
+#include <logging.h>
#include <netaddress.h>
#include <node/interface_ui.h>
#include <sync.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
diff --git a/src/banman.h b/src/banman.h
index 241f01dd2e..5a5f5677b0 100644
--- a/src/banman.h
+++ b/src/banman.h
@@ -7,9 +7,9 @@
#include <addrdb.h>
#include <common/bloom.h>
-#include <fs.h>
#include <net_types.h> // For banmap_t
#include <sync.h>
+#include <util/fs.h>
#include <chrono>
#include <cstdint>
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index d6b52eb587..f044feebba 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -4,6 +4,7 @@
#include <addrman.h>
#include <bench/bench.h>
+#include <netbase.h>
#include <netgroup.h>
#include <random.h>
#include <util/check.h>
@@ -95,6 +96,41 @@ static void AddrManSelect(benchmark::Bench& bench)
});
}
+// The worst case performance of the Select() function is when there is only
+// one address on the table, because it linearly searches every position of
+// several buckets before identifying the correct bucket
+static void AddrManSelectFromAlmostEmpty(benchmark::Bench& bench)
+{
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+
+ // Add one address to the new table
+ CService addr = Lookup("250.3.1.1", 8333, false).value();
+ addrman.Add({CAddress(addr, NODE_NONE)}, addr);
+
+ bench.run([&] {
+ (void)addrman.Select();
+ });
+}
+
+static void AddrManSelectByNetwork(benchmark::Bench& bench)
+{
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+
+ // add single I2P address to new table
+ CService i2p_service;
+ i2p_service.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
+ CAddress i2p_address(i2p_service, NODE_NONE);
+ i2p_address.nTime = Now<NodeSeconds>();
+ const CNetAddr source{LookupHost("252.2.2.2", false).value()};
+ addrman.Add({i2p_address}, source);
+
+ FillAddrMan(addrman);
+
+ bench.run([&] {
+ (void)addrman.Select(/*new_only=*/false, NET_I2P);
+ });
+}
+
static void AddrManGetAddr(benchmark::Bench& bench)
{
AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
@@ -135,5 +171,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
BENCHMARK(AddrManAdd, benchmark::PriorityLevel::HIGH);
BENCHMARK(AddrManSelect, benchmark::PriorityLevel::HIGH);
+BENCHMARK(AddrManSelectFromAlmostEmpty, benchmark::PriorityLevel::HIGH);
+BENCHMARK(AddrManSelectByNetwork, benchmark::PriorityLevel::HIGH);
BENCHMARK(AddrManGetAddr, benchmark::PriorityLevel::HIGH);
BENCHMARK(AddrManAddThenGood, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 4374a63250..84b66bc4b2 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -4,8 +4,8 @@
#include <bench/bench.h>
-#include <fs.h>
#include <test/util/setup_common.h>
+#include <util/fs.h>
#include <util/string.h>
#include <chrono>
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 22c63a797b..78196134e7 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_BENCH_BENCH_H
#define BITCOIN_BENCH_BENCH_H
-#include <fs.h>
+#include <util/fs.h>
#include <util/macros.h>
#include <chrono>
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 06e32f684f..8c421c3fec 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -5,10 +5,10 @@
#include <bench/bench.h>
#include <clientversion.h>
+#include <common/args.h>
#include <crypto/sha256.h>
-#include <fs.h>
+#include <util/fs.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <chrono>
#include <cstdint>
diff --git a/src/bench/bip324_ecdh.cpp b/src/bench/bip324_ecdh.cpp
new file mode 100644
index 0000000000..659da0f08e
--- /dev/null
+++ b/src/bench/bip324_ecdh.cpp
@@ -0,0 +1,51 @@
+// Copyright (c) 2022 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 <bench/bench.h>
+
+#include <key.h>
+#include <pubkey.h>
+#include <random.h>
+#include <span.h>
+
+#include <array>
+#include <cstddef>
+
+static void BIP324_ECDH(benchmark::Bench& bench)
+{
+ ECC_Start();
+ FastRandomContext rng;
+
+ std::array<std::byte, 32> key_data;
+ std::array<std::byte, EllSwiftPubKey::size()> our_ellswift_data;
+ std::array<std::byte, EllSwiftPubKey::size()> their_ellswift_data;
+
+ rng.fillrand(key_data);
+ rng.fillrand(our_ellswift_data);
+ rng.fillrand(their_ellswift_data);
+
+ bench.batch(1).unit("ecdh").run([&] {
+ CKey key;
+ key.Set(UCharCast(key_data.data()), UCharCast(key_data.data()) + 32, true);
+ EllSwiftPubKey our_ellswift(our_ellswift_data);
+ EllSwiftPubKey their_ellswift(their_ellswift_data);
+
+ auto ret = key.ComputeBIP324ECDHSecret(their_ellswift, our_ellswift, true);
+
+ // To make sure that the computation is not the same on every iteration (ellswift decoding
+ // is variable-time), distribute bytes from the shared secret over the 3 inputs. The most
+ // important one is their_ellswift, because that one is actually decoded, so it's given most
+ // bytes. The data is copied into the middle, so that both halves are affected:
+ // - Copy 8 bytes from the resulting shared secret into middle of the private key.
+ std::copy(ret.begin(), ret.begin() + 8, key_data.begin() + 12);
+ // - Copy 8 bytes from the resulting shared secret into the middle of our ellswift key.
+ std::copy(ret.begin() + 8, ret.begin() + 16, our_ellswift_data.begin() + 28);
+ // - Copy 16 bytes from the resulting shared secret into the middle of their ellswift key.
+ std::copy(ret.begin() + 16, ret.end(), their_ellswift_data.begin() + 24);
+ });
+
+ ECC_Stop();
+}
+
+BENCHMARK(BIP324_ECDH, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 8dd4117a3e..4d032cefc5 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -27,7 +27,7 @@ static void AssembleBlock(benchmark::Bench& bench)
std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
for (size_t b{0}; b < NUM_BLOCKS; ++b) {
CMutableTransaction tx;
- tx.vin.push_back(MineBlock(test_setup->m_node, P2WSH_OP_TRUE));
+ tx.vin.push_back(CTxIn{MineBlock(test_setup->m_node, P2WSH_OP_TRUE)});
tx.vin.back().scriptWitness = witness;
tx.vout.emplace_back(1337, P2WSH_OP_TRUE);
if (NUM_BLOCKS - b >= COINBASE_MATURITY)
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index ee76f7b767..269ac847a5 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -6,9 +6,10 @@
#include <bench/data.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/validation.h>
#include <streams.h>
-#include <util/system.h>
+#include <util/chaintype.h>
#include <validation.h>
// These are the two major time-sinks which happen after we have fully received
@@ -36,7 +37,7 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
stream.write({&a, 1}); // Prevent compaction
ArgsManager bench_args;
- const auto chainParams = CreateChainParams(bench_args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(bench_args, ChainType::MAIN);
bench.unit("block").run([&] {
CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 8ad6fde6bf..70e0b86eba 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -4,11 +4,11 @@
#include <bench/bench.h>
#include <checkqueue.h>
+#include <common/system.h>
#include <key.h>
#include <prevector.h>
#include <pubkey.h>
#include <random.h>
-#include <util/system.h>
#include <vector>
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 265d4bf655..0e110a653a 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -5,9 +5,11 @@
#include <bench/bench.h>
#include <interfaces/chain.h>
#include <node/context.h>
+#include <policy/policy.h>
#include <wallet/coinselection.h>
#include <wallet/spend.h>
#include <wallet/wallet.h>
+#include <wallet/test/util.h>
#include <set>
@@ -19,7 +21,7 @@ using wallet::CWallet;
using wallet::CWalletTx;
using wallet::CoinEligibilityFilter;
using wallet::CoinSelectionParams;
-using wallet::CreateDummyWalletDatabase;
+using wallet::CreateMockableWalletDatabase;
using wallet::OutputGroup;
using wallet::SelectCoinsBnB;
using wallet::TxStateInactive;
@@ -45,7 +47,7 @@ static void CoinSelection(benchmark::Bench& bench)
{
NodeContext node;
auto chain = interfaces::MakeChain(node);
- CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(chain.get(), "", CreateMockableWalletDatabase());
std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet);
@@ -115,7 +117,7 @@ static void BnBExhaustion(benchmark::Bench& bench)
bench.run([&] {
// Benchmark
CAmount target = make_hard_case(17, utxo_pool);
- SelectCoinsBnB(utxo_pool, target, 0); // Should exhaust
+ SelectCoinsBnB(utxo_pool, target, 0, MAX_STANDARD_TX_WEIGHT); // Should exhaust
// Cleanup
utxo_pool.clear();
diff --git a/src/bench/ellswift.cpp b/src/bench/ellswift.cpp
new file mode 100644
index 0000000000..75729e170c
--- /dev/null
+++ b/src/bench/ellswift.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2022-2023 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 <bench/bench.h>
+
+#include <key.h>
+#include <random.h>
+
+static void EllSwiftCreate(benchmark::Bench& bench)
+{
+ ECC_Start();
+
+ CKey key;
+ key.MakeNewKey(true);
+
+ uint256 entropy = GetRandHash();
+
+ bench.batch(1).unit("pubkey").run([&] {
+ auto ret = key.EllSwiftCreate(AsBytes(Span{entropy}));
+ /* Use the first 32 bytes of the ellswift encoded public key as next private key. */
+ key.Set(UCharCast(ret.data()), UCharCast(ret.data()) + 32, true);
+ assert(key.IsValid());
+ /* Use the last 32 bytes of the ellswift encoded public key as next entropy. */
+ std::copy(ret.begin() + 32, ret.begin() + 64, AsBytePtr(entropy.data()));
+ });
+
+ ECC_Stop();
+}
+
+BENCHMARK(EllSwiftCreate, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/load_external.cpp b/src/bench/load_external.cpp
index 0fd842c7c3..2ff72a3012 100644
--- a/src/bench/load_external.cpp
+++ b/src/bench/load_external.cpp
@@ -6,6 +6,7 @@
#include <bench/data.h>
#include <chainparams.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#include <validation.h>
/**
@@ -22,7 +23,7 @@
*/
static void LoadExternalBlockFile(benchmark::Bench& bench)
{
- const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN)};
+ const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
// Create a single block as in the blocks files (magic bytes, block size,
// block data) as a stream object.
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
index 161f9af621..6851ed0bd8 100644
--- a/src/bench/lockedpool.cpp
+++ b/src/bench/lockedpool.cpp
@@ -17,9 +17,7 @@ static void BenchLockedPool(benchmark::Bench& bench)
const size_t synth_size = 1024*1024;
Arena b(synth_base, synth_size, 16);
- std::vector<void*> addr;
- for (int x=0; x<ASIZE; ++x)
- addr.push_back(nullptr);
+ std::vector<void*> addr{ASIZE, nullptr};
uint32_t s = 0x12345678;
bench.run([&] {
int idx = s & (addr.size() - 1);
diff --git a/src/bench/logging.cpp b/src/bench/logging.cpp
index 9aedb26236..c97c4e151b 100644
--- a/src/bench/logging.cpp
+++ b/src/bench/logging.cpp
@@ -5,6 +5,7 @@
#include <bench/bench.h>
#include <logging.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
// All but 2 of the benchmarks should have roughly similar performance:
//
@@ -18,7 +19,7 @@ static void Logging(benchmark::Bench& bench, const std::vector<const char*>& ext
LogInstance().DisableCategory(BCLog::LogFlags::ALL);
TestingSetup test_setup{
- CBaseChainParams::REGTEST,
+ ChainType::REGTEST,
extra_args,
};
diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp
index 80c959cdfb..826da73800 100644
--- a/src/bench/mempool_stress.cpp
+++ b/src/bench/mempool_stress.cpp
@@ -7,6 +7,7 @@
#include <policy/policy.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
+#include <util/chaintype.h>
#include <validation.h>
#include <vector>
@@ -88,7 +89,7 @@ static void ComplexMemPool(benchmark::Bench& bench)
childTxs = static_cast<int>(bench.complexityN());
}
std::vector<CTransactionRef> ordered_coins = CreateOrderedCoins(det_rand, childTxs, /*min_ancestors=*/1);
- const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN);
+ const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN);
CTxMemPool& pool = *testing_setup.get()->m_node.mempool;
LOCK2(cs_main, pool.cs);
bench.run([&]() NO_THREAD_SAFETY_ANALYSIS {
@@ -103,7 +104,7 @@ static void ComplexMemPool(benchmark::Bench& bench)
static void MempoolCheck(benchmark::Bench& bench)
{
FastRandomContext det_rand{true};
- auto testing_setup = MakeNoLogFileContext<TestChain100Setup>(CBaseChainParams::REGTEST, {"-checkmempool=1"});
+ auto testing_setup = MakeNoLogFileContext<TestChain100Setup>(ChainType::REGTEST, {"-checkmempool=1"});
CTxMemPool& pool = *testing_setup.get()->m_node.mempool;
LOCK2(cs_main, pool.cs);
testing_setup->PopulateMempool(det_rand, 400, true);
diff --git a/src/bench/pool.cpp b/src/bench/pool.cpp
new file mode 100644
index 0000000000..b3e54d85a2
--- /dev/null
+++ b/src/bench/pool.cpp
@@ -0,0 +1,50 @@
+// Copyright (c) 2022 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 <bench/bench.h>
+#include <support/allocators/pool.h>
+
+#include <unordered_map>
+
+template <typename Map>
+void BenchFillClearMap(benchmark::Bench& bench, Map& map)
+{
+ size_t batch_size = 5000;
+
+ // make sure each iteration of the benchmark contains exactly 5000 inserts and one clear.
+ // do this at least 10 times so we get reasonable accurate results
+
+ bench.batch(batch_size).minEpochIterations(10).run([&] {
+ auto rng = ankerl::nanobench::Rng(1234);
+ for (size_t i = 0; i < batch_size; ++i) {
+ map[rng()];
+ }
+ map.clear();
+ });
+}
+
+static void PoolAllocator_StdUnorderedMap(benchmark::Bench& bench)
+{
+ auto map = std::unordered_map<uint64_t, uint64_t>();
+ BenchFillClearMap(bench, map);
+}
+
+static void PoolAllocator_StdUnorderedMapWithPoolResource(benchmark::Bench& bench)
+{
+ using Map = std::unordered_map<uint64_t,
+ uint64_t,
+ std::hash<uint64_t>,
+ std::equal_to<uint64_t>,
+ PoolAllocator<std::pair<const uint64_t, uint64_t>,
+ sizeof(std::pair<const uint64_t, uint64_t>) + 4 * sizeof(void*),
+ alignof(void*)>>;
+
+ // make sure the resource supports large enough pools to hold the node. We do this by adding the size of a few pointers to it.
+ auto pool_resource = Map::allocator_type::ResourceType();
+ auto map = Map{0, std::hash<uint64_t>{}, std::equal_to<uint64_t>{}, &pool_resource};
+ BenchFillClearMap(bench, map);
+}
+
+BENCHMARK(PoolAllocator_StdUnorderedMap, benchmark::PriorityLevel::HIGH);
+BENCHMARK(PoolAllocator_StdUnorderedMapWithPoolResource, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index f68b6acb5b..a9b197b190 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -8,6 +8,7 @@
#include <rpc/blockchain.h>
#include <streams.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#include <validation.h>
#include <univalue.h>
@@ -15,7 +16,7 @@
namespace {
struct TestBlockAndIndex {
- const std::unique_ptr<const TestingSetup> testing_setup{MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN)};
+ const std::unique_ptr<const TestingSetup> testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
CBlock block{};
uint256 blockHash{};
CBlockIndex blockindex{};
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
index e3e1a07c83..7e274370e0 100644
--- a/src/bench/rpc_mempool.cpp
+++ b/src/bench/rpc_mempool.cpp
@@ -3,12 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <chainparamsbase.h>
#include <kernel/cs_main.h>
#include <kernel/mempool_entry.h>
#include <rpc/mempool.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
+#include <util/chaintype.h>
#include <univalue.h>
@@ -21,7 +21,7 @@ static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& poo
static void RpcMempool(benchmark::Bench& bench)
{
- const auto testing_setup = MakeNoLogFileContext<const ChainTestingSetup>(CBaseChainParams::MAIN);
+ const auto testing_setup = MakeNoLogFileContext<const ChainTestingSetup>(ChainType::MAIN);
CTxMemPool& pool = *Assert(testing_setup->m_node.mempool);
LOCK2(cs_main, pool.cs);
diff --git a/src/bench/streams_findbyte.cpp b/src/bench/streams_findbyte.cpp
new file mode 100644
index 0000000000..77f5940926
--- /dev/null
+++ b/src/bench/streams_findbyte.cpp
@@ -0,0 +1,31 @@
+// Copyright (c) 2023 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 <bench/bench.h>
+
+#include <util/fs.h>
+#include <streams.h>
+
+static void FindByte(benchmark::Bench& bench)
+{
+ // Setup
+ FILE* file = fsbridge::fopen("streams_tmp", "w+b");
+ const size_t file_size = 200;
+ uint8_t data[file_size] = {0};
+ data[file_size-1] = 1;
+ fwrite(&data, sizeof(uint8_t), file_size, file);
+ rewind(file);
+ CBufferedFile bf(file, /*nBufSize=*/file_size + 1, /*nRewindIn=*/file_size, 0, 0);
+
+ bench.run([&] {
+ bf.SetPos(0);
+ bf.FindByte(std::byte(1));
+ });
+
+ // Cleanup
+ bf.fclose();
+ fs::remove("streams_tmp");
+}
+
+BENCHMARK(FindByte, benchmark::PriorityLevel::HIGH);
diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp
index 8dbbdec28c..4cbc0dfbbd 100644
--- a/src/bench/util_time.cpp
+++ b/src/bench/util_time.cpp
@@ -32,7 +32,7 @@ static void BenchTimeMillis(benchmark::Bench& bench)
static void BenchTimeMillisSys(benchmark::Bench& bench)
{
bench.run([&] {
- (void)GetTimeMillis();
+ (void)TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
});
}
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index d5d057e96d..bf2195293e 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -4,6 +4,7 @@
#include <bench/bench.h>
#include <interfaces/chain.h>
+#include <node/chainstate.h>
#include <node/context.h>
#include <test/util/mining.h>
#include <test/util/setup_common.h>
@@ -14,26 +15,21 @@
#include <optional>
-using wallet::CWallet;
-using wallet::CreateMockWalletDatabase;
-using wallet::DBErrors;
-using wallet::GetBalance;
-using wallet::WALLET_FLAG_DESCRIPTORS;
-
-const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";
-
+namespace wallet {
static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_mine)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
const auto& ADDRESS_WATCHONLY = ADDRESS_BCRT1_UNSPENDABLE;
- CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
+ // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
+ // The reason is 'generatetoaddress', which creates a chain with deterministic timestamps in the past.
+ SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
+ CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet.SetupDescriptorScriptPubKeyMans();
- if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
}
auto handler = test_setup->m_node.chain->handleNotifications({&wallet, [](CWallet*) {}});
@@ -63,3 +59,4 @@ BENCHMARK(WalletBalanceDirty, benchmark::PriorityLevel::HIGH);
BENCHMARK(WalletBalanceClean, benchmark::PriorityLevel::HIGH);
BENCHMARK(WalletBalanceMine, benchmark::PriorityLevel::HIGH);
BENCHMARK(WalletBalanceWatch, benchmark::PriorityLevel::HIGH);
+} // namespace wallet
diff --git a/src/bench/wallet_create_tx.cpp b/src/bench/wallet_create_tx.cpp
index bd32a5abdc..5e5bc76fd2 100644
--- a/src/bench/wallet_create_tx.cpp
+++ b/src/bench/wallet_create_tx.cpp
@@ -15,7 +15,7 @@
#include <wallet/wallet.h>
using wallet::CWallet;
-using wallet::CreateMockWalletDatabase;
+using wallet::CreateMockableWalletDatabase;
using wallet::DBErrors;
using wallet::WALLET_FLAG_DESCRIPTORS;
@@ -83,7 +83,9 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
- CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
+ // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
+ SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
+ CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -102,7 +104,7 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
}
// Check available balance
- auto bal = wallet::GetAvailableBalance(wallet); // Cache
+ auto bal = WITH_LOCK(wallet.cs_wallet, return wallet::AvailableCoins(wallet).GetTotalAmount()); // Cache
assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY));
wallet::CCoinControl coin_control;
@@ -136,7 +138,9 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type
static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType>& output_type)
{
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
- CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
+ // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process.
+ SetMockTime(test_setup->m_node.chainman->GetParams().GenesisBlock().nTime);
+ CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()};
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -146,6 +150,7 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType
// Generate destinations
std::vector<CScript> dest_wallet;
+ dest_wallet.reserve(output_type.size());
for (auto type : output_type) {
dest_wallet.emplace_back(GetScriptForDestination(getNewDestination(wallet, type)));
}
@@ -160,7 +165,7 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector<OutputType
}
// Check available balance
- auto bal = wallet::GetAvailableBalance(wallet); // Cache
+ auto bal = WITH_LOCK(wallet.cs_wallet, return wallet::AvailableCoins(wallet).GetTotalAmount()); // Cache
assert(bal == 50 * COIN * (chain_size - COINBASE_MATURITY));
bench.epochIterations(2).run([&] {
diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp
index 6b09adcc9d..5453238728 100644
--- a/src/bench/wallet_loading.cpp
+++ b/src/bench/wallet_loading.cpp
@@ -16,33 +16,7 @@
#include <optional>
-using wallet::CWallet;
-using wallet::DatabaseFormat;
-using wallet::DatabaseOptions;
-using wallet::TxStateInactive;
-using wallet::WALLET_FLAG_DESCRIPTORS;
-using wallet::WalletContext;
-using wallet::WalletDatabase;
-
-static std::shared_ptr<CWallet> BenchLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, DatabaseOptions& options)
-{
- bilingual_str error;
- std::vector<bilingual_str> warnings;
- auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings);
- NotifyWalletLoaded(context, wallet);
- if (context.chain) {
- wallet->postInitProcess();
- }
- return wallet;
-}
-
-static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)
-{
- SyncWithValidationInterfaceQueue();
- wallet->m_chain_notifications_handler.reset();
- UnloadWallet(std::move(wallet));
-}
-
+namespace wallet{
static void AddTx(CWallet& wallet)
{
CMutableTransaction mtx;
@@ -55,7 +29,6 @@ static void AddTx(CWallet& wallet)
static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet)
{
const auto test_setup = MakeNoLogFileContext<TestingSetup>();
- test_setup->m_args.ForceSetArg("-unsafesqlitesync", "1");
WalletContext context;
context.args = &test_setup->m_args;
@@ -63,32 +36,29 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet)
// Setup the wallet
// Loading the wallet will also create it
- DatabaseOptions options;
- if (legacy_wallet) {
- options.require_format = DatabaseFormat::BERKELEY;
- } else {
- options.create_flags = WALLET_FLAG_DESCRIPTORS;
- options.require_format = DatabaseFormat::SQLITE;
+ uint64_t create_flags = 0;
+ if (!legacy_wallet) {
+ create_flags = WALLET_FLAG_DESCRIPTORS;
}
- auto database = CreateMockWalletDatabase(options);
- auto wallet = BenchLoadWallet(std::move(database), context, options);
+ auto database = CreateMockableWalletDatabase();
+ auto wallet = TestLoadWallet(std::move(database), context, create_flags);
// Generate a bunch of transactions and addresses to put into the wallet
for (int i = 0; i < 1000; ++i) {
AddTx(*wallet);
}
- database = DuplicateMockDatabase(wallet->GetDatabase(), options);
+ database = DuplicateMockDatabase(wallet->GetDatabase());
// reload the wallet for the actual benchmark
- BenchUnloadWallet(std::move(wallet));
+ TestUnloadWallet(std::move(wallet));
bench.epochs(5).run([&] {
- wallet = BenchLoadWallet(std::move(database), context, options);
+ wallet = TestLoadWallet(std::move(database), context, create_flags);
// Cleanup
- database = DuplicateMockDatabase(wallet->GetDatabase(), options);
- BenchUnloadWallet(std::move(wallet));
+ database = DuplicateMockDatabase(wallet->GetDatabase());
+ TestUnloadWallet(std::move(wallet));
});
}
@@ -101,3 +71,4 @@ BENCHMARK(WalletLoadingLegacy, benchmark::PriorityLevel::HIGH);
static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); }
BENCHMARK(WalletLoadingDescriptors, benchmark::PriorityLevel::HIGH);
#endif
+} // namespace wallet
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index abe3af70c3..432bdc8e33 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -12,11 +12,11 @@
// It is part of the libbitcoinkernel project.
#include <kernel/chainparams.h>
+#include <kernel/chainstatemanager_opts.h>
#include <kernel/checks.h>
#include <kernel/context.h>
#include <kernel/validation_cache_sizes.h>
-#include <chainparams.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <node/blockstorage.h>
@@ -24,15 +24,18 @@
#include <node/chainstate.h>
#include <scheduler.h>
#include <script/sigcache.h>
-#include <util/system.h>
+#include <util/chaintype.h>
#include <util/thread.h>
#include <validation.h>
#include <validationinterface.h>
#include <cassert>
+#include <cstdint>
#include <filesystem>
#include <functional>
#include <iosfwd>
+#include <memory>
+#include <string>
int main(int argc, char* argv[])
{
@@ -48,18 +51,14 @@ int main(int argc, char* argv[])
}
std::filesystem::path abs_datadir = std::filesystem::absolute(argv[1]);
std::filesystem::create_directories(abs_datadir);
- gArgs.ForceSetArg("-datadir", abs_datadir.string());
- // SETUP: Misc Globals
- SelectParams(CBaseChainParams::MAIN);
- auto chainparams = CChainParams::Main();
-
+ // SETUP: Context
kernel::Context kernel_context{};
// We can't use a goto here, but we can use an assert since none of the
// things instantiated so far requires running the epilogue to be torn down
// properly
- assert(!kernel::SanityChecks(kernel_context).has_value());
+ assert(kernel::SanityChecks(kernel_context));
// Necessary for CheckInputScripts (eventually called by ProcessNewBlock),
// which will try the script cache first and fall back to actually
@@ -79,14 +78,42 @@ int main(int argc, char* argv[])
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+ class KernelNotifications : public kernel::Notifications
+ {
+ public:
+ void blockTip(SynchronizationState, CBlockIndex&) override
+ {
+ std::cout << "Block tip changed" << std::endl;
+ }
+ void headerTip(SynchronizationState, int64_t height, int64_t timestamp, bool presync) override
+ {
+ std::cout << "Header tip changed: " << height << ", " << timestamp << ", " << presync << std::endl;
+ }
+ void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override
+ {
+ std::cout << "Progress: " << title.original << ", " << progress_percent << ", " << resume_possible << std::endl;
+ }
+ void warning(const bilingual_str& warning) override
+ {
+ std::cout << "Warning: " << warning.original << std::endl;
+ }
+ };
+ auto notifications = std::make_unique<KernelNotifications>();
+
// SETUP: Chainstate
+ auto chainparams = CChainParams::Main();
const ChainstateManager::Options chainman_opts{
.chainparams = *chainparams,
- .datadir = gArgs.GetDataDirNet(),
+ .datadir = abs_datadir,
.adjusted_time_callback = NodeClock::now,
+ .notifications = *notifications,
+ };
+ const node::BlockManager::Options blockman_opts{
+ .chainparams = chainman_opts.chainparams,
+ .blocks_dir = abs_datadir / "blocks",
};
- ChainstateManager chainman{chainman_opts, {}};
+ ChainstateManager chainman{chainman_opts, blockman_opts};
node::CacheSizes cache_sizes;
cache_sizes.block_tree_db = 2 << 20;
@@ -117,7 +144,8 @@ int main(int argc, char* argv[])
// Main program logic starts here
std::cout
<< "Hello! I'm going to print out some information about your datadir." << std::endl
- << "\t" << "Path: " << gArgs.GetDataDirNet() << std::endl;
+ << "\t"
+ << "Path: " << abs_datadir << std::endl;
{
LOCK(chainman.GetMutex());
std::cout
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index eb52b30ae4..45db7a9a66 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -9,6 +9,8 @@
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/args.h>
+#include <common/system.h>
#include <common/url.h>
#include <compat/compat.h>
#include <compat/stdin.h>
@@ -19,9 +21,10 @@
#include <rpc/request.h>
#include <tinyformat.h>
#include <univalue.h>
+#include <util/chaintype.h>
#include <util/exception.h>
#include <util/strencodings.h>
-#include <util/system.h>
+#include <util/time.h>
#include <util/translation.h>
#include <algorithm>
@@ -71,10 +74,10 @@ static void SetupCliArgs(ArgsManager& argsman)
{
SetupHelpOptions(argsman);
- const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
- const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
- const auto signetBaseParams = CreateBaseChainParams(CBaseChainParams::SIGNET);
- const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST);
+ const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN);
+ const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET);
+ const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET);
+ const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST);
argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -172,7 +175,7 @@ static int AppInitRPC(int argc, char* argv[])
}
// Check for chain settings (BaseParams() calls are only valid after this clause)
try {
- SelectBaseParams(gArgs.GetChainName());
+ SelectBaseParams(gArgs.GetChainType());
} catch (const std::exception& e) {
tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
@@ -424,10 +427,17 @@ private:
std::vector<Peer> m_peers;
std::string ChainToString() const
{
- if (gArgs.GetChainName() == CBaseChainParams::TESTNET) return " testnet";
- if (gArgs.GetChainName() == CBaseChainParams::SIGNET) return " signet";
- if (gArgs.GetChainName() == CBaseChainParams::REGTEST) return " regtest";
- return "";
+ switch (gArgs.GetChainType()) {
+ case ChainType::TESTNET:
+ return " testnet";
+ case ChainType::SIGNET:
+ return " signet";
+ case ChainType::REGTEST:
+ return " regtest";
+ case ChainType::MAIN:
+ return "";
+ }
+ assert(false);
}
std::string PingTimeToString(double seconds) const
{
@@ -861,7 +871,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str
try {
response = CallRPC(rh, strMethod, args, rpcwallet);
if (fWait) {
- const UniValue& error = find_value(response, "error");
+ const UniValue& error = response.find_value("error");
if (!error.isNull() && error["code"].getInt<int>() == RPC_IN_WARMUP) {
throw CConnectionFailed("server in warmup");
}
@@ -889,8 +899,8 @@ static void ParseResult(const UniValue& result, std::string& strPrint)
static void ParseError(const UniValue& error, std::string& strPrint, int& nRet)
{
if (error.isObject()) {
- const UniValue& err_code = find_value(error, "code");
- const UniValue& err_msg = find_value(error, "message");
+ const UniValue& err_code = error.find_value("code");
+ const UniValue& err_msg = error.find_value("message");
if (!err_code.isNull()) {
strPrint = "error code: " + err_code.getValStr() + "\n";
}
@@ -916,15 +926,15 @@ static void GetWalletBalances(UniValue& result)
{
DefaultRequestHandler rh;
const UniValue listwallets = ConnectAndCallRPC(&rh, "listwallets", /* args=*/{});
- if (!find_value(listwallets, "error").isNull()) return;
- const UniValue& wallets = find_value(listwallets, "result");
+ if (!listwallets.find_value("error").isNull()) return;
+ const UniValue& wallets = listwallets.find_value("result");
if (wallets.size() <= 1) return;
UniValue balances(UniValue::VOBJ);
for (const UniValue& wallet : wallets.getValues()) {
const std::string& wallet_name = wallet.get_str();
const UniValue getbalances = ConnectAndCallRPC(&rh, "getbalances", /* args=*/{}, wallet_name);
- const UniValue& balance = find_value(getbalances, "result")["mine"]["trusted"];
+ const UniValue& balance = getbalances.find_value("result")["mine"]["trusted"];
balances.pushKV(wallet_name, balance);
}
result.pushKV("balances", balances);
@@ -960,7 +970,7 @@ static void GetProgressBar(double progress, std::string& progress_bar)
*/
static void ParseGetInfoResult(UniValue& result)
{
- if (!find_value(result, "error").isNull()) return;
+ if (!result.find_value("error").isNull()) return;
std::string RESET, GREEN, BLUE, YELLOW, MAGENTA, CYAN;
bool should_colorize = false;
@@ -1032,6 +1042,7 @@ static void ParseGetInfoResult(UniValue& result)
}
std::vector<std::string> formatted_proxies;
+ formatted_proxies.reserve(ordered_proxies.size());
for (const std::string& proxy : ordered_proxies) {
formatted_proxies.emplace_back(strprintf("%s (%s)", proxy, Join(proxy_networks.find(proxy)->second, ", ")));
}
@@ -1171,9 +1182,9 @@ static int CommandLineRPC(int argc, char *argv[])
rh.reset(new NetinfoRequestHandler());
} else if (gArgs.GetBoolArg("-generate", false)) {
const UniValue getnewaddress{GetNewAddress()};
- const UniValue& error{find_value(getnewaddress, "error")};
+ const UniValue& error{getnewaddress.find_value("error")};
if (error.isNull()) {
- SetGenerateToAddressArgs(find_value(getnewaddress, "result").get_str(), args);
+ SetGenerateToAddressArgs(getnewaddress.find_value("result").get_str(), args);
rh.reset(new GenerateToAddressRequestHandler());
} else {
ParseError(error, strPrint, nRet);
@@ -1195,8 +1206,8 @@ static int CommandLineRPC(int argc, char *argv[])
const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name);
// Parse reply
- UniValue result = find_value(reply, "result");
- const UniValue& error = find_value(reply, "error");
+ UniValue result = reply.find_value("result");
+ const UniValue& error = reply.find_value("error");
if (error.isNull()) {
if (gArgs.GetBoolArg("-getinfo", false)) {
if (!gArgs.IsArgSet("-rpcwallet")) {
@@ -1227,7 +1238,7 @@ static int CommandLineRPC(int argc, char *argv[])
MAIN_FUNCTION
{
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
SetupEnvironment();
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index f36b6054bb..0c25ddf373 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -6,13 +6,15 @@
#include <config/bitcoin-config.h>
#endif
+#include <chainparamsbase.h>
#include <clientversion.h>
#include <coins.h>
+#include <common/args.h>
+#include <common/system.h>
#include <compat/compat.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <core_io.h>
-#include <fs.h>
#include <key_io.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
@@ -21,11 +23,11 @@
#include <script/signingprovider.h>
#include <univalue.h>
#include <util/exception.h>
+#include <util/fs.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <cstdio>
@@ -90,7 +92,7 @@ static int AppInitRawTx(int argc, char* argv[])
// Check for chain settings (Params() calls are only valid after this clause)
try {
- SelectParams(gArgs.GetChainName());
+ SelectParams(gArgs.GetChainType());
} catch (const std::exception& e) {
tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp
index cf59ca9bff..582c18c9c6 100644
--- a/src/bitcoin-util.cpp
+++ b/src/bitcoin-util.cpp
@@ -11,11 +11,12 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/args.h>
+#include <common/system.h>
#include <compat/compat.h>
#include <core_io.h>
#include <streams.h>
#include <util/exception.h>
-#include <util/system.h>
#include <util/translation.h>
#include <version.h>
@@ -74,7 +75,7 @@ static int AppInitUtil(ArgsManager& args, int argc, char* argv[])
// Check for chain settings (Params() calls are only valid after this clause)
try {
- SelectParams(args.GetChainName());
+ SelectParams(args.GetChainType());
} catch (const std::exception& e) {
tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
@@ -127,6 +128,7 @@ static int Grind(const std::vector<std::string>& args, std::string& strPrint)
std::vector<std::thread> threads;
int n_tasks = std::max(1u, std::thread::hardware_concurrency());
+ threads.reserve(n_tasks);
for (int i = 0; i < n_tasks; ++i) {
threads.emplace_back(grind_task, nBits, header, i, n_tasks, std::ref(found), std::ref(proposed_nonce));
}
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 1ebe98b920..d5dfbbec27 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -9,6 +9,8 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
+#include <common/args.h>
+#include <common/system.h>
#include <common/url.h>
#include <compat/compat.h>
#include <interfaces/init.h>
@@ -17,7 +19,6 @@
#include <pubkey.h>
#include <tinyformat.h>
#include <util/exception.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/wallettool.h>
@@ -90,7 +91,7 @@ static std::optional<int> WalletAppInit(ArgsManager& args, int argc, char* argv[
return EXIT_FAILURE;
}
// Check for chain settings (Params() calls are only valid after this clause)
- SelectParams(args.GetChainName());
+ SelectParams(args.GetChainType());
return std::nullopt;
}
@@ -99,7 +100,7 @@ MAIN_FUNCTION
{
ArgsManager& args = gArgs;
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 2ff34125e1..c561f9aa14 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -9,7 +9,9 @@
#include <chainparams.h>
#include <clientversion.h>
+#include <common/args.h>
#include <common/init.h>
+#include <common/system.h>
#include <common/url.h>
#include <compat/compat.h>
#include <init.h>
@@ -24,7 +26,6 @@
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
#include <util/syserror.h>
-#include <util/system.h>
#include <util/threadnames.h>
#include <util/tokenpipe.h>
#include <util/translation.h>
@@ -111,20 +112,30 @@ int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
#endif
-static bool AppInit(NodeContext& node, int argc, char* argv[])
+static bool ParseArgs(ArgsManager& args, int argc, char* argv[])
{
- bool fRet = false;
-
- util::ThreadSetInternalName("init");
-
// If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
- ArgsManager& args = *Assert(node.args);
SetupServerArgs(args);
std::string error;
if (!args.ParseParameters(argc, argv, error)) {
return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
}
+ if (auto error = common::InitConfig(args)) {
+ return InitError(error->message, error->details);
+ }
+
+ // Error out when loose non-argument tokens are encountered on command line
+ for (int i = 1; i < argc; i++) {
+ if (!IsSwitchChar(argv[i][0])) {
+ return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
+ }
+ }
+ return true;
+}
+
+static bool ProcessInitCommands(ArgsManager& args)
+{
// Process help and version before taking care about datadir
if (HelpRequested(args) || args.IsArgSet("-version")) {
std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
@@ -141,6 +152,14 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
return true;
}
+ return false;
+}
+
+static bool AppInit(NodeContext& node)
+{
+ bool fRet = false;
+ ArgsManager& args = *Assert(node.args);
+
#if HAVE_DECL_FORK
// Communication with parent after daemonizing. This is used for signalling in the following ways:
// - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
@@ -152,23 +171,12 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
std::any context{&node};
try
{
- if (auto error = common::InitConfig(args)) {
- return InitError(error->message, error->details);
- }
-
- // Error out when loose non-argument tokens are encountered on command line
- for (int i = 1; i < argc; i++) {
- if (!IsSwitchChar(argv[i][0])) {
- return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
- }
- }
-
// -server defaults to true for bitcoind but not for the GUI so do this here
args.SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
InitLogging(args);
InitParameterInteraction(args);
- if (!AppInitBasicSetup(args)) {
+ if (!AppInitBasicSetup(args, node.exit_status)) {
// InitError will have been called with detailed error, which ends up on console
return false;
}
@@ -235,19 +243,13 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
}
#endif
SetSyscallSandboxPolicy(SyscallSandboxPolicy::SHUTOFF);
- if (fRet) {
- WaitForShutdown();
- }
- Interrupt(node);
- Shutdown(node);
-
return fRet;
}
MAIN_FUNCTION
{
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
@@ -263,5 +265,22 @@ MAIN_FUNCTION
// Connect bitcoind signal handlers
noui_connect();
- return (AppInit(node, argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
+ util::ThreadSetInternalName("init");
+
+ // Interpret command line arguments
+ ArgsManager& args = *Assert(node.args);
+ if (!ParseArgs(args, argc, argv)) return EXIT_FAILURE;
+ // Process early info return commands such as -help or -version
+ if (ProcessInitCommands(args)) return EXIT_SUCCESS;
+
+ // Start application
+ if (AppInit(node)) {
+ WaitForShutdown();
+ } else {
+ node.exit_status = EXIT_FAILURE;
+ }
+ Interrupt(node);
+ Shutdown(node);
+
+ return node.exit_status;
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index a29e4f794e..9aa0a6ba20 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -3,16 +3,16 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <blockencodings.h>
+#include <chainparams.h>
+#include <common/system.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
-#include <chainparams.h>
#include <crypto/sha256.h>
#include <crypto/siphash.h>
#include <random.h>
#include <streams.h>
#include <txmempool.h>
#include <validation.h>
-#include <util/system.h>
#include <unordered_map>
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 6f48ee41b3..539578085b 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -5,15 +5,21 @@
#include <chainparams.h>
-#include <chainparamsseeds.h>
-#include <consensus/merkle.h>
+#include <chainparamsbase.h>
+#include <common/args.h>
+#include <consensus/params.h>
#include <deploymentinfo.h>
-#include <hash.h> // for signet block challenge hash
-#include <script/interpreter.h>
+#include <logging.h>
+#include <tinyformat.h>
+#include <util/chaintype.h>
+#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
-#include <assert.h>
+#include <cassert>
+#include <cstdint>
+#include <limits>
+#include <stdexcept>
+#include <vector>
void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& options)
{
@@ -23,9 +29,13 @@ void ReadSigNetArgs(const ArgsManager& args, CChainParams::SigNetOptions& option
if (args.IsArgSet("-signetchallenge")) {
const auto signet_challenge = args.GetArgs("-signetchallenge");
if (signet_challenge.size() != 1) {
- throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
+ throw std::runtime_error("-signetchallenge cannot be multiple values.");
}
- options.challenge.emplace(ParseHex(signet_challenge[0]));
+ const auto val{TryParseHex<uint8_t>(signet_challenge[0])};
+ if (!val) {
+ throw std::runtime_error(strprintf("-signetchallenge must be hex, not '%s'.", signet_challenge[0]));
+ }
+ options.challenge.emplace(*val);
}
}
@@ -96,26 +106,29 @@ const CChainParams &Params() {
return *globalChainParams;
}
-std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain)
+std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const ChainType chain)
{
- if (chain == CBaseChainParams::MAIN) {
+ switch (chain) {
+ case ChainType::MAIN:
return CChainParams::Main();
- } else if (chain == CBaseChainParams::TESTNET) {
+ case ChainType::TESTNET:
return CChainParams::TestNet();
- } else if (chain == CBaseChainParams::SIGNET) {
+ case ChainType::SIGNET: {
auto opts = CChainParams::SigNetOptions{};
ReadSigNetArgs(args, opts);
return CChainParams::SigNet(opts);
- } else if (chain == CBaseChainParams::REGTEST) {
+ }
+ case ChainType::REGTEST: {
auto opts = CChainParams::RegTestOptions{};
ReadRegTestArgs(args, opts);
return CChainParams::RegTest(opts);
}
- throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
+ }
+ assert(false);
}
-void SelectParams(const std::string& network)
+void SelectParams(const ChainType chain)
{
- SelectBaseParams(network);
- globalChainParams = CreateChainParams(gArgs, network);
+ SelectBaseParams(chain);
+ globalChainParams = CreateChainParams(gArgs, chain);
}
diff --git a/src/chainparams.h b/src/chainparams.h
index cb34d068e1..4743e022db 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -6,27 +6,16 @@
#ifndef BITCOIN_CHAINPARAMS_H
#define BITCOIN_CHAINPARAMS_H
-#include <kernel/chainparams.h>
+#include <kernel/chainparams.h> // IWYU pragma: export
-#include <chainparamsbase.h>
-#include <consensus/params.h>
-#include <netaddress.h>
-#include <primitives/block.h>
-#include <protocol.h>
-#include <util/hash_type.h>
-
-#include <cstdint>
#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
+
+class ArgsManager;
/**
* Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
- * @returns a CChainParams* of the chosen chain.
- * @throws a std::runtime_error if the chain is not supported.
*/
-std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain);
+std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const ChainType chain);
/**
* Return the currently selected parameters. This won't change after app
@@ -35,9 +24,8 @@ std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, c
const CChainParams &Params();
/**
- * Sets the params returned by Params() to those for the given chain name.
- * @throws std::runtime_error when the chain is not supported.
+ * Sets the params returned by Params() to those for the given chain type.
*/
-void SelectParams(const std::string& chain);
+void SelectParams(const ChainType chain);
#endif // BITCOIN_CHAINPARAMS_H
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 71978081ce..8cbf9e85e0 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -5,16 +5,12 @@
#include <chainparamsbase.h>
+#include <common/args.h>
#include <tinyformat.h>
-#include <util/system.h>
+#include <util/chaintype.h>
#include <assert.h>
-const std::string CBaseChainParams::MAIN = "main";
-const std::string CBaseChainParams::TESTNET = "test";
-const std::string CBaseChainParams::SIGNET = "signet";
-const std::string CBaseChainParams::REGTEST = "regtest";
-
void SetupChainParamsBaseOptions(ArgsManager& argsman)
{
argsman.AddArg("-chain=<chain>", "Use the chain <chain> (default: main). Allowed values: main, test, signet, regtest", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
@@ -40,22 +36,23 @@ const CBaseChainParams& BaseParams()
* Port numbers for incoming Tor connections (8334, 18334, 38334, 18445) have
* been chosen arbitrarily to keep ranges of used ports tight.
*/
-std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
+std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const ChainType chain)
{
- if (chain == CBaseChainParams::MAIN) {
+ switch (chain) {
+ case ChainType::MAIN:
return std::make_unique<CBaseChainParams>("", 8332, 8334);
- } else if (chain == CBaseChainParams::TESTNET) {
+ case ChainType::TESTNET:
return std::make_unique<CBaseChainParams>("testnet3", 18332, 18334);
- } else if (chain == CBaseChainParams::SIGNET) {
+ case ChainType::SIGNET:
return std::make_unique<CBaseChainParams>("signet", 38332, 38334);
- } else if (chain == CBaseChainParams::REGTEST) {
+ case ChainType::REGTEST:
return std::make_unique<CBaseChainParams>("regtest", 18443, 18445);
}
- throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
+ assert(false);
}
-void SelectBaseParams(const std::string& chain)
+void SelectBaseParams(const ChainType chain)
{
globalChainBaseParams = CreateBaseChainParams(chain);
- gArgs.SelectConfigNetwork(chain);
+ gArgs.SelectConfigNetwork(ChainTypeToString(chain));
}
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index d593cff722..ea933d1ca8 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_CHAINPARAMSBASE_H
#define BITCOIN_CHAINPARAMSBASE_H
+#include <util/chaintype.h>
+
#include <memory>
#include <string>
@@ -17,14 +19,6 @@ class ArgsManager;
class CBaseChainParams
{
public:
- ///@{
- /** Chain name strings */
- static const std::string MAIN;
- static const std::string TESTNET;
- static const std::string SIGNET;
- static const std::string REGTEST;
- ///@}
-
const std::string& DataDir() const { return strDataDir; }
uint16_t RPCPort() const { return m_rpc_port; }
uint16_t OnionServiceTargetPort() const { return m_onion_service_target_port; }
@@ -41,10 +35,8 @@ private:
/**
* Creates and returns a std::unique_ptr<CBaseChainParams> of the chosen chain.
- * @returns a CBaseChainParams* of the chosen chain.
- * @throws a std::runtime_error if the chain is not supported.
*/
-std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain);
+std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const ChainType chain);
/**
*Set the arguments for chainparams
@@ -57,7 +49,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman);
*/
const CBaseChainParams& BaseParams();
-/** Sets the params returned by Params() to those for the given network. */
-void SelectBaseParams(const std::string& chain);
+/** Sets the params returned by Params() to those for the given chain. */
+void SelectBaseParams(const ChainType chain);
#endif // BITCOIN_CHAINPARAMSBASE_H
diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h
index f065647d49..dca6028c63 100644
--- a/src/chainparamsseeds.h
+++ b/src/chainparamsseeds.h
@@ -7,857 +7,895 @@
* Each line contains a BIP155 serialized (networkID, addr, port) tuple.
*/
static const uint8_t chainparams_seed_main[] = {
- 0x01,0x04,0x02,0x03,0x19,0xb5,0x20,0x8d,
- 0x01,0x04,0x02,0x98,0x4e,0x7c,0x20,0x8d,
- 0x01,0x04,0x05,0x27,0x4a,0xa6,0x20,0x8d,
- 0x01,0x04,0x05,0x2d,0x4f,0x51,0x47,0x9c,
- 0x01,0x04,0x05,0x35,0x10,0x80,0x20,0x8d,
- 0x01,0x04,0x05,0x5f,0xba,0x4e,0x20,0x8d,
+ 0x01,0x04,0x01,0x41,0xc3,0x62,0x20,0x8d,
+ 0x01,0x04,0x02,0x3b,0xec,0x38,0x20,0x8d,
+ 0x01,0x04,0x02,0x53,0x72,0x14,0x20,0x8d,
+ 0x01,0x04,0x02,0xf8,0xc2,0x10,0x20,0x8d,
+ 0x01,0x04,0x05,0x02,0x9a,0x06,0x20,0x8d,
+ 0x01,0x04,0x05,0x65,0x8c,0x1e,0x20,0x8d,
0x01,0x04,0x05,0x80,0x57,0x7e,0x20,0x8d,
- 0x01,0x04,0x05,0x85,0x41,0x52,0x20,0x8d,
- 0x01,0x04,0x05,0x92,0x14,0xe5,0x20,0x8d,
- 0x01,0x04,0x05,0xb4,0x29,0x77,0x20,0x8d,
+ 0x01,0x04,0x05,0x90,0x15,0x31,0x20,0x8d,
+ 0x01,0x04,0x05,0xac,0x84,0x68,0x20,0x8d,
0x01,0x04,0x05,0xbc,0x3e,0x12,0x20,0x8d,
- 0x01,0x04,0x05,0xc7,0xad,0x42,0x20,0x8d,
- 0x01,0x04,0x05,0xff,0x61,0x19,0x20,0x8d,
- 0x01,0x04,0x05,0xff,0x67,0xb4,0x20,0x8d,
- 0x01,0x04,0x08,0xd1,0x46,0x4d,0x20,0x8d,
+ 0x01,0x04,0x05,0xc8,0x02,0xb4,0x20,0x8d,
+ 0x01,0x04,0x08,0x81,0xb8,0xff,0x20,0x8d,
0x01,0x04,0x08,0xd1,0x69,0x8a,0x20,0x8d,
- 0x01,0x04,0x12,0xa2,0xd0,0x99,0xbc,0xcc,
- 0x01,0x04,0x17,0xaf,0x00,0xc8,0x20,0x8d,
+ 0x01,0x04,0x0c,0x22,0x62,0x94,0x20,0x8d,
+ 0x01,0x04,0x0e,0xc7,0x66,0x97,0x20,0x8d,
+ 0x01,0x04,0x12,0x1b,0x4f,0x11,0x20,0x8d,
+ 0x01,0x04,0x12,0x1b,0x7c,0xe7,0x20,0x8d,
+ 0x01,0x04,0x12,0xd8,0xf9,0x97,0x20,0x8d,
+ 0x01,0x04,0x17,0x58,0x9b,0x3a,0x20,0x8d,
+ 0x01,0x04,0x17,0x5d,0x65,0x9e,0x20,0x8d,
+ 0x01,0x04,0x17,0x6d,0x9c,0x4c,0x20,0x8d,
+ 0x01,0x04,0x17,0xaf,0x00,0xdc,0x20,0x8d,
0x01,0x04,0x17,0xaf,0x00,0xde,0x20,0x8d,
- 0x01,0x04,0x17,0xe9,0x6b,0x15,0x20,0x8d,
- 0x01,0x04,0x17,0xec,0x19,0xa9,0x20,0x8d,
- 0x01,0x04,0x18,0x23,0x44,0xe5,0x20,0x8d,
- 0x01,0x04,0x18,0x54,0xa4,0x32,0x20,0x8d,
- 0x01,0x04,0x18,0x74,0x99,0x73,0x20,0x8d,
- 0x01,0x04,0x18,0xb8,0x00,0x92,0x20,0x8d,
- 0x01,0x04,0x1b,0x21,0xa0,0xc4,0x20,0x8d,
+ 0x01,0x04,0x18,0xe8,0x24,0xe1,0x20,0x8d,
0x01,0x04,0x1b,0x7c,0x6c,0x13,0x20,0x8d,
0x01,0x04,0x1b,0x94,0xce,0x8c,0x20,0x8d,
- 0x01,0x04,0x1f,0x11,0x40,0xc0,0x20,0x8d,
- 0x01,0x04,0x1f,0x12,0x72,0x87,0x20,0x8d,
+ 0x01,0x04,0x1f,0x07,0x46,0xc3,0x20,0x8d,
+ 0x01,0x04,0x1f,0x19,0x62,0x10,0x20,0x8d,
0x01,0x04,0x1f,0x29,0x17,0xf9,0x20,0x8d,
- 0x01,0x04,0x1f,0x2a,0xb0,0x8a,0x20,0x8d,
+ 0x01,0x04,0x1f,0x2f,0x66,0x5c,0x20,0x8d,
0x01,0x04,0x1f,0x2f,0xca,0x70,0x20,0x8d,
- 0x01,0x04,0x22,0x41,0x2d,0x9d,0x20,0x8d,
- 0x01,0x04,0x22,0x50,0x86,0x44,0x20,0x8d,
+ 0x01,0x04,0x1f,0xa5,0x4e,0x92,0x20,0x8d,
+ 0x01,0x04,0x1f,0xa5,0xe4,0x8a,0x20,0x8d,
+ 0x01,0x04,0x22,0x40,0x65,0x04,0x20,0x8d,
+ 0x01,0x04,0x22,0x69,0x13,0x61,0x20,0x8d,
+ 0x01,0x04,0x22,0x7e,0x6b,0xb3,0x20,0x8d,
0x01,0x04,0x22,0x7e,0x73,0x23,0x20,0x8d,
- 0x01,0x04,0x25,0x01,0xcc,0xe7,0x20,0x8d,
+ 0x01,0x04,0x23,0xf5,0xba,0x75,0x20,0x8d,
+ 0x01,0x04,0x25,0x0f,0x3c,0x90,0x20,0x8d,
+ 0x01,0x04,0x25,0x10,0x69,0x3f,0x20,0x8d,
0x01,0x04,0x25,0x78,0x9b,0x22,0x20,0x8d,
- 0x01,0x04,0x25,0x8f,0x76,0xae,0x20,0x8d,
+ 0x01,0x04,0x25,0x78,0xb3,0x1d,0x20,0x8d,
+ 0x01,0x04,0x25,0x8b,0x66,0x49,0x20,0x8d,
0x01,0x04,0x25,0xc1,0xe3,0x10,0x20,0x8d,
0x01,0x04,0x25,0xdc,0x87,0x97,0x20,0x8d,
- 0x01,0x04,0x25,0xeb,0x92,0xec,0x20,0x8d,
- 0x01,0x04,0x26,0x7c,0x7e,0x2a,0x20,0x8d,
+ 0x01,0x04,0x26,0x35,0x81,0x43,0x20,0x8d,
+ 0x01,0x04,0x26,0x36,0x0e,0x59,0x20,0x8d,
0x01,0x04,0x26,0x8d,0x86,0x8c,0x20,0x8d,
0x01,0x04,0x26,0x91,0x97,0x96,0x20,0x8d,
- 0x01,0x04,0x28,0x73,0x89,0x1c,0x20,0x8d,
0x01,0x04,0x29,0x48,0x9a,0x42,0x20,0x8d,
- 0x01,0x04,0x29,0x4f,0x46,0x92,0x20,0x8d,
- 0x01,0x04,0x2a,0xc1,0x37,0x87,0x20,0x8d,
- 0x01,0x04,0x2b,0xe1,0x3e,0x6b,0x20,0x8d,
+ 0x01,0x04,0x2b,0x8f,0xcb,0xc6,0x20,0x8d,
+ 0x01,0x04,0x2d,0x0f,0x7c,0x75,0x20,0x8d,
0x01,0x04,0x2d,0x2b,0x61,0x67,0x20,0x8d,
- 0x01,0x04,0x2d,0x55,0x30,0x3a,0x20,0x8d,
- 0x01,0x04,0x2d,0x7e,0x1a,0xe5,0x20,0x8d,
+ 0x01,0x04,0x2d,0x2c,0xd5,0x74,0x20,0x8d,
+ 0x01,0x04,0x2d,0x3a,0xbb,0x65,0x20,0x8d,
+ 0x01,0x04,0x2d,0x4f,0xc0,0xec,0x20,0x8d,
+ 0x01,0x04,0x2d,0x51,0xf1,0x61,0x20,0x8d,
+ 0x01,0x04,0x2d,0x53,0xdc,0x66,0x20,0x8d,
+ 0x01,0x04,0x2d,0x53,0xf1,0x2e,0x20,0x8d,
+ 0x01,0x04,0x2d,0x57,0x6a,0x39,0x20,0x8d,
+ 0x01,0x04,0x2d,0x81,0x26,0x05,0x20,0x8d,
+ 0x01,0x04,0x2d,0x82,0x14,0xb1,0x20,0x8d,
0x01,0x04,0x2d,0x86,0x8e,0x28,0x20,0x8d,
- 0x01,0x04,0x2d,0x9a,0xfc,0xa2,0x20,0x8d,
- 0x01,0x04,0x2e,0x0d,0xd8,0xa9,0x20,0x8d,
+ 0x01,0x04,0x2d,0x87,0x04,0x8f,0x20,0x8d,
+ 0x01,0x04,0x2d,0x87,0x5c,0x7f,0x20,0x8d,
+ 0x01,0x04,0x2d,0x91,0xbc,0x70,0x20,0x8d,
0x01,0x04,0x2e,0x17,0x57,0xda,0x20,0x8d,
- 0x01,0x04,0x2e,0x28,0x7f,0xa4,0x20,0x8d,
- 0x01,0x04,0x2e,0x30,0x7e,0x3a,0x20,0x8d,
- 0x01,0x04,0x2e,0x3b,0x0d,0x23,0x20,0x8d,
- 0x01,0x04,0x2e,0x48,0xee,0x11,0x20,0x8d,
- 0x01,0x04,0x2e,0x80,0x8d,0xb8,0x20,0x8d,
- 0x01,0x04,0x2e,0x92,0xf8,0x59,0x20,0x8d,
- 0x01,0x04,0x2e,0xa5,0xdd,0xd1,0x24,0x75,
+ 0x01,0x04,0x2e,0x20,0x32,0x62,0x20,0x8d,
+ 0x01,0x04,0x2e,0x20,0x4e,0x11,0x20,0x8d,
+ 0x01,0x04,0x2e,0x3b,0x28,0x5b,0x20,0x8d,
+ 0x01,0x04,0x2e,0x8a,0xf6,0x4d,0x20,0x8d,
0x01,0x04,0x2e,0xa6,0x8e,0x02,0x20,0x8d,
+ 0x01,0x04,0x2e,0xa6,0xa2,0x3b,0x20,0x8d,
0x01,0x04,0x2e,0xaf,0xb2,0x03,0x20,0x8d,
- 0x01,0x04,0x2f,0x24,0x90,0x33,0x20,0x8d,
- 0x01,0x04,0x2f,0xb4,0x31,0x9e,0x20,0x8d,
- 0x01,0x04,0x31,0xe4,0x83,0x85,0x08,0xa2,
+ 0x01,0x04,0x2e,0xbc,0x0f,0x06,0x20,0x8d,
+ 0x01,0x04,0x2e,0xbc,0x1e,0x76,0x20,0x8d,
+ 0x01,0x04,0x2e,0xdf,0xdf,0xd8,0x20,0x8d,
+ 0x01,0x04,0x2e,0xe2,0x12,0x87,0x20,0x8d,
+ 0x01,0x04,0x2f,0x58,0x56,0x4f,0x20,0x8d,
+ 0x01,0x04,0x2f,0x94,0x07,0x45,0x20,0x8d,
+ 0x01,0x04,0x2f,0xc6,0xdf,0x3c,0x20,0x8d,
0x01,0x04,0x32,0x02,0x0d,0xa4,0x20,0x8d,
- 0x01,0x04,0x32,0x23,0x47,0x33,0x20,0x8d,
+ 0x01,0x04,0x32,0x04,0x87,0x54,0x20,0x8d,
+ 0x01,0x04,0x32,0x35,0x27,0xed,0x20,0x8d,
0x01,0x04,0x32,0x35,0xfa,0xa2,0x20,0x8d,
- 0x01,0x04,0x33,0x44,0x24,0x39,0x20,0x8d,
- 0x01,0x04,0x33,0x8a,0x04,0x87,0x75,0x31,
+ 0x01,0x04,0x32,0x44,0x79,0x2c,0x20,0x8d,
+ 0x01,0x04,0x32,0x75,0x84,0xb2,0x20,0x8d,
0x01,0x04,0x33,0x9a,0x3e,0x67,0x20,0x8d,
0x01,0x04,0x33,0x9e,0x96,0x9b,0x20,0x8d,
+ 0x01,0x04,0x33,0xfa,0x2e,0xd7,0x20,0x8d,
0x01,0x04,0x36,0xb0,0x3f,0x10,0x20,0x8d,
0x01,0x04,0x3a,0x9e,0x00,0x56,0x20,0x8d,
- 0x01,0x04,0x3b,0x8a,0x73,0x89,0x20,0x8d,
- 0x01,0x04,0x3b,0xa7,0xbf,0x3c,0x20,0x8d,
0x01,0x04,0x3c,0xcd,0xcd,0x77,0x20,0x8d,
- 0x01,0x04,0x3c,0xea,0x7a,0xf5,0x20,0x8d,
- 0x01,0x04,0x3c,0xf0,0xd2,0x9b,0x20,0x8d,
- 0x01,0x04,0x3d,0xef,0x5b,0xfa,0x20,0x8d,
- 0x01,0x04,0x3e,0x4a,0x8f,0x0b,0x20,0x8d,
- 0x01,0x04,0x3e,0x8a,0xa2,0x0c,0x20,0x8d,
- 0x01,0x04,0x3e,0xa9,0x4a,0xe9,0x20,0x8d,
+ 0x01,0x04,0x3d,0x4a,0x63,0xc1,0x20,0x8d,
+ 0x01,0x04,0x3d,0x5c,0x3b,0x68,0x20,0x8d,
+ 0x01,0x04,0x3e,0x7a,0xad,0xab,0x20,0x8d,
0x01,0x04,0x3e,0xab,0x81,0x20,0x20,0x8d,
- 0x01,0x04,0x3e,0xd1,0xc6,0x41,0x20,0x8d,
- 0x01,0x04,0x3f,0xf7,0x93,0xa6,0x20,0x8d,
- 0x01,0x04,0x40,0x62,0x4c,0x3e,0x20,0x8d,
+ 0x01,0x04,0x3e,0xb2,0x1b,0xef,0x20,0x8d,
+ 0x01,0x04,0x3e,0xd1,0xd2,0x03,0x20,0x8d,
+ 0x01,0x04,0x3e,0xd7,0x7f,0x49,0x20,0x8d,
+ 0x01,0x04,0x3e,0xee,0x94,0x68,0x20,0x8d,
+ 0x01,0x04,0x3e,0xf5,0x99,0x08,0x20,0x8d,
+ 0x01,0x04,0x40,0x92,0x88,0x2d,0x20,0x8d,
+ 0x01,0x04,0x41,0x15,0x86,0xb8,0x20,0x8d,
+ 0x01,0x04,0x42,0x12,0x0d,0x92,0x20,0x8d,
+ 0x01,0x04,0x42,0x17,0xe9,0x2b,0x20,0x8d,
+ 0x01,0x04,0x42,0x1b,0x62,0xd8,0x20,0x8d,
0x01,0x04,0x42,0x1d,0x81,0xda,0x20,0x8d,
- 0x01,0x04,0x42,0x60,0xeb,0x1c,0x20,0x8d,
- 0x01,0x04,0x42,0x82,0x78,0x34,0x20,0x8d,
- 0x01,0x04,0x42,0xc6,0xd1,0xf3,0x20,0x8d,
+ 0x01,0x04,0x42,0x26,0x5e,0x0d,0x20,0x8d,
+ 0x01,0x04,0x42,0x2d,0x8d,0x2e,0x20,0x8d,
+ 0x01,0x04,0x42,0x3a,0xf3,0xd7,0x20,0x8d,
+ 0x01,0x04,0x42,0x72,0x21,0x31,0x20,0x8d,
+ 0x01,0x04,0x42,0xc6,0xd3,0xa7,0x20,0x8d,
0x01,0x04,0x42,0xd0,0x40,0x80,0x20,0x8d,
- 0x01,0x04,0x42,0xe1,0xe7,0x94,0x20,0x8d,
- 0x01,0x04,0x43,0x37,0x03,0xc8,0x20,0x8d,
- 0x01,0x04,0x43,0x3a,0xe8,0x6b,0x20,0x8d,
- 0x01,0x04,0x43,0xd3,0x5c,0x02,0x20,0x8d,
- 0x01,0x04,0x43,0xdf,0x77,0x7a,0x20,0x8d,
- 0x01,0x04,0x44,0x30,0x83,0xfb,0x20,0x8d,
- 0x01,0x04,0x44,0xb5,0x04,0x0c,0x20,0x8d,
- 0x01,0x04,0x45,0x0e,0xb9,0x09,0x20,0x8d,
- 0x01,0x04,0x45,0x36,0x1d,0xc1,0x20,0x8d,
+ 0x01,0x04,0x42,0xdb,0xc4,0xaa,0x20,0x8d,
+ 0x01,0x04,0x43,0xd2,0xe4,0xcb,0x20,0x8d,
+ 0x01,0x04,0x44,0xb7,0x4b,0xfb,0x20,0x8d,
+ 0x01,0x04,0x44,0xc2,0x7d,0x8c,0x20,0x8d,
+ 0x01,0x04,0x44,0xc7,0x78,0x11,0x20,0x8d,
+ 0x01,0x04,0x45,0x04,0x5e,0xe2,0x20,0x8d,
+ 0x01,0x04,0x45,0x08,0xaf,0xc9,0x20,0x8d,
0x01,0x04,0x45,0x3b,0x12,0x16,0x20,0x8d,
- 0x01,0x04,0x45,0x83,0x65,0xb0,0x20,0x8d,
- 0x01,0x04,0x45,0xa5,0xcd,0x8e,0x22,0x81,
+ 0x01,0x04,0x45,0xc4,0x98,0x21,0x20,0x8d,
0x01,0x04,0x45,0xe4,0xdb,0x7c,0x20,0x8d,
- 0x01,0x04,0x46,0x3b,0x7b,0x19,0x20,0x8d,
- 0x01,0x04,0x46,0x3e,0x0d,0x96,0x20,0x8d,
- 0x01,0x04,0x46,0x42,0xf8,0xaa,0x20,0x8d,
- 0x01,0x04,0x46,0x70,0x99,0xe5,0x20,0x8d,
+ 0x01,0x04,0x46,0x40,0x1b,0x0c,0x20,0x8d,
0x01,0x04,0x46,0xa0,0xf0,0x84,0x20,0x8d,
- 0x01,0x04,0x46,0xbe,0xb1,0xcc,0x20,0x8d,
- 0x01,0x04,0x47,0x1c,0xbd,0xef,0x20,0x8d,
- 0x01,0x04,0x47,0xea,0x7d,0xc6,0x20,0x8d,
- 0x01,0x04,0x48,0x4a,0x7b,0xb3,0x20,0x8d,
- 0x01,0x04,0x48,0xfd,0xec,0xd9,0x20,0x8d,
- 0x01,0x04,0x49,0xdb,0xfe,0x78,0x20,0x8d,
+ 0x01,0x04,0x47,0x4f,0x6d,0x80,0x20,0x8d,
+ 0x01,0x04,0x47,0xb8,0xc1,0x4b,0x20,0x8d,
+ 0x01,0x04,0x48,0x0f,0x3b,0xad,0x20,0x8d,
+ 0x01,0x04,0x48,0x30,0xfd,0xa8,0x20,0x8d,
+ 0x01,0x04,0x48,0xcf,0xab,0xd2,0x20,0x8d,
+ 0x01,0x04,0x49,0x75,0x84,0x8a,0x20,0x8d,
+ 0x01,0x04,0x49,0xd4,0xe2,0x3b,0x20,0x8d,
+ 0x01,0x04,0x4a,0x4c,0x97,0x6e,0x20,0x8d,
0x01,0x04,0x4a,0x5b,0x73,0xe5,0x20,0x8d,
0x01,0x04,0x4a,0x76,0x89,0x77,0x20,0x8d,
- 0x01,0x04,0x4a,0xc3,0xa6,0x64,0x20,0x8d,
+ 0x01,0x04,0x4a,0xd5,0xaf,0x6c,0x20,0x8d,
+ 0x01,0x04,0x4a,0xd5,0xfb,0xef,0x20,0x8d,
0x01,0x04,0x4a,0xdc,0xff,0xbe,0x20,0x8d,
- 0x01,0x04,0x4c,0x43,0xd3,0x6e,0x20,0x8d,
- 0x01,0x04,0x4c,0xa9,0xa3,0x0e,0x20,0x8d,
- 0x01,0x04,0x4d,0x20,0x79,0xa2,0x20,0x8d,
- 0x01,0x04,0x4d,0x35,0x87,0x4a,0x20,0x8d,
+ 0x01,0x04,0x4a,0xdd,0xbd,0x6d,0x20,0x8d,
+ 0x01,0x04,0x4b,0x53,0xcb,0xe1,0x20,0x8d,
+ 0x01,0x04,0x4b,0xac,0x34,0xba,0x20,0x8d,
+ 0x01,0x04,0x4c,0x18,0x8f,0x16,0x20,0x8d,
+ 0x01,0x04,0x4c,0x45,0xca,0xf7,0x20,0x8d,
+ 0x01,0x04,0x4c,0x49,0xc6,0xf2,0x20,0x8d,
+ 0x01,0x04,0x4c,0x77,0xf8,0xf0,0x20,0x8d,
+ 0x01,0x04,0x4d,0x14,0x30,0x90,0x20,0x8d,
+ 0x01,0x04,0x4d,0x16,0x98,0xef,0x20,0x8d,
+ 0x01,0x04,0x4d,0x25,0xe0,0xde,0x20,0x8d,
+ 0x01,0x04,0x4d,0x30,0xc4,0xea,0x20,0x8d,
0x01,0x04,0x4d,0x46,0x10,0xf5,0x20,0x8d,
- 0x01,0x04,0x4d,0x55,0xcc,0x95,0x20,0x8d,
- 0x01,0x04,0x4d,0x6b,0x26,0xef,0x20,0x8d,
- 0x01,0x04,0x4d,0x78,0x1a,0x66,0x20,0x8d,
0x01,0x04,0x4d,0xa2,0xbe,0x5a,0x20,0x8d,
0x01,0x04,0x4e,0x14,0xe3,0xf9,0x20,0x8d,
0x01,0x04,0x4e,0x15,0xa7,0x08,0x20,0x8d,
- 0x01,0x04,0x4e,0x1b,0x8b,0x0d,0x20,0x8d,
- 0x01,0x04,0x4e,0x5a,0x5b,0xdc,0x20,0x8d,
+ 0x01,0x04,0x4e,0x23,0x93,0xcb,0x20,0x8d,
0x01,0x04,0x4e,0x6c,0x6c,0x19,0x20,0x8d,
- 0x01,0x04,0x4e,0x6c,0x6c,0x26,0x20,0x8d,
- 0x01,0x04,0x4f,0x4d,0xb6,0xb7,0x20,0x8d,
- 0x01,0x04,0x4f,0x62,0x9f,0x07,0x2c,0x45,
- 0x01,0x04,0x4f,0xbd,0xd3,0xc9,0x20,0x8d,
- 0x01,0x04,0x50,0x37,0xe1,0x9e,0x20,0x8d,
- 0x01,0x04,0x50,0x53,0xba,0x23,0x20,0x8d,
- 0x01,0x04,0x50,0x58,0xac,0xe3,0xfb,0x08,
- 0x01,0x04,0x50,0xd1,0x57,0x67,0x24,0x75,
+ 0x01,0x04,0x4e,0x9a,0xed,0x3c,0x20,0x8d,
+ 0x01,0x04,0x4f,0x0b,0x1f,0x4c,0x20,0x8d,
+ 0x01,0x04,0x4f,0x57,0x58,0xeb,0x20,0x8d,
+ 0x01,0x04,0x4f,0x65,0x01,0x19,0x20,0x8d,
+ 0x01,0x04,0x4f,0x7c,0x07,0xf1,0x20,0x8d,
+ 0x01,0x04,0x4f,0x7c,0x07,0xfd,0x20,0x8d,
+ 0x01,0x04,0x4f,0x96,0x44,0x2a,0x20,0x8d,
+ 0x01,0x04,0x4f,0xf9,0x0a,0x35,0x20,0x8d,
+ 0x01,0x04,0x50,0x52,0x15,0x4d,0x20,0x8d,
+ 0x01,0x04,0x50,0x52,0x4c,0x3b,0x20,0x8d,
+ 0x01,0x04,0x50,0x58,0xac,0xe3,0x20,0x8d,
+ 0x01,0x04,0x50,0x5d,0xd5,0xf6,0x20,0x8d,
+ 0x01,0x04,0x50,0x6f,0x8e,0xd5,0x20,0x8d,
+ 0x01,0x04,0x50,0xd0,0xe3,0x86,0x20,0x8d,
+ 0x01,0x04,0x50,0xd0,0xe4,0x09,0x20,0x8d,
+ 0x01,0x04,0x50,0xd1,0x40,0x56,0x20,0x8d,
0x01,0x04,0x50,0xe5,0x1c,0x3c,0x20,0x8d,
0x01,0x04,0x51,0x07,0x10,0xb6,0x20,0x8d,
- 0x01,0x04,0x51,0x07,0x11,0xca,0x20,0x8d,
0x01,0x04,0x51,0x13,0x0a,0x02,0x20,0x8d,
- 0x01,0x04,0x51,0x58,0xdd,0xbe,0x20,0x8d,
+ 0x01,0x04,0x51,0xa2,0xc4,0x2b,0x20,0x8d,
0x01,0x04,0x51,0xab,0x16,0x8f,0x20,0x8d,
+ 0x01,0x04,0x51,0xac,0xdd,0x04,0x20,0x8d,
0x01,0x04,0x51,0xe0,0x2c,0xa4,0x20,0x8d,
- 0x01,0x04,0x51,0xe0,0xa0,0x51,0x20,0x8d,
+ 0x01,0x04,0x51,0xf5,0x60,0x24,0x20,0x8d,
0x01,0x04,0x52,0x01,0x44,0x36,0x20,0x8d,
- 0x01,0x04,0x52,0x15,0xa4,0x2f,0x20,0x8d,
- 0x01,0x04,0x52,0x40,0x74,0x05,0x20,0x8d,
0x01,0x04,0x52,0x42,0x0a,0x0b,0x20,0x8d,
+ 0x01,0x04,0x52,0x42,0xd3,0x1f,0x20,0x8d,
+ 0x01,0x04,0x52,0x47,0x04,0x9a,0x20,0x8d,
0x01,0x04,0x52,0x60,0x60,0x28,0x20,0x8d,
0x01,0x04,0x52,0x74,0x32,0x65,0x20,0x8d,
- 0x01,0x04,0x52,0x81,0x44,0x3e,0x20,0x8d,
- 0x01,0x04,0x52,0x88,0x63,0x7a,0x20,0x8d,
- 0x01,0x04,0x52,0x9a,0x18,0xd1,0x20,0x8d,
- 0x01,0x04,0x52,0xc5,0xd7,0x7d,0x20,0x8d,
- 0x01,0x04,0x53,0x80,0x84,0x5b,0x20,0x8d,
+ 0x01,0x04,0x52,0x88,0x62,0xf9,0x20,0x8d,
+ 0x01,0x04,0x52,0xc3,0xed,0xfd,0x20,0x8d,
0x01,0x04,0x53,0x89,0x29,0x0a,0x20,0x8d,
- 0x01,0x04,0x53,0xd0,0x06,0xd3,0x20,0x8d,
+ 0x01,0x04,0x53,0xab,0xaf,0x05,0x20,0x8d,
0x01,0x04,0x53,0xd0,0xc1,0xf2,0x20,0x8d,
- 0x01,0x04,0x53,0xde,0x8a,0x55,0x20,0x8d,
- 0x01,0x04,0x53,0xf0,0x7c,0x44,0x20,0x8d,
- 0x01,0x04,0x53,0xf3,0xbf,0xc7,0x20,0x8d,
- 0x01,0x04,0x54,0x09,0x05,0xd3,0x20,0x8d,
- 0x01,0x04,0x54,0x1c,0x39,0x5a,0x20,0x8d,
+ 0x01,0x04,0x53,0xe9,0x4c,0xa5,0x20,0x8d,
+ 0x01,0x04,0x53,0xf0,0x59,0xc4,0x20,0x8d,
0x01,0x04,0x54,0x26,0x03,0xf9,0x20,0x8d,
- 0x01,0x04,0x54,0x70,0x3c,0x10,0x20,0x8d,
- 0x01,0x04,0x54,0xd7,0x38,0x77,0x20,0x8d,
- 0x01,0x04,0x54,0xe2,0xf3,0xaf,0x20,0x8d,
- 0x01,0x04,0x54,0xf5,0x0e,0x49,0x20,0x8d,
- 0x01,0x04,0x54,0xfc,0x9d,0x5a,0x47,0x9d,
+ 0x01,0x04,0x54,0x36,0x17,0x30,0x20,0x8d,
+ 0x01,0x04,0x54,0x7e,0xd8,0x4d,0x20,0x8d,
+ 0x01,0x04,0x54,0xd3,0xbb,0xd3,0x20,0x8d,
+ 0x01,0x04,0x54,0xf6,0xc8,0x7a,0x20,0x8d,
0x01,0x04,0x54,0xff,0xf4,0x3d,0x20,0x8d,
- 0x01,0x04,0x55,0x17,0x18,0x7b,0x20,0x8d,
- 0x01,0x04,0x55,0x34,0xb9,0x1d,0x21,0xda,
- 0x01,0x04,0x55,0x3a,0x78,0xc9,0x20,0x8d,
- 0x01,0x04,0x55,0x5d,0x60,0x12,0x20,0x8d,
- 0x01,0x04,0x55,0xa5,0x08,0xc5,0x20,0x8d,
- 0x01,0x04,0x55,0xad,0xa5,0x42,0x20,0x8d,
- 0x01,0x04,0x55,0xb8,0x8f,0x69,0x20,0x8d,
- 0x01,0x04,0x55,0xbf,0x4a,0x67,0x20,0x8d,
+ 0x01,0x04,0x55,0xa5,0x2a,0x73,0x20,0x8d,
0x01,0x04,0x55,0xc2,0xee,0x86,0x20,0x8d,
- 0x01,0x04,0x55,0xc3,0x36,0x6e,0x20,0x8d,
- 0x01,0x04,0x55,0xc3,0xc4,0x8e,0x20,0x8d,
- 0x01,0x04,0x55,0xd0,0x45,0x0b,0x20,0x8d,
0x01,0x04,0x55,0xd0,0x45,0x15,0x20,0x8d,
0x01,0x04,0x55,0xd0,0x47,0x24,0x20,0x8d,
- 0x01,0x04,0x55,0xd0,0x47,0x27,0x20,0x8d,
+ 0x01,0x04,0x55,0xd1,0xf0,0x5b,0x20,0x8d,
0x01,0x04,0x55,0xd6,0x76,0x47,0x20,0x8d,
0x01,0x04,0x55,0xd6,0xa1,0xfc,0x20,0x8d,
- 0x01,0x04,0x55,0xd8,0x20,0x49,0x20,0x8d,
- 0x01,0x04,0x55,0xfe,0x62,0xdd,0x20,0x8d,
- 0x01,0x04,0x56,0x3a,0x0b,0x98,0x20,0x8d,
+ 0x01,0x04,0x55,0xec,0xbe,0xfc,0x20,0x8d,
+ 0x01,0x04,0x55,0xf3,0x73,0x88,0x20,0x8d,
+ 0x01,0x04,0x56,0x16,0x14,0x0d,0x20,0x8d,
+ 0x01,0x04,0x56,0x31,0x22,0x5c,0x20,0x8d,
0x01,0x04,0x56,0x5f,0x08,0xf9,0x20,0x8d,
- 0x01,0x04,0x56,0x64,0x1a,0xbc,0x20,0x8d,
- 0x01,0x04,0x56,0x6a,0x8f,0x8f,0xd8,0x4d,
- 0x01,0x04,0x56,0x7c,0x91,0xb8,0x20,0x8d,
- 0x01,0x04,0x56,0x85,0xfb,0xef,0x22,0xc5,
+ 0x01,0x04,0x56,0x68,0xe4,0x0a,0x20,0x8d,
+ 0x01,0x04,0x56,0x68,0xe4,0x17,0x20,0x8d,
0x01,0x04,0x57,0x4f,0x5e,0xdd,0x20,0x8d,
- 0x01,0x04,0x57,0x78,0x08,0x05,0x4e,0x28,
- 0x01,0x04,0x57,0x7d,0x9d,0xdc,0x20,0x8d,
- 0x01,0x04,0x58,0x09,0x4c,0x85,0x20,0x8d,
- 0x01,0x04,0x58,0x5a,0xb8,0x44,0x20,0x8d,
- 0x01,0x04,0x58,0x97,0x65,0x0e,0x13,0x88,
- 0x01,0x04,0x58,0x97,0x65,0xfd,0x13,0x88,
- 0x01,0x04,0x58,0xc6,0x5c,0x2f,0x20,0x8d,
+ 0x01,0x04,0x58,0x0a,0x59,0x17,0x20,0x8d,
+ 0x01,0x04,0x58,0x54,0xdf,0x1e,0x20,0x8d,
+ 0x01,0x04,0x58,0x56,0x7d,0x32,0x20,0x8d,
+ 0x01,0x04,0x58,0x5a,0x4d,0x64,0x20,0x8d,
+ 0x01,0x04,0x58,0x61,0x28,0x32,0x20,0x8d,
+ 0x01,0x04,0x58,0x89,0x6d,0x3e,0x20,0x8d,
+ 0x01,0x04,0x58,0x93,0xf4,0xfa,0x20,0x8d,
0x01,0x04,0x58,0xd0,0x73,0x46,0x20,0x8d,
- 0x01,0x04,0x58,0xd2,0x0f,0x18,0x20,0x8d,
- 0x01,0x04,0x58,0xd4,0x2d,0xa6,0x20,0x8d,
- 0x01,0x04,0x59,0x66,0xce,0xee,0x20,0x8d,
- 0x01,0x04,0x59,0x67,0x6f,0x22,0x20,0x8d,
- 0x01,0x04,0x59,0x72,0x8f,0x71,0x20,0x8d,
- 0x01,0x04,0x59,0x86,0x3e,0x4a,0x20,0x8d,
- 0x01,0x04,0x59,0x98,0x08,0xe7,0x20,0x8d,
- 0x01,0x04,0x59,0xa1,0x1a,0x4e,0x20,0x8d,
- 0x01,0x04,0x59,0xcf,0x83,0x13,0x20,0x8d,
- 0x01,0x04,0x59,0xf8,0xc1,0xe5,0x20,0x8d,
- 0x01,0x04,0x5a,0x03,0x30,0x3e,0x20,0x8d,
- 0x01,0x04,0x5a,0x92,0x79,0x61,0x20,0x8d,
+ 0x01,0x04,0x58,0xd4,0x35,0xf6,0x20,0x8d,
+ 0x01,0x04,0x59,0x23,0x8e,0xa8,0x20,0x8d,
+ 0x01,0x04,0x59,0x4e,0x6f,0xc5,0x20,0x8d,
+ 0x01,0x04,0x59,0x75,0x3b,0x81,0x20,0x8d,
+ 0x01,0x04,0x59,0x93,0x6c,0xc8,0x20,0x8d,
+ 0x01,0x04,0x59,0xa3,0x84,0xb4,0x20,0x8d,
+ 0x01,0x04,0x59,0xa5,0xe8,0xf2,0x20,0x8d,
+ 0x01,0x04,0x59,0xd8,0x15,0x60,0x20,0x8d,
+ 0x01,0x04,0x5a,0x32,0xac,0xb6,0x20,0x8d,
0x01,0x04,0x5a,0x92,0x82,0xd6,0x20,0x8d,
- 0x01,0x04,0x5a,0xc4,0xa9,0x3a,0x20,0x8d,
- 0x01,0x04,0x5a,0xfa,0x09,0x01,0x20,0x8d,
+ 0x01,0x04,0x5a,0x92,0xd0,0xa2,0x20,0x8d,
+ 0x01,0x04,0x5a,0x9c,0x1a,0x94,0x20,0x8d,
+ 0x01,0x04,0x5a,0xa3,0xac,0x8b,0x20,0x8d,
+ 0x01,0x04,0x5a,0xb1,0xa3,0x4d,0x20,0x8d,
+ 0x01,0x04,0x5b,0x43,0x91,0x6e,0x20,0x8d,
0x01,0x04,0x5b,0x5d,0xc2,0x9a,0x20,0x8d,
- 0x01,0x04,0x5b,0x7e,0x28,0x6d,0x20,0x8d,
- 0x01,0x04,0x5b,0xcc,0x63,0xb2,0x20,0x8d,
+ 0x01,0x04,0x5b,0x7b,0xb6,0xa4,0x20,0x8d,
+ 0x01,0x04,0x5b,0x7b,0xb7,0xdb,0x20,0x8d,
+ 0x01,0x04,0x5b,0x87,0x00,0xbb,0x20,0x8d,
+ 0x01,0x04,0x5b,0x93,0xe8,0x62,0x20,0x8d,
+ 0x01,0x04,0x5b,0xb8,0xa8,0xf9,0x20,0x8d,
+ 0x01,0x04,0x5b,0xc1,0xed,0x74,0x20,0x8d,
+ 0x01,0x04,0x5b,0xc7,0x29,0x2d,0x20,0x8d,
0x01,0x04,0x5b,0xcc,0x95,0x05,0x20,0x8d,
- 0x01,0x04,0x5b,0xce,0x11,0xc3,0x20,0x8d,
- 0x01,0x04,0x5b,0xd1,0x33,0x83,0x20,0x8d,
0x01,0x04,0x5b,0xd7,0x5b,0xfe,0x20,0x8d,
- 0x01,0x04,0x5c,0x5b,0x1b,0x3c,0x20,0x8d,
+ 0x01,0x04,0x5b,0xdb,0x19,0xe8,0x20,0x8d,
+ 0x01,0x04,0x5b,0xed,0x58,0xda,0x20,0x8d,
+ 0x01,0x04,0x5c,0x1b,0x96,0x2e,0x20,0x8d,
+ 0x01,0x04,0x5c,0x1b,0x96,0x2f,0x20,0x8d,
0x01,0x04,0x5c,0xdd,0x14,0xe8,0x20,0x8d,
- 0x01,0x04,0x5c,0xff,0x55,0x1f,0x20,0x8d,
- 0x01,0x04,0x5d,0x04,0x65,0x25,0x20,0x8d,
- 0x01,0x04,0x5d,0x2e,0x51,0x05,0x20,0x8d,
- 0x01,0x04,0x5d,0x39,0x51,0xa2,0x20,0x8d,
- 0x01,0x04,0x5d,0x49,0x27,0xc4,0x20,0x8d,
- 0x01,0x04,0x5d,0x5a,0x52,0xe2,0x20,0x8d,
+ 0x01,0x04,0x5c,0xdd,0x7e,0x41,0x20,0x8d,
+ 0x01,0x04,0x5d,0x21,0xc0,0xcc,0x20,0x8d,
+ 0x01,0x04,0x5d,0x29,0xed,0x4e,0x20,0x8d,
0x01,0x04,0x5d,0x5f,0x58,0x0d,0x20,0x8d,
+ 0x01,0x04,0x5d,0x5f,0xe3,0x7d,0x20,0x8d,
+ 0x01,0x04,0x5d,0x67,0x0d,0x01,0x20,0x8d,
+ 0x01,0x04,0x5d,0x73,0x56,0xef,0x20,0x8d,
0x01,0x04,0x5d,0x7b,0xb4,0xa4,0x20,0x8d,
- 0x01,0x04,0x5d,0xbd,0x91,0xa9,0x20,0x8d,
- 0x01,0x04,0x5e,0x11,0xb9,0x6b,0x20,0x8d,
- 0x01,0x04,0x5e,0x4b,0xc6,0x78,0x20,0x8d,
- 0x01,0x04,0x5e,0x72,0xc4,0xa9,0x20,0x8d,
- 0x01,0x04,0x5e,0x8e,0xd5,0xfa,0xd8,0xf8,
+ 0x01,0x04,0x5d,0xba,0xc9,0xad,0x20,0x8d,
+ 0x01,0x04,0x5d,0xbe,0x75,0x1a,0x20,0x8d,
+ 0x01,0x04,0x5e,0x13,0x07,0x37,0x20,0x8d,
+ 0x01,0x04,0x5e,0x17,0x15,0x50,0x20,0x8d,
+ 0x01,0x04,0x5e,0x17,0xcd,0x6e,0x20,0x8d,
+ 0x01,0x04,0x5e,0x83,0x00,0x49,0x20,0x8d,
+ 0x01,0x04,0x5e,0x8e,0xed,0x04,0x20,0x8d,
0x01,0x04,0x5e,0x9a,0x9f,0x63,0x20,0x8d,
- 0x01,0x04,0x5e,0x9e,0xf6,0xb7,0x20,0x8d,
- 0x01,0x04,0x5e,0xef,0x91,0x20,0x20,0x8d,
- 0x01,0x04,0x5f,0x1f,0x0c,0x16,0x20,0x8d,
- 0x01,0x04,0x5f,0x1f,0xc4,0x0f,0x20,0x8d,
- 0x01,0x04,0x5f,0x6e,0x85,0xdf,0x20,0x8d,
+ 0x01,0x04,0x5e,0xca,0x32,0xc8,0x20,0x8d,
+ 0x01,0x04,0x5e,0xe7,0xfd,0x12,0x20,0x8d,
+ 0x01,0x04,0x5f,0x2a,0x8c,0x8e,0x20,0x8d,
+ 0x01,0x04,0x5f,0x43,0x12,0x64,0x20,0x8d,
+ 0x01,0x04,0x5f,0x46,0xee,0xb0,0x20,0x8d,
+ 0x01,0x04,0x5f,0x53,0x49,0x1f,0x20,0x8d,
+ 0x01,0x04,0x5f,0x5a,0x80,0x03,0x20,0x8d,
0x01,0x04,0x5f,0x6e,0xea,0x5d,0x20,0x8d,
0x01,0x04,0x5f,0xa1,0x0c,0x2d,0x20,0x8d,
+ 0x01,0x04,0x5f,0xac,0x3e,0xa7,0x20,0x8d,
+ 0x01,0x04,0x5f,0xb3,0x80,0x57,0x20,0x8d,
0x01,0x04,0x5f,0xbf,0x82,0x64,0x20,0x8d,
- 0x01,0x04,0x5f,0xd0,0x9e,0xa1,0x20,0x8d,
- 0x01,0x04,0x5f,0xd5,0x91,0xda,0x20,0x8d,
0x01,0x04,0x5f,0xd6,0x35,0x9a,0x20,0x8d,
- 0x01,0x04,0x5f,0xd6,0x35,0xa0,0x20,0x8d,
- 0x01,0x04,0x60,0x2c,0x9c,0xc7,0x20,0x8d,
+ 0x01,0x04,0x60,0x03,0x35,0xfe,0x20,0x8d,
0x01,0x04,0x61,0x4b,0x91,0x0c,0x20,0x8d,
+ 0x01,0x04,0x61,0x51,0xc6,0xb4,0x20,0x8d,
+ 0x01,0x04,0x61,0x57,0xd8,0x6e,0x20,0x8d,
+ 0x01,0x04,0x63,0xe5,0xd2,0x6f,0x20,0x8d,
+ 0x01,0x04,0x63,0xf6,0x57,0x02,0x20,0x8d,
+ 0x01,0x04,0x65,0x2b,0x7c,0xc3,0x20,0x8d,
0x01,0x04,0x66,0x84,0xc0,0x8d,0x20,0x8d,
- 0x01,0x04,0x67,0x0e,0xf5,0xfa,0x20,0x8d,
- 0x01,0x04,0x67,0x55,0x26,0xcd,0x20,0x8d,
- 0x01,0x04,0x67,0x58,0x5c,0x4e,0x20,0x8c,
+ 0x01,0x04,0x67,0x15,0x03,0x59,0x20,0x8d,
+ 0x01,0x04,0x67,0x23,0x79,0x48,0x20,0x8d,
0x01,0x04,0x67,0x63,0xa8,0x64,0x20,0x8d,
0x01,0x04,0x67,0x63,0xa8,0x8c,0x20,0x8d,
0x01,0x04,0x67,0x63,0xaa,0xd2,0x20,0x8d,
0x01,0x04,0x67,0x63,0xaa,0xdc,0x20,0x8d,
- 0x01,0x04,0x67,0x64,0x2c,0x46,0x20,0x8d,
- 0x01,0x04,0x67,0xb2,0xec,0x1b,0x20,0x8d,
- 0x01,0x04,0x67,0xd1,0x0c,0x90,0x20,0x8d,
- 0x01,0x04,0x68,0x3b,0x93,0x0f,0x20,0x8d,
- 0x01,0x04,0x68,0x81,0xab,0x79,0x20,0x8d,
- 0x01,0x04,0x68,0xc8,0x41,0xea,0x20,0x8d,
+ 0x01,0x04,0x67,0x69,0xca,0x32,0x20,0x8d,
0x01,0x04,0x68,0xee,0xdc,0xc7,0x20,0x8d,
+ 0x01,0x04,0x68,0xf3,0x21,0xa5,0x20,0x8d,
0x01,0x04,0x68,0xf4,0x49,0x06,0x20,0x8d,
- 0x01,0x04,0x6a,0x47,0x77,0xe6,0x20,0x8d,
- 0x01,0x04,0x6b,0xad,0xa6,0x2b,0x20,0x8d,
- 0x01,0x04,0x6c,0xa1,0x16,0x4e,0x20,0x8d,
- 0x01,0x04,0x6c,0xae,0x3f,0xea,0x20,0x8d,
+ 0x01,0x04,0x6c,0x1a,0x7d,0xd6,0x20,0x8d,
+ 0x01,0x04,0x6d,0x56,0x3c,0x21,0x20,0x8d,
0x01,0x04,0x6d,0x63,0x3f,0x9f,0x20,0x8d,
- 0x01,0x04,0x6d,0x69,0x28,0xf7,0x20,0x8d,
- 0x01,0x04,0x6d,0x6b,0xb9,0x82,0x20,0x8d,
- 0x01,0x04,0x6d,0x6e,0xef,0x04,0x20,0x8d,
- 0x01,0x04,0x6d,0xad,0x29,0x2b,0x20,0x8d,
+ 0x01,0x04,0x6d,0x78,0xc2,0x88,0x20,0x8d,
+ 0x01,0x04,0x6d,0x7b,0xe9,0x8a,0x20,0x8d,
+ 0x01,0x04,0x6d,0x7b,0xf0,0x35,0x20,0x8d,
+ 0x01,0x04,0x6d,0x99,0x5e,0x23,0x20,0x8d,
+ 0x01,0x04,0x6d,0xad,0x7e,0x9d,0x20,0x8d,
+ 0x01,0x04,0x6d,0xc1,0x4c,0xc8,0x20,0x8d,
+ 0x01,0x04,0x6d,0xdd,0xe5,0xc5,0x20,0x8d,
0x01,0x04,0x6d,0xec,0x5a,0x75,0x20,0x8d,
0x01,0x04,0x6d,0xf8,0xce,0x0d,0x20,0x8d,
- 0x01,0x04,0x6d,0xff,0x6a,0xce,0x20,0x8d,
0x01,0x04,0x6f,0x5a,0x8c,0x17,0x20,0x8d,
0x01,0x04,0x6f,0x5a,0x8c,0x2e,0x20,0x8d,
- 0x01,0x04,0x6f,0x5a,0x9f,0xf6,0x20,0x8d,
- 0x01,0x04,0x70,0x76,0xbc,0x32,0x20,0x8d,
- 0x01,0x04,0x73,0x2f,0x8d,0xfa,0x22,0xb5,
+ 0x01,0x04,0x6f,0x5a,0x91,0x25,0x20,0x8d,
+ 0x01,0x04,0x72,0xad,0x9f,0xd1,0x20,0x8d,
0x01,0x04,0x74,0x3a,0xab,0x43,0x20,0x8d,
- 0x01,0x04,0x76,0x5c,0x6b,0x6c,0x20,0x8d,
+ 0x01,0x04,0x77,0x1f,0xb3,0xca,0x20,0x8d,
0x01,0x04,0x77,0x2a,0x37,0xcb,0x20,0x8d,
- 0x01,0x04,0x78,0x4f,0x47,0x48,0x20,0x8d,
- 0x01,0x04,0x79,0x63,0xf0,0x57,0x20,0x8d,
+ 0x01,0x04,0x7a,0xde,0xa0,0xbe,0x20,0x8d,
0x01,0x04,0x7b,0x3c,0xd5,0xc0,0x20,0x8d,
- 0x01,0x04,0x7c,0x9c,0x9e,0x64,0x20,0x8d,
- 0x01,0x04,0x7c,0xde,0x7b,0xee,0x20,0x8d,
- 0x01,0x04,0x7d,0xb2,0x06,0x74,0x20,0x8d,
+ 0x01,0x04,0x7c,0xc5,0x36,0x71,0x20,0x8d,
+ 0x01,0x04,0x7d,0xa8,0x8c,0x6c,0x20,0x8d,
0x01,0x04,0x80,0x00,0xbe,0x1a,0x20,0x8d,
0x01,0x04,0x80,0x41,0xc2,0x88,0x20,0x8d,
0x01,0x04,0x81,0x0d,0xbd,0xd4,0x20,0x8d,
- 0x01,0x04,0x81,0x7e,0xac,0x73,0x20,0x8d,
- 0x01,0x04,0x81,0x92,0x34,0xae,0x20,0x8d,
- 0x01,0x04,0x82,0x2c,0xa8,0xca,0x20,0x8d,
- 0x01,0x04,0x83,0xa1,0x50,0xa6,0x20,0x8d,
+ 0x01,0x04,0x81,0x0d,0xbd,0xd7,0x20,0x8d,
+ 0x01,0x04,0x81,0xe2,0xd8,0x94,0x20,0x8d,
0x01,0x04,0x83,0xbc,0x28,0xbf,0x20,0x8d,
+ 0x01,0x04,0x86,0x41,0x09,0x3f,0x20,0x8d,
+ 0x01,0x04,0x86,0x7a,0xc8,0xa0,0x20,0x8d,
0x01,0x04,0x86,0xc3,0xb9,0x34,0x20,0x8d,
- 0x01,0x04,0x87,0x86,0xee,0x2f,0x20,0x8d,
- 0x01,0x04,0x87,0xb4,0xda,0x3a,0x20,0x8d,
- 0x01,0x04,0x87,0xb5,0xd7,0xed,0x20,0x8d,
- 0x01,0x04,0x88,0x1d,0x6d,0xb4,0x20,0x8d,
+ 0x01,0x04,0x87,0x13,0xfd,0x65,0x20,0x8d,
+ 0x01,0x04,0x88,0x1d,0x6d,0x3a,0x20,0x8d,
0x01,0x04,0x88,0x20,0xee,0x06,0x20,0x8d,
- 0x01,0x04,0x88,0x38,0xaa,0x60,0x20,0x8d,
- 0x01,0x04,0x89,0x19,0x26,0x6c,0x20,0x8d,
+ 0x01,0x04,0x88,0x31,0xc9,0x18,0x20,0x8d,
0x01,0x04,0x89,0xe2,0x22,0x2e,0x20,0x8d,
- 0x01,0x04,0x8a,0xcf,0xd3,0x6a,0x20,0x8d,
+ 0x01,0x04,0x8a,0xcf,0xd3,0xbd,0x20,0x8d,
0x01,0x04,0x8b,0x82,0x29,0x52,0x20,0x8d,
- 0x01,0x04,0x8b,0x99,0xff,0x6b,0x20,0x8d,
- 0x01,0x04,0x8c,0xbe,0x0c,0x81,0x20,0x8d,
+ 0x01,0x04,0x8c,0xee,0xdc,0x63,0x20,0x8d,
0x01,0x04,0x8e,0x36,0xb5,0xda,0x20,0x8d,
+ 0x01,0x04,0x8e,0xa6,0x13,0x17,0x20,0x8d,
+ 0x01,0x04,0x8e,0xfe,0x57,0x73,0x20,0x8d,
0x01,0x04,0x8f,0xb1,0xe5,0x95,0x20,0x8d,
- 0x01,0x04,0x8f,0xb2,0x40,0x0a,0x20,0x8d,
- 0x01,0x04,0x90,0x18,0xf5,0xb7,0x20,0x8d,
- 0x01,0x04,0x90,0x7e,0x82,0xb2,0x20,0x8d,
- 0x01,0x04,0x92,0x04,0x7c,0x81,0x20,0x8d,
+ 0x01,0x04,0x90,0x02,0x65,0x15,0x20,0x8d,
+ 0x01,0x04,0x90,0x18,0xec,0x40,0x20,0x8d,
+ 0x01,0x04,0x91,0x28,0x33,0x34,0x20,0x8d,
0x01,0x04,0x92,0x47,0x45,0x67,0x20,0x8d,
- 0x01,0x04,0x92,0x53,0x38,0x45,0x20,0x8d,
- 0x01,0x04,0x93,0xc2,0xb1,0xa5,0x20,0x8d,
- 0x01,0x04,0x95,0x5a,0xd6,0x4e,0x20,0x8d,
- 0x01,0x04,0x95,0x66,0x9d,0x9c,0x20,0x8d,
- 0x01,0x04,0x97,0xf8,0x9c,0x37,0x20,0x8d,
- 0x01,0x04,0x97,0xfc,0xc1,0xf5,0x20,0x8d,
- 0x01,0x04,0x99,0x5c,0x5d,0x72,0x20,0x8d,
- 0x01,0x04,0x9a,0xd3,0x06,0x02,0x20,0x8d,
- 0x01,0x04,0x9c,0x11,0x67,0x02,0x1f,0x98,
+ 0x01,0x04,0x92,0x78,0xf1,0xad,0x20,0x8d,
+ 0x01,0x04,0x93,0x32,0xee,0x35,0x20,0x8d,
+ 0x01,0x04,0x94,0x67,0x65,0x84,0x20,0x8d,
+ 0x01,0x04,0x95,0x4b,0x30,0x5c,0x20,0x8d,
+ 0x01,0x04,0x98,0x2c,0x89,0x53,0x20,0x8d,
+ 0x01,0x04,0x9a,0x00,0x03,0xc2,0x20,0x8d,
+ 0x01,0x04,0x9a,0x1a,0x89,0x69,0x20,0x8d,
+ 0x01,0x04,0x9a,0x1a,0x9a,0x49,0x20,0x8d,
+ 0x01,0x04,0x9a,0x39,0x05,0x0b,0x20,0x8d,
+ 0x01,0x04,0x9b,0x04,0x37,0x15,0x20,0x8d,
+ 0x01,0x04,0x9c,0x92,0x89,0x8e,0x20,0x8d,
0x01,0x04,0x9c,0x92,0xb1,0xdd,0x20,0x8d,
- 0x01,0x04,0x9d,0x83,0x8f,0xad,0x20,0x8d,
- 0x01,0x04,0x9e,0x3a,0xbc,0x25,0x20,0x8d,
- 0x01,0x04,0x9e,0xf8,0x27,0xef,0x20,0x8d,
- 0x01,0x04,0x9f,0x59,0xe6,0x80,0x20,0x8d,
+ 0x01,0x04,0x9d,0x16,0x48,0xaf,0x20,0x8d,
+ 0x01,0x04,0x9d,0x61,0x00,0x76,0x20,0x8d,
+ 0x01,0x04,0x9e,0x8c,0x8d,0x45,0x20,0x8d,
+ 0x01,0x04,0x9e,0xb5,0x84,0x54,0x20,0x8d,
+ 0x01,0x04,0x9f,0x02,0xd7,0x62,0x20,0x8d,
0x01,0x04,0x9f,0xc4,0x03,0xef,0x20,0x8d,
0x01,0x04,0x9f,0xe0,0xbd,0xfa,0x20,0x8d,
- 0x01,0x04,0xa0,0x48,0x33,0x9a,0x20,0x8d,
- 0x01,0x04,0xa1,0x1d,0xec,0x37,0x20,0x8d,
- 0x01,0x04,0xa1,0x61,0x77,0xa6,0x20,0x8d,
+ 0x01,0x04,0xa0,0x50,0x0c,0x10,0x20,0x8d,
+ 0x01,0x04,0xa1,0xe6,0x26,0xa0,0x20,0x8d,
0x01,0x04,0xa1,0xf6,0x0b,0xe6,0x20,0x8d,
+ 0x01,0x04,0xa2,0x00,0xd2,0x98,0x20,0x8d,
0x01,0x04,0xa2,0x3e,0x12,0xe2,0x20,0x8d,
- 0x01,0x04,0xa2,0xfa,0x7b,0xb3,0x20,0x8d,
- 0x01,0x04,0xa2,0xfa,0xbf,0xde,0x20,0x8d,
0x01,0x04,0xa2,0xfe,0x76,0x14,0x20,0x8d,
- 0x01,0x04,0xa3,0xac,0x51,0x46,0x20,0x8d,
- 0x01,0x04,0xa4,0x5a,0x2f,0x08,0x20,0x8d,
+ 0x01,0x04,0xa3,0x9e,0xa8,0xb5,0x20,0x8d,
+ 0x01,0x04,0xa5,0xad,0x13,0x21,0x20,0x8d,
0x01,0x04,0xa5,0xe4,0xae,0x75,0x20,0x8d,
- 0x01,0x04,0xa6,0x46,0x91,0x97,0x20,0x8d,
- 0x01,0x04,0xa8,0x5b,0xee,0x08,0x20,0x8d,
- 0x01,0x04,0xaa,0xfd,0x0b,0x19,0x20,0x8d,
- 0x01,0x04,0xab,0x67,0xaa,0x73,0x20,0x8d,
- 0x01,0x04,0xac,0x5d,0xa6,0x87,0x20,0x8d,
- 0x01,0x04,0xac,0x67,0xd9,0xec,0x20,0x8d,
+ 0x01,0x04,0xa5,0xff,0xf1,0xb8,0x20,0x8d,
+ 0x01,0x04,0xa7,0x58,0x0b,0xcb,0x20,0x8d,
+ 0x01,0x04,0xa7,0xb3,0x93,0x9b,0x20,0x8d,
+ 0x01,0x04,0xaa,0x11,0x97,0xeb,0x20,0x8d,
+ 0x01,0x04,0xaa,0x40,0xae,0xe6,0x20,0x8d,
+ 0x01,0x04,0xac,0x5c,0x66,0x73,0x20,0x8d,
0x01,0x04,0xac,0x69,0x15,0xd8,0x20,0x8d,
- 0x01,0x04,0xac,0x70,0x99,0x5f,0x20,0x8d,
- 0x01,0x04,0xad,0x03,0xda,0x5b,0x20,0x8d,
- 0x01,0x04,0xad,0x0c,0x77,0x85,0x20,0x8d,
- 0x01,0x04,0xad,0x22,0x7f,0xb5,0x20,0x8d,
- 0x01,0x04,0xad,0x4c,0x7b,0xad,0x20,0x8d,
- 0x01,0x04,0xad,0xb0,0xc6,0x44,0x20,0x8d,
- 0x01,0x04,0xad,0xd0,0x98,0xda,0x20,0x8d,
- 0x01,0x04,0xad,0xf1,0xe3,0xf3,0x20,0x8d,
- 0x01,0x04,0xad,0xf6,0x1b,0x07,0x20,0x8d,
- 0x01,0x04,0xad,0xff,0xf0,0xcd,0x20,0x8d,
- 0x01,0x04,0xae,0x1e,0x2f,0x0f,0x20,0x8d,
- 0x01,0x04,0xae,0x72,0xfa,0x56,0x20,0x8d,
- 0x01,0x04,0xae,0x8a,0x23,0xe5,0x20,0x8d,
- 0x01,0x04,0xae,0x8e,0xbf,0x88,0x20,0x8d,
- 0x01,0x04,0xb0,0x0a,0x8f,0xbe,0x20,0x8d,
+ 0x01,0x04,0xac,0x6f,0xb0,0xf4,0x20,0x8d,
+ 0x01,0x04,0xac,0xff,0x62,0x6c,0x20,0x8d,
+ 0x01,0x04,0xad,0x52,0x05,0xca,0x20,0x8d,
+ 0x01,0x04,0xad,0xb5,0x23,0x32,0x20,0x8d,
+ 0x01,0x04,0xad,0xd4,0xfd,0x89,0x20,0x8d,
+ 0x01,0x04,0xad,0xeb,0x49,0x57,0x20,0x8d,
+ 0x01,0x04,0xae,0x1e,0x1d,0x55,0x20,0x8d,
+ 0x01,0x04,0xae,0x8d,0xd1,0x28,0x20,0x8d,
+ 0x01,0x04,0xb0,0x09,0x11,0x79,0x20,0x8d,
+ 0x01,0x04,0xb0,0x0c,0x10,0x87,0x20,0x8d,
0x01,0x04,0xb0,0x4a,0x88,0xed,0x20,0x8d,
- 0x01,0x04,0xb0,0x76,0xdc,0x1d,0x20,0x8d,
- 0x01,0x04,0xb0,0x7e,0x74,0x07,0x20,0x8d,
+ 0x01,0x04,0xb0,0x4a,0x8b,0x78,0x20,0x8d,
+ 0x01,0x04,0xb0,0x7a,0x7a,0x86,0x20,0x8d,
0x01,0x04,0xb0,0x7e,0xa7,0x0a,0x20,0x8d,
+ 0x01,0x04,0xb0,0x97,0xf4,0x82,0x20,0x8d,
+ 0x01,0x04,0xb0,0xba,0x13,0x6a,0x20,0x8d,
0x01,0x04,0xb0,0xd4,0xb9,0x99,0x20,0x8d,
- 0x01,0x04,0xb0,0xeb,0xd1,0xba,0x20,0x8d,
- 0x01,0x04,0xb1,0x51,0xec,0x75,0x20,0x8d,
- 0x01,0x04,0xb1,0x59,0xcd,0x46,0x20,0x8d,
- 0x01,0x04,0xb2,0x30,0xa8,0x0c,0x20,0x8d,
+ 0x01,0x04,0xb1,0x8e,0x92,0xc1,0x20,0x8d,
+ 0x01,0x04,0xb2,0x15,0x76,0xb2,0x20,0x8d,
+ 0x01,0x04,0xb2,0x3d,0x8d,0xc6,0x20,0x8d,
0x01,0x04,0xb2,0x7c,0xa2,0xd1,0x20,0x8d,
+ 0x01,0x04,0xb2,0x8f,0x19,0xc2,0x20,0x8d,
+ 0x01,0x04,0xb2,0x9a,0xe9,0xc5,0x20,0x8d,
0x01,0x04,0xb2,0x9f,0x62,0x85,0x20,0x8d,
- 0x01,0x04,0xb2,0xc4,0x59,0xd1,0x20,0x8d,
+ 0x01,0x04,0xb2,0xe8,0xba,0xbf,0x20,0x8d,
0x01,0x04,0xb2,0xec,0x89,0x3f,0x20,0x8d,
- 0x01,0x04,0xb2,0xfc,0x7b,0x18,0x20,0x8d,
- 0x01,0x04,0xb3,0x2b,0xaa,0xba,0x20,0x8d,
- 0x01,0x04,0xb4,0x96,0x2e,0xbb,0x20,0x8d,
- 0x01,0x04,0xb5,0x75,0x80,0x8c,0x20,0x8d,
- 0x01,0x04,0xb8,0x13,0x13,0x10,0x20,0x8d,
- 0x01,0x04,0xb9,0x15,0xd9,0x30,0x20,0x8d,
+ 0x01,0x04,0xb3,0x3c,0x95,0x04,0x20,0x8d,
+ 0x01,0x04,0xb8,0xa0,0x6e,0x68,0x20,0x8d,
+ 0x01,0x04,0xb8,0xae,0x25,0x8b,0x20,0x8d,
+ 0x01,0x04,0xb9,0x08,0x68,0xb3,0x20,0x8d,
+ 0x01,0x04,0xb9,0x0e,0x1e,0x19,0x20,0x8d,
0x01,0x04,0xb9,0x19,0x30,0xb8,0x20,0x8d,
- 0x01,0x04,0xb9,0x1f,0x88,0xf6,0x20,0x8d,
0x01,0x04,0xb9,0x34,0x5d,0x2d,0x20,0x8d,
0x01,0x04,0xb9,0x40,0x74,0x0f,0x20,0x8d,
- 0x01,0x04,0xb9,0x44,0xf9,0x5b,0x20,0x8d,
+ 0x01,0x04,0xb9,0x45,0x69,0x75,0x20,0x8d,
0x01,0x04,0xb9,0x62,0x36,0x14,0x20,0x8d,
0x01,0x04,0xb9,0x6b,0x53,0x37,0x20,0x8d,
+ 0x01,0x04,0xb9,0x84,0x6d,0x7a,0x20,0x8d,
+ 0x01,0x04,0xb9,0x87,0x51,0x32,0x20,0x8d,
0x01,0x04,0xb9,0x8c,0xfd,0xa9,0x20,0x8d,
- 0x01,0x04,0xb9,0x94,0x91,0x4a,0x20,0x8d,
+ 0x01,0x04,0xb9,0x94,0x03,0xe3,0x20,0x8d,
+ 0x01,0x04,0xb9,0x9a,0x02,0x03,0x20,0x8d,
+ 0x01,0x04,0xb9,0xa2,0x5c,0x24,0x20,0x8d,
+ 0x01,0x04,0xb9,0xa3,0x2c,0x24,0x20,0x8d,
0x01,0x04,0xb9,0xa5,0xaa,0x13,0x20,0x8d,
0x01,0x04,0xb9,0xa7,0x71,0x3b,0x20,0x8d,
- 0x01,0x04,0xb9,0xb9,0x1a,0x8d,0x1f,0xaf,
- 0x01,0x04,0xb9,0xc5,0xa3,0x88,0x20,0x8d,
+ 0x01,0x04,0xb9,0xb9,0x3b,0x0c,0x20,0x8d,
+ 0x01,0x04,0xb9,0xcb,0x29,0x94,0x20,0x8d,
0x01,0x04,0xb9,0xd1,0x0c,0x4c,0x20,0x8d,
0x01,0x04,0xb9,0xd1,0x46,0x11,0x20,0x8d,
- 0x01,0x04,0xb9,0xe3,0x9c,0xe2,0x20,0x8d,
+ 0x01,0x04,0xb9,0xd2,0x7d,0x21,0x20,0x8d,
0x01,0x04,0xb9,0xe9,0xbd,0xd2,0x20,0x8d,
+ 0x01,0x04,0xb9,0xee,0x83,0x13,0x20,0x8d,
+ 0x01,0x04,0xb9,0xef,0xdc,0xd2,0x20,0x8d,
0x01,0x04,0xb9,0xef,0xdd,0x05,0x20,0x8d,
- 0x01,0x04,0xb9,0xf4,0x64,0x6a,0x20,0x8d,
- 0x01,0x04,0xb9,0xfe,0x61,0xa4,0x20,0x8d,
- 0x01,0x04,0xba,0x21,0xa7,0x0b,0x20,0x8d,
- 0x01,0x04,0xba,0xb0,0x62,0x25,0x20,0x8d,
+ 0x01,0x04,0xb9,0xfa,0x5a,0xf6,0x20,0x8d,
0x01,0x04,0xba,0xf9,0xd9,0x19,0x20,0x8d,
0x01,0x04,0xba,0xfa,0x5f,0x84,0x20,0x8d,
- 0x01,0x04,0xbc,0x20,0x0e,0x1f,0x20,0x8e,
0x01,0x04,0xbc,0x23,0xa7,0x0e,0x20,0x8d,
- 0x01,0x04,0xbc,0x44,0x2d,0x8f,0x20,0x8d,
- 0x01,0x04,0xbc,0x75,0xc8,0xd4,0x20,0x8d,
- 0x01,0x04,0xbc,0x8a,0x58,0x0e,0x20,0x8d,
- 0x01,0x04,0xbc,0x97,0xed,0x9e,0x20,0x8d,
- 0x01,0x04,0xbc,0x9a,0xec,0x31,0x20,0x8d,
- 0x01,0x04,0xbd,0x7b,0xb1,0x80,0x20,0x8d,
+ 0x01,0x04,0xbc,0x44,0x35,0x2c,0x20,0x8d,
+ 0x01,0x04,0xbc,0x78,0xff,0x73,0x20,0x8d,
+ 0x01,0x04,0xbd,0x06,0xc3,0x6f,0x20,0x8d,
+ 0x01,0x04,0xbe,0x02,0x82,0x2c,0x20,0x8d,
+ 0x01,0x04,0xbe,0x0d,0x7a,0x59,0x20,0x8d,
0x01,0x04,0xbe,0x7b,0x1b,0x0b,0x20,0x8d,
0x01,0x04,0xbe,0x91,0x7f,0xfe,0x20,0x8d,
- 0x01,0x04,0xc0,0x45,0x35,0x4d,0x20,0x8d,
+ 0x01,0x04,0xbf,0xdc,0x9c,0x40,0x20,0x8d,
+ 0x01,0x04,0xc0,0x1f,0x88,0x5a,0x20,0x8d,
+ 0x01,0x04,0xc0,0x45,0x35,0x2b,0x20,0x8d,
0x01,0x04,0xc0,0x92,0x89,0x2c,0x20,0x8d,
- 0x01,0x04,0xc0,0xde,0x18,0x36,0x20,0x8d,
- 0x01,0x04,0xc0,0xde,0x93,0x8d,0x20,0x8d,
- 0x01,0x04,0xc1,0x20,0x7f,0xa2,0xee,0x29,
- 0x01,0x04,0xc1,0x6f,0xc6,0xbb,0x1f,0xaf,
- 0x01,0x04,0xc1,0xc4,0x25,0x3e,0x20,0x8d,
- 0x01,0x04,0xc2,0x0d,0x50,0xb9,0x3c,0x46,
- 0x01,0x04,0xc2,0x93,0x71,0xc9,0x20,0x8d,
- 0x01,0x04,0xc2,0xa5,0x1e,0x14,0x20,0x8d,
- 0x01,0x04,0xc2,0xbf,0xef,0x62,0x20,0x8d,
- 0x01,0x04,0xc3,0x38,0x3f,0x04,0x20,0x8d,
- 0x01,0x04,0xc3,0x38,0x3f,0x0a,0x20,0x8d,
- 0x01,0x04,0xc3,0x7b,0xef,0xb9,0x20,0x8d,
- 0x01,0x04,0xc3,0x8c,0xe2,0x9a,0x20,0x8d,
- 0x01,0x04,0xc6,0x01,0xe7,0x06,0x20,0x8d,
- 0x01,0x04,0xc6,0x94,0x70,0x1b,0x20,0x8d,
- 0x01,0x04,0xc7,0x7e,0xea,0xed,0x20,0x8d,
- 0x01,0x04,0xc7,0xc1,0xae,0xad,0x20,0x8d,
+ 0x01,0x04,0xc0,0xae,0x79,0x21,0x20,0x8d,
+ 0x01,0x04,0xc0,0xde,0x93,0xaf,0x20,0x8d,
+ 0x01,0x04,0xc1,0xc6,0x22,0x18,0x20,0x8d,
+ 0x01,0x04,0xc1,0xde,0x82,0x0e,0x20,0x8d,
+ 0x01,0x04,0xc2,0x23,0xb9,0xa7,0x20,0x8d,
+ 0x01,0x04,0xc2,0x36,0x53,0xea,0x20,0x8d,
+ 0x01,0x04,0xc2,0xe9,0x54,0x64,0x20,0x8d,
+ 0x01,0x04,0xc3,0x02,0x49,0x58,0x20,0x8d,
+ 0x01,0x04,0xc3,0x30,0x0c,0x08,0x20,0x8d,
+ 0x01,0x04,0xc3,0x9a,0xc8,0x9d,0x20,0x8d,
+ 0x01,0x04,0xc5,0xd3,0x85,0x0f,0x20,0x8d,
+ 0x01,0x04,0xc6,0x54,0x92,0x08,0x20,0x8d,
+ 0x01,0x04,0xc6,0x62,0x37,0x56,0x20,0x8d,
0x01,0x04,0xc7,0xf7,0x07,0xd0,0x20,0x8d,
- 0x01,0x04,0xc8,0x7a,0xb5,0x2e,0x20,0x8d,
+ 0x01,0x04,0xc8,0x74,0x9a,0x83,0x20,0x8d,
0x01,0x04,0xc9,0xbf,0x06,0x67,0x20,0x8d,
- 0x01,0x04,0xc9,0xd4,0x24,0xd1,0x20,0x8d,
0x01,0x04,0xc9,0xdd,0xea,0xc8,0x20,0x8d,
+ 0x01,0x04,0xca,0x2f,0xe1,0xf2,0x20,0x8d,
+ 0x01,0x04,0xca,0x6b,0xdb,0x82,0x20,0x8d,
0x01,0x04,0xca,0x6c,0xd3,0x87,0x20,0x8d,
- 0x01,0x04,0xca,0xa9,0x11,0xb2,0x20,0x8d,
- 0x01,0x04,0xca,0xb1,0x18,0x8c,0x20,0x8d,
- 0x01,0x04,0xcb,0x82,0x30,0x75,0x22,0xb5,
- 0x01,0x04,0xcb,0x84,0x5e,0xc4,0x20,0x8d,
+ 0x01,0x04,0xca,0x8a,0x0d,0x7a,0x20,0x8d,
+ 0x01,0x04,0xcb,0x56,0xc3,0x20,0x20,0x8d,
+ 0x01,0x04,0xcb,0xb8,0x34,0xf7,0x20,0x8d,
+ 0x01,0x04,0xcc,0x6f,0xa3,0x72,0x20,0x8d,
0x01,0x04,0xcd,0xb2,0x29,0x7c,0x20,0x8d,
- 0x01,0x04,0xce,0x48,0xc9,0xe4,0x20,0x8d,
0x01,0x04,0xce,0xc0,0xcb,0x00,0x20,0x8d,
- 0x01,0x04,0xce,0xdf,0x99,0x34,0x20,0x8d,
- 0x01,0x04,0xcf,0x86,0xd8,0x91,0x20,0x8e,
- 0x01,0x04,0xcf,0xbc,0x9a,0x32,0x20,0x8d,
0x01,0x04,0xcf,0xe5,0x2e,0x50,0x20,0x8d,
+ 0x01,0x04,0xcf,0xf4,0xf8,0x51,0x20,0x8d,
0x01,0x04,0xcf,0xff,0xc1,0x2f,0x20,0x8d,
- 0x01,0x04,0xd0,0x68,0x5c,0x4a,0x20,0x8d,
+ 0x01,0x04,0xd0,0x3b,0x85,0x3f,0x20,0x8d,
0x01,0x04,0xd1,0x3a,0x91,0x9d,0x20,0x8d,
- 0x01,0x04,0xd1,0x3a,0x9e,0xe8,0x20,0x8f,
- 0x01,0x04,0xd1,0x8d,0x2b,0xf3,0x20,0x8d,
- 0x01,0x04,0xd1,0xe2,0x8e,0x3e,0x20,0x8d,
- 0x01,0x04,0xd1,0xed,0x7f,0xe3,0x20,0x8d,
+ 0x01,0x04,0xd1,0x61,0xbd,0xf9,0x20,0x8d,
+ 0x01,0x04,0xd1,0xb1,0x8a,0xf5,0x20,0x8d,
0x01,0x04,0xd1,0xed,0x85,0x36,0x20,0x8d,
- 0x01,0x04,0xd3,0xf8,0x5a,0x32,0x20,0x8d,
- 0x01,0x04,0xd4,0x15,0x12,0x4e,0x20,0x8d,
+ 0x01,0x04,0xd2,0x36,0x25,0xbe,0x20,0x8d,
+ 0x01,0x04,0xd2,0x36,0x27,0xee,0x20,0x8d,
0x01,0x04,0xd4,0x22,0xe1,0x76,0x20,0x8d,
- 0x01,0x04,0xd4,0x33,0x92,0x89,0x20,0x8d,
- 0x01,0x04,0xd4,0xe3,0xd3,0x57,0x20,0x8d,
- 0x01,0x04,0xd5,0x00,0x45,0x4c,0x20,0x8d,
- 0x01,0x04,0xd5,0x05,0x24,0x3a,0x20,0x8d,
+ 0x01,0x04,0xd4,0x29,0x09,0x1e,0x20,0x8d,
+ 0x01,0x04,0xd4,0x33,0x84,0xb0,0x20,0x8d,
+ 0x01,0x04,0xd4,0x45,0x3c,0x4d,0x20,0x8d,
+ 0x01,0x04,0xd4,0x56,0x20,0x6a,0x20,0x8d,
0x01,0x04,0xd5,0x2f,0x40,0x69,0x20,0x8d,
- 0x01,0x04,0xd5,0x59,0x87,0x97,0x20,0x8d,
0x01,0x04,0xd5,0x8d,0x9a,0xc9,0x20,0x8d,
- 0x01,0x04,0xd5,0x9f,0xc6,0x2d,0x20,0x8d,
+ 0x01,0x04,0xd5,0x8e,0x94,0xa9,0x20,0x8d,
0x01,0x04,0xd5,0xb8,0xf4,0x18,0x20,0x8d,
- 0x01,0x04,0xd5,0xd6,0x42,0xb6,0x20,0x8d,
- 0x01,0x04,0xd5,0xe2,0x7b,0x4c,0x20,0x8d,
+ 0x01,0x04,0xd5,0xe3,0x93,0xf4,0x20,0x8d,
+ 0x01,0x04,0xd5,0xfa,0x15,0x70,0x20,0x8d,
0x01,0x04,0xd8,0x92,0xfb,0x08,0x20,0x8d,
- 0x01,0x04,0xd8,0xba,0xee,0x0e,0x20,0x8d,
- 0x01,0x04,0xd9,0x05,0x96,0x72,0x20,0x8d,
+ 0x01,0x04,0xd8,0xe8,0x9d,0x68,0x20,0x8d,
0x01,0x04,0xd9,0x0f,0xb2,0x0b,0x20,0x8d,
- 0x01,0x04,0xd9,0x18,0xef,0x6d,0x20,0x8d,
- 0x01,0x04,0xd9,0x40,0x2f,0x8a,0x20,0x8d,
- 0x01,0x04,0xd9,0x49,0x50,0x68,0x20,0x8d,
- 0x01,0x04,0xd9,0x4f,0xb5,0x26,0x20,0x8d,
+ 0x01,0x04,0xd9,0x1a,0x20,0x0a,0x20,0x8d,
+ 0x01,0x04,0xd9,0x40,0x2f,0xc8,0x20,0x8d,
+ 0x01,0x04,0xd9,0x4c,0x33,0x19,0x20,0x8d,
0x01,0x04,0xd9,0x5c,0x37,0xf6,0x20,0x8d,
- 0x01,0x04,0xd9,0x71,0x79,0xa9,0x20,0x8d,
- 0x01,0x04,0xd9,0x73,0x74,0xfa,0x20,0x8d,
- 0x01,0x04,0xd9,0x9b,0xf4,0xaa,0x20,0x8d,
0x01,0x04,0xd9,0xaa,0x7c,0xaa,0x20,0x8d,
- 0x01,0x04,0xdc,0x84,0x87,0x36,0x20,0x8d,
- 0x01,0x04,0xdc,0xe9,0xb2,0xc7,0x20,0x8d,
- 0x01,0x04,0xde,0x9a,0x6f,0x2e,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x16,0x20,0x05,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x19,0xf0,0x60,0x01,0x39,0xaa,0x54,0x00,0x03,0xff,0xfe,0xf0,0x09,0x16,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x19,0xf0,0x80,0x01,0x0f,0x71,0x54,0x00,0x04,0xff,0xfe,0x10,0x6a,0x63,0x20,0x8d,
+ 0x01,0x04,0xd9,0xb4,0xdd,0xa2,0x20,0x8d,
+ 0x01,0x04,0xd9,0xb4,0xee,0x89,0x20,0x8d,
+ 0x01,0x04,0xdc,0x54,0xe8,0x2e,0x20,0x8d,
+ 0x01,0x04,0xdc,0x85,0x27,0x3d,0x20,0x8d,
+ 0x01,0x04,0xdc,0xe9,0x5b,0xb6,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x10,0x00,0x1d,0xb3,0x54,0x00,0x04,0xff,0xfe,0x56,0x5a,0x8d,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x05,0x24,0xda,0x3e,0xec,0xef,0xff,0xfe,0xb9,0xf3,0x6e,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x05,0x24,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x05,0x45,0x35,0x3e,0xec,0xef,0xff,0xfe,0xb9,0x87,0xe4,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x19,0xf0,0x00,0x05,0x45,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x20,0x01,0x1b,0xc0,0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x1c,0x02,0x01,0x1e,0x35,0x00,0xdf,0x25,0x63,0x21,0x82,0x60,0xd9,0xbe,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x41,0xd0,0x10,0x04,0x1b,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x93,
+ 0x02,0x10,0x20,0x01,0x1c,0x04,0x40,0x08,0x63,0x00,0x8a,0x5f,0x26,0x78,0x11,0x4b,0xa6,0x60,0x20,0x8d,
0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0x37,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0xaa,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0x8f,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x20,0x01,0x41,0xd0,0x02,0x03,0xbb,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x02,0xbf,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x03,0x65,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x41,0xd0,0x06,0x02,0x44,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x08,0xb9,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x03,0x03,0xde,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x04,0x03,0x3d,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x04,0x05,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x08,0xed,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x20,0x01,0x41,0xd0,0x00,0x0a,0x69,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x20,0x01,0x41,0xf0,0x00,0x00,0x00,0x00,0x00,0x62,0x69,0x74,0x63,0x6f,0x69,0x6e,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x44,0xb8,0x02,0x56,0x5d,0x11,0x02,0x16,0x3e,0xff,0xfe,0x39,0xd5,0xd4,0x20,0x8d,
0x02,0x10,0x20,0x01,0x04,0x70,0x1b,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x07,0x08,0x03,0x02,0x0c,0x29,0xff,0xfe,0x2d,0x58,0x79,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x05,0x04,0x3b,0x28,0x31,0x85,0x30,0x71,0x79,0x58,0x64,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x09,0x0b,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x20,0x8d,
0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x15,0x01,0x06,0xe2,0xd5,0x5e,0xff,0xfe,0x42,0x7a,0xe5,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x15,0x0c,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x04,0x70,0x00,0x26,0x04,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x7c,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x1b,0x03,0x65,0xaa,0x20,0x66,0xff,0xfe,0x3f,0x19,0x09,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x1f,0x1b,0x05,0xa6,0x02,0x16,0x3e,0xff,0xfe,0x24,0x11,0x62,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x6a,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
0x02,0x10,0x20,0x01,0x04,0x70,0x75,0xe9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x04,0x70,0xde,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xec,0x24,0x75,
- 0x02,0x10,0x20,0x01,0x4b,0xa0,0xba,0xbe,0x05,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0x8c,0xa0,0x00,0x02,0x4e,0x72,0xb9,0xff,0xfe,0x56,0xf8,0xb8,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x04,0x70,0xdb,0xc7,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x4b,0xa0,0xca,0xfe,0x14,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4b,0xa0,0xff,0xff,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x30,0xb7,0x1d,0x7b,0x6f,0xec,0x4c,0x5c,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x08,0x8e,0xb4,0xff,0x2a,0xd0,0x69,0x9b,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0x9c,0x1c,0xcc,0x31,0x9f,0xe8,0x55,0x05,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0xa0,0xc4,0xd4,0x1f,0x04,0xc4,0x1b,0xb0,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x00,0xfd,0x76,0xc1,0xd3,0x18,0x54,0x5b,0xd9,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x01,0x00,0x00,0x00,0x00,0x76,0x76,0x80,0x90,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0x35,0x64,0x00,0x01,0xb9,0x77,0xbd,0x71,0x46,0x12,0x8e,0x40,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x00,0x00,0x69,0x00,0x01,0x20,0x8d,
0x02,0x10,0x20,0x01,0x4d,0xd0,0xaf,0x0e,0x35,0x64,0x00,0x00,0x00,0x00,0x00,0x69,0x00,0x90,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x4d,0xe8,0xb1,0xb2,0x00,0x01,0x00,0x00,0xde,0xad,0xbe,0xef,0x00,0x07,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x05,0x60,0x44,0x1f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x8d,
0x02,0x10,0x20,0x01,0x06,0x38,0xa0,0x00,0x41,0x40,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x91,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x06,0x78,0x0a,0xcc,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x06,0x7c,0x25,0xdc,0x00,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x20,0x01,0x06,0x7c,0x26,0xb4,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x20,0x8d,
0x02,0x10,0x20,0x01,0x06,0x7c,0x2d,0xb8,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x07,0xc0,0x23,0x10,0x00,0x00,0xf8,0x16,0x3e,0xff,0xfe,0x0d,0x4a,0xb6,0x20,0x8d,
0x02,0x10,0x20,0x01,0x07,0xc0,0x23,0x10,0x00,0x00,0xf8,0x16,0x3e,0xff,0xfe,0x6c,0x4f,0x58,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x08,0x61,0x32,0x46,0x0a,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x0b,0x07,0x02,0xe6,0x38,0xd7,0xba,0x27,0xeb,0xff,0xfe,0x60,0x3d,0xc1,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x08,0x61,0x32,0x42,0x84,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x08,0xb0,0x13,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0xb0,0x30,0x24,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x02,0xef,0x6e,0x4a,0x00,0x3d,0x97,0x4e,0x78,0x4a,0x68,0x4b,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x5d,0x32,0xb1,0x42,0x8f,0x77,0x3c,0x7d,0xa2,0xfd,0xed,0x2e,0x20,0x8d,
0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x61,0x78,0x11,0x04,0x89,0xd2,0xda,0x0e,0x07,0x1a,0xf7,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x0b,0x07,0x0a,0xc9,0x44,0x2b,0x79,0xd6,0xbb,0xbe,0xb3,0x7c,0xa7,0x83,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x6b,0x80,0x74,0x32,0xe8,0x92,0x43,0xa3,0x37,0xe6,0x0a,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x64,0x6b,0x80,0x74,0x4c,0xc6,0x79,0xa5,0x3a,0xf7,0x71,0x32,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0x07,0x0a,0xd4,0xca,0x4b,0x7d,0xd5,0x84,0x71,0x50,0xc3,0x53,0x63,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x12,0x01,0x07,0x1a,0x2e,0x59,0xe5,0xff,0xfe,0x42,0x52,0xf4,0x20,0x8d,
0x02,0x10,0x20,0x01,0x0b,0xc8,0x16,0x00,0x00,0x00,0x02,0x08,0xa2,0xff,0xfe,0x0c,0x8a,0x2e,0x20,0x8d,
0x02,0x10,0x20,0x01,0x0b,0xc8,0x32,0x3c,0x00,0xff,0xa6,0x34,0x38,0x4f,0x18,0x49,0xf4,0xbc,0x20,0x8d,
0x02,0x10,0x20,0x01,0x0b,0xc8,0x32,0x3c,0x00,0xff,0xd2,0x17,0xc2,0xff,0xfe,0x07,0x2c,0xd9,0x20,0x8d,
- 0x02,0x10,0x20,0x01,0x0b,0xc8,0x3b,0xec,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x20,0x02,0x2f,0x5b,0xa5,0xf9,0x00,0x00,0x00,0x00,0x00,0x00,0x2f,0x5b,0xa5,0xf9,0x22,0xb5,
- 0x02,0x10,0x20,0x03,0x00,0xcb,0x87,0x13,0x61,0x02,0xaa,0xa1,0x59,0xff,0xfe,0x57,0x77,0x79,0x20,0x8d,
- 0x02,0x10,0x20,0x03,0x00,0xe0,0x37,0x0e,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x8d,
- 0x02,0x10,0x20,0x03,0x00,0xf6,0x3f,0x10,0x67,0x00,0x4c,0x9f,0x76,0x20,0x83,0x24,0xd4,0xa7,0x20,0x8d,
- 0x02,0x10,0x24,0x00,0x24,0x10,0xce,0xa2,0x0d,0x00,0x41,0xbc,0xc9,0xea,0x86,0x1b,0x51,0xee,0x20,0x8d,
- 0x02,0x10,0x24,0x00,0x24,0x11,0xa3,0xe1,0x49,0x00,0x25,0x68,0x68,0x4b,0x0e,0x99,0x71,0x20,0x20,0x8d,
- 0x02,0x10,0x24,0x00,0x24,0x11,0xa3,0xe1,0x49,0x00,0x29,0x87,0xb8,0x8f,0x61,0xe0,0x84,0xfa,0x20,0x8d,
- 0x02,0x10,0x24,0x00,0x3b,0x00,0x00,0x20,0x00,0x0c,0xba,0xcb,0x29,0xff,0xfe,0xab,0x88,0x86,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x07,0x00,0x2b,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0b,0xc8,0x07,0x00,0x8d,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x20,0x01,0x0e,0x68,0x54,0x00,0x58,0xd0,0xbd,0x15,0xea,0x8c,0x5b,0x20,0x75,0x23,0x20,0x8d,
+ 0x02,0x10,0x24,0x00,0x24,0x11,0xa3,0xe1,0x49,0x00,0x72,0x98,0xf5,0x50,0x67,0xe7,0xb9,0x9b,0x20,0x8d,
+ 0x02,0x10,0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x2b,0x5c,0x0b,0x20,0x8d,
+ 0x02,0x10,0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x5a,0x68,0x5c,0x20,0x8d,
0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x10,0x20,0x8d,
0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x20,0x20,0x8d,
- 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x01,0x00,0x20,0x8d,
- 0x02,0x10,0x24,0x01,0xb1,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x01,0x30,0x20,0x8d,
0x02,0x10,0x24,0x01,0xd0,0x02,0x39,0x02,0x07,0x00,0xd7,0x2c,0x5e,0x22,0x4e,0x95,0x38,0x9d,0x20,0x8d,
- 0x02,0x10,0x24,0x04,0x44,0x08,0x67,0x52,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0x99,0x20,0x8d,
- 0x02,0x10,0x24,0x04,0x7a,0x85,0x41,0x61,0x2b,0x00,0x49,0xa1,0x42,0x7a,0x0f,0xac,0x34,0x09,0x20,0x8d,
- 0x02,0x10,0x24,0x05,0x98,0x00,0xb9,0x72,0xab,0x58,0x0c,0x05,0xe9,0x38,0x26,0x7e,0x02,0x71,0x20,0x8d,
+ 0x02,0x10,0x24,0x04,0x44,0x08,0x63,0xa4,0x0a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x50,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0x34,0x00,0x02,0x16,0x8b,0x00,0x02,0x11,0x32,0xff,0xfe,0xca,0x33,0x6b,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0x8c,0x00,0x00,0x00,0x34,0x22,0x01,0x33,0x00,0x18,0x02,0x28,0x01,0x08,0x20,0x8d,
0x02,0x10,0x24,0x06,0xda,0x11,0x01,0x69,0x0b,0x03,0x32,0xb5,0xf9,0x01,0x9f,0x7c,0x3e,0x4b,0x20,0x8d,
- 0x02,0x10,0x24,0x06,0xda,0x14,0x03,0x35,0xb6,0x01,0xce,0xb7,0xb4,0xfc,0xa8,0x55,0xf3,0xa5,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0xda,0x18,0x09,0xf1,0xf3,0x01,0x7d,0x2e,0xc2,0x56,0xc1,0x12,0xf2,0xbe,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0xda,0x18,0x09,0xf1,0xf3,0x03,0xc1,0xc9,0xc5,0x69,0xb7,0x99,0x20,0x57,0x20,0x8d,
+ 0x02,0x10,0x24,0x06,0xda,0x1e,0x0a,0x4e,0x8a,0x00,0x20,0xdb,0xdd,0x8d,0x36,0x70,0x28,0xf0,0x20,0x8d,
0x02,0x10,0x24,0x06,0xda,0x1e,0x0a,0x4e,0x8a,0x03,0x2a,0xad,0x49,0x6b,0x76,0x8d,0xe4,0x97,0x20,0x8d,
- 0x02,0x10,0x24,0x07,0x88,0x00,0xbc,0x61,0x22,0x02,0xa0,0xc6,0x01,0x07,0x50,0x2b,0x4e,0x3b,0x20,0x8d,
- 0x02,0x10,0x24,0x09,0x00,0x10,0xca,0x20,0x1d,0xf0,0x02,0x24,0xe8,0xff,0xfe,0x1f,0x60,0xd9,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x17,0x00,0x22,0xf1,0x64,0x1f,0x00,0xe8,0x39,0xc8,0xeb,0x1d,0xa1,0xeb,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x17,0x00,0x9c,0x5d,0x0e,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x17,0x00,0x9c,0x5d,0x0e,0xd0,0xd0,0xd6,0x01,0xd9,0x5c,0xc2,0xab,0x47,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x17,0x02,0x1c,0xe0,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x1f,0x14,0x04,0x0e,0xe3,0x01,0xd1,0x55,0xaa,0x3a,0x77,0xbe,0x96,0x0e,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x1f,0x16,0x0a,0x08,0xb9,0x01,0x1a,0xfa,0xef,0x4e,0x4c,0xe7,0x2b,0xa4,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x1f,0x1c,0x02,0xd3,0x24,0x03,0x5b,0xac,0x3f,0xc6,0x65,0x13,0x7a,0x63,0x20,0x8d,
+ 0x02,0x10,0x24,0x07,0x36,0x40,0x21,0x07,0x12,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x24,0x07,0x36,0x40,0x30,0x10,0x40,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x24,0x07,0x88,0x00,0xbc,0x61,0x22,0x02,0xd6,0x3d,0x7e,0xff,0xfe,0x6c,0xdc,0x36,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x17,0x00,0x5c,0x5b,0x00,0xb0,0xaa,0xa1,0x59,0xff,0xfe,0x5f,0x61,0x5a,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x17,0x00,0xec,0x7b,0x57,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x00,0x4c,0xc4,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x00,0x4c,0xc4,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x00,0x4c,0xc4,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x00,0x4c,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x19,0x00,0x40,0x30,0xa2,0x5e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x1f,0x14,0x04,0x0e,0xe3,0x01,0xaf,0xdd,0xad,0x00,0xe5,0x68,0xd2,0x20,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x1f,0x1c,0x02,0xd3,0x24,0x00,0xf1,0x5e,0x2f,0x2a,0x76,0x0d,0xa3,0x3d,0x20,0x8d,
0x02,0x10,0x26,0x00,0x21,0x04,0x10,0x03,0xc5,0xab,0xdc,0x5e,0x90,0xff,0xfe,0x18,0x1d,0x08,0x20,0x8d,
0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x92,0x27,0x45,0x20,0x8d,
0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0xcf,0x61,0xb6,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0xb3,0x01,0xb6,0x20,0x8d,
0x02,0x10,0x26,0x00,0x3c,0x00,0xe0,0x02,0x2e,0x32,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x14,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x2a,0x52,0x66,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x74,0x5f,0x59,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0xe6,0x21,0x46,0x20,0x8d,
0x02,0x10,0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x92,0xff,0xfe,0x5d,0x09,0xfb,0x20,0x8d,
- 0x02,0x10,0x26,0x00,0x40,0x40,0x28,0x54,0x5e,0x00,0xc6,0xe9,0x84,0xff,0xfe,0x46,0x0e,0xe8,0x21,0xda,
- 0x02,0x10,0x26,0x00,0x6c,0x54,0x71,0x00,0x1a,0xd1,0xbd,0xdf,0x55,0x0e,0x91,0xbe,0xf9,0xe1,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x40,0x40,0x20,0x04,0x32,0x01,0x45,0x9f,0x8f,0xe8,0x44,0x4d,0xba,0xf1,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x40,0x40,0x45,0x41,0x49,0x00,0x04,0xe1,0xb5,0x8a,0x84,0x38,0x45,0x0e,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x6c,0x54,0x71,0x00,0x1a,0xd1,0xc9,0x2e,0x03,0x6d,0x06,0x51,0xbd,0x18,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x88,0x01,0x2f,0x80,0x04,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x1c,0x20,0x8d,
+ 0x02,0x10,0x26,0x00,0x88,0x01,0x8d,0x00,0x3e,0xb0,0x02,0x0c,0x29,0xff,0xfe,0xc3,0xd7,0x99,0x20,0x8d,
0x02,0x10,0x26,0x00,0x88,0x05,0x24,0x00,0x01,0x4e,0x12,0xdd,0xb1,0xff,0xfe,0xf2,0x30,0x13,0x20,0x8d,
- 0x02,0x10,0x26,0x01,0x01,0x84,0x03,0x00,0x0b,0xde,0x3c,0x29,0x8e,0x94,0x1b,0xa8,0xfd,0xe3,0x20,0x8d,
- 0x02,0x10,0x26,0x01,0x01,0x8c,0x80,0x80,0x30,0x0f,0x02,0x19,0xd1,0xff,0xfe,0x75,0xdc,0x2f,0x20,0x8d,
- 0x02,0x10,0x26,0x01,0x01,0x8d,0x46,0x00,0x43,0xf1,0x20,0xe7,0xb3,0xff,0xfe,0xcf,0x0a,0x99,0x20,0x8d,
- 0x02,0x10,0x26,0x01,0x01,0x8d,0x87,0x01,0xc2,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x20,0x8d,
- 0x02,0x10,0x26,0x01,0x02,0x46,0x4d,0x7f,0x9e,0x28,0xf3,0x21,0x36,0xca,0x7a,0x71,0xc6,0x87,0x20,0x8d,
- 0x02,0x10,0x26,0x01,0x06,0x40,0xc2,0x01,0x96,0x0d,0x86,0xeb,0xf2,0x7d,0x66,0xa2,0xf2,0xc1,0x20,0x8d,
- 0x02,0x10,0x26,0x02,0x02,0x41,0x75,0xd1,0x2b,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x20,0x8d,
- 0x02,0x10,0x26,0x02,0xff,0xb8,0x00,0x00,0x00,0x00,0x02,0x08,0x00,0x72,0x00,0x57,0x02,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x01,0x84,0x03,0x00,0x15,0x6c,0xba,0x4c,0x00,0x30,0x09,0xda,0x6c,0x06,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x03,0x46,0x0d,0x7f,0xff,0xf7,0x18,0xc6,0x48,0x56,0xef,0x75,0x74,0x4c,0x20,0x8d,
+ 0x02,0x10,0x26,0x01,0x04,0x05,0x4a,0x00,0x08,0x76,0xc8,0xd3,0xf0,0x81,0x2c,0xe8,0xba,0x8e,0x20,0x8d,
+ 0x02,0x10,0x26,0x02,0x02,0x4c,0x0b,0x8f,0xcd,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x20,0x8d,
+ 0x02,0x10,0x26,0x02,0xfe,0xc3,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x20,0x8d,
+ 0x02,0x10,0x26,0x02,0xff,0x16,0x00,0x01,0x00,0x00,0x00,0x01,0x04,0x12,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x01,0x26,0x18,0xc0,0x00,0x2e,0xc1,0xdf,0x1f,0xa4,0x63,0x91,0x19,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x03,0x01,0x1b,0xe1,0x00,0x02,0x0c,0x29,0xff,0xfe,0x38,0xbb,0xc0,0x20,0x8d,
0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x85,0x1f,0x58,0x4d,0x7a,0xba,0xaf,0xfb,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x02,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x30,0x04,0x07,0x0d,0x14,0x00,0x85,0x32,0x29,0x00,0xce,0x6f,0xac,0xdf,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x30,0x04,0x07,0x45,0x09,0x00,0xf0,0xd7,0x55,0x6a,0x0a,0x8c,0xce,0xd5,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x60,0x80,0xc0,0x00,0x5d,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x4f,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x80,0x00,0xd1,0x00,0x89,0x91,0xcc,0x29,0xcc,0xff,0xfe,0x42,0x30,0x0c,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7b,0xba,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x04,0x06,0xa1,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf6,0x67,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x24,0x16,0x06,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xec,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x30,0x24,0x18,0xee,0x80,0x00,0x02,0x0e,0xc4,0xff,0xfe,0xd1,0xef,0x15,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x60,0x00,0xa4,0x00,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x60,0x10,0x70,0x01,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x01,0x20,0x8d,
0x02,0x10,0x26,0x03,0x80,0x80,0x1f,0x07,0x6f,0xdd,0x7d,0xe2,0xd9,0x69,0x78,0xc9,0xb7,0xea,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x80,0x80,0x73,0x00,0x05,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xea,0x20,0x8d,
- 0x02,0x10,0x26,0x03,0x80,0xa0,0x07,0x03,0x40,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0x01,0x80,0x00,0xf3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x18,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0x3d,0x08,0x00,0x00,0x00,0x05,0xd9,0x41,0x4b,0x03,0xa0,0x93,0x13,0x1b,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0x7c,0x00,0x01,0x20,0x00,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0xeb,0x24,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0x0a,0x00,0x00,0x21,0x30,0x43,0xbf,0x6a,0x53,0x5e,0xdf,0xeb,0x5b,0x7b,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1c,0xe7,0x40,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x1d,0x44,0xe0,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x80,0x80,0xd6,0x00,0x18,0x00,0x7c,0xe1,0x74,0xa2,0x6a,0x8a,0x46,0x43,0x20,0x8d,
+ 0x02,0x10,0x26,0x03,0x80,0x81,0x6c,0x00,0x30,0x6e,0x02,0x15,0x5d,0xff,0xfe,0x02,0x15,0x0a,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0x3d,0x09,0x71,0x82,0x87,0x00,0xbb,0xa9,0xcd,0xe6,0x5b,0x37,0xa8,0xdf,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0x40,0x80,0x10,0x36,0x80,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xbe,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0x0a,0x00,0x00,0x03,0x12,0x23,0x02,0x16,0x3e,0xff,0xfe,0x27,0x76,0xe0,0x20,0x8d,
0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x26,0x1f,0x60,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0xa8,0x80,0x04,0x00,0x00,0xd1,0x00,0x00,0x00,0x00,0x07,0xe2,0xe0,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0x14,0x30,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x01,0x3e,0xf0,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x01,0x7a,0x70,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0xc1,0x30,0x00,0x20,0x8d,
0x02,0x10,0x26,0x04,0xa8,0x80,0x00,0x04,0x01,0xd0,0x00,0x00,0x00,0x00,0x00,0xe5,0xb0,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x05,0x4a,0x80,0xa3,0x02,0x79,0x40,0x72,0x54,0x1e,0xd4,0x90,0xd7,0x4f,0x39,0x20,0x8d,
+ 0x02,0x10,0x26,0x05,0x4a,0x80,0xa3,0x02,0x79,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x26,0x05,0x64,0x00,0x00,0x30,0xf2,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x26,0x05,0x6f,0x80,0x00,0x00,0x00,0x07,0xfc,0x1b,0xcc,0xff,0xfe,0x8a,0xd8,0x22,0x20,0x8d,
- 0x02,0x10,0x26,0x05,0xa1,0x40,0x20,0x76,0x82,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x05,0xa1,0x40,0x30,0x07,0x12,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x05,0xa1,0x40,0x30,0x10,0x40,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x26,0x05,0xae,0x00,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x03,0x20,0x8d,
+ 0x02,0x10,0x26,0x05,0x0b,0x40,0x14,0xd0,0x5b,0x00,0x79,0x88,0x0e,0xb8,0x6b,0xb6,0x66,0xe2,0x20,0x8d,
0x02,0x10,0x26,0x05,0xc0,0x00,0x2a,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x20,0x8d,
- 0x02,0x10,0x26,0x07,0x1a,0x00,0x00,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x11,0x7c,0x4d,0x20,0x8d,
- 0x02,0x10,0x26,0x07,0x53,0x00,0x02,0x03,0x12,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
+ 0x02,0x10,0x26,0x07,0x53,0x00,0x00,0x61,0x08,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x14,0x25,0xb5,0x20,0x8d,
0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0x9c,0x2f,0x20,0x8d,
0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0xbf,0x32,0x20,0x8d,
0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x33,0x4d,0x1b,0x20,0x8d,
0x02,0x10,0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x3d,0x04,0x01,0x20,0x8d,
- 0x02,0x10,0x26,0x07,0xf2,0xc0,0xe1,0xc2,0x00,0x69,0x12,0xc3,0x7b,0xff,0xfe,0x4d,0x94,0x31,0x20,0x8d,
- 0x02,0x10,0x26,0x07,0xf2,0xc0,0xe1,0xc2,0x00,0x69,0xec,0xb2,0x6e,0x88,0x9f,0x33,0x50,0x57,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x00,0x06,0x20,0x03,0x01,0x05,0x02,0xd8,0x61,0xff,0xfe,0x0f,0x08,0x53,0x20,0x8d,
0x02,0x10,0x26,0x20,0x00,0x6e,0xa0,0x00,0x00,0x01,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x42,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0xd5,0x70,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x2a,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x16,0x31,0x20,0x8d,
- 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0c,0xe6,0x34,0x20,0x8d,
- 0x02,0x10,0x28,0x00,0x00,0x40,0x00,0x33,0x08,0xab,0xa0,0xe7,0xb2,0x15,0xfc,0x83,0x5c,0x31,0x20,0x8d,
- 0x02,0x10,0x28,0x00,0x0b,0xf0,0x01,0x49,0x0f,0x4b,0xf8,0xdf,0x8d,0x7d,0x80,0x1b,0xe2,0x5e,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x01,0x4c,0x01,0x98,0x80,0xd5,0x76,0x03,0x41,0xd1,0xd3,0xfc,0xe7,0x97,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x01,0x4d,0xae,0x81,0x82,0x7b,0x99,0xa8,0x1e,0x3f,0x6d,0xb2,0x29,0xdb,0x20,0x8d,
- 0x02,0x10,0x28,0x04,0x0d,0x57,0x55,0x37,0x48,0x00,0x3e,0x7c,0x3f,0xff,0xfe,0x7b,0x80,0xaa,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x12,0xe0,0x01,0x01,0x00,0x99,0x02,0x0c,0x29,0xff,0xfe,0x29,0xd0,0x3f,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x13,0x28,0xe1,0x01,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x63,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x05,0x16,0x01,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x09,0x90,0x0b,0x20,0x8d,
+ 0x02,0x10,0x26,0x20,0x00,0xa6,0x20,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x0b,0x30,0x0e,0x20,0x8d,
+ 0x02,0x10,0x28,0x00,0x01,0x50,0x01,0x1d,0x0d,0x2f,0xbd,0xac,0x78,0x07,0x02,0xf5,0x4a,0xa0,0x20,0x8d,
+ 0x02,0x10,0x28,0x03,0x98,0x00,0xa0,0x07,0x82,0xba,0x65,0x0b,0x82,0xb8,0x83,0x77,0x00,0xd0,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x01,0x4c,0x01,0x55,0x45,0xe0,0x1e,0x86,0x15,0xa3,0xef,0xd9,0x72,0x87,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x01,0x4c,0x65,0x7d,0x40,0x30,0x28,0xb4,0x0e,0xff,0xfe,0x9b,0x88,0x94,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x01,0x4d,0x10,0x87,0x94,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x02,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x09,0x54,0x00,0x24,0x00,0x02,0xb3,0x90,0xd8,0x3b,0x35,0x8a,0xdb,0x53,0x20,0x8d,
+ 0x02,0x10,0x28,0x04,0x0d,0x57,0x55,0x4d,0xde,0x00,0x3e,0x7c,0x3f,0xff,0xfe,0x7b,0x80,0xaa,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x10,0x28,0x83,0x8c,0x56,0x3a,0xfd,0x25,0x87,0xb6,0x5a,0x54,0x08,0x11,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x12,0x98,0x80,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0x42,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x02,0x15,0x5d,0xff,0xfe,0xd6,0x10,0x33,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0x03,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x16,0x30,0x00,0x10,0x10,0x03,0x00,0x00,0x0b,0x19,0xb0,0x0b,0xba,0xbe,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x6a,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x18,0x28,0xa0,0x04,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x66,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x1c,0x10,0x00,0x02,0x07,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17,0x56,0xcc,
0x02,0x10,0x2a,0x00,0x1f,0x40,0x50,0x01,0x01,0x08,0x5d,0x17,0x77,0x03,0xb0,0xf5,0x41,0x33,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x23,0xc5,0xfe,0x80,0x73,0x01,0xd6,0xae,0x52,0xff,0xfe,0xd5,0x56,0xa5,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x23,0xc6,0x5c,0x91,0x58,0x08,0xc0,0x5a,0x4d,0xff,0xfe,0x65,0x9d,0x69,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x60,0x20,0x1b,0xfa,0xd4,0x00,0x02,0x0c,0x29,0xff,0xfe,0x61,0x4a,0x4c,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x82,0x92,0x00,0x49,0x1a,0x35,0x8c,0xd8,0xf7,0x01,0xda,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x60,0x20,0x13,0xdc,0xbc,0x00,0x55,0x59,0x02,0x58,0x02,0x7d,0xb5,0x2b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x60,0x20,0x45,0x03,0x37,0x00,0x02,0x0c,0x29,0xff,0xfe,0x61,0x4a,0x4c,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x34,0xeb,0x00,0xde,0xa6,0x32,0xff,0xfe,0x0d,0xa5,0xc0,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x60,0x20,0xb4,0x89,0x20,0x00,0x50,0x54,0x00,0xff,0xfe,0xfc,0x5e,0xd8,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x01,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0x7a,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x7c,0x80,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x8a,0x60,0xe0,0x12,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0xae,0x40,0x24,0x0e,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xbb,0xe0,0x00,0xcc,0x00,0x00,0x5a,0x11,0x22,0xff,0xfe,0xb4,0x8f,0x5c,0x20,0x8d,
0x02,0x10,0x2a,0x00,0xbb,0xe0,0x00,0xcc,0x00,0x00,0x62,0xa4,0x4c,0xff,0xfe,0x23,0x75,0x10,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0x0c,0xa8,0x0a,0x1f,0x30,0x25,0xf9,0x49,0xe4,0x42,0xc9,0x40,0x13,0xe8,0x20,0x8d,
- 0x02,0x10,0x2a,0x00,0xd4,0xe0,0x00,0x02,0xd0,0x02,0x44,0x67,0x31,0xe0,0x6f,0xa5,0xb3,0xef,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x0c,0xa8,0x0a,0x15,0x9a,0x5b,0x8b,0x42,0xa8,0x86,0x7d,0x48,0x7a,0x21,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0x0c,0xa8,0x0a,0x1f,0xf9,0xb7,0xcb,0x55,0x57,0x66,0x52,0x4b,0xac,0xaa,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xd4,0xe0,0x00,0xff,0xfc,0x02,0x5e,0x55,0x4a,0x7c,0xb8,0x3b,0xe5,0xa1,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xd5,0x20,0x00,0x09,0x93,0x00,0x42,0x0b,0x54,0x4e,0x80,0x19,0x6d,0x3a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x00,0xd8,0x80,0x00,0x05,0x00,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0x29,0x20,0x8d,
0x02,0x10,0x2a,0x00,0x0e,0xe2,0x12,0x00,0x19,0x00,0x08,0xd3,0xd2,0xff,0xfe,0xb1,0xbc,0x58,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x02,0x38,0x42,0x0f,0x92,0x00,0xfa,0x5a,0x1a,0x4b,0x1e,0x6a,0xfa,0xdf,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x02,0x38,0x43,0x89,0xc4,0x00,0x3b,0x26,0xd9,0x4e,0x38,0xd5,0x44,0xef,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x04,0x90,0x00,0x16,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x4b,0x00,0x80,0x7c,0x31,0x00,0xcd,0xa1,0x0c,0x6a,0x2b,0xad,0x24,0x18,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x41,0x22,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x73,0x23,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x04,0xf8,0x01,0x90,0x91,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x00,0x72,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x02,0x03,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x21,0x44,0xd7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x31,0x09,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x2a,0x1c,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x61,0x2b,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x61,0x3c,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf8,0x02,0x61,0x42,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x2b,0x02,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x4a,0x31,0xde,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x52,0x00,0x00,0x6c,0x61,0x62,0x7a,0x61,0x74,0x6b,0x6f,0x2e,0x73,0x6b,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x63,0x80,0xff,0xfe,0x00,0x73,0x10,0xfb,0xd0,0x12,0x85,0x81,0xb4,0xd7,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x04,0xf9,0x00,0x3a,0x2d,0xd2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x07,0xa7,0x00,0x02,0x28,0x04,0xae,0x1f,0x6b,0xff,0xfe,0x9d,0x6c,0x94,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xac,0x00,0x89,0x50,0x54,0x00,0xff,0xfe,0xb7,0xf5,0xcb,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xc2,0x01,0x80,0x50,0x54,0x00,0xff,0xfe,0x56,0x8d,0x10,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x07,0xc8,0xaa,0xc9,0x00,0xc9,0x50,0x54,0x00,0xff,0xfe,0xdf,0xff,0x95,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x07,0xc8,0xd0,0x01,0x01,0xc1,0x50,0x54,0x00,0xff,0xfe,0xee,0x3e,0x1a,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x07,0xc8,0xd0,0x09,0x02,0xaa,0x50,0x54,0x00,0xff,0xfe,0x1b,0xa1,0x96,0x2d,0x00,
- 0x02,0x10,0x2a,0x01,0x07,0xc8,0xff,0xfa,0x05,0x0e,0xdd,0xfe,0xc9,0x24,0xca,0x0a,0xcb,0xab,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x59,0x66,0xdc,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x7e,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x3b,0xbb,0x5b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x7e,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x93,0xff,0xfe,0x49,0x2f,0x5b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x87,0x40,0x00,0x01,0x07,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0xe5,0xcb,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x87,0x40,0x00,0x01,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x8c,0x6a,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x9f,0x40,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0xcb,0x00,0x0d,0x3d,0x77,0x00,0x02,0x27,0x0e,0xff,0xfe,0x28,0xc5,0x65,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0x20,0x73,0x50,0x91,0x9c,0xb1,0xc3,0x8b,0x83,0xad,0xf9,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0xcb,0x00,0x0b,0x63,0xc0,0x00,0x02,0x27,0x0e,0xff,0xfe,0x28,0xc5,0x65,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0xcb,0x19,0x06,0x88,0xe9,0x00,0xaa,0x60,0xb6,0xff,0xfe,0x29,0xbb,0xae,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x01,0x63,0xc0,0xb0,0x9d,0xa5,0x16,0x90,0xa1,0x2b,0xbe,0xde,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x02,0x82,0x67,0xb0,0xb4,0xf4,0xaa,0xff,0xfe,0x7c,0x44,0xa6,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0x01,0x70,0x10,0xb8,0x7d,0xe1,0x4b,0xce,0xa9,0xb9,0x98,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x04,0x8b,0x2d,0x10,0x94,0xf2,0x4d,0x5c,0xca,0x5f,0xbf,0x49,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x05,0x30,0xa0,0xa0,0xf4,0x65,0x0a,0xf5,0xbe,0x1b,0x90,0x75,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x0a,0xa7,0xc8,0xc0,0x96,0x79,0xaf,0xfa,0xb6,0xe5,0xef,0xc7,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0x20,0x39,0xa0,0x32,0x5a,0x3a,0xff,0xfe,0x02,0x31,0x80,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x03,0x51,0x9f,0xb0,0x6b,0xf2,0x95,0xd6,0xb7,0xbd,0xb8,0x46,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x05,0xfa,0xa0,0xa0,0xca,0x1f,0x66,0xff,0xfe,0xce,0xb8,0xa2,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x08,0x3d,0xdd,0x30,0x36,0x76,0x5d,0x8e,0x8a,0x6f,0x11,0x5a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x09,0xe9,0xc2,0x40,0x7b,0x44,0xf3,0x2a,0x6e,0xc0,0xa8,0xaf,0x20,0x8d,
+ 0x02,0x10,0x2a,0x01,0x0e,0x0a,0x00,0xb5,0x7f,0x50,0xc2,0x57,0xa5,0x5b,0x48,0x46,0x97,0xe1,0x20,0x8d,
0x02,0x10,0x2a,0x01,0x0e,0x11,0x10,0x0c,0x00,0x70,0xcb,0xc8,0x9e,0x31,0x4b,0x77,0x16,0x26,0x20,0x8d,
- 0x02,0x10,0x2a,0x01,0x0e,0x34,0xee,0x78,0x30,0x60,0x02,0x30,0x48,0xff,0xfe,0x81,0xf1,0xc6,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x12,0x10,0x14,0xa9,0x67,0x00,0x0a,0x00,0x27,0xff,0xfe,0x4e,0x82,0xb6,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x12,0x10,0x46,0x39,0x0f,0x00,0x10,0xa7,0xe9,0x65,0x50,0x9a,0x7a,0x4a,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x12,0x10,0x7c,0x92,0x51,0x00,0x02,0x11,0x32,0xff,0xfe,0xae,0x15,0x2d,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x12,0x10,0x86,0xbf,0xf1,0x00,0x31,0x78,0xd7,0x00,0xd4,0x4d,0x6b,0xb1,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x12,0x10,0x94,0x87,0xa2,0x00,0xed,0xc1,0x93,0xa4,0x09,0x45,0x9a,0x92,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x2c,0xdf,0x46,0x00,0x02,0xbc,0xe0,0x3e,0x43,0xe8,0x47,0x18,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x86,0xbf,0xf1,0x00,0xa9,0xac,0xd0,0x41,0x1f,0x8e,0x69,0x25,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x12,0x10,0x94,0xc3,0x34,0x00,0xd8,0xc3,0x74,0x3c,0x90,0xf6,0xa4,0x8a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x01,0x68,0x20,0x00,0x00,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x01,0x68,0x42,0x0b,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x01,0x68,0x63,0x28,0x00,0x00,0x4a,0x21,0x0b,0xff,0xfe,0x26,0x38,0xc3,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x01,0x68,0x67,0x6e,0x00,0x00,0xe6,0x5f,0x01,0xff,0xfe,0x09,0x35,0x91,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x17,0x48,0xf3,0x9f,0x58,0x72,0xde,0xad,0xbe,0xef,0xb1,0xac,0xc0,0xfe,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x17,0x48,0xf3,0x9f,0x58,0x72,0x02,0x16,0x3e,0xff,0xfe,0x21,0x02,0x66,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x01,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x05,0x17,0x10,0xb6,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x21,0x68,0xa3,0x79,0xd1,0x00,0x96,0xde,0x80,0xff,0xfe,0xa3,0xfd,0x00,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x27,0x80,0x90,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x27,0x80,0x90,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x27,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x1a,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x2e,0x02,0x39,0x00,0x54,0x00,0xa0,0x99,0xe1,0xff,0xfe,0xb6,0x0d,0x0e,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x2f,0x05,0x66,0x0e,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x00,0x58,0x00,0x97,0x7d,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x6d,0x40,0x30,0x73,0x0c,0x01,0xde,0xa6,0x32,0xff,0xfe,0x44,0x4b,0x25,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x2f,0x05,0x60,0x08,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x03,0x90,0x90,0x00,0x00,0x00,0xaa,0xa1,0x59,0xff,0xfe,0x43,0xb5,0x7b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x05,0x78,0x85,0xce,0x16,0x00,0x1e,0x1b,0x0d,0xff,0xfe,0xe3,0x77,0x4b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x07,0x68,0xf9,0x2b,0xdb,0x46,0x5e,0x46,0x77,0x2b,0x07,0x1d,0x29,0xb7,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x7a,0x01,0x00,0x00,0x00,0x00,0x00,0x91,0x02,0x28,0x00,0x45,0x01,0x30,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x7b,0x40,0x50,0xd0,0xe3,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x7b,0x40,0x50,0xd1,0xe3,0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x7b,0x40,0x59,0x28,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x7b,0x40,0xc3,0xb5,0xf5,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0x83,0x08,0x80,0x87,0xaa,0x00,0x9e,0xa8,0x01,0xb2,0xef,0x98,0x56,0xbf,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x7b,0x40,0xb9,0x45,0x34,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x7b,0x40,0xd4,0x18,0x6d,0x9a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x80,0x70,0x0b,0x84,0x6a,0xe0,0xf9,0xc6,0xfb,0xb9,0x1c,0x41,0x81,0xaa,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x80,0x70,0xf1,0x86,0x38,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0xd5,0xa6,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x80,0x84,0x01,0x03,0x68,0x10,0x1e,0x69,0x7a,0xff,0xfe,0xa2,0x1a,0xcc,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x83,0x08,0x80,0x81,0xf3,0x00,0x03,0xb8,0x7e,0xc0,0x28,0x37,0x1b,0x57,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x83,0x88,0xe3,0x02,0x79,0x80,0x6f,0x85,0xa0,0xb3,0x4b,0x4d,0x8b,0x0f,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x83,0x88,0xe5,0xc3,0x4a,0x80,0x02,0x01,0x2e,0xff,0xfe,0x82,0xb3,0xcc,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x84,0x2a,0x01,0xdf,0x8a,0x01,0x1e,0x1b,0x0d,0xff,0xfe,0x0b,0x23,0x6d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa2,0x10,0x28,0xbe,0x5f,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x11,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x4b,0x5c,0xf9,0x00,0x01,0xb6,0x2e,0x99,0xff,0xfe,0x49,0xd4,0x92,0x20,0x8d,
0x02,0x10,0x2a,0x02,0xa4,0x4d,0x14,0xd6,0x00,0x01,0x02,0xc0,0x08,0xff,0xfe,0x8f,0xb3,0xb2,0x20,0x8d,
0x02,0x10,0x2a,0x02,0xa4,0x5a,0x94,0xcd,0xf0,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xa4,0x5f,0x3b,0x9d,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xa4,0x67,0x78,0x33,0x00,0x01,0x72,0x85,0xc2,0xff,0xfe,0x2c,0x21,0xe9,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xaa,0x14,0x23,0x80,0xb3,0x00,0x40,0x40,0xbe,0x88,0x8b,0x01,0x0d,0x38,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x5f,0x3b,0x9d,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x99,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x64,0x3d,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x6c,0x7f,0x8e,0x00,0x01,0x35,0xbf,0x3a,0xeb,0x13,0x7c,0x1d,0x35,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xa4,0x6d,0x03,0x6f,0x00,0x01,0x02,0x0d,0xb9,0xff,0xfe,0x4e,0x63,0x98,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x05,0x20,0x21,0x42,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x44,0x98,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x82,0x12,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xc2,0x06,0x30,0x08,0x23,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xc2,0x07,0x00,0x00,0x49,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x14,0xd4,
+ 0x02,0x10,0x2a,0x02,0xc2,0x06,0x20,0x75,0x33,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x00,0x00,0x38,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x14,0x41,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x24,0x61,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x14,0x87,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x26,0x66,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x20,0x34,0x73,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x02,0xc2,0x07,0x30,0x02,0x74,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xc2,0x07,0x30,0x08,0x45,0x92,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0xcb,0x43,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x78,0x20,0x8d,
+ 0x02,0x10,0x2a,0x02,0x0e,0x5e,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x20,0x8d,
0x02,0x10,0x2a,0x02,0x0e,0x98,0x00,0x20,0x15,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x06,0x41,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x06,0xf8,0x14,0x54,0x8b,0x17,0xff,0xfe,0x31,0xb6,0x4a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x28,0x00,0x68,0x74,0x11,0x53,0xff,0xfe,0x4c,0x02,0x1d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0x40,0x00,0x00,0x65,0x0f,0xdc,0x34,0x62,0x66,0xff,0xfe,0x05,0xec,0x5c,0x20,0x8d,
0x02,0x10,0x2a,0x03,0x60,0x00,0x08,0x70,0x00,0x00,0x00,0x46,0x00,0x23,0x00,0x87,0x02,0x18,0x20,0x8d,
0x02,0x10,0x2a,0x03,0x94,0xe0,0xff,0xff,0x01,0x85,0x02,0x43,0x02,0x18,0x00,0x00,0x00,0x19,0x20,0x8d,
0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x01,0x00,0xe0,0x00,0x00,0x00,0x00,0x03,0x97,0x60,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xf0,0x00,0x00,0x00,0x00,0x01,0x63,0x30,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xf0,0x00,0x00,0x00,0x00,0x01,0x8a,0xd0,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x0f,0x3e,0x20,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0xe2,0xc0,0x13,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x03,0x0e,0xc0,0x00,0x00,0x09,0x28,0x00,0x00,0x00,0x00,0x07,0x01,0x07,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x03,0xc4,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8e,
- 0x02,0x10,0x2a,0x04,0x52,0xc0,0x30,0x07,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x01,0x00,0xe0,0x00,0x00,0x00,0x00,0x07,0x94,0x90,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xf0,0x00,0x00,0x00,0x00,0x02,0x88,0xc0,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xf0,0x00,0x00,0x00,0x00,0x03,0x0c,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x0e,0x3b,0x50,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x03,0xcf,0xc0,0x80,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x5f,0xd6,0x35,0x57,0x20,0x8d,
+ 0x02,0x10,0x2a,0x04,0x21,0x80,0xdc,0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x04,0x21,0x80,0xff,0xff,0xff,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x20,0x8d,
+ 0x02,0x10,0x2a,0x04,0x52,0xc0,0x01,0x03,0xc4,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x04,0xbc,0x40,0x1d,0xc3,0x00,0x8d,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x01,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0x15,0x00,0x07,0x02,0x00,0x00,0x1c,0x00,0x40,0xff,0xfe,0x00,0x00,0x0c,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0x35,0x80,0xd1,0x01,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0x35,0x80,0xdb,0x0b,0x16,0x00,0xc4,0x89,0x76,0xed,0x31,0x3d,0x0b,0x33,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x01,0x81,0x27,0xaf,0xa7,0xda,0xf9,0xd9,0x1b,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x01,0xf6,0xab,0xdd,0x5e,0x40,0x39,0xb4,0x6c,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x03,0x65,0x23,0x50,0xa1,0x01,0x52,0xe8,0x8c,0x20,0x8d,
- 0x02,0x10,0x2a,0x05,0xd0,0x1a,0x0b,0x7b,0x3c,0x01,0x8b,0xf7,0xae,0x14,0xaf,0xb3,0x33,0xae,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0x35,0x80,0xdc,0x0b,0x16,0x00,0xde,0xf4,0x5a,0x62,0xde,0x42,0x32,0x4a,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x14,0x0a,0x55,0x40,0x00,0x8d,0xde,0x06,0x9f,0x4a,0xc7,0x0b,0x26,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x16,0x09,0x8f,0x52,0x01,0x6b,0xe0,0xa4,0xde,0x80,0xc7,0x32,0xd5,0x20,0x8d,
+ 0x02,0x10,0x2a,0x05,0xd0,0x18,0x0a,0x75,0x6c,0x03,0x07,0x5b,0x2c,0x73,0x8c,0xaa,0x41,0x4b,0x20,0x8d,
0x02,0x10,0x2a,0x05,0xf4,0x80,0x18,0x00,0x06,0x97,0x54,0x00,0x02,0xff,0xfe,0xb6,0xc3,0x6d,0x20,0x8d,
0x02,0x10,0x2a,0x06,0xe0,0x40,0x76,0x03,0x29,0x18,0xc6,0xef,0x46,0x4e,0x9f,0xe5,0x73,0xec,0x20,0x8d,
- 0x02,0x10,0x2a,0x07,0xab,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x09,0x46,0x20,0x8d,
+ 0x02,0x10,0x2a,0x07,0xab,0xc4,0x00,0x00,0x00,0x00,0x00,0x89,0x02,0x34,0x01,0x80,0x01,0x94,0x20,0x8d,
+ 0x02,0x10,0x2a,0x07,0xd8,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x7e,0x20,0x8d,
+ 0x02,0x10,0x2a,0x09,0x26,0x81,0x10,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x20,0x8d,
0x02,0x10,0x2a,0x09,0x26,0x81,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x20,0x8d,
- 0x02,0x10,0x2a,0x0a,0xc8,0x01,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x83,0x20,0x8d,
- 0x02,0x10,0x2a,0x0c,0x5a,0x80,0x12,0x10,0xa8,0x00,0x6a,0xf7,0x28,0xff,0xfe,0xe5,0x6b,0x3a,0x20,0x8d,
- 0x02,0x10,0x2a,0x0d,0x56,0x00,0x00,0x24,0x0a,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0xa9,0x1e,0xd8,0x4d,
- 0x02,0x10,0x2a,0x0d,0x7c,0x40,0x30,0x00,0x0b,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
+ 0x02,0x10,0x2a,0x0b,0xf3,0x00,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
0x02,0x10,0x2a,0x0d,0x83,0x40,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x8d,
- 0x02,0x10,0x2a,0x0f,0xdf,0x00,0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x62,0x20,0x8d,
- 0x02,0x10,0x2a,0x10,0x37,0x81,0x16,0xb9,0x00,0x01,0xfe,0x3f,0xdb,0xff,0xfe,0x04,0x2d,0x4c,0x20,0x8d,
- 0x02,0x10,0x2a,0x10,0x37,0x81,0x08,0x4b,0x00,0x01,0xb1,0x23,0x63,0x06,0x94,0x3a,0xf0,0x9b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x0e,0x8f,0x02,0x21,0xd1,0x01,0x44,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x0e,0xb7,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xd1,0xf0,0x5b,0x20,0x8d,
+ 0x02,0x10,0x2a,0x10,0x37,0x81,0x2c,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
0x02,0x10,0x2a,0x10,0xd2,0x00,0x00,0x01,0x00,0x33,0xa6,0xbf,0x01,0xff,0xfe,0x6a,0x46,0xa9,0x20,0x8d,
- 0x02,0x10,0x2c,0x0f,0xf4,0xc0,0x22,0x02,0x20,0xb0,0x26,0x1c,0x04,0xff,0xfe,0x14,0xda,0xa0,0x20,0x8d,
- 0x02,0x10,0x2c,0x0f,0xf8,0xf0,0xda,0x51,0x00,0x00,0x70,0xc3,0xee,0xa9,0x97,0x17,0x95,0x79,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2a,0x12,0x8e,0x40,0x56,0x68,0xe4,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x8d,
+ 0x02,0x10,0x2c,0x0f,0xf8,0xf0,0xda,0x51,0x00,0x00,0x3a,0x45,0xfc,0x57,0x5e,0x30,0x25,0x93,0x20,0x8d,
+ 0x04,0x20,0xd0,0x60,0x63,0xb5,0x63,0xa7,0x98,0x2a,0x1b,0x8f,0x42,0xb2,0xf8,0xd8,0xf3,0x4a,0x5b,0x2c,0x10,0x64,0x88,0xa7,0x51,0x23,0xca,0x58,0xad,0x92,0x3d,0xa9,0x1f,0x3c,0x20,0x8d,
+ 0x04,0x20,0xe2,0xe3,0xbb,0x69,0x18,0xc2,0xfb,0x4e,0xaf,0xd3,0x74,0x91,0x91,0x2f,0x0a,0x2f,0x6b,0xb9,0x32,0x11,0x74,0x06,0xdd,0x23,0x87,0xda,0xa1,0xe7,0x94,0x21,0x48,0x75,0x20,0x8d,
0x04,0x20,0xe9,0xbf,0xa7,0xbd,0x9b,0x54,0x54,0xe8,0xc8,0xae,0x78,0x99,0xa0,0xa3,0xf6,0x5d,0x78,0xe3,0x9e,0x5c,0xa7,0x18,0xb9,0x13,0x0c,0x04,0x9b,0xf3,0x7f,0x27,0x18,0xb0,0x20,0x8d,
+ 0x04,0x20,0xec,0x82,0xc1,0x2f,0x8c,0xe8,0x1e,0x8e,0xce,0x00,0x2a,0x38,0x61,0x09,0x51,0x6e,0xf1,0xdd,0x4b,0x3d,0x64,0x95,0x72,0xee,0x7e,0x45,0xb8,0x17,0xfc,0x91,0xb2,0x1f,0x20,0x8d,
+ 0x04,0x20,0xff,0xfc,0x02,0x19,0x7f,0x99,0x4e,0x6f,0x39,0x10,0x86,0x3f,0xe4,0xb6,0xd1,0xb0,0x6a,0x2c,0x4e,0x57,0xd4,0x08,0x61,0x18,0xfa,0x62,0x61,0x44,0xad,0x7c,0xdf,0xfc,0x20,0x8d,
+ 0x04,0x20,0xff,0xd8,0x39,0x93,0x9a,0x94,0x57,0xcd,0x48,0xe3,0x3e,0x98,0x79,0xa6,0x3f,0x69,0x7e,0x36,0x10,0x70,0x8d,0xbc,0x15,0x08,0x64,0x51,0xc7,0x56,0x35,0x63,0xf3,0x93,0x20,0x8d,
+ 0x04,0x20,0x06,0x42,0xf9,0x1f,0x80,0x8c,0x16,0xcf,0x73,0x9a,0xb1,0x50,0xcc,0x7e,0x11,0xf7,0x42,0xc3,0x83,0x59,0x39,0x92,0x6f,0xd8,0x20,0x4a,0x3d,0x5a,0x82,0x86,0xee,0xcf,0x20,0x8d,
0x04,0x20,0x0f,0xb9,0x71,0x05,0x64,0x83,0x2c,0x68,0x6a,0x9c,0xf0,0x4f,0xc3,0x90,0xcd,0x5c,0x73,0x9a,0xdd,0xb3,0xc6,0x42,0xca,0x09,0xbb,0xcc,0xfe,0x29,0x49,0x9f,0xc7,0x28,0x20,0x8d,
- 0x04,0x20,0x2a,0x47,0x8b,0xa0,0x4f,0x67,0x1d,0xcd,0x5d,0x84,0x1a,0xec,0xbd,0xd2,0xaa,0xe9,0x99,0x01,0x96,0x5d,0x4e,0xff,0x64,0x47,0xba,0xde,0xbf,0x56,0x89,0x39,0xac,0xde,0x20,0x8d,
+ 0x04,0x20,0x0c,0xa0,0x19,0x89,0xe0,0x8c,0x4a,0x83,0xae,0xce,0x5c,0xf9,0x73,0x24,0x25,0xe0,0x8d,0x01,0x2a,0xb1,0xac,0x8b,0x8a,0xe3,0xd5,0x3a,0x21,0x16,0x9f,0x96,0xf1,0x8e,0x20,0x8d,
+ 0x04,0x20,0x0c,0xa0,0x19,0x8a,0x74,0x59,0x74,0x6e,0x26,0x69,0x90,0xca,0x65,0xe8,0x83,0xfc,0x25,0xec,0xe7,0xb6,0x85,0xf5,0xf8,0x37,0x08,0x42,0xbe,0xb0,0x38,0x4a,0x8e,0x2b,0x20,0x8d,
+ 0x04,0x20,0x15,0x91,0xb2,0x2a,0x36,0x3a,0x0d,0xcf,0x8c,0xe7,0xc9,0x48,0xd8,0xf4,0xe1,0xa8,0x94,0x9f,0x97,0x20,0x72,0x70,0x6a,0x83,0x28,0xd2,0xe8,0x29,0x11,0xb6,0x0e,0x6c,0x20,0x8d,
+ 0x04,0x20,0x19,0x2a,0x86,0x86,0x62,0x65,0x95,0x44,0x4e,0xb7,0x5e,0xe6,0x54,0x75,0xc5,0xe6,0x41,0x4e,0x7b,0x0c,0x20,0x1a,0xd5,0x26,0xbe,0x2b,0xdb,0x85,0xa8,0xc5,0xdc,0x3a,0x20,0x8d,
+ 0x04,0x20,0x19,0x2a,0x86,0x86,0x62,0x9d,0x3f,0x41,0x4d,0x7f,0x3a,0xf1,0xa4,0xd2,0x9b,0x99,0xc2,0x62,0x22,0xa5,0x6d,0x6d,0xb1,0x29,0x3b,0x79,0xf1,0xe6,0xe2,0xaf,0x6d,0xfd,0x20,0x8d,
+ 0x04,0x20,0x19,0x2a,0x86,0x86,0x62,0xc2,0xbd,0xcd,0xa2,0x34,0xc9,0x5e,0x0b,0xdb,0x6e,0x6e,0x92,0xa2,0x4f,0xf1,0x0a,0x59,0x6c,0x19,0x9c,0xd0,0xd8,0x3c,0x50,0x3b,0x41,0x27,0x20,0x8d,
+ 0x04,0x20,0x1c,0xe0,0xbe,0xd4,0x48,0xe2,0x00,0xc5,0xf0,0x0d,0x65,0x08,0x59,0xc2,0x3f,0x09,0x4d,0x98,0x2c,0x14,0xc9,0x71,0xc8,0x8b,0x53,0x29,0xa8,0xb5,0x8c,0x7b,0x22,0xb0,0x20,0x8d,
+ 0x04,0x20,0x23,0x33,0x80,0xcc,0x5a,0xeb,0x86,0x37,0x03,0x4f,0x8b,0x97,0xac,0xb5,0xf9,0xd0,0x2e,0xd8,0x9b,0xca,0xff,0xef,0x63,0x22,0x2c,0x3d,0x7e,0x83,0x39,0x14,0x10,0xc7,0x20,0x8d,
+ 0x04,0x20,0x23,0x33,0x80,0xcc,0x5b,0x25,0x8f,0xfc,0xa0,0xef,0x50,0xeb,0x4b,0x2c,0xd7,0x89,0xf2,0x2b,0xe3,0x4f,0xe9,0x6a,0x93,0x19,0xff,0x69,0x92,0x1b,0x8b,0x13,0xbd,0x67,0x20,0x8d,
+ 0x04,0x20,0x23,0x33,0x80,0xcc,0x5c,0xef,0x09,0x60,0xd5,0x10,0x6b,0x0d,0x33,0x5f,0x71,0x35,0x02,0xb9,0x19,0x4a,0xd6,0xe3,0xc7,0x34,0x27,0x40,0xc5,0x5d,0xfa,0xd1,0x23,0x28,0x20,0x8d,
+ 0x04,0x20,0x23,0x33,0x80,0xcc,0x5d,0x0b,0x5e,0x1d,0x3b,0xc6,0x3f,0x78,0xe8,0x51,0x0e,0xbf,0x78,0xee,0x47,0xf8,0x6f,0x01,0xab,0x21,0x16,0xcc,0x52,0xe6,0xad,0xd4,0x02,0x02,0x20,0x8d,
0x04,0x20,0x2b,0xf3,0xe8,0xf5,0xef,0x90,0x14,0xab,0x61,0xe9,0x11,0x97,0x9f,0x18,0x4d,0xb4,0xff,0x89,0x94,0xf7,0x92,0x94,0x53,0xe6,0x9e,0xd4,0xdb,0x85,0x89,0x4d,0x3e,0xc9,0x20,0x8d,
- 0x04,0x20,0x35,0xdd,0xd0,0x36,0xa5,0x69,0x4a,0xd2,0xcc,0xb8,0xe9,0x62,0xa3,0x55,0xeb,0x86,0xe2,0xf3,0x03,0x48,0x26,0xe6,0x20,0xad,0xda,0xaa,0xff,0xde,0x16,0xad,0x39,0x9d,0x20,0x8d,
- 0x04,0x20,0x41,0x47,0x4e,0xc2,0xa1,0x71,0x63,0x3e,0x11,0x54,0x46,0x91,0x80,0xed,0x41,0x16,0x32,0x29,0x19,0x60,0xc9,0xef,0xa3,0xb7,0x96,0x2c,0x94,0xa8,0xdf,0x55,0xd7,0x21,0x20,0x8d,
- 0x04,0x20,0x44,0xf3,0xb7,0x5e,0x48,0x3c,0xbd,0xa6,0x52,0xaa,0x68,0xb5,0xbf,0xdc,0x01,0x5f,0x4b,0xeb,0x7a,0x25,0xcb,0x4a,0x70,0xbc,0x18,0x8c,0x97,0x5d,0x27,0x54,0x09,0x17,0x20,0x8d,
+ 0x04,0x20,0x38,0x1b,0x57,0x6c,0xf9,0x80,0x4e,0x28,0x33,0xb5,0x01,0xce,0x8e,0x83,0x62,0xcd,0xee,0x3b,0x0b,0xf5,0x9f,0x7c,0xfe,0x9a,0x3f,0x0a,0x0a,0x2a,0x91,0x60,0x85,0x23,0x20,0x8d,
+ 0x04,0x20,0x3e,0x7e,0xe8,0x36,0x75,0x4f,0x00,0x38,0xda,0x70,0x03,0xde,0x23,0x02,0xe5,0x8a,0x02,0x6e,0xd3,0x91,0xa9,0x54,0xfb,0x2d,0xdb,0xbd,0x1f,0xd2,0x8a,0x98,0xae,0x16,0x20,0x8d,
+ 0x04,0x20,0x44,0xf1,0x1b,0x9d,0x03,0xaa,0x5a,0x96,0x97,0xc8,0x66,0x71,0x48,0x41,0xaa,0x55,0xa2,0x81,0xa5,0xa4,0x0a,0x82,0xe5,0x5f,0x5d,0x93,0xb7,0x2a,0x43,0x65,0xc9,0x32,0x20,0x8d,
+ 0x04,0x20,0x4c,0xdd,0xa4,0x94,0x32,0xb9,0xc3,0xec,0x54,0xe2,0x8c,0x52,0x31,0xc4,0xc1,0x02,0xa6,0x4f,0x4c,0xd2,0xc6,0xc5,0xbc,0xed,0xf1,0x94,0xbd,0xc3,0x34,0x66,0xab,0xab,0x20,0x8d,
+ 0x04,0x20,0x57,0xda,0x1d,0xc7,0xe7,0xba,0x3a,0x4b,0xd6,0x3c,0xbb,0x2a,0xd4,0x2c,0xe5,0xb7,0x8e,0x44,0x7e,0x56,0xe4,0x6d,0x9d,0x4f,0xce,0x69,0xf8,0xfc,0x7a,0xc1,0x74,0x41,0x20,0x8d,
0x04,0x20,0x53,0xcd,0x56,0x48,0x48,0x8c,0x47,0x07,0x91,0x41,0x82,0x65,0x5b,0x76,0x64,0x03,0x4e,0x09,0xe6,0x6f,0x7e,0x8c,0xbf,0x10,0x84,0xe6,0x54,0xeb,0x56,0xc5,0xbd,0x88,0x20,0x8d,
+ 0x04,0x20,0x5f,0xd5,0x6d,0xd5,0x32,0xe0,0x8b,0xd6,0x36,0x84,0x4a,0x4d,0x01,0x5e,0x36,0xf5,0xad,0x24,0xb0,0x01,0x5a,0xe1,0xb3,0xec,0x0c,0xc7,0x0b,0xd8,0x6f,0x63,0xf0,0x8c,0x20,0x8d,
0x04,0x20,0x67,0xc4,0x17,0xa5,0xcb,0x77,0xbd,0xaa,0x11,0x7f,0x8b,0xc0,0x81,0xf3,0xc0,0x96,0x9d,0x31,0x27,0x9c,0xad,0x6c,0x6d,0x98,0x42,0x70,0xdb,0x50,0x12,0x96,0x0b,0x36,0x20,0x8d,
+ 0x04,0x20,0x63,0xac,0x1d,0x42,0xcf,0x49,0xa5,0xa0,0x7a,0x1b,0xc2,0x77,0x70,0x7d,0xb7,0x52,0xcb,0x29,0x51,0x7c,0xb7,0xf0,0xd7,0x37,0x18,0x15,0xb7,0x4c,0x39,0xe5,0xa6,0xef,0x20,0x8d,
0x04,0x20,0x65,0x98,0x55,0xd0,0x8a,0xe0,0x29,0xe6,0x5e,0xef,0xb7,0x8b,0x8f,0xc9,0x27,0x53,0x3d,0xd0,0x8c,0xa2,0xfa,0x32,0x2f,0xad,0xf9,0xdc,0xe2,0x4b,0x14,0x66,0x3e,0x23,0x20,0x8d,
- 0x04,0x20,0x8b,0xfe,0xad,0x19,0xdb,0x97,0x57,0x84,0xec,0xad,0x4f,0xb2,0xdf,0x69,0x53,0x04,0x57,0x19,0x16,0x7a,0x71,0xd7,0x2b,0xab,0x03,0xfd,0x76,0x4d,0xa0,0x70,0xc3,0xe7,0x20,0x8d,
+ 0x04,0x20,0x89,0x60,0xc6,0xee,0x04,0xdf,0xa8,0x07,0xcd,0x57,0x38,0xea,0x8f,0xf1,0xfc,0x3e,0x23,0x93,0xa2,0x3e,0xa9,0xd9,0x90,0xe8,0xf0,0x8e,0x2e,0xe1,0xa0,0xdc,0x35,0x09,0x20,0x8d,
+ 0x04,0x20,0x8c,0x8d,0x69,0xb5,0xd4,0x91,0x45,0xfc,0xe0,0xdc,0x84,0x99,0xb3,0x54,0x59,0x4d,0xfe,0x24,0x1c,0xfa,0x6a,0x70,0x90,0xa5,0x7b,0x85,0x44,0x9d,0xdc,0xdf,0xb3,0x2a,0x20,0x8d,
+ 0x04,0x20,0x96,0x87,0xdd,0x04,0x33,0x9d,0x2c,0x25,0xed,0xe3,0x8d,0xb2,0x7b,0xbd,0x87,0x9d,0xdb,0xb4,0x9b,0x5b,0x38,0x2a,0x98,0x1b,0xa4,0xc1,0xac,0x79,0xa2,0xde,0x59,0xb0,0x20,0x8d,
+ 0x04,0x20,0xa3,0xeb,0x33,0xe3,0xfc,0x39,0xaa,0x60,0xc1,0x1e,0xb6,0xf2,0x3d,0x31,0x62,0x3b,0x91,0xd9,0xd6,0xb6,0xf8,0x7a,0x77,0xb1,0x87,0x10,0xc6,0x3e,0x95,0xad,0xb4,0x51,0x20,0x8d,
+ 0x04,0x20,0xb1,0xdd,0xb8,0x4b,0x84,0x82,0xe1,0x97,0x5c,0xf0,0x81,0x80,0xde,0x30,0xdd,0xe5,0x01,0xda,0x67,0x6c,0x57,0x16,0x9d,0xec,0x06,0xee,0xc8,0x8e,0x3a,0x35,0x6e,0x5b,0x20,0x8d,
+ 0x04,0x20,0xb2,0x32,0x14,0x4f,0xbd,0xef,0x43,0x29,0x2e,0xd5,0xe0,0xa7,0x17,0x35,0xb2,0x32,0xbb,0x53,0xea,0xda,0x78,0xef,0xfa,0xfc,0x98,0xa2,0x2a,0xbc,0x51,0xd3,0x21,0x12,0x20,0x8d,
+ 0x04,0x20,0xc4,0x58,0x41,0xc7,0x7d,0x9c,0xf9,0x68,0x15,0xb6,0x32,0x16,0xb9,0xdc,0xfd,0x0b,0x68,0xa2,0x51,0x57,0x4b,0xcc,0x6d,0xa7,0x2c,0x64,0xb0,0xb1,0xf5,0x66,0x93,0x7a,0x20,0x8d,
0x05,0x20,0xd7,0x7a,0x53,0x89,0xfe,0x02,0x6a,0x59,0xb7,0x0e,0xf8,0x6d,0x9d,0x81,0xbb,0x9f,0x01,0xc0,0xc4,0xee,0x7b,0x36,0x10,0x33,0x07,0xd2,0x29,0xd8,0xec,0xcd,0x8e,0xa3,0x00,0x00,
0x05,0x20,0xd7,0xf1,0x19,0x9e,0x7d,0x0f,0x43,0x97,0x33,0x56,0xe8,0x12,0x1d,0x7d,0xa0,0x4d,0x21,0x5a,0x60,0x73,0xc8,0x7e,0x10,0x55,0x60,0x56,0xbb,0x65,0x50,0xa4,0x17,0x59,0x00,0x00,
- 0x05,0x20,0xd1,0x17,0xe2,0x34,0x4a,0x61,0x70,0x8b,0x04,0xa2,0xb4,0xb0,0x65,0x59,0x52,0x75,0x67,0x86,0xe6,0x48,0x33,0x31,0x5d,0x87,0x38,0x57,0xd3,0xf8,0x40,0x07,0x73,0xa8,0x00,0x00,
0x05,0x20,0xd9,0x9c,0x20,0xfe,0xc2,0xe6,0x6a,0x16,0x30,0x81,0x54,0xc9,0x3f,0x9a,0x89,0x10,0xa9,0x4b,0xf1,0x05,0x56,0xd5,0x04,0x2d,0xb7,0x6a,0x7b,0x67,0x8d,0xf0,0xbe,0x8f,0x00,0x00,
- 0x05,0x20,0xdc,0xdb,0x2d,0x39,0xd5,0xe4,0xda,0xb5,0xb6,0x6e,0x98,0x33,0x8f,0x51,0x99,0x54,0x38,0x53,0xa8,0x4e,0xda,0x29,0xd8,0xb5,0x57,0x9d,0x36,0xf0,0x97,0x37,0x18,0x3f,0x00,0x00,
0x05,0x20,0xe1,0x44,0x2d,0x6e,0xd3,0xd9,0xf0,0x95,0x6c,0x52,0x2e,0x44,0x3c,0x27,0x3d,0x78,0xac,0x6e,0x8f,0x27,0x1c,0x0c,0xc0,0x78,0x22,0x3e,0xa1,0x84,0x01,0x42,0x08,0x5c,0x00,0x00,
0x05,0x20,0xe3,0xa5,0x88,0x11,0x4d,0x3d,0xfb,0x02,0xec,0x1f,0xda,0x48,0x86,0x12,0xf6,0x12,0xd9,0x3e,0x68,0x49,0xa7,0xae,0x37,0xfd,0x02,0x48,0x38,0x8b,0xdc,0xd4,0xa6,0x8f,0x00,0x00,
0x05,0x20,0xe5,0x19,0x24,0x71,0xab,0x61,0xb0,0xfe,0x44,0x4a,0x74,0x8d,0xca,0x90,0xc3,0xd6,0x24,0xb4,0xd5,0x03,0xe7,0xf3,0x4f,0xbe,0x12,0x72,0xd6,0xa0,0x4b,0x22,0x0b,0xe1,0x00,0x00,
- 0x05,0x20,0xee,0xab,0xea,0x3b,0xc2,0x8a,0xe2,0xb3,0xe5,0xe7,0x92,0xf0,0x88,0x05,0x68,0x8d,0x2f,0xe7,0x2c,0xd2,0x00,0x39,0xd4,0x5d,0x07,0xfc,0xa1,0xd6,0xbf,0x89,0xa2,0x40,0x00,0x00,
0x05,0x20,0xf2,0x74,0x4c,0x90,0xc3,0xd9,0x34,0x4d,0x5f,0x6e,0xdb,0xdd,0x7d,0xef,0xa5,0xed,0x6e,0x59,0x9e,0x31,0x41,0x94,0x38,0x84,0xc5,0x08,0xd2,0x23,0xb3,0xa7,0xe0,0x2c,0x00,0x00,
0x05,0x20,0xf3,0x77,0xe5,0xa7,0x11,0xef,0x65,0x91,0x23,0xb8,0x32,0x06,0xcb,0xc0,0x91,0xf7,0x21,0x1d,0x70,0xbc,0x83,0x1b,0x86,0x34,0x35,0x31,0x0f,0x9f,0xc1,0x0d,0xbb,0x56,0x00,0x00,
0x05,0x20,0xfe,0xb0,0x99,0x79,0x95,0x58,0x71,0xb5,0x63,0xcc,0x33,0xeb,0x55,0x91,0x8c,0xb4,0x3a,0xf2,0x8b,0x2d,0x8e,0x47,0xbe,0x25,0x47,0x12,0xcd,0x14,0x48,0xf0,0x1d,0xea,0x00,0x00,
- 0x05,0x20,0xfc,0x79,0x14,0x77,0x6b,0x0e,0x34,0x8d,0xde,0x01,0x33,0xed,0xb4,0x0e,0xa7,0xc9,0x15,0x4f,0xd0,0x27,0x2c,0xd6,0x5f,0xe9,0x63,0x82,0x8d,0xd5,0x0c,0x9e,0x18,0x29,0x00,0x00,
0x05,0x20,0x07,0x61,0x26,0xd7,0x6c,0x05,0xbf,0xf6,0x2d,0x8c,0xca,0xc4,0x65,0xd3,0xd3,0xb2,0x49,0xe9,0xcc,0x53,0x1e,0xca,0x77,0x84,0xb6,0x10,0x5e,0xc2,0x5a,0xfe,0x28,0xb3,0x00,0x00,
0x05,0x20,0x03,0xaa,0x47,0xe9,0xe2,0x77,0xeb,0xa5,0x72,0x27,0x23,0x8b,0x13,0x62,0x61,0x32,0xb5,0xb2,0x1b,0x5a,0x18,0xb2,0xf9,0x26,0x06,0x84,0xee,0x28,0x42,0xac,0xba,0xbc,0x00,0x00,
- 0x05,0x20,0x08,0xc6,0x19,0x31,0x40,0x96,0xf3,0xe2,0x81,0x4e,0x88,0x54,0x54,0x9e,0xbf,0xfa,0x38,0x7a,0xfa,0x38,0x96,0x13,0x2a,0xc4,0x69,0xa2,0xae,0xe5,0x94,0xc7,0x16,0xb7,0x00,0x00,
0x05,0x20,0x0a,0x26,0x27,0x23,0xdd,0xf3,0x56,0xbe,0x9e,0x9e,0xa7,0xc6,0x3c,0xc5,0x99,0xc4,0x87,0x3b,0x4d,0xb9,0x13,0x62,0x91,0xf2,0x25,0x1c,0x02,0x42,0x63,0xe3,0x63,0x7a,0x00,0x00,
0x05,0x20,0x0c,0x50,0x55,0x46,0x87,0x5a,0x8d,0x14,0xfb,0xa7,0x29,0x70,0x18,0xa6,0x29,0x80,0x8c,0x33,0x42,0x5a,0x8f,0xe4,0x84,0x64,0x3d,0x0e,0xb5,0xbd,0x36,0x34,0x42,0xb6,0x00,0x00,
0x05,0x20,0x17,0x0c,0x56,0xce,0x72,0xa5,0xa0,0xe6,0x23,0x06,0xa3,0xc7,0x08,0x43,0x18,0xee,0x3a,0x46,0x35,0x5d,0x17,0xf6,0x78,0x96,0xa0,0x9c,0x51,0xef,0xbe,0x23,0xfd,0x71,0x00,0x00,
0x05,0x20,0x18,0x31,0xb3,0x9a,0xf8,0x8c,0xec,0x99,0x2e,0x7d,0xe4,0x90,0xa2,0x54,0x27,0xbd,0xe5,0xc8,0x65,0xdf,0x1f,0xaa,0x8f,0xe9,0x0f,0x64,0x85,0x09,0xc3,0x70,0x62,0x13,0x00,0x00,
- 0x05,0x20,0x1a,0x35,0x98,0x78,0xb1,0xd9,0x48,0x62,0xe9,0x23,0x10,0xfe,0x71,0xdb,0x10,0x5f,0x28,0xc8,0xf3,0xda,0x33,0x9b,0x26,0xcb,0x4d,0xbe,0x7b,0x03,0x76,0xb9,0xe0,0x54,0x00,0x00,
+ 0x05,0x20,0x1d,0x3a,0xac,0x0e,0x8c,0x62,0x35,0xb0,0xa4,0xaf,0xf0,0x47,0xf7,0x5a,0x55,0x8a,0x12,0x69,0xff,0x27,0xad,0xd9,0x9e,0x9f,0xa5,0xec,0x9e,0x24,0x38,0x8e,0x24,0xed,0x00,0x00,
0x05,0x20,0x27,0x7a,0xaf,0x5a,0x9c,0xf4,0x72,0xfe,0x3c,0xdd,0x7a,0xba,0xd7,0x98,0x31,0xde,0x73,0xce,0x84,0x5b,0x41,0xe7,0x9a,0x6a,0xe2,0xc1,0x3b,0x5b,0x37,0x23,0xc7,0xdf,0x00,0x00,
0x05,0x20,0x20,0x90,0xe3,0xd3,0xad,0x87,0xeb,0x2a,0xd9,0x29,0x17,0x74,0x47,0xc9,0x54,0x57,0xfa,0x3d,0x71,0x02,0x11,0xb2,0xc3,0x87,0x31,0xb3,0x9b,0x6f,0x2e,0xfc,0x30,0xea,0x00,0x00,
0x05,0x20,0x22,0x56,0xd6,0x98,0x11,0x61,0xe1,0x5a,0x34,0x9f,0xe2,0x9d,0xf5,0x2b,0xbd,0xbc,0xcc,0x1c,0xf5,0x1d,0x68,0xa5,0xca,0xb1,0xb5,0x4b,0xf1,0xb5,0xff,0x1e,0xdd,0xc0,0x00,0x00,
- 0x05,0x20,0x37,0x3e,0x28,0x39,0xef,0xa6,0xbc,0xf8,0xf1,0xba,0x11,0x40,0x87,0x42,0xff,0x58,0x46,0x8f,0xb0,0x80,0xfe,0x20,0x75,0xc5,0x43,0xce,0xec,0x9b,0x5d,0x37,0x19,0xf4,0x00,0x00,
- 0x05,0x20,0x3e,0xe3,0xe0,0xa9,0xbc,0xf4,0x2e,0x59,0xd9,0x20,0xee,0xdf,0x74,0x61,0x4d,0x99,0x0c,0x5c,0x15,0x30,0x9b,0x72,0x16,0x79,0x15,0xf4,0x7a,0xca,0x34,0xcc,0x81,0x99,0x00,0x00,
+ 0x05,0x20,0x29,0xf2,0xb7,0xee,0xf1,0x70,0x02,0xe3,0xb5,0x89,0x73,0x69,0xd4,0x40,0x19,0xb1,0xd6,0x10,0xd8,0xfd,0x13,0xe8,0x9a,0xdb,0x40,0xc8,0xa9,0xb9,0x46,0x03,0x11,0x12,0x00,0x00,
+ 0x05,0x20,0x2d,0xfc,0xd7,0xed,0xc7,0x20,0x05,0x1d,0xcf,0xe6,0x5d,0x0b,0x38,0xc1,0xda,0x85,0xd6,0x30,0x84,0x13,0x35,0xb8,0x72,0x3d,0xff,0xa2,0xc3,0xc4,0xf6,0x38,0xef,0xc4,0x00,0x00,
+ 0x05,0x20,0x31,0x0f,0x30,0x0b,0x9d,0x70,0x0c,0x7c,0xf7,0x98,0x7e,0x1c,0xf4,0x33,0xdc,0x64,0x17,0xf7,0x00,0x7a,0x0c,0x04,0xb5,0x83,0xfc,0x5f,0xa6,0x52,0x39,0x79,0x63,0x87,0x00,0x00,
0x05,0x20,0x39,0xca,0x8e,0x62,0x0a,0x36,0xa7,0x68,0x22,0xc4,0xcc,0x4a,0xa9,0x16,0x69,0x4b,0x8a,0x1c,0x5f,0x6e,0x4a,0x98,0xb6,0x95,0x82,0xb3,0x66,0x66,0xc5,0x29,0x3a,0xb0,0x00,0x00,
- 0x05,0x20,0x3b,0xd0,0x80,0xc4,0xab,0x82,0x83,0x11,0x48,0xe5,0x3b,0x23,0x3b,0x17,0x04,0x0f,0xd8,0x39,0x7c,0x1b,0x70,0x73,0x68,0x98,0x11,0x22,0x49,0x51,0x8f,0x20,0x65,0x65,0x00,0x00,
- 0x05,0x20,0x47,0x1f,0x83,0xc8,0xa3,0x87,0x35,0xcf,0x8e,0x8d,0x22,0xfe,0xf0,0x02,0x63,0x04,0x3a,0x6a,0x49,0x1a,0x3b,0x70,0x17,0xeb,0x05,0xed,0xaf,0x61,0xb6,0x26,0xb8,0x21,0x00,0x00,
- 0x05,0x20,0x45,0xbd,0x33,0x3d,0x81,0x1e,0x14,0x52,0x88,0x8a,0xa7,0x46,0x0f,0x37,0x25,0xd0,0x59,0x9f,0x78,0xb5,0x7f,0x4a,0xf1,0x54,0x8c,0x2d,0x36,0x32,0xf8,0x10,0xf3,0xcc,0x00,0x00,
- 0x05,0x20,0x4a,0x8b,0x40,0x25,0xdc,0x06,0x2a,0xed,0x44,0x35,0xec,0x06,0x9e,0x73,0x70,0xf0,0x07,0x06,0x35,0xd1,0x60,0x4f,0x22,0xe8,0xbf,0x8a,0xdf,0xd9,0xeb,0x97,0x73,0x06,0x00,0x00,
0x05,0x20,0x4e,0x77,0x2e,0x12,0x91,0x67,0x6b,0x94,0xc4,0x92,0x2f,0x19,0x67,0x7d,0xcd,0x47,0x02,0xad,0xf8,0x60,0x72,0xed,0x73,0xf1,0x10,0x99,0x2c,0x05,0x61,0x66,0x55,0xd9,0x00,0x00,
0x05,0x20,0x5a,0x29,0xfe,0x8a,0xaa,0x9d,0x78,0x81,0x04,0x53,0x37,0xf5,0x6f,0xb6,0xe1,0x57,0x08,0x80,0xcf,0xf6,0x03,0x11,0x92,0x8d,0x08,0xe3,0x99,0x9f,0x98,0x4a,0x27,0x6b,0x00,0x00,
- 0x05,0x20,0x5a,0x65,0x0a,0x52,0x9b,0xc7,0x2e,0x92,0x79,0x7b,0xd3,0xf7,0xa4,0x35,0xbe,0x8e,0xb1,0xea,0x2d,0x7e,0x73,0x84,0x6a,0x3f,0xc9,0x9a,0x62,0xe3,0xc6,0x17,0x0e,0x7c,0x00,0x00,
0x05,0x20,0x5c,0x40,0x7f,0x80,0x43,0x91,0x9c,0xfc,0x04,0xdc,0xdc,0x8e,0x01,0xda,0xc8,0xaf,0x90,0x62,0x64,0x16,0xf7,0x11,0xe4,0x87,0xac,0xa4,0x06,0x6f,0x8d,0x87,0x4e,0xd6,0x00,0x00,
0x05,0x20,0x5e,0x69,0x4f,0x31,0x33,0xa7,0xea,0x3e,0xf4,0x7a,0x0a,0x1e,0x74,0x09,0x07,0xa1,0x50,0xf7,0x03,0xf5,0xc6,0x19,0xeb,0x95,0xaa,0x63,0x17,0x10,0x6e,0x68,0xca,0x10,0x00,0x00,
0x05,0x20,0x67,0x82,0xfc,0x36,0xea,0xae,0x95,0x3b,0x5d,0x46,0xf3,0xf4,0x6c,0x50,0x69,0x29,0xc7,0x47,0x87,0xca,0xa6,0x40,0x12,0x40,0x6d,0x12,0x94,0x35,0x17,0x8a,0xba,0x56,0x00,0x00,
0x05,0x20,0x67,0xab,0xce,0xf2,0xe3,0xf3,0xf6,0x19,0xf6,0x56,0xa2,0x4c,0xca,0x91,0x4b,0x93,0xfe,0xbc,0x85,0x50,0x5c,0x20,0x51,0x69,0xfb,0xf0,0x92,0xbb,0x57,0xa3,0x0d,0x05,0x00,0x00,
0x05,0x20,0x62,0xcc,0x44,0x66,0x31,0x76,0x1b,0x43,0xbe,0xe1,0xc9,0x1d,0x20,0x26,0x7d,0xa7,0x06,0x31,0x57,0x0d,0xb9,0x58,0x20,0xb3,0xca,0xb2,0x5e,0x0a,0x15,0x0b,0xba,0x0d,0x00,0x00,
+ 0x05,0x20,0x77,0xa7,0xc2,0xc7,0xa0,0xc1,0x40,0x3c,0xa0,0x94,0x9c,0xa6,0x6b,0x09,0x6b,0xad,0xae,0x4a,0x65,0x2b,0xbb,0x33,0x26,0x3d,0x3b,0x3b,0xd5,0x52,0x14,0xf9,0x28,0x08,0x00,0x00,
0x05,0x20,0x71,0x68,0x1b,0xc7,0x48,0x8f,0xe9,0xa3,0x53,0x29,0xb6,0x23,0x5a,0x25,0x02,0x45,0x72,0xca,0xa1,0xb6,0x06,0xfc,0xda,0x65,0x71,0x37,0xe6,0xd9,0x30,0x81,0x02,0xfe,0x00,0x00,
- 0x05,0x20,0x72,0x8b,0x72,0x38,0xfe,0x44,0xe9,0xc2,0xf4,0xbc,0xd8,0xce,0x1c,0xd5,0x50,0xb1,0x63,0x56,0x74,0x5e,0xf2,0xd3,0xe5,0xd5,0x29,0xe4,0x34,0x1d,0xf5,0x1c,0x7a,0xb9,0x00,0x00,
0x05,0x20,0x76,0x74,0x80,0x6c,0xab,0x7b,0x36,0x3a,0x6a,0x78,0xa4,0xa8,0xb8,0xb7,0xe7,0xf9,0x34,0x47,0x6d,0x34,0xca,0xa2,0xc6,0xef,0x81,0xab,0x62,0xb1,0x46,0x86,0xaf,0xd0,0x00,0x00,
+ 0x05,0x20,0x7b,0x8e,0x51,0x44,0xa2,0xfb,0xe2,0xde,0x06,0xad,0xe5,0xe5,0x3b,0x79,0xb3,0xd9,0x3e,0x74,0xb0,0x3f,0x55,0x13,0xc1,0xa6,0x72,0x2c,0x25,0x25,0x58,0xec,0x3b,0x5a,0x00,0x00,
0x05,0x20,0x80,0xfc,0x95,0xc8,0x95,0x91,0x2f,0x6b,0x6e,0xc4,0x2b,0xe1,0x2f,0xa0,0xcb,0xb8,0x76,0x5f,0x6f,0x1c,0x27,0xb0,0x3a,0x2c,0xb9,0x8d,0x6c,0x55,0xbd,0x02,0x60,0xe0,0x00,0x00,
- 0x05,0x20,0x80,0xc6,0x6f,0xb3,0x18,0x5a,0x1a,0xde,0x4e,0xde,0x50,0xd2,0xc6,0x3f,0xc5,0x96,0x09,0x35,0x3a,0x4d,0x88,0x5f,0xa3,0x49,0x37,0xff,0xe6,0xc5,0x43,0x10,0xaf,0xa8,0x00,0x00,
+ 0x05,0x20,0x89,0x52,0xac,0x8f,0x35,0xe0,0xac,0xfb,0xbb,0xc7,0xcd,0x1a,0x24,0x0a,0xb4,0xc5,0x11,0xff,0x5a,0xf0,0xbe,0xc1,0xad,0xaf,0x0d,0x87,0xf4,0xa9,0xda,0x12,0xf8,0x12,0x00,0x00,
0x05,0x20,0x8a,0x32,0x54,0x37,0x12,0x24,0xb5,0x1d,0xba,0x3c,0x45,0x03,0x2e,0xda,0xfe,0xf1,0x87,0x8f,0x31,0xe5,0xfe,0xed,0xfa,0x38,0x25,0x00,0x99,0xa5,0xf4,0x51,0x02,0xf7,0x00,0x00,
- 0x05,0x20,0x97,0x4e,0x74,0xcd,0x8b,0x37,0x76,0x15,0x3b,0x6d,0xb5,0xa4,0xa0,0x4b,0xf7,0x34,0x98,0x48,0x67,0x1e,0x99,0xe7,0x24,0xf4,0x00,0xf7,0x06,0x9c,0x45,0x69,0x34,0x01,0x00,0x00,
0x05,0x20,0x91,0x06,0xd1,0x9e,0xbd,0xab,0xc4,0x61,0xb3,0x0a,0xc2,0x3b,0x29,0xf3,0x10,0x38,0xee,0xbd,0x9d,0xe3,0x99,0x97,0x30,0x70,0x6e,0xe6,0xfb,0x6a,0x3c,0x07,0x3d,0xfd,0x00,0x00,
- 0x05,0x20,0x9c,0x97,0xc1,0xad,0xf4,0xd2,0x07,0xae,0xe8,0x3e,0x14,0x42,0x36,0x85,0x71,0xa0,0xa7,0xef,0x72,0x44,0xf1,0x74,0x8b,0x6f,0xa5,0xa4,0x2c,0x0d,0xcc,0x9f,0xb0,0x9d,0x00,0x00,
0x05,0x20,0x9d,0x0d,0x0f,0x58,0x1a,0x5c,0xb4,0x1a,0xeb,0xef,0x8e,0x91,0x8d,0x8c,0x1b,0x57,0x5d,0x6d,0x97,0x24,0x28,0x45,0x54,0x8a,0x3a,0xd5,0x05,0xfb,0x76,0xac,0x25,0x52,0x00,0x00,
0x05,0x20,0xa4,0xb3,0x30,0x54,0x28,0x0f,0xfb,0xe5,0x76,0xb0,0x31,0xb2,0x65,0x62,0x56,0x72,0x7c,0xc9,0xcd,0x07,0x4d,0x5f,0xb1,0x69,0xe0,0xf7,0x35,0x3d,0x30,0x3c,0x7d,0x64,0x00,0x00,
0x05,0x20,0xa9,0xa9,0xe5,0xae,0x01,0xc2,0x5e,0x76,0x2f,0x5d,0xa3,0x07,0xdc,0xce,0xb8,0xbc,0x6f,0x47,0xaf,0x3a,0x37,0xf8,0x5c,0x86,0xff,0xe9,0xb6,0xa5,0x00,0x93,0x76,0x11,0x00,0x00,
0x05,0x20,0xb2,0x63,0x45,0xf5,0x36,0xb0,0x79,0x58,0x0d,0x8a,0x54,0x52,0x16,0x2f,0x1f,0x74,0x93,0xe0,0x30,0x82,0x1b,0xe4,0x01,0x76,0xf5,0x03,0xa1,0x19,0xa3,0x8d,0x0e,0xce,0x00,0x00,
- 0x05,0x20,0xb5,0x55,0x31,0x3f,0xe7,0xc7,0x17,0xe4,0x31,0x87,0x47,0x45,0x7c,0x67,0x43,0x5c,0x82,0x73,0xd6,0x62,0x64,0x94,0x92,0x32,0x2d,0x81,0x0e,0x01,0x35,0xc0,0x7e,0xb7,0x00,0x00,
0x05,0x20,0xb5,0x83,0x6f,0xb6,0x11,0xd8,0x0e,0xa8,0x57,0xda,0x15,0x20,0x5b,0x1a,0x6d,0x21,0x15,0x5a,0xbd,0xb4,0x17,0x11,0xc2,0xfb,0x0e,0xfc,0xde,0xe8,0x26,0x56,0xa8,0xac,0x00,0x00,
- 0x05,0x20,0xba,0xe0,0xd1,0xe5,0x2e,0x27,0x5b,0x1d,0x36,0x57,0x77,0xaf,0x64,0x04,0xfc,0xe1,0x8f,0x8c,0xf1,0x25,0x81,0x2b,0x4f,0x6a,0xf8,0x55,0x48,0xc2,0x5e,0x6f,0x62,0x43,0x00,0x00,
+ 0x05,0x20,0xb9,0x54,0x08,0xb2,0xaa,0xe6,0xea,0x55,0x16,0xa7,0x51,0x0f,0x8f,0xa1,0xc9,0xd0,0x7d,0x69,0x94,0x6b,0x26,0x6a,0xc5,0x81,0x41,0x5e,0x77,0x0e,0x47,0xec,0x10,0x8b,0x00,0x00,
0x05,0x20,0xc0,0xb9,0x7b,0x21,0xbd,0xa2,0x48,0xda,0x8a,0x3e,0xc3,0x6c,0xac,0xfd,0x6d,0x63,0x21,0xb6,0xb3,0x37,0xa9,0x4d,0x42,0x2c,0x9e,0x75,0x61,0x07,0xdc,0xc9,0xab,0x9b,0x00,0x00,
0x05,0x20,0xc8,0xdc,0x00,0xc8,0xdf,0xa1,0xb2,0xe9,0x9f,0x00,0xb3,0x86,0x93,0xc3,0xbc,0x6d,0x56,0xe2,0x83,0xfc,0xf4,0x6e,0x55,0x5d,0xed,0x4e,0x53,0xe6,0xd1,0x4c,0x38,0x3c,0x00,0x00,
0x05,0x20,0xcc,0xaf,0x6c,0x3b,0xd0,0x13,0x76,0x23,0xc3,0x36,0xbb,0x64,0x4a,0x4a,0x06,0x93,0x69,0x6d,0xb0,0x10,0x6e,0x66,0xa4,0x61,0xf8,0x2d,0xe7,0x80,0x72,0x4d,0x53,0x94,0x00,0x00,
0x05,0x20,0xce,0x25,0x15,0xbd,0x08,0xe9,0x67,0x1c,0xa2,0xa5,0x16,0x0e,0x38,0xd9,0xe4,0xc6,0x20,0x31,0x86,0x23,0x21,0x5a,0x5a,0x76,0x1e,0x74,0xd5,0xd3,0x4e,0x86,0x61,0xf4,0x00,0x00,
0x06,0x10,0xfc,0x32,0x17,0xea,0xe4,0x15,0xc3,0xbf,0x98,0x08,0x14,0x9d,0xb5,0xa2,0xc9,0xaa,0x20,0x8d,
0x06,0x10,0xfc,0xc7,0xbe,0x49,0xcc,0xd1,0xdc,0x91,0x31,0x25,0xf0,0xda,0x45,0x7d,0x08,0xce,0x20,0x8d,
+ 0x06,0x10,0xfc,0xdc,0x73,0xae,0xb1,0xa9,0x1b,0xf8,0xd4,0xc2,0x08,0x11,0xa4,0xc7,0xc3,0x4e,0x20,0x8d,
};
static const uint8_t chainparams_seed_test[] = {
diff --git a/src/coins.cpp b/src/coins.cpp
index 5a6ae525a7..0fe642e46b 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -34,7 +34,7 @@ size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
CCoinsViewCache::CCoinsViewCache(CCoinsView* baseIn, bool deterministic) :
CCoinsViewBacked(baseIn), m_deterministic(deterministic),
- cacheCoins(0, SaltedOutpointHasher(/*deterministic=*/deterministic))
+ cacheCoins(0, SaltedOutpointHasher(/*deterministic=*/deterministic), CCoinsMap::key_equal{}, &m_cache_coins_memory_resource)
{}
size_t CCoinsViewCache::DynamicMemoryUsage() const {
@@ -253,9 +253,12 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, /*erase=*/true);
- if (fOk && !cacheCoins.empty()) {
- /* BatchWrite must erase all cacheCoins elements when erase=true. */
- throw std::logic_error("Not all cached coins were erased");
+ if (fOk) {
+ if (!cacheCoins.empty()) {
+ /* BatchWrite must erase all cacheCoins elements when erase=true. */
+ throw std::logic_error("Not all cached coins were erased");
+ }
+ ReallocateCache();
}
cachedCoinsUsage = 0;
return fOk;
@@ -314,7 +317,9 @@ void CCoinsViewCache::ReallocateCache()
// Cache should be empty when we're calling this.
assert(cacheCoins.size() == 0);
cacheCoins.~CCoinsMap();
- ::new (&cacheCoins) CCoinsMap(0, SaltedOutpointHasher(/*deterministic=*/m_deterministic));
+ m_cache_coins_memory_resource.~CCoinsMapMemoryResource();
+ ::new (&m_cache_coins_memory_resource) CCoinsMapMemoryResource{};
+ ::new (&cacheCoins) CCoinsMap{0, SaltedOutpointHasher{/*deterministic=*/m_deterministic}, CCoinsMap::key_equal{}, &m_cache_coins_memory_resource};
}
void CCoinsViewCache::SanityCheck() const
diff --git a/src/coins.h b/src/coins.h
index dd336b210a..039a07054d 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -11,6 +11,7 @@
#include <memusage.h>
#include <primitives/transaction.h>
#include <serialize.h>
+#include <support/allocators/pool.h>
#include <uint256.h>
#include <util/hasher.h>
@@ -131,7 +132,23 @@ struct CCoinsCacheEntry
CCoinsCacheEntry(Coin&& coin_, unsigned char flag) : coin(std::move(coin_)), flags(flag) {}
};
-typedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;
+/**
+ * PoolAllocator's MAX_BLOCK_SIZE_BYTES parameter here uses sizeof the data, and adds the size
+ * of 4 pointers. We do not know the exact node size used in the std::unordered_node implementation
+ * because it is implementation defined. Most implementations have an overhead of 1 or 2 pointers,
+ * so nodes can be connected in a linked list, and in some cases the hash value is stored as well.
+ * Using an additional sizeof(void*)*4 for MAX_BLOCK_SIZE_BYTES should thus be sufficient so that
+ * all implementations can allocate the nodes from the PoolAllocator.
+ */
+using CCoinsMap = std::unordered_map<COutPoint,
+ CCoinsCacheEntry,
+ SaltedOutpointHasher,
+ std::equal_to<COutPoint>,
+ PoolAllocator<std::pair<const COutPoint, CCoinsCacheEntry>,
+ sizeof(std::pair<const COutPoint, CCoinsCacheEntry>) + sizeof(void*) * 4,
+ alignof(void*)>>;
+
+using CCoinsMapMemoryResource = CCoinsMap::allocator_type::ResourceType;
/** Cursor for iterating over CoinsView state */
class CCoinsViewCursor
@@ -220,6 +237,7 @@ protected:
* declared as "const".
*/
mutable uint256 hashBlock;
+ mutable CCoinsMapMemoryResource m_cache_coins_memory_resource{};
mutable CCoinsMap cacheCoins;
/* Cached dynamic memory usage for the inner Coin objects. */
diff --git a/src/util/system.cpp b/src/common/args.cpp
index 98e89f82e7..643838399f 100644
--- a/src/util/system.cpp
+++ b/src/common/args.cpp
@@ -3,147 +3,44 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/system.h>
+#include <common/args.h>
#include <chainparamsbase.h>
-#include <fs.h>
+#include <common/settings.h>
+#include <logging.h>
#include <sync.h>
+#include <tinyformat.h>
+#include <univalue.h>
+#include <util/chaintype.h>
#include <util/check.h>
-#include <util/getuniquepath.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/strencodings.h>
-#include <util/string.h>
-#include <util/syserror.h>
-#include <util/translation.h>
-
-
-#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
-#include <pthread.h>
-#include <pthread_np.h>
-#endif
-#ifndef WIN32
-// for posix_fallocate, in configure.ac we check if it is present after this
-#ifdef __linux__
-
-#ifdef _POSIX_C_SOURCE
-#undef _POSIX_C_SOURCE
+#ifdef WIN32
+#include <codecvt> /* for codecvt_utf8_utf16 */
+#include <shellapi.h> /* for CommandLineToArgvW */
+#include <shlobj.h> /* for CSIDL_APPDATA */
#endif
-#define _POSIX_C_SOURCE 200112L
-
-#endif // __linux__
-
#include <algorithm>
#include <cassert>
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-
-#else
-
-#include <codecvt>
-
-#include <io.h> /* for _commit */
-#include <shellapi.h>
-#include <shlobj.h>
-#endif
-
-#ifdef HAVE_MALLOPT_ARENA_MAX
-#include <malloc.h>
-#endif
-
-#include <univalue.h>
-
-#include <fstream>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <filesystem>
#include <map>
-#include <memory>
#include <optional>
+#include <stdexcept>
#include <string>
-#include <system_error>
-#include <thread>
-#include <typeinfo>
-
-// Application startup time (used for uptime calculation)
-const int64_t nStartupTime = GetTime();
+#include <utility>
+#include <variant>
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
ArgsManager gArgs;
-/** Mutex to protect dir_locks. */
-static GlobalMutex cs_dir_locks;
-/** A map that contains all the currently held directory locks. After
- * successful locking, these will be held here until the global destructor
- * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
- * is called.
- */
-static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks);
-
-bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only)
-{
- LOCK(cs_dir_locks);
- fs::path pathLockFile = directory / lockfile_name;
-
- // If a lock for this directory already exists in the map, don't try to re-lock it
- if (dir_locks.count(fs::PathToString(pathLockFile))) {
- return true;
- }
-
- // Create empty lock file if it doesn't exist.
- FILE* file = fsbridge::fopen(pathLockFile, "a");
- if (file) fclose(file);
- auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
- if (!lock->TryLock()) {
- return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
- }
- if (!probe_only) {
- // Lock successful and we're not just probing, put it into the map
- dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
- }
- return true;
-}
-
-void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name)
-{
- LOCK(cs_dir_locks);
- dir_locks.erase(fs::PathToString(directory / lockfile_name));
-}
-
-void ReleaseDirectoryLocks()
-{
- LOCK(cs_dir_locks);
- dir_locks.clear();
-}
-
-bool DirIsWritable(const fs::path& directory)
-{
- fs::path tmpFile = GetUniquePath(directory);
-
- FILE* file = fsbridge::fopen(tmpFile, "a");
- if (!file) return false;
-
- fclose(file);
- remove(tmpFile);
-
- return true;
-}
-
-bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)
-{
- constexpr uint64_t min_disk_space = 52428800; // 50 MiB
-
- uint64_t free_bytes_available = fs::space(dir).available;
- return free_bytes_available >= min_disk_space + additional_bytes;
-}
-
-std::streampos GetFileSize(const char* path, std::streamsize max) {
- std::ifstream file{path, std::ios::binary};
- file.ignore(max);
- return file.gcount();
-}
-
/**
* Interpret a string argument as a boolean.
*
@@ -171,12 +68,6 @@ static std::string SettingName(const std::string& arg)
return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
}
-struct KeyInfo {
- std::string name;
- std::string section;
- bool negated{false};
-};
-
/**
* Parse "name", "section.name", "noname", "section.noname" settings keys.
*
@@ -213,8 +104,8 @@ KeyInfo InterpretKey(std::string key)
* @return parsed settings value if it is valid, otherwise nullopt accompanied
* by a descriptive error string
*/
-static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
- unsigned int flags, std::string& error)
+std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
+ unsigned int flags, std::string& error)
{
// Return negated settings as false values.
if (key.negated) {
@@ -252,7 +143,7 @@ std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
if (m_network.empty()) return std::set<std::string> {};
// if it's okay to use the default section for this network, don't worry
- if (m_network == CBaseChainParams::MAIN) return std::set<std::string> {};
+ if (m_network == ChainTypeToString(ChainType::MAIN)) return std::set<std::string> {};
for (const auto& arg : m_network_only_args) {
if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) {
@@ -266,10 +157,10 @@ std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
{
// Section names to be recognized in the config file.
static const std::set<std::string> available_sections{
- CBaseChainParams::REGTEST,
- CBaseChainParams::SIGNET,
- CBaseChainParams::TESTNET,
- CBaseChainParams::MAIN
+ ChainTypeToString(ChainType::REGTEST),
+ ChainTypeToString(ChainType::SIGNET),
+ ChainTypeToString(ChainType::TESTNET),
+ ChainTypeToString(ChainType::MAIN),
};
LOCK(cs_args);
@@ -347,15 +238,15 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin
return false;
}
- std::optional<util::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
+ std::optional<common::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
if (!value) return false;
m_settings.command_line_options[keyinfo.name].push_back(*value);
}
// we do not allow -includeconf from command line, only -noincludeconf
- if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
- const util::SettingsSpan values{*includes};
+ if (auto* includes = common::FindKey(m_settings.command_line_options, "includeconf")) {
+ const common::SettingsSpan values{*includes};
// Range may be empty if -noincludeconf was passed
if (!values.empty()) {
error = "-includeconf cannot be used from commandline; -includeconf=" + values.begin()->write();
@@ -470,7 +361,7 @@ std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
{
std::vector<std::string> result;
- for (const util::SettingsValue& value : GetSettingsList(strArg)) {
+ for (const common::SettingsValue& value : GetSettingsList(strArg)) {
result.push_back(value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
}
return result;
@@ -517,7 +408,7 @@ bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
LOCK(cs_args);
m_settings.rw_settings.clear();
std::vector<std::string> read_errors;
- if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
+ if (!common::ReadSettings(path, m_settings.rw_settings, read_errors)) {
SaveErrors(read_errors, errors);
return false;
}
@@ -539,7 +430,7 @@ bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backu
LOCK(cs_args);
std::vector<std::string> write_errors;
- if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
+ if (!common::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
SaveErrors(write_errors, errors);
return false;
}
@@ -550,11 +441,11 @@ bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backu
return true;
}
-util::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const
+common::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const
{
LOCK(cs_args);
- return util::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name),
- /*ignore_nonpersistent=*/true, /*get_chain_name=*/false);
+ return common::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name),
+ /*ignore_nonpersistent=*/true, /*get_chain_type=*/false);
}
bool ArgsManager::IsArgNegated(const std::string& strArg) const
@@ -569,11 +460,11 @@ std::string ArgsManager::GetArg(const std::string& strArg, const std::string& st
std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const
{
- const util::SettingsValue value = GetSetting(strArg);
+ const common::SettingsValue value = GetSetting(strArg);
return SettingToString(value);
}
-std::optional<std::string> SettingToString(const util::SettingsValue& value)
+std::optional<std::string> SettingToString(const common::SettingsValue& value)
{
if (value.isNull()) return std::nullopt;
if (value.isFalse()) return "0";
@@ -582,7 +473,7 @@ std::optional<std::string> SettingToString(const util::SettingsValue& value)
return value.get_str();
}
-std::string SettingToString(const util::SettingsValue& value, const std::string& strDefault)
+std::string SettingToString(const common::SettingsValue& value, const std::string& strDefault)
{
return SettingToString(value).value_or(strDefault);
}
@@ -594,11 +485,11 @@ int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) cons
std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const
{
- const util::SettingsValue value = GetSetting(strArg);
+ const common::SettingsValue value = GetSetting(strArg);
return SettingToInt(value);
}
-std::optional<int64_t> SettingToInt(const util::SettingsValue& value)
+std::optional<int64_t> SettingToInt(const common::SettingsValue& value)
{
if (value.isNull()) return std::nullopt;
if (value.isFalse()) return 0;
@@ -607,7 +498,7 @@ std::optional<int64_t> SettingToInt(const util::SettingsValue& value)
return LocaleIndependentAtoi<int64_t>(value.get_str());
}
-int64_t SettingToInt(const util::SettingsValue& value, int64_t nDefault)
+int64_t SettingToInt(const common::SettingsValue& value, int64_t nDefault)
{
return SettingToInt(value).value_or(nDefault);
}
@@ -619,18 +510,18 @@ bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const
{
- const util::SettingsValue value = GetSetting(strArg);
+ const common::SettingsValue value = GetSetting(strArg);
return SettingToBool(value);
}
-std::optional<bool> SettingToBool(const util::SettingsValue& value)
+std::optional<bool> SettingToBool(const common::SettingsValue& value)
{
if (value.isNull()) return std::nullopt;
if (value.isBool()) return value.get_bool();
return InterpretBool(value.get_str());
}
-bool SettingToBool(const util::SettingsValue& value, bool fDefault)
+bool SettingToBool(const common::SettingsValue& value, bool fDefault)
{
return SettingToBool(value).value_or(fDefault);
}
@@ -823,249 +714,79 @@ bool CheckDataDirOption(const ArgsManager& args)
return datadir.empty() || fs::is_directory(fs::absolute(datadir));
}
-fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path)
-{
- return AbsPathForConfigVal(args, configuration_file_path, /*net_specific=*/false);
-}
-
-static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
-{
- std::string str, prefix;
- std::string::size_type pos;
- int linenr = 1;
- while (std::getline(stream, str)) {
- bool used_hash = false;
- if ((pos = str.find('#')) != std::string::npos) {
- str = str.substr(0, pos);
- used_hash = true;
- }
- const static std::string pattern = " \t\r\n";
- str = TrimString(str, pattern);
- if (!str.empty()) {
- if (*str.begin() == '[' && *str.rbegin() == ']') {
- const std::string section = str.substr(1, str.size() - 2);
- sections.emplace_back(SectionInfo{section, filepath, linenr});
- prefix = section + '.';
- } else if (*str.begin() == '-') {
- error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
- return false;
- } else if ((pos = str.find('=')) != std::string::npos) {
- std::string name = prefix + TrimString(std::string_view{str}.substr(0, pos), pattern);
- std::string_view value = TrimStringView(std::string_view{str}.substr(pos + 1), pattern);
- if (used_hash && name.find("rpcpassword") != std::string::npos) {
- error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
- return false;
- }
- options.emplace_back(name, value);
- if ((pos = name.rfind('.')) != std::string::npos && prefix.length() <= pos) {
- sections.emplace_back(SectionInfo{name.substr(0, pos), filepath, linenr});
- }
- } else {
- error = strprintf("parse error on line %i: %s", linenr, str);
- if (str.size() >= 2 && str.substr(0, 2) == "no") {
- error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str);
- }
- return false;
- }
- }
- ++linenr;
- }
- return true;
-}
-
-bool IsConfSupported(KeyInfo& key, std::string& error) {
- if (key.name == "conf") {
- error = "conf cannot be set in the configuration file; use includeconf= if you want to include additional config files";
- return false;
- }
- if (key.name == "reindex") {
- // reindex can be set in a config file but it is strongly discouraged as this will cause the node to reindex on
- // every restart. Allow the config but throw a warning
- LogPrintf("Warning: reindex=1 is set in the configuration file, which will significantly slow down startup. Consider removing or commenting out this option for better performance, unless there is currently a condition which makes rebuilding the indexes necessary\n");
- return true;
- }
- return true;
-}
-
-bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys)
+fs::path ArgsManager::GetConfigFilePath() const
{
LOCK(cs_args);
- std::vector<std::pair<std::string, std::string>> options;
- if (!GetConfigOptions(stream, filepath, error, options, m_config_sections)) {
- return false;
- }
- for (const std::pair<std::string, std::string>& option : options) {
- KeyInfo key = InterpretKey(option.first);
- std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
- if (!IsConfSupported(key, error)) return false;
- if (flags) {
- std::optional<util::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
- if (!value) {
- return false;
- }
- m_settings.ro_config[key.section][key.name].push_back(*value);
- } else {
- if (ignore_invalid_keys) {
- LogPrintf("Ignoring unknown configuration value %s\n", option.first);
- } else {
- error = strprintf("Invalid configuration value %s", option.first);
- return false;
- }
- }
- }
- return true;
+ return *Assert(m_config_path);
}
-fs::path ArgsManager::GetConfigFilePath() const
+ChainType ArgsManager::GetChainType() const
{
- return GetConfigFile(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME));
+ std::variant<ChainType, std::string> arg = GetChainArg();
+ if (auto* parsed = std::get_if<ChainType>(&arg)) return *parsed;
+ throw std::runtime_error(strprintf("Unknown chain %s.", std::get<std::string>(arg)));
}
-bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
+std::string ArgsManager::GetChainTypeString() const
{
- {
- LOCK(cs_args);
- m_settings.ro_config.clear();
- m_config_sections.clear();
- }
-
- const auto conf_path{GetConfigFilePath()};
- std::ifstream stream{conf_path};
-
- // not ok to have a config file specified that cannot be opened
- if (IsArgSet("-conf") && !stream.good()) {
- error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
- return false;
- }
- // ok to not have a config file
- if (stream.good()) {
- if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) {
- return false;
- }
- // `-includeconf` cannot be included in the command line arguments except
- // as `-noincludeconf` (which indicates that no included conf file should be used).
- bool use_conf_file{true};
- {
- LOCK(cs_args);
- if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
- // ParseParameters() fails if a non-negated -includeconf is passed on the command-line
- assert(util::SettingsSpan(*includes).last_negated());
- use_conf_file = false;
- }
- }
- if (use_conf_file) {
- std::string chain_id = GetChainName();
- std::vector<std::string> conf_file_names;
-
- auto add_includes = [&](const std::string& network, size_t skip = 0) {
- size_t num_values = 0;
- LOCK(cs_args);
- if (auto* section = util::FindKey(m_settings.ro_config, network)) {
- if (auto* values = util::FindKey(*section, "includeconf")) {
- for (size_t i = std::max(skip, util::SettingsSpan(*values).negated()); i < values->size(); ++i) {
- conf_file_names.push_back((*values)[i].get_str());
- }
- num_values = values->size();
- }
- }
- return num_values;
- };
-
- // We haven't set m_network yet (that happens in SelectParams()), so manually check
- // for network.includeconf args.
- const size_t chain_includes = add_includes(chain_id);
- const size_t default_includes = add_includes({});
-
- for (const std::string& conf_file_name : conf_file_names) {
- std::ifstream conf_file_stream{GetConfigFile(*this, fs::PathFromString(conf_file_name))};
- if (conf_file_stream.good()) {
- if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
- return false;
- }
- LogPrintf("Included configuration file %s\n", conf_file_name);
- } else {
- error = "Failed to include configuration file " + conf_file_name;
- return false;
- }
- }
-
- // Warn about recursive -includeconf
- conf_file_names.clear();
- add_includes(chain_id, /* skip= */ chain_includes);
- add_includes({}, /* skip= */ default_includes);
- std::string chain_id_final = GetChainName();
- if (chain_id_final != chain_id) {
- // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
- add_includes(chain_id_final);
- }
- for (const std::string& conf_file_name : conf_file_names) {
- tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", conf_file_name);
- }
- }
- }
-
- // If datadir is changed in .conf file:
- ClearPathCache();
- if (!CheckDataDirOption(*this)) {
- error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
- return false;
- }
- return true;
+ auto arg = GetChainArg();
+ if (auto* parsed = std::get_if<ChainType>(&arg)) return ChainTypeToString(*parsed);
+ return std::get<std::string>(arg);
}
-std::string ArgsManager::GetChainName() const
+std::variant<ChainType, std::string> ArgsManager::GetChainArg() const
{
auto get_net = [&](const std::string& arg) {
LOCK(cs_args);
- util::SettingsValue value = util::GetSetting(m_settings, /* section= */ "", SettingName(arg),
+ common::SettingsValue value = common::GetSetting(m_settings, /* section= */ "", SettingName(arg),
/* ignore_default_section_config= */ false,
/*ignore_nonpersistent=*/false,
- /* get_chain_name= */ true);
+ /* get_chain_type= */ true);
return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
};
const bool fRegTest = get_net("-regtest");
const bool fSigNet = get_net("-signet");
const bool fTestNet = get_net("-testnet");
- const bool is_chain_arg_set = IsArgSet("-chain");
+ const auto chain_arg = GetArg("-chain");
- if ((int)is_chain_arg_set + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
+ if ((int)chain_arg.has_value() + (int)fRegTest + (int)fSigNet + (int)fTestNet > 1) {
throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet and -chain. Can use at most one.");
}
- if (fRegTest)
- return CBaseChainParams::REGTEST;
- if (fSigNet) {
- return CBaseChainParams::SIGNET;
+ if (chain_arg) {
+ if (auto parsed = ChainTypeFromString(*chain_arg)) return *parsed;
+ // Not a known string, so return original string
+ return *chain_arg;
}
- if (fTestNet)
- return CBaseChainParams::TESTNET;
-
- return GetArg("-chain", CBaseChainParams::MAIN);
+ if (fRegTest) return ChainType::REGTEST;
+ if (fSigNet) return ChainType::SIGNET;
+ if (fTestNet) return ChainType::TESTNET;
+ return ChainType::MAIN;
}
bool ArgsManager::UseDefaultSection(const std::string& arg) const
{
- return m_network == CBaseChainParams::MAIN || m_network_only_args.count(arg) == 0;
+ return m_network == ChainTypeToString(ChainType::MAIN) || m_network_only_args.count(arg) == 0;
}
-util::SettingsValue ArgsManager::GetSetting(const std::string& arg) const
+common::SettingsValue ArgsManager::GetSetting(const std::string& arg) const
{
LOCK(cs_args);
- return util::GetSetting(
+ return common::GetSetting(
m_settings, m_network, SettingName(arg), !UseDefaultSection(arg),
- /*ignore_nonpersistent=*/false, /*get_chain_name=*/false);
+ /*ignore_nonpersistent=*/false, /*get_chain_type=*/false);
}
-std::vector<util::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const
+std::vector<common::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const
{
LOCK(cs_args);
- return util::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg));
+ return common::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg));
}
void ArgsManager::logArgsPrefix(
const std::string& prefix,
const std::string& section,
- const std::map<std::string, std::vector<util::SettingsValue>>& args) const
+ const std::map<std::string, std::vector<common::SettingsValue>>& args) const
{
std::string section_str = section.empty() ? "" : "[" + section + "] ";
for (const auto& arg : args) {
@@ -1091,281 +812,7 @@ void ArgsManager::LogArgs() const
logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
}
-bool RenameOver(fs::path src, fs::path dest)
-{
-#ifdef __MINGW64__
- // This is a workaround for a bug in libstdc++ which
- // implements std::filesystem::rename with _wrename function.
- // This bug has been fixed in upstream:
- // - GCC 10.3: 8dd1c1085587c9f8a21bb5e588dfe1e8cdbba79e
- // - GCC 11.1: 1dfd95f0a0ca1d9e6cbc00e6cbfd1fa20a98f312
- // For more details see the commits mentioned above.
- return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
- MOVEFILE_REPLACE_EXISTING) != 0;
-#else
- std::error_code error;
- fs::rename(src, dest, error);
- return !error;
-#endif
-}
-
-/**
- * Ignores exceptions thrown by create_directories if the requested directory exists.
- * Specifically handles case where path p exists, but it wasn't possible for the user to
- * write to the parent directory.
- */
-bool TryCreateDirectories(const fs::path& p)
-{
- try
- {
- return fs::create_directories(p);
- } catch (const fs::filesystem_error&) {
- if (!fs::exists(p) || !fs::is_directory(p))
- throw;
- }
-
- // create_directories didn't create the directory, it had to have existed already
- return false;
-}
-
-bool FileCommit(FILE *file)
-{
- if (fflush(file) != 0) { // harmless if redundantly called
- LogPrintf("%s: fflush failed: %d\n", __func__, errno);
- return false;
- }
-#ifdef WIN32
- HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
- if (FlushFileBuffers(hFile) == 0) {
- LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
- return false;
- }
-#elif defined(MAC_OSX) && defined(F_FULLFSYNC)
- if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
- LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
- return false;
- }
-#elif HAVE_FDATASYNC
- if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
- LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
- return false;
- }
-#else
- if (fsync(fileno(file)) != 0 && errno != EINVAL) {
- LogPrintf("%s: fsync failed: %d\n", __func__, errno);
- return false;
- }
-#endif
- return true;
-}
-
-void DirectoryCommit(const fs::path &dirname)
-{
-#ifndef WIN32
- FILE* file = fsbridge::fopen(dirname, "r");
- if (file) {
- fsync(fileno(file));
- fclose(file);
- }
-#endif
-}
-
-bool TruncateFile(FILE *file, unsigned int length) {
-#if defined(WIN32)
- return _chsize(_fileno(file), length) == 0;
-#else
- return ftruncate(fileno(file), length) == 0;
-#endif
-}
-
-/**
- * this function tries to raise the file descriptor limit to the requested number.
- * It returns the actual file descriptor limit (which may be more or less than nMinFD)
- */
-int RaiseFileDescriptorLimit(int nMinFD) {
-#if defined(WIN32)
- return 2048;
-#else
- struct rlimit limitFD;
- if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
- if (limitFD.rlim_cur < (rlim_t)nMinFD) {
- limitFD.rlim_cur = nMinFD;
- if (limitFD.rlim_cur > limitFD.rlim_max)
- limitFD.rlim_cur = limitFD.rlim_max;
- setrlimit(RLIMIT_NOFILE, &limitFD);
- getrlimit(RLIMIT_NOFILE, &limitFD);
- }
- return limitFD.rlim_cur;
- }
- return nMinFD; // getrlimit failed, assume it's fine
-#endif
-}
-
-/**
- * this function tries to make a particular range of a file allocated (corresponding to disk space)
- * it is advisory, and the range specified in the arguments will never contain live data
- */
-void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
-#if defined(WIN32)
- // Windows-specific version
- HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
- LARGE_INTEGER nFileSize;
- int64_t nEndPos = (int64_t)offset + length;
- nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
- nFileSize.u.HighPart = nEndPos >> 32;
- SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
- SetEndOfFile(hFile);
-#elif defined(MAC_OSX)
- // OSX specific version
- // NOTE: Contrary to other OS versions, the OSX version assumes that
- // NOTE: offset is the size of the file.
- fstore_t fst;
- fst.fst_flags = F_ALLOCATECONTIG;
- fst.fst_posmode = F_PEOFPOSMODE;
- fst.fst_offset = 0;
- fst.fst_length = length; // mac os fst_length takes the # of free bytes to allocate, not desired file size
- fst.fst_bytesalloc = 0;
- if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
- fst.fst_flags = F_ALLOCATEALL;
- fcntl(fileno(file), F_PREALLOCATE, &fst);
- }
- ftruncate(fileno(file), static_cast<off_t>(offset) + length);
-#else
- #if defined(HAVE_POSIX_FALLOCATE)
- // Version using posix_fallocate
- off_t nEndPos = (off_t)offset + length;
- if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
- #endif
- // Fallback version
- // TODO: just write one byte per block
- static const char buf[65536] = {};
- if (fseek(file, offset, SEEK_SET)) {
- return;
- }
- while (length > 0) {
- unsigned int now = 65536;
- if (length < now)
- now = length;
- fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
- length -= now;
- }
-#endif
-}
-
-#ifdef WIN32
-fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
-{
- WCHAR pszPath[MAX_PATH] = L"";
-
- if(SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate))
- {
- return fs::path(pszPath);
- }
-
- LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
- return fs::path("");
-}
-#endif
-
-#ifndef WIN32
-std::string ShellEscape(const std::string& arg)
-{
- std::string escaped = arg;
- ReplaceAll(escaped, "'", "'\"'\"'");
- return "'" + escaped + "'";
-}
-#endif
-
-#if HAVE_SYSTEM
-void runCommand(const std::string& strCommand)
-{
- if (strCommand.empty()) return;
-#ifndef WIN32
- int nErr = ::system(strCommand.c_str());
-#else
- int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
-#endif
- if (nErr)
- LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
-}
-#endif
-
-
-void SetupEnvironment()
-{
-#ifdef HAVE_MALLOPT_ARENA_MAX
- // glibc-specific: On 32-bit systems set the number of arenas to 1.
- // By default, since glibc 2.10, the C library will create up to two heap
- // arenas per core. This is known to cause excessive virtual address space
- // usage in our usage. Work around it by setting the maximum number of
- // arenas to 1.
- if (sizeof(void*) == 4) {
- mallopt(M_ARENA_MAX, 1);
- }
-#endif
- // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
- // may be invalid, in which case the "C.UTF-8" locale is used as fallback.
-#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
- try {
- std::locale(""); // Raises a runtime error if current locale is invalid
- } catch (const std::runtime_error&) {
- setenv("LC_ALL", "C.UTF-8", 1);
- }
-#elif defined(WIN32)
- // Set the default input/output charset is utf-8
- SetConsoleCP(CP_UTF8);
- SetConsoleOutputCP(CP_UTF8);
-#endif
-
-#ifndef WIN32
- constexpr mode_t private_umask = 0077;
- umask(private_umask);
-#endif
-}
-
-bool SetupNetworking()
-{
-#ifdef WIN32
- // Initialize Windows Sockets
- WSADATA wsadata;
- int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
- if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
- return false;
-#endif
- return true;
-}
-
-int GetNumCores()
-{
- return std::thread::hardware_concurrency();
-}
-
-// Obtain the application startup time (used for uptime calculation)
-int64_t GetStartupTime()
-{
- return nStartupTime;
-}
-
-fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific)
-{
- if (path.is_absolute()) {
- return path;
- }
- return fsbridge::AbsPathJoin(net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
-}
-
-void ScheduleBatchPriority()
-{
-#ifdef SCHED_BATCH
- const static sched_param param{};
- const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param);
- if (rc != 0) {
- LogPrintf("Failed to pthread_setschedparam: %s\n", SysErrorString(rc));
- }
-#endif
-}
-
-namespace util {
+namespace common {
#ifdef WIN32
WinCmdLineArgs::WinCmdLineArgs()
{
@@ -1390,4 +837,4 @@ std::pair<int, char**> WinCmdLineArgs::get()
return std::make_pair(argc, argv);
}
#endif
-} // namespace util
+} // namespace common
diff --git a/src/util/system.h b/src/common/args.h
index 7292262bea..ae3ed02bc7 100644
--- a/src/util/system.h
+++ b/src/common/args.h
@@ -1,102 +1,33 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2022 The Bitcoin Core developers
+// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-/**
- * Server/client environment: argument handling, config file parsing,
- * thread wrappers, startup time
- */
-#ifndef BITCOIN_UTIL_SYSTEM_H
-#define BITCOIN_UTIL_SYSTEM_H
-
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
+#ifndef BITCOIN_COMMON_ARGS_H
+#define BITCOIN_COMMON_ARGS_H
+#include <common/settings.h>
#include <compat/compat.h>
-#include <compat/assumptions.h>
-#include <fs.h>
-#include <logging.h>
#include <sync.h>
-#include <util/settings.h>
-#include <util/time.h>
+#include <util/chaintype.h>
+#include <util/fs.h>
-#include <any>
+#include <iosfwd>
+#include <list>
#include <map>
#include <optional>
#include <set>
#include <stdint.h>
#include <string>
-#include <utility>
+#include <variant>
#include <vector>
class ArgsManager;
-class UniValue;
-
-// Application startup time (used for uptime calculation)
-int64_t GetStartupTime();
extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_SETTINGS_FILENAME;
-void SetupEnvironment();
-bool SetupNetworking();
-
-/**
- * Ensure file contents are fully committed to disk, using a platform-specific
- * feature analogous to fsync().
- */
-bool FileCommit(FILE *file);
-
-/**
- * Sync directory contents. This is required on some environments to ensure that
- * newly created files are committed to disk.
- */
-void DirectoryCommit(const fs::path &dirname);
-
-bool TruncateFile(FILE *file, unsigned int length);
-int RaiseFileDescriptorLimit(int nMinFD);
-void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
-
-/**
- * Rename src to dest.
- * @return true if the rename was successful.
- */
-[[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
-
-bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only=false);
-void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name);
-bool DirIsWritable(const fs::path& directory);
-bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
-
-/** Get the size of a file by scanning it.
- *
- * @param[in] path The file path
- * @param[in] max Stop seeking beyond this limit
- * @return The file size or max
- */
-std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max());
-
-/** Release all directory locks. This is used for unit testing only, at runtime
- * the global destructor will take care of the locks.
- */
-void ReleaseDirectoryLocks();
-
-bool TryCreateDirectories(const fs::path& p);
-fs::path GetDefaultDataDir();
// Return true if -datadir option points to a valid directory or is not specified.
bool CheckDataDirOption(const ArgsManager& args);
-fs::path GetConfigFile(const ArgsManager& args, const fs::path& configuration_file_path);
-#ifdef WIN32
-fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
-#endif
-#ifndef WIN32
-std::string ShellEscape(const std::string& arg);
-#endif
-#if HAVE_SYSTEM
-void runCommand(const std::string& strCommand);
-#endif
/**
* Most paths passed as configuration arguments are treated as relative to
@@ -136,21 +67,31 @@ enum class OptionsCategory {
HIDDEN // Always the last option to avoid printing these in the help
};
-struct SectionInfo
-{
+struct KeyInfo {
+ std::string name;
+ std::string section;
+ bool negated{false};
+};
+
+KeyInfo InterpretKey(std::string key);
+
+std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
+ unsigned int flags, std::string& error);
+
+struct SectionInfo {
std::string m_name;
std::string m_file;
int m_line;
};
-std::string SettingToString(const util::SettingsValue&, const std::string&);
-std::optional<std::string> SettingToString(const util::SettingsValue&);
+std::string SettingToString(const common::SettingsValue&, const std::string&);
+std::optional<std::string> SettingToString(const common::SettingsValue&);
-int64_t SettingToInt(const util::SettingsValue&, int64_t);
-std::optional<int64_t> SettingToInt(const util::SettingsValue&);
+int64_t SettingToInt(const common::SettingsValue&, int64_t);
+std::optional<int64_t> SettingToInt(const common::SettingsValue&);
-bool SettingToBool(const util::SettingsValue&, bool);
-std::optional<bool> SettingToBool(const util::SettingsValue&);
+bool SettingToBool(const common::SettingsValue&, bool);
+std::optional<bool> SettingToBool(const common::SettingsValue&);
class ArgsManager
{
@@ -189,13 +130,14 @@ protected:
};
mutable RecursiveMutex cs_args;
- util::Settings m_settings GUARDED_BY(cs_args);
+ common::Settings m_settings GUARDED_BY(cs_args);
std::vector<std::string> m_command GUARDED_BY(cs_args);
std::string m_network GUARDED_BY(cs_args);
std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
bool m_accept_any_command GUARDED_BY(cs_args){true};
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
+ std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
@@ -217,12 +159,12 @@ protected:
* false if "-nosetting" argument was passed, and a string if a "-setting=value"
* argument was passed.
*/
- util::SettingsValue GetSetting(const std::string& arg) const;
+ common::SettingsValue GetSetting(const std::string& arg) const;
/**
* Get list of setting values.
*/
- std::vector<util::SettingsValue> GetSettingsList(const std::string& arg) const;
+ std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const;
ArgsManager();
~ArgsManager();
@@ -383,10 +325,18 @@ protected:
void ForceSetArg(const std::string& strArg, const std::string& strValue);
/**
- * Returns the appropriate chain name from the program arguments.
- * @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
+ * Returns the appropriate chain type from the program arguments.
+ * @return ChainType::MAIN by default; raises runtime error if an invalid
+ * combination, or unknown chain is given.
+ */
+ ChainType GetChainType() const;
+
+ /**
+ * Returns the appropriate chain type string from the program arguments.
+ * @return ChainType::MAIN string by default; raises runtime error if an
+ * invalid combination is given.
*/
- std::string GetChainName() const;
+ std::string GetChainTypeString() const;
/**
* Add argument
@@ -444,7 +394,7 @@ protected:
* Get current setting from config file or read/write settings file,
* ignoring nonpersistent command line or forced settings values.
*/
- util::SettingsValue GetPersistentSetting(const std::string& name) const;
+ common::SettingsValue GetPersistentSetting(const std::string& name) const;
/**
* Access settings with lock held.
@@ -471,11 +421,19 @@ private:
*/
const fs::path& GetDataDir(bool net_specific) const;
+ /**
+ * Return -regtest/-signet/-testnet/-chain= setting as a ChainType enum if a
+ * recognized chain type was set, or as a string if an unrecognized chain
+ * name was set. Raise an exception if an invalid combination of flags was
+ * provided.
+ */
+ std::variant<ChainType, std::string> GetChainArg() const;
+
// Helper function for LogArgs().
void logArgsPrefix(
const std::string& prefix,
const std::string& section,
- const std::map<std::string, std::vector<util::SettingsValue>>& args) const;
+ const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
};
extern ArgsManager gArgs;
@@ -505,43 +463,7 @@ std::string HelpMessageGroup(const std::string& message);
*/
std::string HelpMessageOpt(const std::string& option, const std::string& message);
-/**
- * Return the number of cores available on the current system.
- * @note This does count virtual cores, such as those provided by HyperThreading.
- */
-int GetNumCores();
-
-/**
- * On platforms that support it, tell the kernel the calling thread is
- * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
- *
- */
-void ScheduleBatchPriority();
-
-namespace util {
-
-//! Simplification of std insertion
-template <typename Tdst, typename Tsrc>
-inline void insert(Tdst& dst, const Tsrc& src) {
- dst.insert(dst.begin(), src.begin(), src.end());
-}
-template <typename TsetT, typename Tsrc>
-inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
- dst.insert(src.begin(), src.end());
-}
-
-/**
- * Helper function to access the contained object of a std::any instance.
- * Returns a pointer to the object if passed instance has a value and the type
- * matches, nullptr otherwise.
- */
-template<typename T>
-T* AnyPtr(const std::any& any) noexcept
-{
- T* const* ptr = std::any_cast<T*>(&any);
- return ptr ? *ptr : nullptr;
-}
-
+namespace common {
#ifdef WIN32
class WinCmdLineArgs
{
@@ -556,7 +478,6 @@ private:
std::vector<std::string> args;
};
#endif
+} // namespace common
-} // namespace util
-
-#endif // BITCOIN_UTIL_SYSTEM_H
+#endif // BITCOIN_COMMON_ARGS_H
diff --git a/src/common/config.cpp b/src/common/config.cpp
new file mode 100644
index 0000000000..1c85273f69
--- /dev/null
+++ b/src/common/config.cpp
@@ -0,0 +1,217 @@
+// Copyright (c) 2023 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 <common/args.h>
+
+#include <common/settings.h>
+#include <logging.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <univalue.h>
+#include <util/chaintype.h>
+#include <util/fs.h>
+#include <util/string.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
+{
+ std::string str, prefix;
+ std::string::size_type pos;
+ int linenr = 1;
+ while (std::getline(stream, str)) {
+ bool used_hash = false;
+ if ((pos = str.find('#')) != std::string::npos) {
+ str = str.substr(0, pos);
+ used_hash = true;
+ }
+ const static std::string pattern = " \t\r\n";
+ str = TrimString(str, pattern);
+ if (!str.empty()) {
+ if (*str.begin() == '[' && *str.rbegin() == ']') {
+ const std::string section = str.substr(1, str.size() - 2);
+ sections.emplace_back(SectionInfo{section, filepath, linenr});
+ prefix = section + '.';
+ } else if (*str.begin() == '-') {
+ error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
+ return false;
+ } else if ((pos = str.find('=')) != std::string::npos) {
+ std::string name = prefix + TrimString(std::string_view{str}.substr(0, pos), pattern);
+ std::string_view value = TrimStringView(std::string_view{str}.substr(pos + 1), pattern);
+ if (used_hash && name.find("rpcpassword") != std::string::npos) {
+ error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
+ return false;
+ }
+ options.emplace_back(name, value);
+ if ((pos = name.rfind('.')) != std::string::npos && prefix.length() <= pos) {
+ sections.emplace_back(SectionInfo{name.substr(0, pos), filepath, linenr});
+ }
+ } else {
+ error = strprintf("parse error on line %i: %s", linenr, str);
+ if (str.size() >= 2 && str.substr(0, 2) == "no") {
+ error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str);
+ }
+ return false;
+ }
+ }
+ ++linenr;
+ }
+ return true;
+}
+
+bool IsConfSupported(KeyInfo& key, std::string& error) {
+ if (key.name == "conf") {
+ error = "conf cannot be set in the configuration file; use includeconf= if you want to include additional config files";
+ return false;
+ }
+ if (key.name == "reindex") {
+ // reindex can be set in a config file but it is strongly discouraged as this will cause the node to reindex on
+ // every restart. Allow the config but throw a warning
+ LogPrintf("Warning: reindex=1 is set in the configuration file, which will significantly slow down startup. Consider removing or commenting out this option for better performance, unless there is currently a condition which makes rebuilding the indexes necessary\n");
+ return true;
+ }
+ return true;
+}
+
+bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys)
+{
+ LOCK(cs_args);
+ std::vector<std::pair<std::string, std::string>> options;
+ if (!GetConfigOptions(stream, filepath, error, options, m_config_sections)) {
+ return false;
+ }
+ for (const std::pair<std::string, std::string>& option : options) {
+ KeyInfo key = InterpretKey(option.first);
+ std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
+ if (!IsConfSupported(key, error)) return false;
+ if (flags) {
+ std::optional<common::SettingsValue> value = InterpretValue(key, &option.second, *flags, error);
+ if (!value) {
+ return false;
+ }
+ m_settings.ro_config[key.section][key.name].push_back(*value);
+ } else {
+ if (ignore_invalid_keys) {
+ LogPrintf("Ignoring unknown configuration value %s\n", option.first);
+ } else {
+ error = strprintf("Invalid configuration value %s", option.first);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
+{
+ {
+ LOCK(cs_args);
+ m_settings.ro_config.clear();
+ m_config_sections.clear();
+ m_config_path = AbsPathForConfigVal(*this, GetPathArg("-conf", BITCOIN_CONF_FILENAME), /*net_specific=*/false);
+ }
+
+ const auto conf_path{GetConfigFilePath()};
+ std::ifstream stream{conf_path};
+
+ // not ok to have a config file specified that cannot be opened
+ if (IsArgSet("-conf") && !stream.good()) {
+ error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
+ return false;
+ }
+ // ok to not have a config file
+ if (stream.good()) {
+ if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) {
+ return false;
+ }
+ // `-includeconf` cannot be included in the command line arguments except
+ // as `-noincludeconf` (which indicates that no included conf file should be used).
+ bool use_conf_file{true};
+ {
+ LOCK(cs_args);
+ if (auto* includes = common::FindKey(m_settings.command_line_options, "includeconf")) {
+ // ParseParameters() fails if a non-negated -includeconf is passed on the command-line
+ assert(common::SettingsSpan(*includes).last_negated());
+ use_conf_file = false;
+ }
+ }
+ if (use_conf_file) {
+ std::string chain_id = GetChainTypeString();
+ std::vector<std::string> conf_file_names;
+
+ auto add_includes = [&](const std::string& network, size_t skip = 0) {
+ size_t num_values = 0;
+ LOCK(cs_args);
+ if (auto* section = common::FindKey(m_settings.ro_config, network)) {
+ if (auto* values = common::FindKey(*section, "includeconf")) {
+ for (size_t i = std::max(skip, common::SettingsSpan(*values).negated()); i < values->size(); ++i) {
+ conf_file_names.push_back((*values)[i].get_str());
+ }
+ num_values = values->size();
+ }
+ }
+ return num_values;
+ };
+
+ // We haven't set m_network yet (that happens in SelectParams()), so manually check
+ // for network.includeconf args.
+ const size_t chain_includes = add_includes(chain_id);
+ const size_t default_includes = add_includes({});
+
+ for (const std::string& conf_file_name : conf_file_names) {
+ std::ifstream conf_file_stream{AbsPathForConfigVal(*this, fs::PathFromString(conf_file_name), /*net_specific=*/false)};
+ if (conf_file_stream.good()) {
+ if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
+ return false;
+ }
+ LogPrintf("Included configuration file %s\n", conf_file_name);
+ } else {
+ error = "Failed to include configuration file " + conf_file_name;
+ return false;
+ }
+ }
+
+ // Warn about recursive -includeconf
+ conf_file_names.clear();
+ add_includes(chain_id, /* skip= */ chain_includes);
+ add_includes({}, /* skip= */ default_includes);
+ std::string chain_id_final = GetChainTypeString();
+ if (chain_id_final != chain_id) {
+ // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
+ add_includes(chain_id_final);
+ }
+ for (const std::string& conf_file_name : conf_file_names) {
+ tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", conf_file_name);
+ }
+ }
+ }
+
+ // If datadir is changed in .conf file:
+ ClearPathCache();
+ if (!CheckDataDirOption(*this)) {
+ error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", ""));
+ return false;
+ }
+ return true;
+}
+
+fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific)
+{
+ if (path.is_absolute()) {
+ return path;
+ }
+ return fsbridge::AbsPathJoin(net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
+}
diff --git a/src/common/init.cpp b/src/common/init.cpp
index 159eb7e2ef..412d73aec7 100644
--- a/src/common/init.cpp
+++ b/src/common/init.cpp
@@ -2,11 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <common/init.h>
#include <chainparams.h>
-#include <fs.h>
+#include <common/args.h>
+#include <common/init.h>
+#include <logging.h>
#include <tinyformat.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <util/translation.h>
#include <algorithm>
@@ -20,13 +21,26 @@ std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn setting
if (!CheckDataDirOption(args)) {
return ConfigError{ConfigStatus::FAILED, strprintf(_("Specified data directory \"%s\" does not exist."), args.GetArg("-datadir", ""))};
}
+
+ // Record original datadir and config paths before parsing the config
+ // file. It is possible for the config file to contain a datadir= line
+ // that changes the datadir path after it is parsed. This is useful for
+ // CLI tools to let them use a different data storage location without
+ // needing to pass it every time on the command line. (It is not
+ // possible for the config file to cause another configuration to be
+ // used, though. Specifying a conf= option in the config file causes a
+ // parse error, and specifying a datadir= location containing another
+ // bitcoin.conf file just ignores the other file.)
+ const fs::path orig_datadir_path{args.GetDataDirBase()};
+ const fs::path orig_config_path{AbsPathForConfigVal(args, args.GetPathArg("-conf", BITCOIN_CONF_FILENAME), /*net_specific=*/false)};
+
std::string error;
if (!args.ReadConfigFiles(error, true)) {
return ConfigError{ConfigStatus::FAILED, strprintf(_("Error reading configuration file: %s"), error)};
}
// Check for chain settings (Params() calls are only valid after this clause)
- SelectParams(args.GetChainName());
+ SelectParams(args.GetChainType());
// Create datadir if it does not exist.
const auto base_path{args.GetDataDirBase()};
@@ -48,6 +62,32 @@ std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn setting
fs::create_directories(net_path / "wallets");
}
+ // Show an error or warning if there is a bitcoin.conf file in the
+ // datadir that is being ignored.
+ const fs::path base_config_path = base_path / BITCOIN_CONF_FILENAME;
+ if (fs::exists(base_config_path) && !fs::equivalent(orig_config_path, base_config_path)) {
+ const std::string cli_config_path = args.GetArg("-conf", "");
+ const std::string config_source = cli_config_path.empty()
+ ? strprintf("data directory %s", fs::quoted(fs::PathToString(orig_datadir_path)))
+ : strprintf("command line argument %s", fs::quoted("-conf=" + cli_config_path));
+ const std::string error = strprintf(
+ "Data directory %1$s contains a %2$s file which is ignored, because a different configuration file "
+ "%3$s from %4$s is being used instead. Possible ways to address this would be to:\n"
+ "- Delete or rename the %2$s file in data directory %1$s.\n"
+ "- Change datadir= or conf= options to specify one configuration file, not two, and use "
+ "includeconf= to include any other configuration files.\n"
+ "- Set allowignoredconf=1 option to treat this condition as a warning, not an error.",
+ fs::quoted(fs::PathToString(base_path)),
+ fs::quoted(BITCOIN_CONF_FILENAME),
+ fs::quoted(fs::PathToString(orig_config_path)),
+ config_source);
+ if (args.GetBoolArg("-allowignoredconf", false)) {
+ LogPrintf("Warning: %s\n", error);
+ } else {
+ return ConfigError{ConfigStatus::FAILED, Untranslated(error)};
+ }
+ }
+
// Create settings.json if -nosettings was not specified.
if (args.GetSettingsPath()) {
std::vector<std::string> details;
diff --git a/src/util/settings.cpp b/src/common/settings.cpp
index a2e30098dc..5761e8b321 100644
--- a/src/util/settings.cpp
+++ b/src/common/settings.cpp
@@ -2,18 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <fs.h>
-#include <util/settings.h>
+#include <common/settings.h>
#include <tinyformat.h>
#include <univalue.h>
+#include <util/fs.h>
+#include <algorithm>
#include <fstream>
+#include <iterator>
#include <map>
#include <string>
+#include <utility>
#include <vector>
-namespace util {
+namespace common {
namespace {
enum class Source {
@@ -112,7 +115,7 @@ bool WriteSettings(const fs::path& path,
{
SettingsValue out(SettingsValue::VOBJ);
for (const auto& value : values) {
- out.__pushKV(value.first, value.second);
+ out.pushKVEnd(value.first, value.second);
}
std::ofstream file;
file.open(path);
@@ -130,7 +133,7 @@ SettingsValue GetSetting(const Settings& settings,
const std::string& name,
bool ignore_default_section_config,
bool ignore_nonpersistent,
- bool get_chain_name)
+ bool get_chain_type)
{
SettingsValue result;
bool done = false; // Done merging any more settings sources.
@@ -145,17 +148,17 @@ SettingsValue GetSetting(const Settings& settings,
// assigned value instead of last. In general, later settings take
// precedence over early settings, but for backwards compatibility in
// the config file the precedence is reversed for all settings except
- // chain name settings.
+ // chain type settings.
const bool reverse_precedence =
(source == Source::CONFIG_FILE_NETWORK_SECTION || source == Source::CONFIG_FILE_DEFAULT_SECTION) &&
- !get_chain_name;
+ !get_chain_type;
// Weird behavior preserved for backwards compatibility: Negated
// -regtest and -testnet arguments which you would expect to override
// values set in the configuration file are currently accepted but
// silently ignored. It would be better to apply these just like other
// negated values, or at least warn they are ignored.
- const bool skip_negated_command_line = get_chain_name;
+ const bool skip_negated_command_line = get_chain_type;
if (done) return;
@@ -255,4 +258,4 @@ size_t SettingsSpan::negated() const
return 0;
}
-} // namespace util
+} // namespace common
diff --git a/src/util/settings.h b/src/common/settings.h
index b0d8acb711..0e9d376e23 100644
--- a/src/util/settings.h
+++ b/src/common/settings.h
@@ -2,18 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_UTIL_SETTINGS_H
-#define BITCOIN_UTIL_SETTINGS_H
+#ifndef BITCOIN_COMMON_SETTINGS_H
+#define BITCOIN_COMMON_SETTINGS_H
-#include <fs.h>
+#include <util/fs.h>
+#include <cstddef>
#include <map>
#include <string>
#include <vector>
class UniValue;
-namespace util {
+namespace common {
//! Settings value type (string/integer/boolean/null variant).
//!
@@ -60,14 +61,14 @@ bool WriteSettings(const fs::path& path,
//! command line). Only return settings in the
//! read-only config and read-write settings
//! files.
-//! @param get_chain_name - enable special backwards compatible behavior
-//! for GetChainName
+//! @param get_chain_type - enable special backwards compatible behavior
+//! for GetChainType
SettingsValue GetSetting(const Settings& settings,
const std::string& section,
const std::string& name,
bool ignore_default_section_config,
bool ignore_nonpersistent,
- bool get_chain_name);
+ bool get_chain_type);
//! Get combined setting value similar to GetSetting(), except if setting was
//! specified multiple times, return a list of all the values specified.
@@ -109,6 +110,6 @@ auto FindKey(Map&& map, Key&& key) -> decltype(&map.at(key))
return it == map.end() ? nullptr : &it->second;
}
-} // namespace util
+} // namespace common
-#endif // BITCOIN_UTIL_SETTINGS_H
+#endif // BITCOIN_COMMON_SETTINGS_H
diff --git a/src/common/system.cpp b/src/common/system.cpp
new file mode 100644
index 0000000000..1d1c5fa56a
--- /dev/null
+++ b/src/common/system.cpp
@@ -0,0 +1,107 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2022 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 <common/system.h>
+
+#include <logging.h>
+#include <util/string.h>
+#include <util/time.h>
+
+#ifndef WIN32
+#include <sys/stat.h>
+#else
+#include <codecvt>
+#endif
+
+#ifdef HAVE_MALLOPT_ARENA_MAX
+#include <malloc.h>
+#endif
+
+#include <cstdlib>
+#include <locale>
+#include <stdexcept>
+#include <string>
+#include <thread>
+
+// Application startup time (used for uptime calculation)
+const int64_t nStartupTime = GetTime();
+
+#ifndef WIN32
+std::string ShellEscape(const std::string& arg)
+{
+ std::string escaped = arg;
+ ReplaceAll(escaped, "'", "'\"'\"'");
+ return "'" + escaped + "'";
+}
+#endif
+
+#if HAVE_SYSTEM
+void runCommand(const std::string& strCommand)
+{
+ if (strCommand.empty()) return;
+#ifndef WIN32
+ int nErr = ::system(strCommand.c_str());
+#else
+ int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
+#endif
+ if (nErr)
+ LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
+}
+#endif
+
+void SetupEnvironment()
+{
+#ifdef HAVE_MALLOPT_ARENA_MAX
+ // glibc-specific: On 32-bit systems set the number of arenas to 1.
+ // By default, since glibc 2.10, the C library will create up to two heap
+ // arenas per core. This is known to cause excessive virtual address space
+ // usage in our usage. Work around it by setting the maximum number of
+ // arenas to 1.
+ if (sizeof(void*) == 4) {
+ mallopt(M_ARENA_MAX, 1);
+ }
+#endif
+ // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
+ // may be invalid, in which case the "C.UTF-8" locale is used as fallback.
+#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+ try {
+ std::locale(""); // Raises a runtime error if current locale is invalid
+ } catch (const std::runtime_error&) {
+ setenv("LC_ALL", "C.UTF-8", 1);
+ }
+#elif defined(WIN32)
+ // Set the default input/output charset is utf-8
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
+#endif
+
+#ifndef WIN32
+ constexpr mode_t private_umask = 0077;
+ umask(private_umask);
+#endif
+}
+
+bool SetupNetworking()
+{
+#ifdef WIN32
+ // Initialize Windows Sockets
+ WSADATA wsadata;
+ int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
+ if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
+ return false;
+#endif
+ return true;
+}
+
+int GetNumCores()
+{
+ return std::thread::hardware_concurrency();
+}
+
+// Obtain the application startup time (used for uptime calculation)
+int64_t GetStartupTime()
+{
+ return nStartupTime;
+}
diff --git a/src/common/system.h b/src/common/system.h
new file mode 100644
index 0000000000..40206aaa01
--- /dev/null
+++ b/src/common/system.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2022 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_COMMON_SYSTEM_H
+#define BITCOIN_COMMON_SYSTEM_H
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <compat/assumptions.h>
+#include <compat/compat.h>
+
+#include <set>
+#include <stdint.h>
+#include <string>
+
+// Application startup time (used for uptime calculation)
+int64_t GetStartupTime();
+
+void SetupEnvironment();
+bool SetupNetworking();
+#ifndef WIN32
+std::string ShellEscape(const std::string& arg);
+#endif
+#if HAVE_SYSTEM
+void runCommand(const std::string& strCommand);
+#endif
+
+/**
+ * Return the number of cores available on the current system.
+ * @note This does count virtual cores, such as those provided by HyperThreading.
+ */
+int GetNumCores();
+
+#endif // BITCOIN_COMMON_SYSTEM_H
diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h
index 92615b582a..4488db0886 100644
--- a/src/compat/assumptions.h
+++ b/src/compat/assumptions.h
@@ -8,6 +8,7 @@
#ifndef BITCOIN_COMPAT_ASSUMPTIONS_H
#define BITCOIN_COMPAT_ASSUMPTIONS_H
+#include <cstddef>
#include <limits>
// Assumption: We assume that the macro NDEBUG is not defined.
diff --git a/src/compat/compat.h b/src/compat/compat.h
index 88f58120b8..8195bceaec 100644
--- a/src/compat/compat.h
+++ b/src/compat/compat.h
@@ -62,15 +62,6 @@ typedef unsigned int SOCKET;
#endif
#endif
-// Windows doesn't define S_IRUSR or S_IWUSR. We define both
-// here, with the same values as glibc (see stat.h).
-#ifdef WIN32
-#ifndef S_IRUSR
-#define S_IRUSR 0400
-#define S_IWUSR 0200
-#endif
-#endif
-
// Windows defines MAX_PATH as it's maximum path length.
// We define MAX_PATH for use on non-Windows systems.
#ifndef WIN32
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index ad8ee676b2..d5bf08cd61 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -145,7 +145,7 @@ class BlockValidationState : public ValidationState<BlockValidationResult> {};
// using only serialization with and without witness data. As witness_size
// is equal to total_size - stripped_size, this formula is identical to:
// weight = (stripped_size * 3) + total_size.
-static inline int64_t GetTransactionWeight(const CTransaction& tx)
+static inline int32_t GetTransactionWeight(const CTransaction& tx)
{
return ::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * (WITNESS_SCALE_FACTOR - 1) + ::GetSerializeSize(tx, PROTOCOL_VERSION);
}
diff --git a/src/core_write.cpp b/src/core_write.cpp
index b0e3b0b3c4..54ca306f60 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -4,6 +4,7 @@
#include <core_io.h>
+#include <common/system.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
@@ -17,7 +18,6 @@
#include <univalue.h>
#include <util/check.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <map>
#include <string>
diff --git a/src/crypto/sha256_avx2.cpp b/src/crypto/sha256_avx2.cpp
index 624bdb42e4..df8cb7a6c9 100644
--- a/src/crypto/sha256_avx2.cpp
+++ b/src/crypto/sha256_avx2.cpp
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <immintrin.h>
+#include <attributes.h>
#include <crypto/common.h>
namespace sha256d64_avx2 {
@@ -36,7 +37,7 @@ __m256i inline sigma0(__m256i x) { return Xor(Or(ShR(x, 7), ShL(x, 25)), Or(ShR(
__m256i inline sigma1(__m256i x) { return Xor(Or(ShR(x, 17), ShL(x, 15)), Or(ShR(x, 19), ShL(x, 13)), ShR(x, 10)); }
/** One round of SHA-256. */
-void inline __attribute__((always_inline)) Round(__m256i a, __m256i b, __m256i c, __m256i& d, __m256i e, __m256i f, __m256i g, __m256i& h, __m256i k)
+void ALWAYS_INLINE Round(__m256i a, __m256i b, __m256i c, __m256i& d, __m256i e, __m256i f, __m256i g, __m256i& h, __m256i k)
{
__m256i t1 = Add(h, Sigma1(e), Ch(e, f, g), k);
__m256i t2 = Add(Sigma0(a), Maj(a, b, c));
diff --git a/src/crypto/sha256_sse41.cpp b/src/crypto/sha256_sse41.cpp
index 4eaf7d7b18..d041fdfefc 100644
--- a/src/crypto/sha256_sse41.cpp
+++ b/src/crypto/sha256_sse41.cpp
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <immintrin.h>
+#include <attributes.h>
#include <crypto/common.h>
namespace sha256d64_sse41 {
@@ -36,7 +37,7 @@ __m128i inline sigma0(__m128i x) { return Xor(Or(ShR(x, 7), ShL(x, 25)), Or(ShR(
__m128i inline sigma1(__m128i x) { return Xor(Or(ShR(x, 17), ShL(x, 15)), Or(ShR(x, 19), ShL(x, 13)), ShR(x, 10)); }
/** One round of SHA-256. */
-void inline __attribute__((always_inline)) Round(__m128i a, __m128i b, __m128i c, __m128i& d, __m128i e, __m128i f, __m128i g, __m128i& h, __m128i k)
+void ALWAYS_INLINE Round(__m128i a, __m128i b, __m128i c, __m128i& d, __m128i e, __m128i f, __m128i g, __m128i& h, __m128i k)
{
__m128i t1 = Add(h, Sigma1(e), Ch(e, f, g), k);
__m128i t2 = Add(Sigma0(a), Maj(a, b, c));
diff --git a/src/crypto/sha256_x86_shani.cpp b/src/crypto/sha256_x86_shani.cpp
index e3143a55c2..79871bfcc1 100644
--- a/src/crypto/sha256_x86_shani.cpp
+++ b/src/crypto/sha256_x86_shani.cpp
@@ -11,43 +11,45 @@
#include <stdint.h>
#include <immintrin.h>
+#include <attributes.h>
+
namespace {
alignas(__m128i) const uint8_t MASK[16] = {0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c};
alignas(__m128i) const uint8_t INIT0[16] = {0x8c, 0x68, 0x05, 0x9b, 0x7f, 0x52, 0x0e, 0x51, 0x85, 0xae, 0x67, 0xbb, 0x67, 0xe6, 0x09, 0x6a};
alignas(__m128i) const uint8_t INIT1[16] = {0x19, 0xcd, 0xe0, 0x5b, 0xab, 0xd9, 0x83, 0x1f, 0x3a, 0xf5, 0x4f, 0xa5, 0x72, 0xf3, 0x6e, 0x3c};
-void inline __attribute__((always_inline)) QuadRound(__m128i& state0, __m128i& state1, uint64_t k1, uint64_t k0)
+void ALWAYS_INLINE QuadRound(__m128i& state0, __m128i& state1, uint64_t k1, uint64_t k0)
{
const __m128i msg = _mm_set_epi64x(k1, k0);
state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
state0 = _mm_sha256rnds2_epu32(state0, state1, _mm_shuffle_epi32(msg, 0x0e));
}
-void inline __attribute__((always_inline)) QuadRound(__m128i& state0, __m128i& state1, __m128i m, uint64_t k1, uint64_t k0)
+void ALWAYS_INLINE QuadRound(__m128i& state0, __m128i& state1, __m128i m, uint64_t k1, uint64_t k0)
{
const __m128i msg = _mm_add_epi32(m, _mm_set_epi64x(k1, k0));
state1 = _mm_sha256rnds2_epu32(state1, state0, msg);
state0 = _mm_sha256rnds2_epu32(state0, state1, _mm_shuffle_epi32(msg, 0x0e));
}
-void inline __attribute__((always_inline)) ShiftMessageA(__m128i& m0, __m128i m1)
+void ALWAYS_INLINE ShiftMessageA(__m128i& m0, __m128i m1)
{
m0 = _mm_sha256msg1_epu32(m0, m1);
}
-void inline __attribute__((always_inline)) ShiftMessageC(__m128i& m0, __m128i m1, __m128i& m2)
+void ALWAYS_INLINE ShiftMessageC(__m128i& m0, __m128i m1, __m128i& m2)
{
m2 = _mm_sha256msg2_epu32(_mm_add_epi32(m2, _mm_alignr_epi8(m1, m0, 4)), m1);
}
-void inline __attribute__((always_inline)) ShiftMessageB(__m128i& m0, __m128i m1, __m128i& m2)
+void ALWAYS_INLINE ShiftMessageB(__m128i& m0, __m128i m1, __m128i& m2)
{
ShiftMessageC(m0, m1, m2);
ShiftMessageA(m0, m1);
}
-void inline __attribute__((always_inline)) Shuffle(__m128i& s0, __m128i& s1)
+void ALWAYS_INLINE Shuffle(__m128i& s0, __m128i& s1)
{
const __m128i t1 = _mm_shuffle_epi32(s0, 0xB1);
const __m128i t2 = _mm_shuffle_epi32(s1, 0x1B);
@@ -55,7 +57,7 @@ void inline __attribute__((always_inline)) Shuffle(__m128i& s0, __m128i& s1)
s1 = _mm_blend_epi16(t2, t1, 0xF0);
}
-void inline __attribute__((always_inline)) Unshuffle(__m128i& s0, __m128i& s1)
+void ALWAYS_INLINE Unshuffle(__m128i& s0, __m128i& s1)
{
const __m128i t1 = _mm_shuffle_epi32(s0, 0x1B);
const __m128i t2 = _mm_shuffle_epi32(s1, 0xB1);
@@ -63,12 +65,12 @@ void inline __attribute__((always_inline)) Unshuffle(__m128i& s0, __m128i& s1)
s1 = _mm_alignr_epi8(t2, t1, 0x08);
}
-__m128i inline __attribute__((always_inline)) Load(const unsigned char* in)
+__m128i ALWAYS_INLINE Load(const unsigned char* in)
{
return _mm_shuffle_epi8(_mm_loadu_si128((const __m128i*)in), _mm_load_si128((const __m128i*)MASK));
}
-void inline __attribute__((always_inline)) Save(unsigned char* out, __m128i s)
+void ALWAYS_INLINE Save(unsigned char* out, __m128i s)
{
_mm_storeu_si128((__m128i*)out, _mm_shuffle_epi8(s, _mm_load_si128((const __m128i*)MASK)));
}
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 0c6debfa80..2aade14ef4 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -4,12 +4,12 @@
#include <dbwrapper.h>
-#include <fs.h>
#include <logging.h>
#include <random.h>
#include <tinyformat.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <algorithm>
#include <cassert>
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index 578d9880ac..35782edca6 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -6,11 +6,11 @@
#define BITCOIN_DBWRAPPER_H
#include <clientversion.h>
-#include <fs.h>
#include <logging.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
+#include <util/fs.h>
#include <cstddef>
#include <cstdint>
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index 028c6ebae1..9160ec19e6 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -2,7 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/system.h>
+#include <common/args.h>
+#include <logging.h>
#include <walletinitinterface.h>
class ArgsManager;
diff --git a/src/external_signer.cpp b/src/external_signer.cpp
index 5524b943f4..6b1e1f0241 100644
--- a/src/external_signer.cpp
+++ b/src/external_signer.cpp
@@ -30,7 +30,7 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS
}
for (const UniValue& signer : result.getValues()) {
// Check for error
- const UniValue& error = find_value(signer, "error");
+ const UniValue& error = signer.find_value("error");
if (!error.isNull()) {
if (!error.isStr()) {
throw std::runtime_error(strprintf("'%s' error", command));
@@ -38,11 +38,11 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS
throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr()));
}
// Check if fingerprint is present
- const UniValue& fingerprint = find_value(signer, "fingerprint");
+ const UniValue& fingerprint = signer.find_value("fingerprint");
if (fingerprint.isNull()) {
throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command));
}
- const std::string fingerprintStr = fingerprint.get_str();
+ const std::string& fingerprintStr{fingerprint.get_str()};
// Skip duplicate signer
bool duplicate = false;
for (const ExternalSigner& signer : signers) {
@@ -50,7 +50,7 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS
}
if (duplicate) break;
std::string name;
- const UniValue& model_field = find_value(signer, "model");
+ const UniValue& model_field = signer.find_value("model");
if (model_field.isStr() && model_field.getValStr() != "") {
name += model_field.getValStr();
}
@@ -97,19 +97,19 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str
const UniValue signer_result = RunCommandParseJSON(command, stdinStr);
- if (find_value(signer_result, "error").isStr()) {
- error = find_value(signer_result, "error").get_str();
+ if (signer_result.find_value("error").isStr()) {
+ error = signer_result.find_value("error").get_str();
return false;
}
- if (!find_value(signer_result, "psbt").isStr()) {
+ if (!signer_result.find_value("psbt").isStr()) {
error = "Unexpected result from signer";
return false;
}
PartiallySignedTransaction signer_psbtx;
std::string signer_psbt_error;
- if (!DecodeBase64PSBT(signer_psbtx, find_value(signer_result, "psbt").get_str(), signer_psbt_error)) {
+ if (!DecodeBase64PSBT(signer_psbtx, signer_result.find_value("psbt").get_str(), signer_psbt_error)) {
error = strprintf("TX decode failed %s", signer_psbt_error);
return false;
}
diff --git a/src/external_signer.h b/src/external_signer.h
index 90f07478e3..81a601811a 100644
--- a/src/external_signer.h
+++ b/src/external_signer.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_EXTERNAL_SIGNER_H
#define BITCOIN_EXTERNAL_SIGNER_H
+#include <common/system.h>
#include <univalue.h>
-#include <util/system.h>
#include <string>
#include <vector>
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index d6e84d02c1..59861a08ad 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -8,7 +8,7 @@
#include <flatfile.h>
#include <logging.h>
#include <tinyformat.h>
-#include <util/system.h>
+#include <util/fs_helpers.h>
FlatFileSeq::FlatFileSeq(fs::path dir, const char* prefix, size_t chunk_size) :
m_dir(std::move(dir)),
diff --git a/src/flatfile.h b/src/flatfile.h
index e4be9a9cb1..26b466db71 100644
--- a/src/flatfile.h
+++ b/src/flatfile.h
@@ -8,8 +8,8 @@
#include <string>
-#include <fs.h>
#include <serialize.h>
+#include <util/fs.h>
struct FlatFilePos
{
diff --git a/src/headerssync.cpp b/src/headerssync.cpp
index 757b942cd9..a3adfb4f70 100644
--- a/src/headerssync.cpp
+++ b/src/headerssync.cpp
@@ -24,11 +24,11 @@ static_assert(sizeof(CompressedHeader) == 48);
HeadersSyncState::HeadersSyncState(NodeId id, const Consensus::Params& consensus_params,
const CBlockIndex* chain_start, const arith_uint256& minimum_required_work) :
+ m_commit_offset(GetRand<unsigned>(HEADER_COMMITMENT_PERIOD)),
m_id(id), m_consensus_params(consensus_params),
m_chain_start(chain_start),
m_minimum_required_work(minimum_required_work),
m_current_chain_work(chain_start->nChainWork),
- m_commit_offset(GetRand<unsigned>(HEADER_COMMITMENT_PERIOD)),
m_last_header_received(m_chain_start->GetBlockHeader()),
m_current_height(chain_start->nHeight)
{
diff --git a/src/headerssync.h b/src/headerssync.h
index 16da964246..e93f67e6da 100644
--- a/src/headerssync.h
+++ b/src/headerssync.h
@@ -175,6 +175,13 @@ public:
*/
CBlockLocator NextHeadersRequestLocator() const;
+protected:
+ /** The (secret) offset on the heights for which to create commitments.
+ *
+ * m_header_commitments entries are created at any height h for which
+ * (h % HEADER_COMMITMENT_PERIOD) == m_commit_offset. */
+ const unsigned m_commit_offset;
+
private:
/** Clear out all download state that might be in progress (freeing any used
* memory), and mark this object as no longer usable.
@@ -222,12 +229,6 @@ private:
/** A queue of commitment bits, created during the 1st phase, and verified during the 2nd. */
bitdeque<> m_header_commitments;
- /** The (secret) offset on the heights for which to create commitments.
- *
- * m_header_commitments entries are created at any height h for which
- * (h % HEADER_COMMITMENT_PERIOD) == m_commit_offset. */
- const unsigned m_commit_offset;
-
/** m_max_commitments is a bound we calculate on how long an honest peer's chain could be,
* given the MTP rule.
*
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 86166a5ca4..661406e122 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -4,13 +4,14 @@
#include <httprpc.h>
+#include <common/args.h>
#include <crypto/hmac_sha256.h>
#include <httpserver.h>
+#include <logging.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <walletinitinterface.h>
#include <algorithm>
@@ -75,7 +76,7 @@ static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const Uni
{
// Send error reply from json-rpc error object
int nStatus = HTTP_INTERNAL_SERVER_ERROR;
- int code = find_value(objError, "code").getInt<int>();
+ int code = objError.find_value("code").getInt<int>();
if (code == RPC_INVALID_REQUEST)
nStatus = HTTP_BAD_REQUEST;
@@ -212,7 +213,7 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
} else {
const UniValue& request = valRequest[reqIdx].get_obj();
// Parse method
- std::string strMethod = find_value(request, "method").get_str();
+ std::string strMethod = request.find_value("method").get_str();
if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) {
LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod);
req->WriteReply(HTTP_FORBIDDEN);
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 942caa042d..128c4e3c56 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -9,7 +9,9 @@
#include <httpserver.h>
#include <chainparamsbase.h>
+#include <common/args.h>
#include <compat/compat.h>
+#include <logging.h>
#include <netbase.h>
#include <node/interface_ui.h>
#include <rpc/protocol.h> // For HTTP status codes
@@ -17,7 +19,6 @@
#include <sync.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/threadnames.h>
#include <util/translation.h>
@@ -169,12 +170,8 @@ static bool ClientAllowed(const CNetAddr& netaddr)
static bool InitHTTPAllowList()
{
rpc_allow_subnets.clear();
- CNetAddr localv4;
- CNetAddr localv6;
- LookupHost("127.0.0.1", localv4, false);
- LookupHost("::1", localv6, false);
- rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet
- rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost
+ rpc_allow_subnets.push_back(CSubNet{LookupHost("127.0.0.1", false).value(), 8}); // always allow IPv4 local subnet
+ rpc_allow_subnets.push_back(CSubNet{LookupHost("::1", false).value()}); // always allow IPv6 localhost
for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
CSubNet subnet;
LookupSubNet(strAllow, subnet);
@@ -337,8 +334,8 @@ static bool HTTPBindAddresses(struct evhttp* http)
LogPrintf("Binding RPC on address %s port %i\n", i->first, i->second);
evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second);
if (bind_handle) {
- CNetAddr addr;
- if (i->first.empty() || (LookupHost(i->first, addr, false) && addr.IsBindAny())) {
+ const std::optional<CNetAddr> addr{LookupHost(i->first, false)};
+ if (i->first.empty() || (addr.has_value() && addr->IsBindAny())) {
LogPrintf("WARNING: the RPC server is not safe to expose to untrusted networks such as the public internet\n");
}
boundSockets.push_back(bind_handle);
@@ -673,6 +670,9 @@ std::optional<std::string> HTTPRequest::GetQueryParameter(const std::string& key
std::optional<std::string> GetQueryParameterFromUri(const char* uri, const std::string& key)
{
evhttp_uri* uri_parsed{evhttp_uri_parse(uri)};
+ if (!uri_parsed) {
+ throw std::runtime_error("URI parsing failed, it likely contained RFC 3986 invalid characters");
+ }
const char* query{evhttp_uri_get_query(uri_parsed)};
std::optional<std::string> result;
diff --git a/src/i2p.cpp b/src/i2p.cpp
index a3bfc23a65..f03e375adf 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -3,21 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <compat/endian.h>
#include <crypto/sha256.h>
-#include <fs.h>
#include <i2p.h>
#include <logging.h>
#include <netaddress.h>
#include <netbase.h>
#include <random.h>
#include <tinyformat.h>
+#include <util/fs.h>
#include <util/readwritefile.h>
#include <util/sock.h>
#include <util/spanparsing.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
#include <chrono>
@@ -336,7 +336,7 @@ void Session::GenerateAndSavePrivateKey(const Sock& sock)
{
DestGenerate(sock);
- // umask is set to 0077 in util/system.cpp, which is ok.
+ // umask is set to 0077 in common/system.cpp, which is ok.
if (!WriteBinaryFile(m_private_key_file,
std::string(m_private_key.begin(), m_private_key.end()))) {
throw std::runtime_error(
diff --git a/src/i2p.h b/src/i2p.h
index 6e7bafc945..c9c99292d9 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -6,9 +6,9 @@
#define BITCOIN_I2P_H
#include <compat/compat.h>
-#include <fs.h>
#include <netaddress.h>
#include <sync.h>
+#include <util/fs.h>
#include <util/sock.h>
#include <util/threadinterrupt.h>
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 8a311296c2..a713be3480 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
#include <index/base.h>
#include <interfaces/chain.h>
#include <kernel/chain.h>
@@ -14,7 +15,6 @@
#include <shutdown.h>
#include <tinyformat.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/translation.h>
#include <validation.h> // For g_chainman
@@ -23,7 +23,7 @@
#include <string>
#include <utility>
-using node::ReadBlockFromDisk;
+using node::g_indexes_ready_to_sync;
constexpr uint8_t DB_BEST_BLOCK{'B'};
@@ -33,11 +33,7 @@ constexpr auto SYNC_LOCATOR_WRITE_INTERVAL{30s};
template <typename... Args>
static void FatalError(const char* fmt, const Args&... args)
{
- std::string strMessage = tfm::format(fmt, args...);
- SetMiscWarning(Untranslated(strMessage));
- LogPrintf("*** %s\n", strMessage);
- InitError(_("A fatal internal error occurred, see debug.log for details"));
- StartShutdown();
+ AbortNode(tfm::format(fmt, args...));
}
CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)
@@ -94,16 +90,21 @@ bool BaseIndex::Init()
if (locator.IsNull()) {
SetBestBlockIndex(nullptr);
} else {
- SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
+ // Setting the best block to the locator's top block. If it is not part of the
+ // best chain, we will rewind to the fork point during index sync
+ const CBlockIndex* locator_index{m_chainstate->m_blockman.LookupBlockIndex(locator.vHave.at(0))};
+ if (!locator_index) {
+ return InitError(strprintf(Untranslated("%s: best block of the index not found. Please rebuild the index."), GetName()));
+ }
+ SetBestBlockIndex(locator_index);
}
- // Note: this will latch to true immediately if the user starts up with an empty
- // datadir and an index enabled. If this is the case, indexation will happen solely
- // via `BlockConnected` signals until, possibly, the next restart.
- m_synced = m_best_block_index.load() == active_chain.Tip();
- if (!m_synced) {
+ // Skip pruning check if indexes are not ready to sync (because reindex-chainstate has wiped the chain).
+ const CBlockIndex* start_block = m_best_block_index.load();
+ bool synced = start_block == active_chain.Tip();
+ if (!synced && g_indexes_ready_to_sync) {
bool prune_violation = false;
- if (!m_best_block_index) {
+ if (!start_block) {
// index is not built yet
// make sure we have all block data back to the genesis
prune_violation = m_chainstate->m_blockman.GetFirstStoredBlock(*active_chain.Tip()) != active_chain.Genesis();
@@ -111,7 +112,7 @@ bool BaseIndex::Init()
// in case the index has a best block set and is not fully synced
// check if we have the required blocks to continue building the index
else {
- const CBlockIndex* block_to_test = m_best_block_index.load();
+ const CBlockIndex* block_to_test = start_block;
if (!active_chain.Contains(block_to_test)) {
// if the bestblock is not part of the mainchain, find the fork
// and make sure we have all data down to the fork
@@ -135,6 +136,16 @@ bool BaseIndex::Init()
return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName()));
}
}
+
+ // Child init
+ if (!CustomInit(start_block ? std::make_optional(interfaces::BlockKey{start_block->GetBlockHash(), start_block->nHeight}) : std::nullopt)) {
+ return false;
+ }
+
+ // Note: this will latch to true immediately if the user starts up with an empty
+ // datadir and an index enabled. If this is the case, indexation will happen solely
+ // via `BlockConnected` signals until, possibly, the next restart.
+ m_synced = synced;
return true;
}
@@ -157,10 +168,14 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain&
void BaseIndex::ThreadSync()
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::TX_INDEX);
+ // Wait for a possible reindex-chainstate to finish until continuing
+ // with the index sync
+ while (!g_indexes_ready_to_sync) {
+ if (!m_interrupt.sleep_for(std::chrono::milliseconds(500))) return;
+ }
+
const CBlockIndex* pindex = m_best_block_index.load();
if (!m_synced) {
- auto& consensus_params = Params().GetConsensus();
-
std::chrono::steady_clock::time_point last_log_time{0s};
std::chrono::steady_clock::time_point last_locator_write_time{0s};
while (true) {
@@ -207,7 +222,7 @@ void BaseIndex::ThreadSync()
CBlock block;
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
- if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
+ if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *pindex)) {
FatalError("%s: Failed to read block %s from disk",
__func__, pindex->GetBlockHash().ToString());
return;
@@ -396,11 +411,6 @@ bool BaseIndex::Start()
RegisterValidationInterface(this);
if (!Init()) return false;
- const CBlockIndex* index = m_best_block_index.load();
- if (!CustomInit(index ? std::make_optional(interfaces::BlockKey{index->GetBlockHash(), index->nHeight}) : std::nullopt)) {
- return false;
- }
-
m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
return true;
}
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 59bf6d34cf..a860b3a94d 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -4,15 +4,14 @@
#include <map>
+#include <common/args.h>
#include <dbwrapper.h>
#include <hash.h>
#include <index/blockfilterindex.h>
#include <node/blockstorage.h>
-#include <util/system.h>
+#include <util/fs_helpers.h>
#include <validation.h>
-using node::UndoReadFromDisk;
-
/* The index database stores three items for each block: the disk location of the encoded filter,
* its dSHA256 hash, and the header. Those belonging to blocks on the active chain are indexed by
* height, and those belonging to blocks that have been reorganized out of the active chain are
@@ -222,7 +221,7 @@ bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
// pindex variable gives indexing code access to node internals. It
// will be removed in upcoming commit
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
- if (!UndoReadFromDisk(block_undo, pindex)) {
+ if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
return false;
}
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index 4d637e217a..d80885f842 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <coins.h>
+#include <common/args.h>
#include <crypto/muhash.h>
#include <index/coinstatsindex.h>
#include <kernel/coinstats.h>
@@ -12,16 +13,12 @@
#include <serialize.h>
#include <txdb.h>
#include <undo.h>
-#include <util/system.h>
#include <validation.h>
using kernel::CCoinsStats;
using kernel::GetBogoSize;
using kernel::TxOutSer;
-using node::ReadBlockFromDisk;
-using node::UndoReadFromDisk;
-
static constexpr uint8_t DB_BLOCK_HASH{'s'};
static constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
static constexpr uint8_t DB_MUHASH{'M'};
@@ -125,7 +122,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
// pindex variable gives indexing code access to node internals. It
// will be removed in upcoming commit
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
- if (!UndoReadFromDisk(block_undo, pindex)) {
+ if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
return false;
}
@@ -282,12 +279,11 @@ bool CoinStatsIndex::CustomRewind(const interfaces::BlockKey& current_tip, const
LOCK(cs_main);
const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip.hash)};
const CBlockIndex* new_tip_index{m_chainstate->m_blockman.LookupBlockIndex(new_tip.hash)};
- const auto& consensus_params{Params().GetConsensus()};
do {
CBlock block;
- if (!ReadBlockFromDisk(block, iter_tip, consensus_params)) {
+ if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *iter_tip)) {
return error("%s: Failed to read block %s from disk",
__func__, iter_tip->GetBlockHash().ToString());
}
@@ -409,7 +405,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
// Ignore genesis block
if (pindex->nHeight > 0) {
- if (!UndoReadFromDisk(block_undo, pindex)) {
+ if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
return false;
}
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 9095e7afeb..2e07a35d0d 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -4,14 +4,12 @@
#include <index/txindex.h>
+#include <common/args.h>
#include <index/disktxpos.h>
#include <logging.h>
#include <node/blockstorage.h>
-#include <util/system.h>
#include <validation.h>
-using node::OpenBlockFile;
-
constexpr uint8_t DB_TXINDEX{'t'};
std::unique_ptr<TxIndex> g_txindex;
@@ -80,7 +78,7 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe
return false;
}
- CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
+ CAutoFile file(m_chainstate->m_blockman.OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
return error("%s: OpenBlockFile failed", __func__);
}
diff --git a/src/init.cpp b/src/init.cpp
index 16909f7e47..e86180017a 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -18,9 +18,11 @@
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
+#include <chainparamsbase.h>
+#include <common/args.h>
+#include <common/system.h>
#include <consensus/amount.h>
#include <deploymentstatus.h>
-#include <fs.h>
#include <hash.h>
#include <httprpc.h>
#include <httpserver.h>
@@ -44,6 +46,7 @@
#include <node/chainstatemanager_args.h>
#include <node/context.h>
#include <node/interface_ui.h>
+#include <node/kernel_notifications.h>
#include <node/mempool_args.h>
#include <node/mempool_persist_args.h>
#include <node/miner.h>
@@ -69,15 +72,19 @@
#include <txdb.h>
#include <txmempool.h>
#include <util/asmap.h>
+#include <util/chaintype.h>
#include <util/check.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/moneystr.h>
+#include <util/result.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/syscall_sandbox.h>
#include <util/syserror.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/threadnames.h>
+#include <util/time.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -108,22 +115,25 @@
#include <zmq/zmqrpc.h>
#endif
+using kernel::DEFAULT_STOPAFTERBLOCKIMPORT;
using kernel::DumpMempool;
using kernel::ValidationCacheSizes;
using node::ApplyArgsManOptions;
+using node::BlockManager;
using node::CacheSizes;
using node::CalculateCacheSizes;
using node::DEFAULT_PERSIST_MEMPOOL;
using node::DEFAULT_PRINTPRIORITY;
-using node::DEFAULT_STOPAFTERBLOCKIMPORT;
+using node::fReindex;
+using node::g_indexes_ready_to_sync;
+using node::KernelNotifications;
using node::LoadChainstate;
using node::MempoolPath;
-using node::ShouldPersistMempool;
using node::NodeContext;
+using node::ShouldPersistMempool;
using node::ThreadImport;
using node::VerifyLoadedChainstate;
-using node::fReindex;
static constexpr bool DEFAULT_PROXYRANDOMIZE{true};
static constexpr bool DEFAULT_REST_ENABLE{false};
@@ -324,9 +334,8 @@ void Shutdown(NodeContext& node)
#if ENABLE_ZMQ
if (g_zmq_notification_interface) {
- UnregisterValidationInterface(g_zmq_notification_interface);
- delete g_zmq_notification_interface;
- g_zmq_notification_interface = nullptr;
+ UnregisterValidationInterface(g_zmq_notification_interface.get());
+ g_zmq_notification_interface.reset();
}
#endif
@@ -406,14 +415,14 @@ void SetupServerArgs(ArgsManager& argsman)
init::AddLoggingArgs(argsman);
- const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
- const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
- const auto signetBaseParams = CreateBaseChainParams(CBaseChainParams::SIGNET);
- const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST);
- const auto defaultChainParams = CreateChainParams(argsman, CBaseChainParams::MAIN);
- const auto testnetChainParams = CreateChainParams(argsman, CBaseChainParams::TESTNET);
- const auto signetChainParams = CreateChainParams(argsman, CBaseChainParams::SIGNET);
- const auto regtestChainParams = CreateChainParams(argsman, CBaseChainParams::REGTEST);
+ const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN);
+ const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET);
+ const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET);
+ const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST);
+ const auto defaultChainParams = CreateChainParams(argsman, ChainType::MAIN);
+ const auto testnetChainParams = CreateChainParams(argsman, ChainType::TESTNET);
+ const auto signetChainParams = CreateChainParams(argsman, ChainType::SIGNET);
+ const auto regtestChainParams = CreateChainParams(argsman, ChainType::REGTEST);
// Hidden Options
std::vector<std::string> hidden_args = {
@@ -439,6 +448,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-loadblock=<file>", "Imports blocks from external file on startup", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-maxmempool=<n>", strprintf("Keep the transaction memory pool below <n> megabytes (default: %u)", DEFAULT_MAX_MEMPOOL_SIZE_MB), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-maxorphantx=<n>", strprintf("Keep at most <n> unconnectable transactions in memory (default: %u)", DEFAULT_MAX_ORPHAN_TRANSACTIONS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -452,7 +462,7 @@ void SetupServerArgs(ArgsManager& argsman)
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk. This will also rebuild active optional indexes.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead. Deactivate all optional indexes before running this.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#if HAVE_SYSTEM
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -578,6 +588,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and replacement policy. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
+ argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
@@ -792,7 +803,7 @@ std::set<BlockFilterType> g_enabled_filter_types;
std::terminate();
};
-bool AppInitBasicSetup(const ArgsManager& args)
+bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status)
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
@@ -806,7 +817,7 @@ bool AppInitBasicSetup(const ArgsManager& args)
// Enable heap terminate-on-corruption
HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);
#endif
- if (!InitShutdownState()) {
+ if (!InitShutdownState(exit_status)) {
return InitError(Untranslated("Initializing wait-for-shutdown state failed."));
}
@@ -842,14 +853,14 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
// Error if network-specific options (-addnode, -connect, etc) are
// specified in default section of config file, but not overridden
- // on the command line or in this network's section of the config file.
- std::string network = args.GetChainName();
- if (network == CBaseChainParams::SIGNET) {
+ // on the command line or in this chain's section of the config file.
+ ChainType chain = args.GetChainType();
+ if (chain == ChainType::SIGNET) {
LogPrintf("Signet derived magic (message start): %s\n", HexStr(chainparams.MessageStart()));
}
bilingual_str errors;
for (const auto& arg : args.GetUnsuitableSectionOnlyArgs()) {
- errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, network, network);
+ errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, ChainTypeToString(chain), ChainTypeToString(chain));
}
if (!errors.empty()) {
@@ -941,8 +952,10 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags
- init::SetLoggingCategories(args);
- init::SetLoggingLevel(args);
+ auto result = init::SetLoggingCategories(args);
+ if (!result) return InitError(util::ErrorString(result));
+ result = init::SetLoggingLevel(args);
+ if (!result) return InitError(util::ErrorString(result));
nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
if (nConnectTimeout <= 0) {
@@ -978,19 +991,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
if (args.GetIntArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
return InitError(Untranslated("Unknown rpcserialversion requested."));
- if (args.GetBoolArg("-reindex-chainstate", false)) {
- // indexes that must be deactivated to prevent index corruption, see #24630
- if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
- return InitError(_("-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
- }
- if (g_enabled_filter_types.count(BlockFilterType::BASIC)) {
- return InitError(_("-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
- }
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- return InitError(_("-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
- }
- }
-
#if defined(USE_SYSCALL_SANDBOX)
if (args.IsArgSet("-sandbox") && !args.IsArgNegated("-sandbox")) {
const std::string sandbox_arg{args.GetArg("-sandbox", "")};
@@ -1027,16 +1027,23 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
// Also report errors from parsing before daemonization
{
+ KernelNotifications notifications{};
ChainstateManager::Options chainman_opts_dummy{
.chainparams = chainparams,
.datadir = args.GetDataDirNet(),
+ .notifications = notifications,
};
- if (const auto error{ApplyArgsManOptions(args, chainman_opts_dummy)}) {
- return InitError(*error);
+ auto chainman_result{ApplyArgsManOptions(args, chainman_opts_dummy)};
+ if (!chainman_result) {
+ return InitError(util::ErrorString(chainman_result));
}
- node::BlockManager::Options blockman_opts_dummy{};
- if (const auto error{ApplyArgsManOptions(args, blockman_opts_dummy)}) {
- return InitError(*error);
+ BlockManager::Options blockman_opts_dummy{
+ .chainparams = chainman_opts_dummy.chainparams,
+ .blocks_dir = args.GetBlocksDirPath(),
+ };
+ auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
+ if (!blockman_result) {
+ return InitError(util::ErrorString(blockman_result));
}
}
@@ -1059,8 +1066,9 @@ static bool LockDataDirectory(bool probeOnly)
bool AppInitSanityChecks(const kernel::Context& kernel)
{
// ********************************************************* Step 4: sanity checks
- if (auto error = kernel::SanityChecks(kernel)) {
- InitError(*error);
+ auto result{kernel::SanityChecks(kernel)};
+ if (!result) {
+ InitError(util::ErrorString(result));
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
}
@@ -1235,9 +1243,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Initialize addrman
assert(!node.addrman);
uiInterface.InitMessage(_("Loading P2P addresses…").translated);
- if (const auto error{LoadAddrman(*node.netgroupman, args, node.addrman)}) {
- return InitError(*error);
- }
+ auto addrman{LoadAddrman(*node.netgroupman, args)};
+ if (!addrman) return InitError(util::ErrorString(addrman));
+ node.addrman = std::move(*addrman);
}
assert(!node.banman);
@@ -1250,7 +1258,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
assert(!node.fee_estimator);
// Don't initialize fee estimation with old data if we don't relay transactions,
// as they would never get updated.
- if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args));
+ if (!ignores_incoming_txs) {
+ bool read_stale_estimates = args.GetBoolArg("-acceptstalefeeestimates", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
+ if (read_stale_estimates && (chainparams.GetChainType() != ChainType::REGTEST)) {
+ return InitError(strprintf(_("acceptstalefeeestimates is not supported on %s chain."), chainparams.GetChainTypeString()));
+ }
+ node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args), read_stale_estimates);
+
+ // Flush estimates to disk periodically
+ CBlockPolicyEstimator* fee_estimator = node.fee_estimator.get();
+ node.scheduler->scheduleEvery([fee_estimator] { fee_estimator->FlushFeeEstimates(); }, FEE_FLUSH_INTERVAL);
+ }
// Check port numbers
for (const std::string port_option : {
@@ -1356,12 +1374,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
std::string proxyArg = args.GetArg("-proxy", "");
if (proxyArg != "" && proxyArg != "0") {
- CService proxyAddr;
- if (!Lookup(proxyArg, proxyAddr, 9050, fNameLookup)) {
+ const std::optional<CService> proxyAddr{Lookup(proxyArg, 9050, fNameLookup)};
+ if (!proxyAddr.has_value()) {
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
}
- Proxy addrProxy = Proxy(proxyAddr, proxyRandomize);
+ Proxy addrProxy = Proxy(proxyAddr.value(), proxyRandomize);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg));
@@ -1387,11 +1405,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
"reaching the Tor network is explicitly forbidden: -onion=0"));
}
} else {
- CService addr;
- if (!Lookup(onionArg, addr, 9050, fNameLookup) || !addr.IsValid()) {
+ const std::optional<CService> addr{Lookup(onionArg, 9050, fNameLookup)};
+ if (!addr.has_value() || !addr->IsValid()) {
return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg));
}
- onion_proxy = Proxy{addr, proxyRandomize};
+ onion_proxy = Proxy{addr.value(), proxyRandomize};
}
}
@@ -1411,34 +1429,43 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
for (const std::string& strAddr : args.GetArgs("-externalip")) {
- CService addrLocal;
- if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
- AddLocal(addrLocal, LOCAL_MANUAL);
+ const std::optional<CService> addrLocal{Lookup(strAddr, GetListenPort(), fNameLookup)};
+ if (addrLocal.has_value() && addrLocal->IsValid())
+ AddLocal(addrLocal.value(), LOCAL_MANUAL);
else
return InitError(ResolveErrMsg("externalip", strAddr));
}
#if ENABLE_ZMQ
- g_zmq_notification_interface = CZMQNotificationInterface::Create();
+ g_zmq_notification_interface = CZMQNotificationInterface::Create(
+ [&chainman = node.chainman](CBlock& block, const CBlockIndex& index) {
+ assert(chainman);
+ return chainman->m_blockman.ReadBlockFromDisk(block, index);
+ });
if (g_zmq_notification_interface) {
- RegisterValidationInterface(g_zmq_notification_interface);
+ RegisterValidationInterface(g_zmq_notification_interface.get());
}
#endif
// ********************************************************* Step 7: load block chain
+ node.notifications = std::make_unique<KernelNotifications>();
fReindex = args.GetBoolArg("-reindex", false);
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
.datadir = args.GetDataDirNet(),
.adjusted_time_callback = GetAdjustedTime,
+ .notifications = *node.notifications,
};
- Assert(!ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
+ Assert(ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
- node::BlockManager::Options blockman_opts{};
- Assert(!ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
+ BlockManager::Options blockman_opts{
+ .chainparams = chainman_opts.chainparams,
+ .blocks_dir = args.GetBlocksDirPath(),
+ };
+ Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
// cache size calculations
CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size());
@@ -1461,8 +1488,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
.estimator = node.fee_estimator.get(),
.check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
};
- if (const auto err{ApplyArgsManOptions(args, chainparams, mempool_opts)}) {
- return InitError(*err);
+ auto result{ApplyArgsManOptions(args, chainparams, mempool_opts)};
+ if (!result) {
+ return InitError(util::ErrorString(result));
}
mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000);
@@ -1517,7 +1545,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}
- if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
+ if (status == node::ChainstateLoadStatus::FAILURE_FATAL || status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
return InitError(error);
}
@@ -1557,9 +1585,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
RegisterValidationInterface(node.peerman.get());
// ********************************************************* Step 8: start indexers
+
+ // If reindex-chainstate was specified, delay syncing indexes until ThreadImport has reindexed the chain
+ if (!fReindexChainState) g_indexes_ready_to_sync = true;
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) {
- return InitError(*error);
+ auto result{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))};
+ if (!result) {
+ return InitError(util::ErrorString(result));
}
g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, fReindex);
@@ -1666,7 +1698,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &chainman, &args] {
- ThreadImport(chainman, vImportFiles, args, ShouldPersistMempool(args) ? MempoolPath(args) : fs::path{});
+ ThreadImport(chainman, vImportFiles, ShouldPersistMempool(args) ? MempoolPath(args) : fs::path{});
});
// Wait for genesis block to be processed
@@ -1737,13 +1769,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
};
for (const std::string& bind_arg : args.GetArgs("-bind")) {
- CService bind_addr;
+ std::optional<CService> bind_addr;
const size_t index = bind_arg.rfind('=');
if (index == std::string::npos) {
- if (Lookup(bind_arg, bind_addr, default_bind_port, /*fAllowLookup=*/false)) {
- connOptions.vBinds.push_back(bind_addr);
- if (IsBadPort(bind_addr.GetPort())) {
- InitWarning(BadPortWarning("-bind", bind_addr.GetPort()));
+ bind_addr = Lookup(bind_arg, default_bind_port, /*fAllowLookup=*/false);
+ if (bind_addr.has_value()) {
+ connOptions.vBinds.push_back(bind_addr.value());
+ if (IsBadPort(bind_addr.value().GetPort())) {
+ InitWarning(BadPortWarning("-bind", bind_addr.value().GetPort()));
}
continue;
}
@@ -1751,8 +1784,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const std::string network_type = bind_arg.substr(index + 1);
if (network_type == "onion") {
const std::string truncated_bind_arg = bind_arg.substr(0, index);
- if (Lookup(truncated_bind_arg, bind_addr, BaseParams().OnionServiceTargetPort(), false)) {
- connOptions.onion_binds.push_back(bind_addr);
+ bind_addr = Lookup(truncated_bind_arg, BaseParams().OnionServiceTargetPort(), false);
+ if (bind_addr.has_value()) {
+ connOptions.onion_binds.push_back(bind_addr.value());
continue;
}
}
@@ -1830,11 +1864,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const std::string& i2psam_arg = args.GetArg("-i2psam", "");
if (!i2psam_arg.empty()) {
- CService addr;
- if (!Lookup(i2psam_arg, addr, 7656, fNameLookup) || !addr.IsValid()) {
+ const std::optional<CService> addr{Lookup(i2psam_arg, 7656, fNameLookup)};
+ if (!addr.has_value() || !addr->IsValid()) {
return InitError(strprintf(_("Invalid -i2psam address or hostname: '%s'"), i2psam_arg));
}
- SetProxy(NET_I2P, Proxy{addr});
+ SetProxy(NET_I2P, Proxy{addr.value()});
} else {
if (args.IsArgSet("-onlynet") && IsReachable(NET_I2P)) {
return InitError(
diff --git a/src/init.h b/src/init.h
index 8c5b2e77d3..fabb4f66d6 100644
--- a/src/init.h
+++ b/src/init.h
@@ -38,7 +38,7 @@ void InitParameterInteraction(ArgsManager& args);
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read.
*/
-bool AppInitBasicSetup(const ArgsManager& args);
+bool AppInitBasicSetup(const ArgsManager& args, std::atomic<int>& exit_status);
/**
* Initialization: parameter interaction.
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp
index 100b4ef7ee..ddbdaa6cd0 100644
--- a/src/init/bitcoin-gui.cpp
+++ b/src/init/bitcoin-gui.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -10,7 +11,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp
index 1418e63777..b04596f986 100644
--- a/src/init/bitcoin-node.cpp
+++ b/src/init/bitcoin-node.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -10,7 +11,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp
index e27be0e598..dd5826d982 100644
--- a/src/init/bitcoin-qt.cpp
+++ b/src/init/bitcoin-qt.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -9,7 +10,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp
index 7ad1f64e64..210608370c 100644
--- a/src/init/bitcoind.cpp
+++ b/src/init/bitcoind.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <interfaces/chain.h>
#include <interfaces/echo.h>
#include <interfaces/init.h>
@@ -9,7 +10,6 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <util/check.h>
-#include <util/system.h>
#include <memory>
diff --git a/src/init/common.cpp b/src/init/common.cpp
index a7829c5d99..f3f7c696c5 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -7,12 +7,14 @@
#endif
#include <clientversion.h>
-#include <fs.h>
+#include <common/args.h>
#include <logging.h>
#include <node/interface_ui.h>
#include <tinyformat.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
+#include <util/result.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/translation.h>
@@ -57,27 +59,28 @@ void SetLoggingOptions(const ArgsManager& args)
fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS);
}
-void SetLoggingLevel(const ArgsManager& args)
+util::Result<void> SetLoggingLevel(const ArgsManager& args)
{
if (args.IsArgSet("-loglevel")) {
for (const std::string& level_str : args.GetArgs("-loglevel")) {
if (level_str.find_first_of(':', 3) == std::string::npos) {
// user passed a global log level, i.e. -loglevel=<level>
if (!LogInstance().SetLogLevel(level_str)) {
- InitWarning(strprintf(_("Unsupported global logging level -loglevel=%s. Valid values: %s."), level_str, LogInstance().LogLevelsString()));
+ return util::Error{strprintf(_("Unsupported global logging level %s=%s. Valid values: %s."), "-loglevel", level_str, LogInstance().LogLevelsString())};
}
} else {
// user passed a category-specific log level, i.e. -loglevel=<category>:<level>
const auto& toks = SplitString(level_str, ':');
if (!(toks.size() == 2 && LogInstance().SetCategoryLogLevel(toks[0], toks[1]))) {
- InitWarning(strprintf(_("Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s."), level_str, LogInstance().LogCategoriesString(), LogInstance().LogLevelsString()));
+ return util::Error{strprintf(_("Unsupported category-specific logging level %1$s=%2$s. Expected %1$s=<category>:<loglevel>. Valid categories: %3$s. Valid loglevels: %4$s."), "-loglevel", level_str, LogInstance().LogCategoriesString(), LogInstance().LogLevelsString())};
}
}
}
}
+ return {};
}
-void SetLoggingCategories(const ArgsManager& args)
+util::Result<void> SetLoggingCategories(const ArgsManager& args)
{
if (args.IsArgSet("-debug")) {
// Special-case: if -debug=0/-nodebug is set, turn off debugging messages
@@ -87,7 +90,7 @@ void SetLoggingCategories(const ArgsManager& args)
[](std::string cat){return cat == "0" || cat == "none";})) {
for (const auto& cat : categories) {
if (!LogInstance().EnableCategory(cat)) {
- InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
+ return util::Error{strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)};
}
}
}
@@ -96,9 +99,10 @@ void SetLoggingCategories(const ArgsManager& args)
// Now remove the logging categories which were explicitly excluded
for (const std::string& cat : args.GetArgs("-debugexclude")) {
if (!LogInstance().DisableCategory(cat)) {
- InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
+ return util::Error{strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)};
}
}
+ return {};
}
bool StartLogging(const ArgsManager& args)
diff --git a/src/init/common.h b/src/init/common.h
index 44c3a502ee..b61a77c6d4 100644
--- a/src/init/common.h
+++ b/src/init/common.h
@@ -8,13 +8,15 @@
#ifndef BITCOIN_INIT_COMMON_H
#define BITCOIN_INIT_COMMON_H
+#include <util/result.h>
+
class ArgsManager;
namespace init {
void AddLoggingArgs(ArgsManager& args);
void SetLoggingOptions(const ArgsManager& args);
-void SetLoggingCategories(const ArgsManager& args);
-void SetLoggingLevel(const ArgsManager& args);
+[[nodiscard]] util::Result<void> SetLoggingCategories(const ArgsManager& args);
+[[nodiscard]] util::Result<void> SetLoggingLevel(const ArgsManager& args);
bool StartLogging(const ArgsManager& args);
void LogPackageVersion();
} // namespace init
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index a3fa753a98..dd664165d3 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -6,8 +6,8 @@
#define BITCOIN_INTERFACES_CHAIN_H
#include <blockfilter.h>
+#include <common/settings.h>
#include <primitives/transaction.h> // For CTransactionRef
-#include <util/settings.h> // For util::SettingsValue
#include <functional>
#include <memory>
@@ -87,6 +87,9 @@ struct BlockInfo {
unsigned data_pos = 0;
const CBlock* data = nullptr;
const CBlockUndo* undo_data = nullptr;
+ // The maximum time in the chain up to and including this block.
+ // A timestamp that can only move forward.
+ unsigned int chain_time_max{0};
BlockInfo(const uint256& hash LIFETIMEBOUND) : hash(hash) {}
};
@@ -297,17 +300,17 @@ public:
virtual int rpcSerializationFlags() = 0;
//! Get settings value.
- virtual util::SettingsValue getSetting(const std::string& arg) = 0;
+ virtual common::SettingsValue getSetting(const std::string& arg) = 0;
//! Get list of settings values.
- virtual std::vector<util::SettingsValue> getSettingsList(const std::string& arg) = 0;
+ virtual std::vector<common::SettingsValue> getSettingsList(const std::string& arg) = 0;
//! Return <datadir>/settings.json setting value.
- virtual util::SettingsValue getRwSetting(const std::string& name) = 0;
+ virtual common::SettingsValue getRwSetting(const std::string& name) = 0;
//! Write a setting to <datadir>/settings.json. Optionally just update the
//! setting in memory and do not write the file.
- virtual bool updateRwSetting(const std::string& name, const util::SettingsValue& value, bool write=true) = 0;
+ virtual bool updateRwSetting(const std::string& name, const common::SettingsValue& value, bool write=true) = 0;
//! Synchronously send transactionAddedToMempool notifications about all
//! current mempool transactions to the specified handler and return after
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 7e87d5a523..3f8df57124 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -5,13 +5,13 @@
#ifndef BITCOIN_INTERFACES_NODE_H
#define BITCOIN_INTERFACES_NODE_H
+#include <common/settings.h>
#include <consensus/amount.h> // For CAmount
#include <net.h> // For NodeId
#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
#include <netbase.h> // For ConnectionDirection
#include <support/allocators/secure.h> // For SecureString
-#include <util/settings.h> // For util::SettingsValue
#include <util/translation.h>
#include <functional>
@@ -80,6 +80,9 @@ public:
//! Get warnings.
virtual bilingual_str getWarnings() = 0;
+ //! Get exit status.
+ virtual int getExitStatus() = 0;
+
// Get log flags.
virtual uint32_t getLogCategories() = 0;
@@ -103,14 +106,14 @@ public:
virtual bool isSettingIgnored(const std::string& name) = 0;
//! Return setting value from <datadir>/settings.json or bitcoin.conf.
- virtual util::SettingsValue getPersistentSetting(const std::string& name) = 0;
+ virtual common::SettingsValue getPersistentSetting(const std::string& name) = 0;
//! Update a setting in <datadir>/settings.json.
- virtual void updateRwSetting(const std::string& name, const util::SettingsValue& value) = 0;
+ virtual void updateRwSetting(const std::string& name, const common::SettingsValue& value) = 0;
//! Force a setting value to be applied, overriding any other configuration
//! source, but not being persisted.
- virtual void forceSetting(const std::string& name, const util::SettingsValue& value) = 0;
+ virtual void forceSetting(const std::string& name, const common::SettingsValue& value) = 0;
//! Clear all settings in <datadir>/settings.json and store a backup of
//! previous settings in <datadir>/settings.json.bak.
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 86707b20b1..8c31112fc9 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -6,11 +6,11 @@
#define BITCOIN_INTERFACES_WALLET_H
#include <consensus/amount.h>
-#include <fs.h>
#include <interfaces/chain.h> // For ChainClient
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
+#include <util/fs.h>
#include <util/message.h>
#include <util/result.h>
#include <util/ui_change_type.h>
@@ -35,6 +35,7 @@ struct bilingual_str;
namespace wallet {
class CCoinControl;
class CWallet;
+enum class AddressPurpose;
enum isminetype : unsigned int;
struct CRecipient;
struct WalletContext;
@@ -103,7 +104,7 @@ public:
virtual bool haveWatchOnly() = 0;
//! Add or update address.
- virtual bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) = 0;
+ virtual bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<wallet::AddressPurpose>& purpose) = 0;
// Remove address.
virtual bool delAddressBook(const CTxDestination& dest) = 0;
@@ -112,7 +113,7 @@ public:
virtual bool getAddress(const CTxDestination& dest,
std::string* name,
wallet::isminetype* is_mine,
- std::string* purpose) = 0;
+ wallet::AddressPurpose* purpose) = 0;
//! Get wallet address list.
virtual std::vector<WalletAddress> getAddresses() const = 0;
@@ -293,7 +294,7 @@ public:
using AddressBookChangedFn = std::function<void(const CTxDestination& address,
const std::string& label,
bool is_mine,
- const std::string& purpose,
+ wallet::AddressPurpose purpose,
ChangeType status)>;
virtual std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) = 0;
@@ -352,11 +353,11 @@ struct WalletAddress
{
CTxDestination dest;
wallet::isminetype is_mine;
+ wallet::AddressPurpose purpose;
std::string name;
- std::string purpose;
- WalletAddress(CTxDestination dest, wallet::isminetype is_mine, std::string name, std::string purpose)
- : dest(std::move(dest)), is_mine(is_mine), name(std::move(name)), purpose(std::move(purpose))
+ WalletAddress(CTxDestination dest, wallet::isminetype is_mine, wallet::AddressPurpose purpose, std::string name)
+ : dest(std::move(dest)), is_mine(is_mine), purpose(std::move(purpose)), name(std::move(name))
{
}
};
diff --git a/src/ipc/interfaces.cpp b/src/ipc/interfaces.cpp
index 396f3ddf25..e446cc98db 100644
--- a/src/ipc/interfaces.cpp
+++ b/src/ipc/interfaces.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 <fs.h>
+#include <common/system.h>
#include <interfaces/init.h>
#include <interfaces/ipc.h>
#include <ipc/capnp/protocol.h>
@@ -10,7 +10,7 @@
#include <ipc/protocol.h>
#include <logging.h>
#include <tinyformat.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <cstdio>
#include <cstdlib>
diff --git a/src/ipc/process.cpp b/src/ipc/process.cpp
index 4dc88ae44b..9657dcd092 100644
--- a/src/ipc/process.cpp
+++ b/src/ipc/process.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <fs.h>
#include <ipc/process.h>
#include <ipc/protocol.h>
#include <mp/util.h>
#include <tinyformat.h>
+#include <util/fs.h>
#include <util/strencodings.h>
#include <cstdint>
diff --git a/src/ipc/process.h b/src/ipc/process.h
index 4bb2930d9c..40f2d2acf6 100644
--- a/src/ipc/process.h
+++ b/src/ipc/process.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_IPC_PROCESS_H
#define BITCOIN_IPC_PROCESS_H
+#include <util/fs.h>
+
#include <memory>
#include <string>
diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h
index 9dc93b6dd2..8f26422f72 100644
--- a/src/kernel/blockmanager_opts.h
+++ b/src/kernel/blockmanager_opts.h
@@ -5,14 +5,26 @@
#ifndef BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
#define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
+#include <util/fs.h>
+
+#include <cstdint>
+
+class CChainParams;
+
namespace kernel {
+static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false};
+
/**
* An options struct for `BlockManager`, more ergonomically referred to as
* `BlockManager::Options` due to the using-declaration in `BlockManager`.
*/
struct BlockManagerOpts {
+ const CChainParams& chainparams;
uint64_t prune_target{0};
+ bool fast_prune{false};
+ bool stop_after_block_import{DEFAULT_STOPAFTERBLOCKIMPORT};
+ const fs::path blocks_dir;
};
} // namespace kernel
diff --git a/src/kernel/chain.cpp b/src/kernel/chain.cpp
index 82e77125d7..1c877866d0 100644
--- a/src/kernel/chain.cpp
+++ b/src/kernel/chain.cpp
@@ -16,6 +16,7 @@ interfaces::BlockInfo MakeBlockInfo(const CBlockIndex* index, const CBlock* data
if (index) {
info.prev_hash = index->pprev ? index->pprev->phashBlock : nullptr;
info.height = index->nHeight;
+ info.chain_time_max = index->GetBlockTimeMax();
LOCK(::cs_main);
info.file_number = index->nFile;
info.data_pos = index->nDataPos;
diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp
index e0c4aff6f4..d9ed1547b3 100644
--- a/src/kernel/chainparams.cpp
+++ b/src/kernel/chainparams.cpp
@@ -10,13 +10,13 @@
#include <consensus/merkle.h>
#include <consensus/params.h>
#include <hash.h>
-#include <chainparamsbase.h>
#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/interpreter.h>
#include <script/script.h>
#include <uint256.h>
+#include <util/chaintype.h>
#include <util/strencodings.h>
#include <algorithm>
@@ -70,7 +70,7 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits
class CMainParams : public CChainParams {
public:
CMainParams() {
- strNetworkID = CBaseChainParams::MAIN;
+ m_chain_type = ChainType::MAIN;
consensus.signet_blocks = false;
consensus.signet_challenge.clear();
consensus.nSubsidyHalvingInterval = 210000;
@@ -103,8 +103,8 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000003404ba0801921119f903495e");
- consensus.defaultAssumeValid = uint256S("0x00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd"); // 751565
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000044a50fe819c39ad624021859");
+ consensus.defaultAssumeValid = uint256S("0x000000000000000000035c3f0d31e71a5ee24c5aaf3354689f65bd7b07dee632"); // 784000
/**
* The message start string is designed to be unlikely to occur in normal data.
@@ -117,8 +117,8 @@ public:
pchMessageStart[3] = 0xd9;
nDefaultPort = 8333;
nPruneAfterHeight = 100000;
- m_assumed_blockchain_size = 496;
- m_assumed_chain_state_size = 6;
+ m_assumed_blockchain_size = 540;
+ m_assumed_chain_state_size = 7;
genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
@@ -178,10 +178,10 @@ public:
};
chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd
- .nTime = 1661697692,
- .nTxCount = 760120522,
- .dTxRate = 2.925802860942233,
+ // Data from RPC: getchaintxstats 4096 000000000000000000035c3f0d31e71a5ee24c5aaf3354689f65bd7b07dee632
+ .nTime = 1680665245,
+ .nTxCount = 820876044,
+ .dTxRate = 3.672283614033389,
};
}
};
@@ -192,7 +192,7 @@ public:
class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
- strNetworkID = CBaseChainParams::TESTNET;
+ m_chain_type = ChainType::TESTNET;
consensus.signet_blocks = false;
consensus.signet_challenge.clear();
consensus.nSubsidyHalvingInterval = 210000;
@@ -223,8 +223,8 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000076f6e7cbd0beade5d20");
- consensus.defaultAssumeValid = uint256S("0x0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060"); // 2344474
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000977edb0244170858d07");
+ consensus.defaultAssumeValid = uint256S("0x0000000000000021bc50a89cde4870d4a81ffe0153b3c8de77b435a2fd3f6761"); // 2429000
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
@@ -233,7 +233,7 @@ public:
nDefaultPort = 18333;
nPruneAfterHeight = 1000;
m_assumed_blockchain_size = 42;
- m_assumed_chain_state_size = 2;
+ m_assumed_chain_state_size = 3;
genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
@@ -274,10 +274,10 @@ public:
};
chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060
- .nTime = 1661705221,
- .nTxCount = 63531852,
- .dTxRate = 0.1079119341520164,
+ // Data from RPC: getchaintxstats 4096 0000000000000021bc50a89cde4870d4a81ffe0153b3c8de77b435a2fd3f6761
+ .nTime = 1681542696,
+ .nTxCount = 65345929,
+ .dTxRate = 0.09855282814711661,
};
}
};
@@ -300,15 +300,15 @@ public:
vSeeds.emplace_back("178.128.221.177");
vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333");
- consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001291fc22898");
- consensus.defaultAssumeValid = uint256S("0x000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09"); // 105495
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001899d8142b0");
+ consensus.defaultAssumeValid = uint256S("0x0000004429ef154f7e00b4f6b46bfbe2d2678ecd351d95bbfca437ab9a5b84ec"); // 138000
m_assumed_blockchain_size = 1;
m_assumed_chain_state_size = 0;
chainTxData = ChainTxData{
- // Data from RPC: getchaintxstats 4096 000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09
- .nTime = 1661702566,
- .nTxCount = 1903567,
- .dTxRate = 0.02336701143027275,
+ // Data from RPC: getchaintxstats 4096 0000004429ef154f7e00b4f6b46bfbe2d2678ecd351d95bbfca437ab9a5b84ec
+ .nTime = 1681127428,
+ .nTxCount = 2226359,
+ .dTxRate = 0.006424463050600656,
};
} else {
bin = *options.challenge;
@@ -328,7 +328,7 @@ public:
vSeeds = *options.seeds;
}
- strNetworkID = CBaseChainParams::SIGNET;
+ m_chain_type = ChainType::SIGNET;
consensus.signet_blocks = true;
consensus.signet_challenge.assign(bin.begin(), bin.end());
consensus.nSubsidyHalvingInterval = 210000;
@@ -397,7 +397,7 @@ class CRegTestParams : public CChainParams
public:
explicit CRegTestParams(const RegTestOptions& opts)
{
- strNetworkID = CBaseChainParams::REGTEST;
+ m_chain_type = ChainType::REGTEST;
consensus.signet_blocks = false;
consensus.signet_challenge.clear();
consensus.nSubsidyHalvingInterval = 150;
diff --git a/src/kernel/chainparams.h b/src/kernel/chainparams.h
index 32fe618dbd..ad0b49a885 100644
--- a/src/kernel/chainparams.h
+++ b/src/kernel/chainparams.h
@@ -11,6 +11,7 @@
#include <primitives/block.h>
#include <protocol.h>
#include <uint256.h>
+#include <util/chaintype.h>
#include <util/hash_type.h>
#include <cstdint>
@@ -114,8 +115,10 @@ public:
uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
/** Whether it is possible to mine blocks on demand (no retargeting) */
bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
- /** Return the network string */
- std::string NetworkIDString() const { return strNetworkID; }
+ /** Return the chain type string */
+ std::string GetChainTypeString() const { return ChainTypeToString(m_chain_type); }
+ /** Return the chain type */
+ ChainType GetChainType() const { return m_chain_type; }
/** Return the list of hostnames to look up for DNS seeds */
const std::vector<std::string>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
@@ -172,7 +175,7 @@ protected:
std::vector<std::string> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
std::string bech32_hrp;
- std::string strNetworkID;
+ ChainType m_chain_type;
CBlock genesis;
std::vector<uint8_t> vFixedSeeds;
bool fDefaultConsistencyChecks;
diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h
index 2395f60164..035a913d10 100644
--- a/src/kernel/chainstatemanager_opts.h
+++ b/src/kernel/chainstatemanager_opts.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
#define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H
+#include <kernel/notifications_interface.h>
+
#include <arith_uint256.h>
#include <dbwrapper.h>
#include <txdb.h>
@@ -19,6 +21,7 @@ class CChainParams;
static constexpr bool DEFAULT_CHECKPOINTS_ENABLED{true};
static constexpr auto DEFAULT_MAX_TIP_AGE{24h};
+static constexpr int DEFAULT_STOPATHEIGHT{0};
namespace kernel {
@@ -42,6 +45,8 @@ struct ChainstateManagerOpts {
DBOptions block_tree_db{};
DBOptions coins_db{};
CoinsViewOptions coins_view{};
+ Notifications& notifications;
+ int stop_at_height{DEFAULT_STOPATHEIGHT};
};
} // namespace kernel
diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp
index 4c303c172c..bf8a2ec74c 100644
--- a/src/kernel/checks.cpp
+++ b/src/kernel/checks.cpp
@@ -13,21 +13,21 @@
namespace kernel {
-std::optional<bilingual_str> SanityChecks(const Context&)
+util::Result<void> SanityChecks(const Context&)
{
if (!ECC_InitSanityCheck()) {
- return Untranslated("Elliptic curve cryptography sanity check failure. Aborting.");
+ return util::Error{Untranslated("Elliptic curve cryptography sanity check failure. Aborting.")};
}
if (!Random_SanityCheck()) {
- return Untranslated("OS cryptographic RNG sanity check failure. Aborting.");
+ return util::Error{Untranslated("OS cryptographic RNG sanity check failure. Aborting.")};
}
if (!ChronoSanityCheck()) {
- return Untranslated("Clock epoch mismatch. Aborting.");
+ return util::Error{Untranslated("Clock epoch mismatch. Aborting.")};
}
- return std::nullopt;
+ return {};
}
}
diff --git a/src/kernel/checks.h b/src/kernel/checks.h
index 3eb14824fb..fd8c167015 100644
--- a/src/kernel/checks.h
+++ b/src/kernel/checks.h
@@ -5,9 +5,7 @@
#ifndef BITCOIN_KERNEL_CHECKS_H
#define BITCOIN_KERNEL_CHECKS_H
-#include <optional>
-
-struct bilingual_str;
+#include <util/result.h>
namespace kernel {
@@ -16,8 +14,7 @@ struct Context;
/**
* Ensure a usable environment with all necessary library support.
*/
-std::optional<bilingual_str> SanityChecks(const Context&);
-
-}
+[[nodiscard]] util::Result<void> SanityChecks(const Context&);
+} // namespace kernel
#endif // BITCOIN_KERNEL_CHECKS_H
diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp
index 4b75c387a6..527433f45e 100644
--- a/src/kernel/coinstats.cpp
+++ b/src/kernel/coinstats.cpp
@@ -123,7 +123,7 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c
uint256 prevkey;
std::map<uint32_t, Coin> outputs;
while (pcursor->Valid()) {
- interruption_point();
+ if (interruption_point) interruption_point();
COutPoint key;
Coin coin;
if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
diff --git a/src/kernel/mempool_entry.h b/src/kernel/mempool_entry.h
index e1ba4296ef..886e1e1b3a 100644
--- a/src/kernel/mempool_entry.h
+++ b/src/kernel/mempool_entry.h
@@ -57,7 +57,7 @@ struct CompareIteratorByHash {
* ("descendant" transactions).
*
* When a new entry is added to the mempool, we update the descendant state
- * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
+ * (m_count_with_descendants, nSizeWithDescendants, and nModFeesWithDescendants) for
* all ancestors of the newly added transaction.
*
*/
@@ -75,7 +75,7 @@ private:
mutable Parents m_parents;
mutable Children m_children;
const CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
- const size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
+ const int32_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
const size_t nUsageSize; //!< ... and total memory usage
const int64_t nTime; //!< Local time when entering the mempool
const unsigned int entryHeight; //!< Chain height when entering the mempool
@@ -87,13 +87,15 @@ private:
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
// descendants as well.
- uint64_t nCountWithDescendants{1}; //!< number of descendant transactions
- uint64_t nSizeWithDescendants; //!< ... and size
+ int64_t m_count_with_descendants{1}; //!< number of descendant transactions
+ // Using int64_t instead of int32_t to avoid signed integer overflow issues.
+ int64_t nSizeWithDescendants; //!< ... and size
CAmount nModFeesWithDescendants; //!< ... and total fees (all including us)
// Analogous statistics for ancestor transactions
- uint64_t nCountWithAncestors{1};
- uint64_t nSizeWithAncestors;
+ int64_t m_count_with_ancestors{1};
+ // Using int64_t instead of int32_t to avoid signed integer overflow issues.
+ int64_t nSizeWithAncestors;
CAmount nModFeesWithAncestors;
int64_t nSigOpCostWithAncestors;
@@ -104,7 +106,7 @@ public:
int64_t sigops_cost, LockPoints lp)
: tx{tx},
nFee{fee},
- nTxWeight(GetTransactionWeight(*tx)),
+ nTxWeight{GetTransactionWeight(*tx)},
nUsageSize{RecursiveDynamicUsage(tx)},
nTime{time},
entryHeight{entry_height},
@@ -121,11 +123,11 @@ public:
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
const CAmount& GetFee() const { return nFee; }
- size_t GetTxSize() const
+ int32_t GetTxSize() const
{
return GetVirtualTransactionSize(nTxWeight, sigOpCost, ::nBytesPerSigOp);
}
- size_t GetTxWeight() const { return nTxWeight; }
+ int32_t GetTxWeight() const { return nTxWeight; }
std::chrono::seconds GetTime() const { return std::chrono::seconds{nTime}; }
unsigned int GetHeight() const { return entryHeight; }
int64_t GetSigOpCost() const { return sigOpCost; }
@@ -134,9 +136,9 @@ public:
const LockPoints& GetLockPoints() const { return lockPoints; }
// Adjusts the descendant state.
- void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+ void UpdateDescendantState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount);
// Adjusts the ancestor state
- void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
+ void UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
// Updates the modified fees with descendants/ancestors.
void UpdateModifiedFee(CAmount fee_diff)
{
@@ -151,14 +153,14 @@ public:
lockPoints = lp;
}
- uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
- uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
+ uint64_t GetCountWithDescendants() const { return m_count_with_descendants; }
+ int64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
- uint64_t GetCountWithAncestors() const { return nCountWithAncestors; }
- uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
+ uint64_t GetCountWithAncestors() const { return m_count_with_ancestors; }
+ int64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
int64_t GetSigOpCostWithAncestors() const { return nSigOpCostWithAncestors; }
diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp
index a14b2e6163..71f3aac366 100644
--- a/src/kernel/mempool_persist.cpp
+++ b/src/kernel/mempool_persist.cpp
@@ -6,7 +6,6 @@
#include <clientversion.h>
#include <consensus/amount.h>
-#include <fs.h>
#include <logging.h>
#include <primitives/transaction.h>
#include <serialize.h>
@@ -15,7 +14,8 @@
#include <sync.h>
#include <txmempool.h>
#include <uint256.h>
-#include <util/system.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/time.h>
#include <validation.h>
diff --git a/src/kernel/mempool_persist.h b/src/kernel/mempool_persist.h
index ca4917e38b..cb09119e4a 100644
--- a/src/kernel/mempool_persist.h
+++ b/src/kernel/mempool_persist.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_KERNEL_MEMPOOL_PERSIST_H
#define BITCOIN_KERNEL_MEMPOOL_PERSIST_H
-#include <fs.h>
+#include <util/fs.h>
class Chainstate;
class CTxMemPool;
diff --git a/src/kernel/notifications_interface.h b/src/kernel/notifications_interface.h
new file mode 100644
index 0000000000..48248e9aa0
--- /dev/null
+++ b/src/kernel/notifications_interface.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2023 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_KERNEL_NOTIFICATIONS_INTERFACE_H
+#define BITCOIN_KERNEL_NOTIFICATIONS_INTERFACE_H
+
+#include <cstdint>
+#include <string>
+
+class CBlockIndex;
+enum class SynchronizationState;
+struct bilingual_str;
+
+namespace kernel {
+
+/**
+ * A base class defining functions for notifying about certain kernel
+ * events.
+ */
+class Notifications
+{
+public:
+ virtual ~Notifications(){};
+
+ virtual void blockTip(SynchronizationState state, CBlockIndex& index) {}
+ virtual void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) {}
+ virtual void progress(const bilingual_str& title, int progress_percent, bool resume_possible) {}
+ virtual void warning(const bilingual_str& warning) {}
+};
+} // namespace kernel
+
+#endif // BITCOIN_KERNEL_NOTIFICATIONS_INTERFACE_H
diff --git a/src/key.cpp b/src/key.cpp
index 3a3f0b2bc2..efaea5b1b3 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -11,6 +11,7 @@
#include <random.h>
#include <secp256k1.h>
+#include <secp256k1_ellswift.h>
#include <secp256k1_extrakeys.h>
#include <secp256k1_recovery.h>
#include <secp256k1_schnorrsig.h>
@@ -331,6 +332,42 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
return ret;
}
+EllSwiftPubKey CKey::EllSwiftCreate(Span<const std::byte> ent32) const
+{
+ assert(fValid);
+ assert(ent32.size() == 32);
+ std::array<std::byte, EllSwiftPubKey::size()> encoded_pubkey;
+
+ auto success = secp256k1_ellswift_create(secp256k1_context_sign,
+ UCharCast(encoded_pubkey.data()),
+ keydata.data(),
+ UCharCast(ent32.data()));
+
+ // Should always succeed for valid keys (asserted above).
+ assert(success);
+ return {encoded_pubkey};
+}
+
+ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, const EllSwiftPubKey& our_ellswift, bool initiating) const
+{
+ assert(fValid);
+
+ ECDHSecret output;
+ // BIP324 uses the initiator as party A, and the responder as party B. Remap the inputs
+ // accordingly:
+ bool success = secp256k1_ellswift_xdh(secp256k1_context_sign,
+ UCharCast(output.data()),
+ UCharCast(initiating ? our_ellswift.data() : their_ellswift.data()),
+ UCharCast(initiating ? their_ellswift.data() : our_ellswift.data()),
+ keydata.data(),
+ initiating ? 0 : 1,
+ secp256k1_ellswift_xdh_hash_function_bip324,
+ nullptr);
+ // Should always succeed for valid keys (assert above).
+ assert(success);
+ return output;
+}
+
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
out.nDepth = nDepth + 1;
diff --git a/src/key.h b/src/key.h
index 4e092fffea..8382b0a670 100644
--- a/src/key.h
+++ b/src/key.h
@@ -22,6 +22,12 @@
*/
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
+/** Size of ECDH shared secrets. */
+constexpr static size_t ECDH_SECRET_SIZE = CSHA256::OUTPUT_SIZE;
+
+// Used to represent ECDH shared secret (ECDH_SECRET_SIZE bytes)
+using ECDHSecret = std::array<std::byte, ECDH_SECRET_SIZE>;
+
/** An encapsulated private key. */
class CKey
{
@@ -156,6 +162,27 @@ public:
//! Load private key and check that public key matches.
bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck);
+
+ /** Create an ellswift-encoded public key for this key, with specified entropy.
+ *
+ * entropy must be a 32-byte span with additional entropy to use in the encoding. Every
+ * public key has ~2^256 different encodings, and this function will deterministically pick
+ * one of them, based on entropy. Note that even without truly random entropy, the
+ * resulting encoding will be indistinguishable from uniform to any adversary who does not
+ * know the private key (because the private key itself is always used as entropy as well).
+ */
+ EllSwiftPubKey EllSwiftCreate(Span<const std::byte> entropy) const;
+
+ /** Compute a BIP324-style ECDH shared secret.
+ *
+ * - their_ellswift: EllSwiftPubKey that was received from the other side.
+ * - our_ellswift: EllSwiftPubKey that was sent to the other side (must have been generated
+ * from *this using EllSwiftCreate()).
+ * - initiating: whether we are the initiating party (true) or responding party (false).
+ */
+ ECDHSecret ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift,
+ const EllSwiftPubKey& our_ellswift,
+ bool initiating) const;
};
struct CExtKey {
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 4659a59544..454a96df5e 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -124,7 +124,11 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
data.clear();
const auto dec = bech32::Decode(str);
- if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0) {
+ if (dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) {
+ if (dec.data.empty()) {
+ error_str = "Empty Bech32 data section";
+ return CNoDestination();
+ }
// Bech32 decoding
if (dec.hrp != params.Bech32HRP()) {
error_str = strprintf("Invalid or unsupported prefix for Segwit (Bech32) address (expected %s, got %s).", params.Bech32HRP(), dec.hrp);
@@ -142,6 +146,9 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
// The rest of the symbols are converted witness program bytes.
data.reserve(((dec.data.size() - 1) * 5) / 8);
if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) {
+
+ std::string_view byte_str{data.size() == 1 ? "byte" : "bytes"};
+
if (version == 0) {
{
WitnessV0KeyHash keyid;
@@ -158,7 +165,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
}
- error_str = "Invalid Bech32 v0 address data size";
+ error_str = strprintf("Invalid Bech32 v0 address program size (%d %s), per BIP141", data.size(), byte_str);
return CNoDestination();
}
@@ -175,7 +182,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) {
- error_str = "Invalid Bech32 address data size";
+ error_str = strprintf("Invalid Bech32 address program size (%d %s)", data.size(), byte_str);
return CNoDestination();
}
@@ -184,6 +191,9 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
std::copy(data.begin(), data.end(), unk.program);
unk.length = data.size();
return unk;
+ } else {
+ error_str = strprintf("Invalid padding in Bech32 data section");
+ return CNoDestination();
}
}
diff --git a/src/logging.cpp b/src/logging.cpp
index a9b2a2b33a..a5cfb0d28e 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <fs.h>
#include <logging.h>
+#include <util/fs.h>
#include <util/string.h>
#include <util/threadnames.h>
#include <util/time.h>
@@ -179,7 +179,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::LOCK, "lock"},
#endif
{BCLog::UTIL, "util"},
- {BCLog::BLOCKSTORE, "blockstorage"},
+ {BCLog::BLOCKSTORAGE, "blockstorage"},
{BCLog::TXRECONCILIATION, "txreconciliation"},
{BCLog::SCAN, "scan"},
{BCLog::ALL, "1"},
@@ -280,7 +280,7 @@ std::string LogCategoryToStr(BCLog::LogFlags category)
#endif
case BCLog::LogFlags::UTIL:
return "util";
- case BCLog::LogFlags::BLOCKSTORE:
+ case BCLog::LogFlags::BLOCKSTORAGE:
return "blockstorage";
case BCLog::LogFlags::TXRECONCILIATION:
return "txreconciliation";
@@ -352,7 +352,7 @@ std::string BCLog::Logger::LogTimestampStr(const std::string& str)
const auto now{SystemClock::now()};
const auto now_seconds{std::chrono::time_point_cast<std::chrono::seconds>(now)};
strStamped = FormatISO8601DateTime(TicksSinceEpoch<std::chrono::seconds>(now_seconds));
- if (m_log_time_micros) {
+ if (m_log_time_micros && !strStamped.empty()) {
strStamped.pop_back();
strStamped += strprintf(".%06dZ", Ticks<std::chrono::microseconds>(now - now_seconds));
}
diff --git a/src/logging.h b/src/logging.h
index 954731d214..fc03c8eac3 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_LOGGING_H
#define BITCOIN_LOGGING_H
-#include <fs.h>
#include <threadsafety.h>
#include <tinyformat.h>
+#include <util/fs.h>
#include <util/string.h>
#include <atomic>
@@ -65,7 +65,7 @@ namespace BCLog {
LOCK = (1 << 24),
#endif
UTIL = (1 << 25),
- BLOCKSTORE = (1 << 26),
+ BLOCKSTORAGE = (1 << 26),
TXRECONCILIATION = (1 << 27),
SCAN = (1 << 28),
ALL = ~(uint32_t)0,
diff --git a/src/mapport.cpp b/src/mapport.cpp
index 994fd12cf5..118827901a 100644
--- a/src/mapport.cpp
+++ b/src/mapport.cpp
@@ -9,12 +9,12 @@
#include <mapport.h>
#include <clientversion.h>
+#include <common/system.h>
#include <logging.h>
#include <net.h>
#include <netaddress.h>
#include <netbase.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/threadinterrupt.h>
@@ -175,10 +175,10 @@ static bool ProcessUpnp()
LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
} else {
if (externalIPAddress[0]) {
- CNetAddr resolved;
- if (LookupHost(externalIPAddress, resolved, false)) {
- LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToStringAddr());
- AddLocal(resolved, LOCAL_MAPPED);
+ std::optional<CNetAddr> resolved{LookupHost(externalIPAddress, false)};
+ if (resolved.has_value()) {
+ LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved->ToStringAddr());
+ AddLocal(resolved.value(), LOCAL_MAPPED);
}
} else {
LogPrintf("UPnP: GetExternalIPAddress failed.\n");
diff --git a/src/memusage.h b/src/memusage.h
index 9755be0ff5..bb39066a7d 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -7,6 +7,7 @@
#include <indirectmap.h>
#include <prevector.h>
+#include <support/allocators/pool.h>
#include <cassert>
#include <cstdlib>
@@ -166,6 +167,25 @@ static inline size_t DynamicUsage(const std::unordered_map<X, Y, Z>& m)
return MallocUsage(sizeof(unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
}
+template <class Key, class T, class Hash, class Pred, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+static inline size_t DynamicUsage(const std::unordered_map<Key,
+ T,
+ Hash,
+ Pred,
+ PoolAllocator<std::pair<const Key, T>,
+ MAX_BLOCK_SIZE_BYTES,
+ ALIGN_BYTES>>& m)
+{
+ auto* pool_resource = m.get_allocator().resource();
+
+ // The allocated chunks are stored in a std::list. Size per node should
+ // therefore be 3 pointers: next, previous, and a pointer to the chunk.
+ size_t estimated_list_node_size = MallocUsage(sizeof(void*) * 3);
+ size_t usage_resource = estimated_list_node_size * pool_resource->NumAllocatedChunks();
+ size_t usage_chunks = MallocUsage(pool_resource->ChunkSizeBytes()) * pool_resource->NumAllocatedChunks();
+ return usage_resource + usage_chunks + MallocUsage(sizeof(void*) * m.bucket_count());
}
+} // namespace memusage
+
#endif // BITCOIN_MEMUSAGE_H
diff --git a/src/net.cpp b/src/net.cpp
index 59a84f2fdf..a96ffcfbe9 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -13,10 +13,10 @@
#include <addrman.h>
#include <banman.h>
#include <clientversion.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
-#include <fs.h>
#include <i2p.h>
#include <logging.h>
#include <net_permissions.h>
@@ -27,10 +27,10 @@
#include <protocol.h>
#include <random.h>
#include <scheduler.h>
+#include <util/fs.h>
#include <util/sock.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/threadinterrupt.h>
#include <util/trace.h>
@@ -130,14 +130,10 @@ uint16_t GetListenPort()
{
// If -bind= is provided with ":port" part, use that (first one if multiple are provided).
for (const std::string& bind_arg : gArgs.GetArgs("-bind")) {
- CService bind_addr;
constexpr uint16_t dummy_port = 0;
- if (Lookup(bind_arg, bind_addr, dummy_port, /*fAllowLookup=*/false)) {
- if (bind_addr.GetPort() != dummy_port) {
- return bind_addr.GetPort();
- }
- }
+ const std::optional<CService> bind_addr{Lookup(bind_arg, dummy_port, /*fAllowLookup=*/false)};
+ if (bind_addr.has_value() && bind_addr->GetPort() != dummy_port) return bind_addr->GetPort();
}
// Otherwise, if -whitebind= without NetPermissionFlags::NoBan is provided, use that
@@ -461,9 +457,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
Params().GetDefaultPort()};
if (pszDest) {
- std::vector<CService> resolved;
- if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
- const CService rnd{resolved[GetRand(resolved.size())]};
+ const std::vector<CService> resolved{Lookup(pszDest, default_port, fNameLookup && !HaveNameProxy(), 256)};
+ if (!resolved.empty()) {
+ const CService& rnd{resolved[GetRand(resolved.size())]};
addrConnect = CAddress{MaybeFlipIPv6toCJDNS(rnd), NODE_NONE};
if (!addrConnect.IsValid()) {
LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToStringAddrPort(), pszDest);
@@ -573,7 +569,10 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
pszDest ? pszDest : "",
conn_type,
/*inbound_onion=*/false,
- CNodeOptions{ .i2p_sam_session = std::move(i2p_transient_session) });
+ CNodeOptions{
+ .i2p_sam_session = std::move(i2p_transient_session),
+ .recv_flood_size = nReceiveFloodSize,
+ });
pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count)
@@ -917,7 +916,7 @@ bool CConnman::AttemptToEvictConnection()
.m_is_local = node->addr.IsLocal(),
.m_network = node->ConnectedThroughNetwork(),
.m_noban = node->HasPermission(NetPermissionFlags::NoBan),
- .m_conn_type = node->GetConnectionType(),
+ .m_conn_type = node->m_conn_type,
};
vEvictionCandidates.push_back(candidate);
}
@@ -1051,8 +1050,9 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
ConnectionType::INBOUND,
inbound_onion,
CNodeOptions{
- .permission_flags = permission_flags,
- .prefer_evict = discouraged,
+ .permission_flags = permission_flags,
+ .prefer_evict = discouraged,
+ .recv_flood_size = nReceiveFloodSize,
});
pnode->AddRef();
m_msgproc->InitializeNode(*pnode, nodeServices);
@@ -1092,7 +1092,7 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
// Count existing connections
int existing_connections = WITH_LOCK(m_nodes_mutex,
- return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->GetConnectionType() == conn_type; }););
+ 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;
@@ -1328,7 +1328,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
}
RecordBytesRecv(nBytes);
if (notify) {
- pnode->MarkReceivedMsgsForProcessing(nReceiveFloodSize);
+ pnode->MarkReceivedMsgsForProcessing();
WakeMessageHandler();
}
}
@@ -1483,7 +1483,6 @@ void CConnman::ThreadDNSAddressSeed()
if (HaveNameProxy()) {
AddAddrFetch(seed);
} else {
- std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE);
std::string host = strprintf("x%x.%s", requiredServiceBits, seed);
@@ -1492,8 +1491,9 @@ void CConnman::ThreadDNSAddressSeed()
continue;
}
unsigned int nMaxIPs = 256; // Limits number of IPs learned from a DNS seed
- if (LookupHost(host, vIPs, nMaxIPs, true)) {
- for (const CNetAddr& ip : vIPs) {
+ const auto addresses{LookupHost(host, nMaxIPs, true)};
+ if (!addresses.empty()) {
+ for (const CNetAddr& ip : addresses) {
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
vAdd.push_back(addr);
@@ -1637,6 +1637,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
+ const bool use_seednodes{gArgs.IsArgSet("-seednode")};
if (!add_fixed_seeds) {
LogPrintf("Fixed seeds are disabled\n");
@@ -1666,12 +1667,12 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n");
}
- // Checking !dnsseed is cheaper before locking 2 mutexes.
- if (!add_fixed_seeds_now && !dnsseed) {
- LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex);
- if (m_addr_fetches.empty() && m_added_nodes.empty()) {
+ // Perform cheap checks before locking a mutex.
+ else if (!dnsseed && !use_seednodes) {
+ LOCK(m_added_nodes_mutex);
+ if (m_added_nodes.empty()) {
add_fixed_seeds_now = true;
- LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n");
+ LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n");
}
}
@@ -1699,10 +1700,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
//
CAddress addrConnect;
- // Only connect out to one peer per network group (/16 for IPv4).
+ // Only connect out to one peer per ipv4/ipv6 network group (/16 for IPv4).
int nOutboundFullRelay = 0;
int nOutboundBlockRelay = 0;
- std::set<std::vector<unsigned char> > setConnected;
+ int outbound_privacy_network_peers = 0;
+ std::set<std::vector<unsigned char>> outbound_ipv46_peer_netgroups;
{
LOCK(m_nodes_mutex);
@@ -1710,8 +1712,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
- // Make sure our persistent outbound slots belong to different netgroups.
- switch (pnode->GetConnectionType()) {
+ // Make sure our persistent outbound slots to ipv4/ipv6 peers belong to different netgroups.
+ switch (pnode->m_conn_type) {
// We currently don't take inbound connections into account. Since they are
// free to make, an attacker could make them to prevent us from connecting to
// certain peers.
@@ -1724,7 +1726,19 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
case ConnectionType::MANUAL:
case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
- setConnected.insert(m_netgroupman.GetGroup(pnode->addr));
+ const CAddress address{pnode->addr};
+ if (address.IsTor() || address.IsI2P() || address.IsCJDNS()) {
+ // Since our addrman-groups for these networks are
+ // random, without relation to the route we
+ // take to connect to these peers or to the
+ // difficulty in obtaining addresses with diverse
+ // groups, we don't worry about diversity with
+ // respect to our addrman groups when connecting to
+ // these networks.
+ ++outbound_privacy_network_peers;
+ } else {
+ outbound_ipv46_peer_netgroups.insert(m_netgroupman.GetGroup(address));
+ }
} // no default case, so the compiler can warn about missing cases
}
}
@@ -1798,7 +1812,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
m_anchors.pop_back();
if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) ||
!HasAllDesirableServiceFlags(addr.nServices) ||
- setConnected.count(m_netgroupman.GetGroup(addr))) continue;
+ outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue;
addrConnect = addr;
LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort());
break;
@@ -1838,8 +1852,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
std::tie(addr, addr_last_try) = addrman.Select();
}
- // Require outbound connections, other than feelers, to be to distinct network groups
- if (!fFeeler && setConnected.count(m_netgroupman.GetGroup(addr))) {
+ // Require outbound IPv4/IPv6 connections, other than feelers, to be to distinct network groups
+ if (!fFeeler && outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) {
break;
}
@@ -1882,8 +1896,12 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort());
}
-
- OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, conn_type);
+ // Record addrman failure attempts when node has at least 2 persistent outbound connections to peers with
+ // different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks.
+ // Don't record addrman failure attempts when node is offline. This can be identified since all local
+ // network connections (if any) belong in the same netgroup, and the size of `outbound_ipv46_peer_netgroups` would only be 1.
+ const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(nMaxConnections - 1, 2)};
+ OpenNetworkConnection(addrConnect, count_failures, &grant, /*strDest=*/nullptr, conn_type);
}
}
}
@@ -2181,14 +2199,11 @@ void Discover()
char pszHostName[256] = "";
if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
{
- std::vector<CNetAddr> vaddr;
- if (LookupHost(pszHostName, vaddr, 0, true))
+ const std::vector<CNetAddr> addresses{LookupHost(pszHostName, 0, true)};
+ for (const CNetAddr& addr : addresses)
{
- for (const CNetAddr &addr : vaddr)
- {
- if (AddLocal(addr, LOCAL_IF))
- LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToStringAddr());
- }
+ if (AddLocal(addr, LOCAL_IF))
+ LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToStringAddr());
}
}
#elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS)
@@ -2594,6 +2609,11 @@ size_t CConnman::GetNodeCount(ConnectionDirection flags) const
return nNum;
}
+uint32_t CConnman::GetMappedAS(const CNetAddr& addr) const
+{
+ return m_netgroupman.GetMappedAS(addr);
+}
+
void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
{
vstats.clear();
@@ -2602,7 +2622,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
for (CNode* pnode : m_nodes) {
vstats.emplace_back();
pnode->CopyStats(vstats.back());
- vstats.back().m_mapped_as = m_netgroupman.GetMappedAS(pnode->addr);
+ vstats.back().m_mapped_as = GetMappedAS(pnode->addr);
}
}
@@ -2754,8 +2774,6 @@ ServiceFlags CConnman::GetLocalServices() const
return nLocalServices;
}
-unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-
CNode::CNode(NodeId idIn,
std::shared_ptr<Sock> sock,
const CAddress& addrIn,
@@ -2777,9 +2795,10 @@ CNode::CNode(NodeId idIn,
m_inbound_onion{inbound_onion},
m_prefer_evict{node_opts.prefer_evict},
nKeyedNetGroup{nKeyedNetGroupIn},
+ m_conn_type{conn_type_in},
id{idIn},
nLocalHostNonce{nLocalHostNonceIn},
- m_conn_type{conn_type_in},
+ m_recv_flood_size{node_opts.recv_flood_size},
m_i2p_sam_session{std::move(node_opts.i2p_sam_session)}
{
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
@@ -2795,7 +2814,7 @@ CNode::CNode(NodeId idIn,
}
}
-void CNode::MarkReceivedMsgsForProcessing(unsigned int recv_flood_size)
+void CNode::MarkReceivedMsgsForProcessing()
{
AssertLockNotHeld(m_msg_process_queue_mutex);
@@ -2809,10 +2828,10 @@ void CNode::MarkReceivedMsgsForProcessing(unsigned int recv_flood_size)
LOCK(m_msg_process_queue_mutex);
m_msg_process_queue.splice(m_msg_process_queue.end(), vRecvMsg);
m_msg_process_queue_size += nSizeAdded;
- fPauseRecv = m_msg_process_queue_size > recv_flood_size;
+ fPauseRecv = m_msg_process_queue_size > m_recv_flood_size;
}
-std::optional<std::pair<CNetMessage, bool>> CNode::PollMessage(size_t recv_flood_size)
+std::optional<std::pair<CNetMessage, bool>> CNode::PollMessage()
{
LOCK(m_msg_process_queue_mutex);
if (m_msg_process_queue.empty()) return std::nullopt;
@@ -2821,7 +2840,7 @@ std::optional<std::pair<CNetMessage, bool>> CNode::PollMessage(size_t recv_flood
// Just take one message
msgs.splice(msgs.begin(), m_msg_process_queue, m_msg_process_queue.begin());
m_msg_process_queue_size -= msgs.front().m_raw_message_size;
- fPauseRecv = m_msg_process_queue_size > recv_flood_size;
+ fPauseRecv = m_msg_process_queue_size > m_recv_flood_size;
return std::make_pair(std::move(msgs.front()), !m_msg_process_queue.empty());
}
diff --git a/src/net.h b/src/net.h
index 7bb164003e..811007ebee 100644
--- a/src/net.h
+++ b/src/net.h
@@ -200,7 +200,9 @@ public:
int nVersion;
std::string cleanSubVer;
bool fInbound;
+ // We requested high bandwidth connection to peer
bool m_bip152_highbandwidth_to;
+ // Peer requested high bandwidth connection
bool m_bip152_highbandwidth_from;
int m_starting_height;
uint64_t nSendBytes;
@@ -236,6 +238,14 @@ public:
std::string m_type;
CNetMessage(CDataStream&& recv_in) : m_recv(std::move(recv_in)) {}
+ // Only one CNetMessage object will exist for the same message on either
+ // the receive or processing queue. For performance reasons we therefore
+ // delete the copy constructor and assignment operator to avoid the
+ // possibility of copying CNetMessage objects.
+ CNetMessage(CNetMessage&&) = default;
+ CNetMessage(const CNetMessage&) = delete;
+ CNetMessage& operator=(CNetMessage&&) = default;
+ CNetMessage& operator=(const CNetMessage&) = delete;
void SetVersion(int nVersionIn)
{
@@ -342,6 +352,7 @@ struct CNodeOptions
NetPermissionFlags permission_flags = NetPermissionFlags::None;
std::unique_ptr<i2p::sam::Session> i2p_sam_session = nullptr;
bool prefer_evict = false;
+ size_t recv_flood_size{DEFAULT_MAXRECEIVEBUFFER * 1000};
};
/** Information about a peer */
@@ -410,13 +421,10 @@ public:
std::atomic_bool fPauseRecv{false};
std::atomic_bool fPauseSend{false};
- const ConnectionType& GetConnectionType() const
- {
- return m_conn_type;
- }
+ const ConnectionType m_conn_type;
/** Move all messages from the received queue to the processing queue. */
- void MarkReceivedMsgsForProcessing(unsigned int recv_flood_size)
+ void MarkReceivedMsgsForProcessing()
EXCLUSIVE_LOCKS_REQUIRED(!m_msg_process_queue_mutex);
/** Poll the next message from the processing queue of this connection.
@@ -424,7 +432,7 @@ public:
* Returns std::nullopt if the processing queue is empty, or a pair
* consisting of the message and a bool that indicates if the processing
* queue has more entries. */
- std::optional<std::pair<CNetMessage, bool>> PollMessage(size_t recv_flood_size)
+ std::optional<std::pair<CNetMessage, bool>> PollMessage()
EXCLUSIVE_LOCKS_REQUIRED(!m_msg_process_queue_mutex);
/** Account for the total size of a sent message in the per msg type connection stats. */
@@ -614,9 +622,9 @@ public:
private:
const NodeId id;
const uint64_t nLocalHostNonce;
- const ConnectionType m_conn_type;
std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
+ const size_t m_recv_flood_size;
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
Mutex m_msg_process_queue_mutex;
@@ -845,6 +853,7 @@ public:
bool AddConnection(const std::string& address, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
size_t GetNodeCount(ConnectionDirection) const;
+ uint32_t GetMappedAS(const CNetAddr& addr) const;
void GetNodeStats(std::vector<CNodeStats>& vstats) const;
bool DisconnectNode(const std::string& node);
bool DisconnectNode(const CSubNet& subnet);
@@ -879,8 +888,6 @@ public:
/** Get a unique deterministic randomizer. */
CSipHasher GetDeterministicRandomizer(uint64_t id) const;
- unsigned int GetReceiveFloodSize() const;
-
void WakeMessageHandler() EXCLUSIVE_LOCKS_REQUIRED(!mutexMsgProc);
/** Return true if we should disconnect the peer for failing an inactivity check. */
@@ -1212,7 +1219,6 @@ private:
std::vector<CNode*> m_nodes_copy;
};
- friend struct CConnmanTest;
friend struct ConnmanTestMsg;
};
diff --git a/src/net_permissions.cpp b/src/net_permissions.cpp
index f829e56aa2..23226bbb4f 100644
--- a/src/net_permissions.cpp
+++ b/src/net_permissions.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <net_permissions.h>
#include <netbase.h>
#include <util/error.h>
-#include <util/system.h>
#include <util/translation.h>
const std::vector<std::string> NET_PERMISSIONS_DOC{
@@ -88,18 +88,18 @@ bool NetWhitebindPermissions::TryParse(const std::string& str, NetWhitebindPermi
if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
const std::string strBind = str.substr(offset);
- CService addrBind;
- if (!Lookup(strBind, addrBind, 0, false)) {
+ const std::optional<CService> addrBind{Lookup(strBind, 0, false)};
+ if (!addrBind.has_value()) {
error = ResolveErrMsg("whitebind", strBind);
return false;
}
- if (addrBind.GetPort() == 0) {
+ if (addrBind.value().GetPort() == 0) {
error = strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind);
return false;
}
output.m_flags = flags;
- output.m_service = addrBind;
+ output.m_service = addrBind.value();
error = Untranslated("");
return true;
}
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 3df5374e21..8da2c701d3 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -10,6 +10,7 @@
#include <blockencodings.h>
#include <blockfilter.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <deploymentstatus.h>
@@ -39,7 +40,6 @@
#include <txrequest.h>
#include <util/check.h> // For NDEBUG compile time check
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/trace.h>
#include <validation.h>
@@ -51,12 +51,7 @@
#include <optional>
#include <typeinfo>
-using node::ReadBlockFromDisk;
-using node::ReadRawBlockFromDisk;
-
-/** How long to cache transactions in mapRelay for normal relay */
-static constexpr auto RELAY_TX_CACHE_TIME = 15min;
-/** How long a transaction has to be in the mempool before it can unconditionally be relayed (even when not in mapRelay). */
+/** How long a transaction has to be in the mempool before it can unconditionally be relayed. */
static constexpr auto UNCONDITIONAL_RELAY_DELAY = 2min;
/** Headers download timeout.
* Timeout = base + per_header * (expected number of headers) */
@@ -135,7 +130,7 @@ static constexpr double BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 0.5;
/** Maximum number of headers to announce when relaying blocks with headers message.*/
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
/** Maximum number of unconnecting headers announcements before DoS score */
-static const int MAX_UNCONNECTING_HEADERS = 10;
+static const int MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10;
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
/** Average delay between local address broadcasts */
@@ -278,6 +273,9 @@ struct Peer {
/** A bloom filter for which transactions to announce to the peer. See BIP37. */
std::unique_ptr<CBloomFilter> m_bloom_filter PT_GUARDED_BY(m_bloom_filter_mutex) GUARDED_BY(m_bloom_filter_mutex){nullptr};
+ /** A rolling bloom filter of all announced tx CInvs to this peer */
+ CRollingBloomFilter m_recently_announced_invs GUARDED_BY(NetEventsInterface::g_msgproc_mutex){INVENTORY_MAX_RECENT_RELAY, 0.000001};
+
mutable RecursiveMutex m_tx_inventory_mutex;
/** A filter of all the txids and wtxids that the peer has announced to
* us or we have announced to the peer. We use this to avoid announcing
@@ -289,7 +287,8 @@ struct Peer {
* this does not have to be sorted. */
std::set<uint256> m_tx_inventory_to_send GUARDED_BY(m_tx_inventory_mutex);
/** Whether the peer has requested us to send our complete mempool. Only
- * permitted if the peer has NetPermissionFlags::Mempool. See BIP35. */
+ * permitted if the peer has NetPermissionFlags::Mempool or we advertise
+ * NODE_BLOOM. See BIP35. */
bool m_send_mempool GUARDED_BY(m_tx_inventory_mutex){false};
/** The last time a BIP35 `mempool` request was serviced. */
std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
@@ -385,13 +384,22 @@ struct Peer {
/** Whether we've sent our peer a sendheaders message. **/
std::atomic<bool> m_sent_sendheaders{false};
+ /** Length of current-streak of unconnecting headers announcements */
+ int m_num_unconnecting_headers_msgs GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0};
+
+ /** When to potentially disconnect peer for stalling headers download */
+ std::chrono::microseconds m_headers_sync_timeout GUARDED_BY(NetEventsInterface::g_msgproc_mutex){0us};
+
+ /** Whether this peer wants invs or headers (when possible) for block announcements */
+ bool m_prefers_headers GUARDED_BY(NetEventsInterface::g_msgproc_mutex){false};
+
explicit Peer(NodeId id, ServiceFlags our_services)
: m_id{id}
, m_our_services{our_services}
{}
private:
- Mutex m_tx_relay_mutex;
+ mutable Mutex m_tx_relay_mutex;
/** Transaction relay data. May be a nullptr. */
std::unique_ptr<TxRelay> m_tx_relay GUARDED_BY(m_tx_relay_mutex);
@@ -414,22 +422,15 @@ struct CNodeState {
const CBlockIndex* pindexLastCommonBlock{nullptr};
//! The best header we have sent our peer.
const CBlockIndex* pindexBestHeaderSent{nullptr};
- //! Length of current-streak of unconnecting headers announcements
- int nUnconnectingHeaders{0};
//! Whether we've started headers synchronization with this peer.
bool fSyncStarted{false};
- //! When to potentially disconnect peer for stalling headers download
- std::chrono::microseconds m_headers_sync_timeout{0us};
//! Since when we're stalling block download progress (in microseconds), or 0.
std::chrono::microseconds m_stalling_since{0us};
std::list<QueuedBlock> vBlocksInFlight;
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
std::chrono::microseconds m_downloading_since{0us};
- int nBlocksInFlight{0};
//! Whether we consider this a preferred download peer.
bool fPreferredDownload{false};
- //! Whether this peer wants invs or headers (when possible) for block announcements.
- bool fPreferHeaders{false};
/** Whether this peer wants invs or cmpctblocks (when possible) for block announcements. */
bool m_requested_hb_cmpctblocks{false};
/** Whether this peer will send us cmpctblocks if we request them. */
@@ -478,9 +479,6 @@ struct CNodeState {
//! Whether this peer is an inbound connection
const bool m_is_inbound;
- //! A rolling bloom filter of all announced tx CInvs to this peer.
- CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001};
-
CNodeState(bool is_inbound) : m_is_inbound(is_inbound) {}
};
@@ -570,7 +568,7 @@ private:
*
* @return Returns true if the peer was punished (probably disconnected)
*/
- bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "")
+ bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state)
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
/** Maybe disconnect a peer and discourage future connections from its address.
@@ -666,7 +664,8 @@ private:
/** Potentially fetch blocks from this peer upon receipt of a new headers tip */
void HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex& last_header);
/** Update peer state based on received headers message */
- void UpdatePeerStateForReceivedHeaders(CNode& pfrom, const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers);
+ void UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer, const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers)
+ EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
void SendBlockTransactions(CNode& pfrom, Peer& peer, const CBlock& block, const BlockTransactionsRequest& req);
@@ -850,6 +849,7 @@ private:
std::shared_ptr<const CBlock> m_most_recent_block GUARDED_BY(m_most_recent_block_mutex);
std::shared_ptr<const CBlockHeaderAndShortTxIDs> m_most_recent_compact_block GUARDED_BY(m_most_recent_block_mutex);
uint256 m_most_recent_block_hash GUARDED_BY(m_most_recent_block_mutex);
+ std::unique_ptr<const std::map<uint256, CTransactionRef>> m_most_recent_block_txs GUARDED_BY(m_most_recent_block_mutex);
// Data about the low-work headers synchronization, aggregated from all peers' HeadersSyncStates.
/** Mutex guarding the other m_headers_presync_* variables. */
@@ -875,11 +875,17 @@ private:
/** Have we requested this block from a peer */
bool IsBlockRequested(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /** Have we requested this block from an outbound peer */
+ bool IsBlockRequestedFromOutbound(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
/** Remove this block from our tracked requested blocks. Called if:
* - the block has been received from a peer
* - the request for the block has timed out
+ * If "from_peer" is specified, then only remove the block if it is in
+ * flight from that peer (to avoid one peer's network traffic from
+ * affecting another's state).
*/
- void RemoveBlockRequest(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/* Mark a block as in flight
* Returns false, still setting pit, if the block was already in flight from the same peer
@@ -894,25 +900,27 @@ private:
*/
void FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight GUARDED_BY(cs_main);
+ /* Multimap used to preserve insertion order */
+ typedef std::multimap<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator>> BlockDownloadMap;
+ BlockDownloadMap mapBlocksInFlight GUARDED_BY(cs_main);
/** When our tip was last updated. */
std::atomic<std::chrono::seconds> m_last_tip_update{0s};
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
- CTransactionRef FindTxForGetData(const CNode& peer, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main);
+ CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, NetEventsInterface::g_msgproc_mutex);
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc)
- EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex) LOCKS_EXCLUDED(::cs_main);
+ EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex, NetEventsInterface::g_msgproc_mutex)
+ LOCKS_EXCLUDED(::cs_main);
/** Process a new block. Perform any post-processing housekeeping */
void ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked);
- /** Relay map (txid or wtxid -> CTransactionRef) */
- typedef std::map<uint256, CTransactionRef> MapRelay;
- MapRelay mapRelay GUARDED_BY(cs_main);
- /** Expiration-time ordered list of (expire time, relay map entry) pairs. */
- std::deque<std::pair<std::chrono::microseconds, MapRelay::iterator>> g_relay_expiration GUARDED_BY(cs_main);
+ /** Process compact block txns */
+ void ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)
+ EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex, !m_most_recent_block_mutex);
/**
* When a peer sends us a valid block, instruct it to announce blocks to us
@@ -1110,34 +1118,55 @@ std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::micros
bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
{
- return mapBlocksInFlight.find(hash) != mapBlocksInFlight.end();
+ return mapBlocksInFlight.count(hash);
}
-void PeerManagerImpl::RemoveBlockRequest(const uint256& hash)
+bool PeerManagerImpl::IsBlockRequestedFromOutbound(const uint256& hash)
{
- auto it = mapBlocksInFlight.find(hash);
- if (it == mapBlocksInFlight.end()) {
- // Block was not requested
- return;
+ for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
+ auto [nodeid, block_it] = range.first->second;
+ CNodeState& nodestate = *Assert(State(nodeid));
+ if (!nodestate.m_is_inbound) return true;
}
- auto [node_id, list_it] = it->second;
- CNodeState *state = State(node_id);
- assert(state != nullptr);
+ return false;
+}
- if (state->vBlocksInFlight.begin() == list_it) {
- // First block on the queue was received, update the start download time for the next one
- state->m_downloading_since = std::max(state->m_downloading_since, GetTime<std::chrono::microseconds>());
+void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)
+{
+ auto range = mapBlocksInFlight.equal_range(hash);
+ if (range.first == range.second) {
+ // Block was not requested from any peer
+ return;
}
- state->vBlocksInFlight.erase(list_it);
- state->nBlocksInFlight--;
- if (state->nBlocksInFlight == 0) {
- // Last validated block on the queue was received.
- m_peers_downloading_from--;
+ // We should not have requested too many of this block
+ Assume(mapBlocksInFlight.count(hash) <= MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK);
+
+ while (range.first != range.second) {
+ auto [node_id, list_it] = range.first->second;
+
+ if (from_peer && *from_peer != node_id) {
+ range.first++;
+ continue;
+ }
+
+ CNodeState& state = *Assert(State(node_id));
+
+ if (state.vBlocksInFlight.begin() == list_it) {
+ // First block on the queue was received, update the start download time for the next one
+ state.m_downloading_since = std::max(state.m_downloading_since, GetTime<std::chrono::microseconds>());
+ }
+ state.vBlocksInFlight.erase(list_it);
+
+ if (state.vBlocksInFlight.empty()) {
+ // Last validated block on the queue for this peer was received.
+ m_peers_downloading_from--;
+ }
+ state.m_stalling_since = 0us;
+
+ range.first = mapBlocksInFlight.erase(range.first);
}
- state->m_stalling_since = 0us;
- mapBlocksInFlight.erase(it);
}
bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, std::list<QueuedBlock>::iterator** pit)
@@ -1147,27 +1176,29 @@ bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, st
CNodeState *state = State(nodeid);
assert(state != nullptr);
+ Assume(mapBlocksInFlight.count(hash) <= MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK);
+
// Short-circuit most stuff in case it is from the same node
- std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
- if (itInFlight != mapBlocksInFlight.end() && itInFlight->second.first == nodeid) {
- if (pit) {
- *pit = &itInFlight->second.second;
+ for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
+ if (range.first->second.first == nodeid) {
+ if (pit) {
+ *pit = &range.first->second.second;
+ }
+ return false;
}
- return false;
}
- // Make sure it's not listed somewhere already.
- RemoveBlockRequest(hash);
+ // Make sure it's not being fetched already from same peer.
+ RemoveBlockRequest(hash, nodeid);
std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
{&block, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&m_mempool) : nullptr)});
- state->nBlocksInFlight++;
- if (state->nBlocksInFlight == 1) {
+ if (state->vBlocksInFlight.size() == 1) {
// We're starting a block download (batch) from this peer.
state->m_downloading_since = GetTime<std::chrono::microseconds>();
m_peers_downloading_from++;
}
- itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first;
+ auto itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it)));
if (pit) {
*pit = &itInFlight->second.second;
}
@@ -1370,7 +1401,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co
}
} else if (waitingfor == -1) {
// This is the first already-in-flight block.
- waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first;
+ waitingfor = mapBlocksInFlight.lower_bound(pindex->GetBlockHash())->second.first;
}
}
}
@@ -1500,13 +1531,21 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
nSyncStarted--;
for (const QueuedBlock& entry : state->vBlocksInFlight) {
- mapBlocksInFlight.erase(entry.pindex->GetBlockHash());
+ auto range = mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());
+ while (range.first != range.second) {
+ auto [node_id, list_it] = range.first->second;
+ if (node_id != nodeid) {
+ range.first++;
+ } else {
+ range.first = mapBlocksInFlight.erase(range.first);
+ }
+ }
}
m_orphanage.EraseForPeer(nodeid);
m_txrequest.DisconnectedPeer(nodeid);
if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid);
m_num_preferred_download_peers -= state->fPreferredDownload;
- m_peers_downloading_from -= (state->nBlocksInFlight != 0);
+ m_peers_downloading_from -= (!state->vBlocksInFlight.empty());
assert(m_peers_downloading_from >= 0);
m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
assert(m_outbound_peers_with_protect_from_disconnect >= 0);
@@ -1696,7 +1735,7 @@ bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
return false;
}
-bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
+bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state)
{
PeerRef peer{GetPeerRef(nodeid)};
switch (state.GetResult()) {
@@ -1704,7 +1743,7 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
break;
// The node is providing invalid data:
case TxValidationResult::TX_CONSENSUS:
- if (peer) Misbehaving(*peer, 100, message);
+ if (peer) Misbehaving(*peer, 100, "");
return true;
// Conflicting (but not necessarily invalid) data or different policy:
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
@@ -1719,9 +1758,6 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
case TxValidationResult::TX_NO_MEMPOOL:
break;
}
- if (message != "") {
- LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
- }
return false;
}
@@ -1747,11 +1783,10 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
LOCK(cs_main);
- // Mark block as in-flight unless it already is (for this peer).
- // If the peer does not send us a block, vBlocksInFlight remains non-empty,
- // causing us to timeout and disconnect.
- // If a block was already in-flight for a different peer, its BLOCKTXN
- // response will be dropped.
+ // Forget about all prior requests
+ RemoveBlockRequest(block_index.GetBlockHash(), std::nullopt);
+
+ // Mark block as in-flight
if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer";
// Construct message to request the block
@@ -1886,10 +1921,17 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
std::async(std::launch::deferred, [&] { return msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })};
{
+ auto most_recent_block_txs = std::make_unique<std::map<uint256, CTransactionRef>>();
+ for (const auto& tx : pblock->vtx) {
+ most_recent_block_txs->emplace(tx->GetHash(), tx);
+ most_recent_block_txs->emplace(tx->GetWitnessHash(), tx);
+ }
+
LOCK(m_most_recent_block_mutex);
m_most_recent_block_hash = hashBlock;
m_most_recent_block = pblock;
m_most_recent_compact_block = pcmpctblock;
+ m_most_recent_block_txs = std::move(most_recent_block_txs);
}
m_connman.ForEachNode([this, pindex, &lazy_ser, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
@@ -2173,7 +2215,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
// Fast-path: in this case it is possible to serve the block directly from disk,
// as the network format matches the format on disk
std::vector<uint8_t> block_data;
- if (!ReadRawBlockFromDisk(block_data, pindex->GetBlockPos(), m_chainparams.MessageStart())) {
+ if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, pindex->GetBlockPos(), m_chainparams.MessageStart())) {
assert(!"cannot load block from disk");
}
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, Span{block_data}));
@@ -2181,7 +2223,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
} else {
// Send block from disk
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
- if (!ReadBlockFromDisk(*pblockRead, pindex, m_chainparams.GetConsensus())) {
+ if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, *pindex)) {
assert(!"cannot load block from disk");
}
pblock = pblockRead;
@@ -2248,7 +2290,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
}
}
-CTransactionRef PeerManagerImpl::FindTxForGetData(const CNode& peer, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now)
+CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now)
{
auto txinfo = m_mempool.info(gtxid);
if (txinfo.tx) {
@@ -2260,15 +2302,16 @@ CTransactionRef PeerManagerImpl::FindTxForGetData(const CNode& peer, const GenTx
}
}
+ // Otherwise, the transaction might have been announced recently.
+ bool recent = tx_relay.m_recently_announced_invs.contains(gtxid.GetHash());
+ if (recent && txinfo.tx) return std::move(txinfo.tx);
+
+ // Or it might be from the most recent block
{
- LOCK(cs_main);
- // Otherwise, the transaction must have been announced recently.
- if (State(peer.GetId())->m_recently_announced_invs.contains(gtxid.GetHash())) {
- // If it was, it can be relayed from either the mempool...
- if (txinfo.tx) return std::move(txinfo.tx);
- // ... or the relay pool.
- auto mi = mapRelay.find(gtxid.GetHash());
- if (mi != mapRelay.end()) return mi->second;
+ LOCK(m_most_recent_block_mutex);
+ if (m_most_recent_block_txs != nullptr) {
+ auto it = m_most_recent_block_txs->find(gtxid.GetHash());
+ if (it != m_most_recent_block_txs->end()) return it->second;
}
}
@@ -2306,7 +2349,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
continue;
}
- CTransactionRef tx = FindTxForGetData(pfrom, ToGenTxid(inv), mempool_req, now);
+ CTransactionRef tx = FindTxForGetData(*tx_relay, ToGenTxid(inv), mempool_req, now);
if (tx) {
// WTX and WITNESS_TX imply we serialize with witness
int nSendFlags = (inv.IsMsgTx() ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
@@ -2330,8 +2373,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
for (const uint256& parent_txid : parent_ids_to_add) {
// Relaying a transaction with a recent but unconfirmed parent.
if (WITH_LOCK(tx_relay->m_tx_inventory_mutex, return !tx_relay->m_tx_inventory_known_filter.contains(parent_txid))) {
- LOCK(cs_main);
- State(pfrom.GetId())->m_recently_announced_invs.insert(parent_txid);
+ tx_relay->m_recently_announced_invs.insert(parent_txid);
}
}
} else {
@@ -2430,38 +2472,35 @@ arith_uint256 PeerManagerImpl::GetAntiDoSWorkThreshold()
*
* We'll send a getheaders message in response to try to connect the chain.
*
- * The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
+ * The peer can send up to MAX_NUM_UNCONNECTING_HEADERS_MSGS in a row that
* don't connect before given DoS points.
*
* Once a headers message is received that is valid and does connect,
- * nUnconnectingHeaders gets reset back to 0.
+ * m_num_unconnecting_headers_msgs gets reset back to 0.
*/
void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
const std::vector<CBlockHeader>& headers)
{
- const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
-
- LOCK(cs_main);
- CNodeState *nodestate = State(pfrom.GetId());
-
- nodestate->nUnconnectingHeaders++;
+ peer.m_num_unconnecting_headers_msgs++;
// Try to fill in the missing headers.
- if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), peer)) {
- LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
+ const CBlockIndex* best_header{WITH_LOCK(cs_main, return m_chainman.m_best_header)};
+ if (MaybeSendGetHeaders(pfrom, GetLocator(best_header), peer)) {
+ LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, m_num_unconnecting_headers_msgs=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
- m_chainman.m_best_header->nHeight,
- pfrom.GetId(), nodestate->nUnconnectingHeaders);
+ best_header->nHeight,
+ pfrom.GetId(), peer.m_num_unconnecting_headers_msgs);
}
+
// Set hashLastUnknownBlock for this peer, so that if we
// eventually get the headers - even from a different peer -
// we can use this peer to download.
- UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash());
+ WITH_LOCK(cs_main, UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()));
// The peer may just be broken, so periodically assign DoS points if this
// condition persists.
- if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
- Misbehaving(peer, 20, strprintf("%d non-connecting headers", nodestate->nUnconnectingHeaders));
+ if (peer.m_num_unconnecting_headers_msgs % MAX_NUM_UNCONNECTING_HEADERS_MSGS == 0) {
+ Misbehaving(peer, 20, strprintf("%d non-connecting headers", peer.m_num_unconnecting_headers_msgs));
}
}
@@ -2674,7 +2713,7 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
std::vector<CInv> vGetData;
// Download as much as possible, from earliest to latest.
for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
- if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (nodestate->vBlocksInFlight.size() >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
// Can't download any more from this peer
break;
}
@@ -2709,15 +2748,16 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, c
* whether that header was new and whether the headers message was full,
* update the state we keep for the peer.
*/
-void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom,
+void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer,
const CBlockIndex& last_header, bool received_new_header, bool may_have_more_headers)
{
+ if (peer.m_num_unconnecting_headers_msgs > 0) {
+ LogPrint(BCLog::NET, "peer=%d: resetting m_num_unconnecting_headers_msgs (%d -> 0)\n", pfrom.GetId(), peer.m_num_unconnecting_headers_msgs);
+ }
+ peer.m_num_unconnecting_headers_msgs = 0;
+
LOCK(cs_main);
CNodeState *nodestate = State(pfrom.GetId());
- if (nodestate->nUnconnectingHeaders > 0) {
- LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom.GetId(), nodestate->nUnconnectingHeaders);
- }
- nodestate->nUnconnectingHeaders = 0;
UpdateBlockAvailability(pfrom.GetId(), last_header.GetBlockHash());
@@ -2902,7 +2942,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
}
}
- UpdatePeerStateForReceivedHeaders(pfrom, *pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS);
+ UpdatePeerStateForReceivedHeaders(pfrom, peer, *pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS);
// Consider immediately downloading blocks.
HeadersDirectFetchBlocks(pfrom, peer, *pindexLast);
@@ -3154,12 +3194,104 @@ void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlo
m_chainman.ProcessNewBlock(block, force_processing, min_pow_checked, &new_block);
if (new_block) {
node.m_last_block_time = GetTime<std::chrono::seconds>();
+ // In case this block came from a different peer than we requested
+ // from, we can erase the block request now anyway (as we just stored
+ // this block to disk).
+ LOCK(cs_main);
+ RemoveBlockRequest(block->GetHash(), std::nullopt);
} else {
LOCK(cs_main);
mapBlockSource.erase(block->GetHash());
}
}
+void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)
+{
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ bool fBlockRead{false};
+ const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
+ {
+ LOCK(cs_main);
+
+ auto range_flight = mapBlocksInFlight.equal_range(block_transactions.blockhash);
+ size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
+ bool requested_block_from_this_peer{false};
+
+ // Multimap ensures ordering of outstanding requests. It's either empty or first in line.
+ bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());
+
+ while (range_flight.first != range_flight.second) {
+ auto [node_id, block_it] = range_flight.first->second;
+ if (node_id == pfrom.GetId() && block_it->partialBlock) {
+ requested_block_from_this_peer = true;
+ break;
+ }
+ range_flight.first++;
+ }
+
+ if (!requested_block_from_this_peer) {
+ LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
+ return;
+ }
+
+ PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock;
+ ReadStatus status = partialBlock.FillBlock(*pblock, block_transactions.txn);
+ if (status == READ_STATUS_INVALID) {
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
+ Misbehaving(peer, 100, "invalid compact block/non-matching block transactions");
+ return;
+ } else if (status == READ_STATUS_FAILED) {
+ if (first_in_flight) {
+ // Might have collided, fall back to getdata now :(
+ std::vector<CInv> invs;
+ invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(peer), block_transactions.blockhash));
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
+ } else {
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId());
+ LogPrint(BCLog::NET, "Peer %d sent us a compact block but it failed to reconstruct, waiting on first download to complete\n", pfrom.GetId());
+ return;
+ }
+ } else {
+ // Block is either okay, or possibly we received
+ // READ_STATUS_CHECKBLOCK_FAILED.
+ // Note that CheckBlock can only fail for one of a few reasons:
+ // 1. bad-proof-of-work (impossible here, because we've already
+ // accepted the header)
+ // 2. merkleroot doesn't match the transactions given (already
+ // caught in FillBlock with READ_STATUS_FAILED, so
+ // impossible here)
+ // 3. the block is otherwise invalid (eg invalid coinbase,
+ // block is too big, too many legacy sigops, etc).
+ // So if CheckBlock failed, #3 is the only possibility.
+ // Under BIP 152, we don't discourage the peer unless proof of work is
+ // invalid (we don't require all the stateless checks to have
+ // been run). This is handled below, so just treat this as
+ // though the block was successfully read, and rely on the
+ // handling in ProcessNewBlock to ensure the block index is
+ // updated, etc.
+ RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // it is now an empty pointer
+ fBlockRead = true;
+ // mapBlockSource is used for potentially punishing peers and
+ // updating which peers send us compact blocks, so the race
+ // between here and cs_main in ProcessNewBlock is fine.
+ // BIP 152 permits peers to relay compact blocks after validating
+ // the header only; we should not punish peers if the block turns
+ // out to be invalid.
+ mapBlockSource.emplace(block_transactions.blockhash, std::make_pair(pfrom.GetId(), false));
+ }
+ } // Don't hold cs_main when we call into ProcessNewBlock
+ if (fBlockRead) {
+ // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
+ // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
+ // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
+ // disk-space attacks), but this should be safe due to the
+ // protections in the compact block handler -- see related comment
+ // in compact block optimistic reconstruction handling.
+ ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
+ }
+ return;
+}
+
void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
const std::chrono::microseconds time_received,
const std::atomic<bool>& interruptMsgProc)
@@ -3296,11 +3428,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (greatest_common_version >= WTXID_RELAY_VERSION && m_txreconciliation) {
// Per BIP-330, we announce txreconciliation support if:
// - protocol version per the peer's VERSION message supports WTXID_RELAY;
- // - transaction relay is supported per the peer's VERSION message (see m_relays_txs);
- // - this is not a block-relay-only connection and not a feeler (see m_relays_txs);
+ // - transaction relay is supported per the peer's VERSION message
+ // - this is not a block-relay-only connection and not a feeler
// - this is not an addr fetch connection;
// - we are not in -blocksonly mode.
- if (pfrom.m_relays_txs && !pfrom.IsAddrFetchConn() && !m_ignore_incoming_txs) {
+ const auto* tx_relay = peer->GetTxRelay();
+ if (tx_relay && WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs) &&
+ !pfrom.IsAddrFetchConn() && !m_ignore_incoming_txs) {
const uint64_t recon_salt = m_txreconciliation->PreRegisterPeer(pfrom.GetId());
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDTXRCNCL,
TXRECONCILIATION_VERSION, recon_salt));
@@ -3360,10 +3494,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (fLogIPs)
remoteAddr = ", peeraddr=" + pfrom.addr.ToStringAddrPort();
- LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s\n",
+ const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
+ LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s%s\n",
cleanSubVer, pfrom.nVersion,
peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(),
- remoteAddr);
+ remoteAddr, (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
int64_t nTimeOffset = nTime - GetTime();
pfrom.nTimeOffset = nTimeOffset;
@@ -3375,8 +3510,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If the peer is old enough to have the old alert system, send it the final alert.
if (greatest_common_version <= 70012) {
- DataStream finalAlert{ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50")};
- m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make("alert", finalAlert));
+ const auto finalAlert{ParseHex("60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50")};
+ m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make("alert", Span{finalAlert}));
}
// Feeler connections exist only to verify if address is online.
@@ -3403,9 +3538,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (!pfrom.IsInboundConn()) {
- LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
+ const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
+ LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s%s (%s)\n",
pfrom.nVersion.load(), peer->m_starting_height,
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToStringAddrPort()) : ""),
+ (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""),
pfrom.ConnectionTypeAsString());
}
@@ -3446,8 +3583,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::SENDHEADERS) {
- LOCK(cs_main);
- State(pfrom.GetId())->fPreferHeaders = true;
+ peer->m_prefers_headers = true;
return;
}
@@ -3529,7 +3665,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Peer must not offer us reconciliations if they specified no tx relay support in VERSION.
// This flag might also be false in other cases, but the RejectIncomingTxs check above
// eliminates them, so that this flag fully represents what we are looking for.
- if (!pfrom.m_relays_txs) {
+ const auto* tx_relay = peer->GetTxRelay();
+ if (!tx_relay || !WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs)) {
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "sendtxrcncl received from peer=%d which indicated no tx relay to us; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
@@ -3869,7 +4006,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_BLOCKTXN_DEPTH) {
CBlock block;
- bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus());
+ const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pindex)};
assert(ret);
SendBlockTransactions(pfrom, *peer, block, req);
@@ -4227,12 +4364,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
blockhash.ToString(), pfrom.GetId());
}
- // When we succeed in decoding a block's txids from a cmpctblock
- // message we typically jump to the BLOCKTXN handling code, with a
- // dummy (empty) BLOCKTXN message, to re-use the logic there in
- // completing processing of the putative block (without cs_main).
bool fProcessBLOCKTXN = false;
- CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
// If we end up treating this as a plain headers message, call that as well
// without cs_main.
@@ -4257,15 +4389,27 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
nodestate->m_last_block_announcement = GetTime();
}
- std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash());
- bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();
-
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
return;
+ auto range_flight = mapBlocksInFlight.equal_range(pindex->GetBlockHash());
+ size_t already_in_flight = std::distance(range_flight.first, range_flight.second);
+ bool requested_block_from_this_peer{false};
+
+ // Multimap ensures ordering of outstanding requests. It's either empty or first in line.
+ bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());
+
+ while (range_flight.first != range_flight.second) {
+ if (range_flight.first->second.first == pfrom.GetId()) {
+ requested_block_from_this_peer = true;
+ break;
+ }
+ range_flight.first++;
+ }
+
if (pindex->nChainWork <= m_chainman.ActiveChain().Tip()->nChainWork || // We know something better
pindex->nTx != 0) { // We had this block at some point, but pruned it
- if (fAlreadyInFlight) {
+ if (requested_block_from_this_peer) {
// We requested this block for some reason, but our mempool will probably be useless
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
@@ -4276,15 +4420,15 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
// If we're not close to tip yet, give up and let parallel block fetch work its magic
- if (!fAlreadyInFlight && !CanDirectFetch()) {
+ if (!already_in_flight && !CanDirectFetch()) {
return;
}
// We want to be a bit conservative just to be extra careful about DoS
// possibilities in compact block processing...
if (pindex->nHeight <= m_chainman.ActiveChain().Height() + 2) {
- if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
- (fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) {
+ if ((already_in_flight < MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK && nodestate->vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
+ requested_block_from_this_peer) {
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
if (!BlockRequested(pfrom.GetId(), *pindex, &queuedBlockIt)) {
if (!(*queuedBlockIt)->partialBlock)
@@ -4299,14 +4443,19 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status == READ_STATUS_INVALID) {
- RemoveBlockRequest(pindex->GetBlockHash()); // Reset in-flight state in case Misbehaving does not result in a disconnect
+ RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect
Misbehaving(*peer, 100, "invalid compact block");
return;
} else if (status == READ_STATUS_FAILED) {
- // Duplicate txindexes, the block is now in-flight, so just request it
- std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(*peer), blockhash);
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ if (first_in_flight) {
+ // Duplicate txindexes, the block is now in-flight, so just request it
+ std::vector<CInv> vInv(1);
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(*peer), blockhash);
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
+ } else {
+ // Give up for this peer and wait for other peer(s)
+ RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId());
+ }
return;
}
@@ -4316,14 +4465,25 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
req.indexes.push_back(i);
}
if (req.indexes.empty()) {
- // Dirty hack to jump to BLOCKTXN code (TODO: move message handling into their own functions)
- BlockTransactions txn;
- txn.blockhash = blockhash;
- blockTxnMsg << txn;
fProcessBLOCKTXN = true;
- } else {
+ } else if (first_in_flight) {
+ // We will try to round-trip any compact blocks we get on failure,
+ // as long as it's first...
req.blockhash = pindex->GetBlockHash();
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
+ } else if (pfrom.m_bip152_highbandwidth_to &&
+ (!pfrom.IsInboundConn() ||
+ IsBlockRequestedFromOutbound(blockhash) ||
+ already_in_flight < MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK - 1)) {
+ // ... or it's a hb relay peer and:
+ // - peer is outbound, or
+ // - we already have an outbound attempt in flight(so we'll take what we can get), or
+ // - it's not the final parallel download slot (which we may reserve for first outbound)
+ req.blockhash = pindex->GetBlockHash();
+ m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
+ } else {
+ // Give up for this peer and wait for other peer(s)
+ RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId());
}
} else {
// This block is either already in flight from a different
@@ -4344,7 +4504,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
}
} else {
- if (fAlreadyInFlight) {
+ if (requested_block_from_this_peer) {
// We requested this block, but its far into the future, so our
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
@@ -4359,7 +4519,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} // cs_main
if (fProcessBLOCKTXN) {
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, time_received, interruptMsgProc);
+ BlockTransactions txn;
+ txn.blockhash = blockhash;
+ return ProcessCompactBlockTxns(pfrom, *peer, txn);
}
if (fRevertToHeaderProcessing) {
@@ -4394,7 +4556,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// process from some other peer. We do this after calling
// ProcessNewBlock so that a malleated cmpctblock announcement
// can't be used to interfere with block relay.
- RemoveBlockRequest(pblock->GetHash());
+ RemoveBlockRequest(pblock->GetHash(), std::nullopt);
}
}
return;
@@ -4411,68 +4573,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
BlockTransactions resp;
vRecv >> resp;
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
- bool fBlockRead = false;
- {
- LOCK(cs_main);
-
- std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator it = mapBlocksInFlight.find(resp.blockhash);
- if (it == mapBlocksInFlight.end() || !it->second.second->partialBlock ||
- it->second.first != pfrom.GetId()) {
- LogPrint(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());
- return;
- }
-
- PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock;
- ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn);
- if (status == READ_STATUS_INVALID) {
- RemoveBlockRequest(resp.blockhash); // Reset in-flight state in case Misbehaving does not result in a disconnect
- Misbehaving(*peer, 100, "invalid compact block/non-matching block transactions");
- return;
- } else if (status == READ_STATUS_FAILED) {
- // Might have collided, fall back to getdata now :(
- std::vector<CInv> invs;
- invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(*peer), resp.blockhash));
- m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
- } else {
- // Block is either okay, or possibly we received
- // READ_STATUS_CHECKBLOCK_FAILED.
- // Note that CheckBlock can only fail for one of a few reasons:
- // 1. bad-proof-of-work (impossible here, because we've already
- // accepted the header)
- // 2. merkleroot doesn't match the transactions given (already
- // caught in FillBlock with READ_STATUS_FAILED, so
- // impossible here)
- // 3. the block is otherwise invalid (eg invalid coinbase,
- // block is too big, too many legacy sigops, etc).
- // So if CheckBlock failed, #3 is the only possibility.
- // Under BIP 152, we don't discourage the peer unless proof of work is
- // invalid (we don't require all the stateless checks to have
- // been run). This is handled below, so just treat this as
- // though the block was successfully read, and rely on the
- // handling in ProcessNewBlock to ensure the block index is
- // updated, etc.
- RemoveBlockRequest(resp.blockhash); // it is now an empty pointer
- fBlockRead = true;
- // mapBlockSource is used for potentially punishing peers and
- // updating which peers send us compact blocks, so the race
- // between here and cs_main in ProcessNewBlock is fine.
- // BIP 152 permits peers to relay compact blocks after validating
- // the header only; we should not punish peers if the block turns
- // out to be invalid.
- mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom.GetId(), false));
- }
- } // Don't hold cs_main when we call into ProcessNewBlock
- if (fBlockRead) {
- // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
- // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
- // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
- // disk-space attacks), but this should be safe due to the
- // protections in the compact block handler -- see related comment
- // in compact block optimistic reconstruction handling.
- ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true);
- }
- return;
+ return ProcessCompactBlockTxns(pfrom, *peer, resp);
}
if (msg_type == NetMsgType::HEADERS)
@@ -4541,7 +4642,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Always process the block if we requested it, since we may
// need it even when it's not a candidate for a new best tip.
forceProcessing = IsBlockRequested(hash);
- RemoveBlockRequest(hash);
+ RemoveBlockRequest(hash, pfrom.GetId());
// mapBlockSource is only used for punishing peers and setting
// which peers send us compact blocks, so the race between here and
// cs_main in ProcessNewBlock is fine.
@@ -4595,6 +4696,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::MEMPOOL) {
+ // Only process received mempool messages if we advertise NODE_BLOOM
+ // or if the peer has mempool permissions.
if (!(peer->m_our_services & NODE_BLOOM) && !pfrom.HasPermission(NetPermissionFlags::Mempool))
{
if (!pfrom.HasPermission(NetPermissionFlags::NoBan))
@@ -4887,7 +4990,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
// Don't bother if send buffer is too full to respond anyway
if (pfrom->fPauseSend) return false;
- auto poll_result{pfrom->PollMessage(m_connman.GetReceiveFloodSize())};
+ auto poll_result{pfrom->PollMessage()};
if (!poll_result) {
// No message to process
return false;
@@ -4938,7 +5041,6 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seco
AssertLockHeld(cs_main);
CNodeState &state = *State(pto.GetId());
- const CNetMsgMaker msgMaker(pto.GetCommonVersion());
if (!state.m_chain_sync.m_protect && pto.IsOutboundOrBlockRelayConn() && state.fSyncStarted) {
// This is an outbound peer subject to disconnection if they don't
@@ -5025,14 +5127,14 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
// valid headers chain with at least as much work as our tip.
CNodeState *node_state = State(pnode->GetId());
if (node_state == nullptr ||
- (now - pnode->m_connected >= MINIMUM_CONNECT_TIME && node_state->nBlocksInFlight == 0)) {
+ (now - pnode->m_connected >= MINIMUM_CONNECT_TIME && node_state->vBlocksInFlight.empty())) {
pnode->fDisconnect = true;
LogPrint(BCLog::NET, "disconnecting extra block-relay-only peer=%d (last block received at time %d)\n",
pnode->GetId(), count_seconds(pnode->m_last_block_time));
return true;
} else {
LogPrint(BCLog::NET, "keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
- pnode->GetId(), count_seconds(pnode->m_connected), node_state->nBlocksInFlight);
+ pnode->GetId(), count_seconds(pnode->m_connected), node_state->vBlocksInFlight.size());
}
return false;
});
@@ -5072,13 +5174,13 @@ void PeerManagerImpl::EvictExtraOutboundPeers(std::chrono::seconds now)
// Also don't disconnect any peer we're trying to download a
// block from.
CNodeState &state = *State(pnode->GetId());
- if (now - pnode->m_connected > MINIMUM_CONNECT_TIME && state.nBlocksInFlight == 0) {
+ if (now - pnode->m_connected > MINIMUM_CONNECT_TIME && state.vBlocksInFlight.empty()) {
LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement);
pnode->fDisconnect = true;
return true;
} else {
LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n",
- pnode->GetId(), count_seconds(pnode->m_connected), state.nBlocksInFlight);
+ pnode->GetId(), count_seconds(pnode->m_connected), state.vBlocksInFlight.size());
return false;
}
});
@@ -5429,7 +5531,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height);
state.fSyncStarted = true;
- state.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE +
+ peer->m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE +
(
// Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling
// to maintain precision
@@ -5454,7 +5556,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// add all to the inv queue.
LOCK(peer->m_block_inv_mutex);
std::vector<CBlock> vHeaders;
- bool fRevertToInv = ((!state.fPreferHeaders &&
+ bool fRevertToInv = ((!peer->m_prefers_headers &&
(!state.m_requested_hb_cmpctblocks || peer->m_blocks_for_headers_relay.size() > 1)) ||
peer->m_blocks_for_headers_relay.size() > MAX_BLOCKS_TO_ANNOUNCE);
const CBlockIndex *pBestIndex = nullptr; // last header queued for delivery
@@ -5525,13 +5627,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
m_connman.PushMessage(pto, std::move(cached_cmpctblock_msg.value()));
} else {
CBlock block;
- bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
+ const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex)};
assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock{block};
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::CMPCTBLOCK, cmpctblock));
}
state.pindexBestHeaderSent = pBestIndex;
- } else if (state.fPreferHeaders) {
+ } else if (peer->m_prefers_headers) {
if (vHeaders.size() > 1) {
LogPrint(BCLog::NET, "%s: %u headers, range (%s, %s), to peer=%d\n", __func__,
vHeaders.size(),
@@ -5659,7 +5761,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// especially since we have many peers and some will draw much shorter delays.
unsigned int nRelayedTransactions = 0;
LOCK(tx_relay->m_bloom_filter_mutex);
- while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
+ size_t broadcast_max{INVENTORY_BROADCAST_MAX + (tx_relay->m_tx_inventory_to_send.size()/1000)*5};
+ broadcast_max = std::min<size_t>(1000, broadcast_max);
+ while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) {
// Fetch the top element from the heap
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
std::set<uint256>::iterator it = vInvTx.back();
@@ -5678,34 +5782,15 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
continue;
}
auto txid = txinfo.tx->GetHash();
- auto wtxid = txinfo.tx->GetWitnessHash();
// Peer told you to not send transactions at that feerate? Don't bother sending it.
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
continue;
}
if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
// Send
- State(pto->GetId())->m_recently_announced_invs.insert(hash);
+ tx_relay->m_recently_announced_invs.insert(hash);
vInv.push_back(inv);
nRelayedTransactions++;
- {
- // Expire old relay messages
- while (!g_relay_expiration.empty() && g_relay_expiration.front().first < current_time)
- {
- mapRelay.erase(g_relay_expiration.front().second);
- g_relay_expiration.pop_front();
- }
-
- auto ret = mapRelay.emplace(txid, std::move(txinfo.tx));
- if (ret.second) {
- g_relay_expiration.emplace_back(current_time + RELAY_TX_CACHE_TIME, ret.first);
- }
- // Add wtxid-based lookup into mapRelay as well, so that peers can request by wtxid
- auto ret2 = mapRelay.emplace(wtxid, ret.first->second);
- if (ret2.second) {
- g_relay_expiration.emplace_back(current_time + RELAY_TX_CACHE_TIME, ret2.first);
- }
- }
if (vInv.size() == MAX_INV_SZ) {
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
@@ -5731,7 +5816,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
// should only happen during initial block download.
- LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->GetId());
+ LogPrintf("Peer=%d%s is stalling block download, disconnecting\n", pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
pto->fDisconnect = true;
// Increase timeout for the next peer so that we don't disconnect multiple peers if our own
// bandwidth is insufficient.
@@ -5750,27 +5835,27 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
int nOtherPeersWithValidatedDownloads = m_peers_downloading_from - 1;
if (current_time > state.m_downloading_since + std::chrono::seconds{consensusParams.nPowTargetSpacing} * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) {
- LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.pindex->GetBlockHash().ToString(), pto->GetId());
+ LogPrintf("Timeout downloading block %s from peer=%d%s, disconnecting\n", queuedBlock.pindex->GetBlockHash().ToString(), pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
pto->fDisconnect = true;
return true;
}
}
// Check for headers sync timeouts
- if (state.fSyncStarted && state.m_headers_sync_timeout < std::chrono::microseconds::max()) {
+ if (state.fSyncStarted && peer->m_headers_sync_timeout < std::chrono::microseconds::max()) {
// Detect whether this is a stalling initial-headers-sync peer
if (m_chainman.m_best_header->Time() <= GetAdjustedTime() - 24h) {
- if (current_time > state.m_headers_sync_timeout && nSyncStarted == 1 && (m_num_preferred_download_peers - state.fPreferredDownload >= 1)) {
+ if (current_time > peer->m_headers_sync_timeout && nSyncStarted == 1 && (m_num_preferred_download_peers - state.fPreferredDownload >= 1)) {
// Disconnect a peer (without NetPermissionFlags::NoBan permission) if it is our only sync peer,
// and we have others we could be using instead.
// Note: If all our peers are inbound, then we won't
// disconnect our sync peer for stalling; we have bigger
// problems if we can't get any outbound peers.
if (!pto->HasPermission(NetPermissionFlags::NoBan)) {
- LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId());
+ LogPrintf("Timeout downloading headers from peer=%d%s, disconnecting\n", pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
pto->fDisconnect = true;
return true;
} else {
- LogPrintf("Timeout downloading headers from noban peer=%d, not disconnecting\n", pto->GetId());
+ LogPrintf("Timeout downloading headers from noban peer=%d%s, not disconnecting\n", pto->GetId(), fLogIPs ? strprintf(" peeraddr=%s", pto->addr.ToStringAddrPort()) : "");
// Reset the headers sync state so that we have a
// chance to try downloading from a different peer.
// Note: this will also result in at least one more
@@ -5778,13 +5863,13 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// this peer (eventually).
state.fSyncStarted = false;
nSyncStarted--;
- state.m_headers_sync_timeout = 0us;
+ peer->m_headers_sync_timeout = 0us;
}
}
} else {
// After we've caught up once, reset the timeout so we can't trigger
// disconnect later.
- state.m_headers_sync_timeout = std::chrono::microseconds::max();
+ peer->m_headers_sync_timeout = std::chrono::microseconds::max();
}
}
@@ -5796,10 +5881,10 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Message: getdata (blocks)
//
std::vector<CInv> vGetData;
- if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ FindNextBlocksToDownload(*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.vBlocksInFlight.size(), vToDownload, staller);
for (const CBlockIndex *pindex : vToDownload) {
uint32_t nFetchFlags = GetFetchFlags(*peer);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
@@ -5807,7 +5892,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
pindex->nHeight, pto->GetId());
}
- if (state.nBlocksInFlight == 0 && staller != -1) {
+ if (state.vBlocksInFlight.empty() && staller != -1) {
if (State(staller)->m_stalling_since == 0us) {
State(staller)->m_stalling_since = current_time;
LogPrint(BCLog::NET, "Stall started peer=%d\n", staller);
diff --git a/src/net_processing.h b/src/net_processing.h
index af9a02139b..deebb24c94 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -22,6 +22,8 @@ static const bool DEFAULT_PEERBLOOMFILTERS = false;
static const bool DEFAULT_PEERBLOCKFILTERS = false;
/** Threshold for marking a node to be discouraged, e.g. disconnected and added to the discouragement filter. */
static const int DISCOURAGEMENT_THRESHOLD{100};
+/** Maximum number of outstanding CMPCTBLOCK requests for the same block. */
+static const unsigned int MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK = 3;
struct CNodeStateStats {
int nSyncHeight = -1;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index f39a3635f4..8f6f92ea7d 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -36,8 +36,8 @@ static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex);
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = DEFAULT_NAME_LOOKUP;
-// Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
-int g_socks5_recv_timeout = 20 * 1000;
+// Need ample time for negotiation for very slow proxies such as Tor
+std::chrono::milliseconds g_socks5_recv_timeout = 20s;
static std::atomic<bool> interruptSocks5Recv(false);
std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup)
@@ -132,14 +132,9 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable)
return names;
}
-static bool LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
+static std::vector<CNetAddr> LookupIntern(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
- vIP.clear();
-
- if (!ContainsNoNUL(name)) {
- return false;
- }
-
+ if (!ContainsNoNUL(name)) return {};
{
CNetAddr addr;
// From our perspective, onion addresses are not hostnames but rather
@@ -148,83 +143,65 @@ static bool LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, un
// getaddrinfo to decode them and it wouldn't make sense to resolve
// them, we return a network address representing it instead. See
// CNetAddr::SetSpecial(const std::string&) for more details.
- if (addr.SetSpecial(name)) {
- vIP.push_back(addr);
- return true;
- }
+ if (addr.SetSpecial(name)) return {addr};
}
+ std::vector<CNetAddr> addresses;
+
for (const CNetAddr& resolved : dns_lookup_function(name, fAllowLookup)) {
- if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
+ if (nMaxSolutions > 0 && addresses.size() >= nMaxSolutions) {
break;
}
/* Never allow resolving to an internal address. Consider any such result invalid */
if (!resolved.IsInternal()) {
- vIP.push_back(resolved);
+ addresses.push_back(resolved);
}
}
- return (vIP.size() > 0);
+ return addresses;
}
-bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
+std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
- if (!ContainsNoNUL(name)) {
- return false;
- }
+ if (!ContainsNoNUL(name)) return {};
std::string strHost = name;
- if (strHost.empty())
- return false;
+ if (strHost.empty()) return {};
if (strHost.front() == '[' && strHost.back() == ']') {
strHost = strHost.substr(1, strHost.size() - 2);
}
- return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
+ return LookupIntern(strHost, nMaxSolutions, fAllowLookup, dns_lookup_function);
}
-bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function)
+std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
- if (!ContainsNoNUL(name)) {
- return false;
- }
- std::vector<CNetAddr> vIP;
- LookupHost(name, vIP, 1, fAllowLookup, dns_lookup_function);
- if(vIP.empty())
- return false;
- addr = vIP.front();
- return true;
+ const std::vector<CNetAddr> addresses{LookupHost(name, 1, fAllowLookup, dns_lookup_function)};
+ return addresses.empty() ? std::nullopt : std::make_optional(addresses.front());
}
-bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
+std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
{
if (name.empty() || !ContainsNoNUL(name)) {
- return false;
+ return {};
}
uint16_t port{portDefault};
std::string hostname;
SplitHostPort(name, port, hostname);
- std::vector<CNetAddr> vIP;
- bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup, dns_lookup_function);
- if (!fRet)
- return false;
- vAddr.resize(vIP.size());
- for (unsigned int i = 0; i < vIP.size(); i++)
- vAddr[i] = CService(vIP[i], port);
- return true;
+ const std::vector<CNetAddr> addresses{LookupIntern(hostname, nMaxSolutions, fAllowLookup, dns_lookup_function)};
+ if (addresses.empty()) return {};
+ std::vector<CService> services;
+ services.reserve(addresses.size());
+ for (const auto& addr : addresses)
+ services.emplace_back(addr, port);
+ return services;
}
-bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)
+std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
- if (!ContainsNoNUL(name)) {
- return false;
- }
- std::vector<CService> vService;
- bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1, dns_lookup_function);
- if (!fRet)
- return false;
- addr = vService[0];
- return true;
+ const std::vector<CService> services{Lookup(name, portDefault, fAllowLookup, 1, dns_lookup_function)};
+
+ return services.empty() ? std::nullopt : std::make_optional(services.front());
}
CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
@@ -232,12 +209,9 @@ CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupF
if (!ContainsNoNUL(name)) {
return {};
}
- CService addr;
// "1.2:345" will fail to resolve the ip, but will still set the port.
// If the ip fails to resolve, re-init the result.
- if(!Lookup(name, addr, portDefault, false, dns_lookup_function))
- addr = CService();
- return addr;
+ return Lookup(name, portDefault, /*fAllowLookup=*/false, dns_lookup_function).value_or(CService{});
}
/** SOCKS version */
@@ -296,7 +270,7 @@ enum class IntrRecvError {
*
* @param data The buffer where the read bytes should be stored.
* @param len The number of bytes to read into the specified buffer.
- * @param timeout The total timeout in milliseconds for this read.
+ * @param timeout The total timeout for this read.
* @param sock The socket (has to be in non-blocking mode) from which to read bytes.
*
* @returns An IntrRecvError indicating the resulting status of this read.
@@ -306,10 +280,10 @@ enum class IntrRecvError {
* @see This function can be interrupted by calling InterruptSocks5(bool).
* Sockets can be made non-blocking with Sock::SetNonBlocking().
*/
-static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
+static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, std::chrono::milliseconds timeout, const Sock& sock)
{
- int64_t curTime = GetTimeMillis();
- int64_t endTime = curTime + timeout;
+ auto curTime{Now<SteadyMilliseconds>()};
+ const auto endTime{curTime + timeout};
while (len > 0 && curTime < endTime) {
ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first
if (ret > 0) {
@@ -333,7 +307,7 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
}
if (interruptSocks5Recv)
return IntrRecvError::Interrupted;
- curTime = GetTimeMillis();
+ curTime = Now<SteadyMilliseconds>();
}
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
}
@@ -689,27 +663,27 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
const size_t slash_pos{subnet_str.find_last_of('/')};
const std::string str_addr{subnet_str.substr(0, slash_pos)};
- CNetAddr addr;
+ const std::optional<CNetAddr> addr{LookupHost(str_addr, /*fAllowLookup=*/false)};
- if (LookupHost(str_addr, addr, /*fAllowLookup=*/false)) {
+ if (addr.has_value()) {
if (slash_pos != subnet_str.npos) {
const std::string netmask_str{subnet_str.substr(slash_pos + 1)};
uint8_t netmask;
if (ParseUInt8(netmask_str, &netmask)) {
// Valid number; assume CIDR variable-length subnet masking.
- subnet_out = CSubNet{addr, netmask};
+ subnet_out = CSubNet{addr.value(), netmask};
return subnet_out.IsValid();
} else {
// Invalid number; try full netmask syntax. Never allow lookup for netmask.
- CNetAddr full_netmask;
- if (LookupHost(netmask_str, full_netmask, /*fAllowLookup=*/false)) {
- subnet_out = CSubNet{addr, full_netmask};
+ const std::optional<CNetAddr> full_netmask{LookupHost(netmask_str, /*fAllowLookup=*/false)};
+ if (full_netmask.has_value()) {
+ subnet_out = CSubNet{addr.value(), full_netmask.value()};
return subnet_out.IsValid();
}
}
} else {
// Single IP subnet (<ipv4>/32 or <ipv6>/128).
- subnet_out = CSubNet{addr};
+ subnet_out = CSubNet{addr.value()};
return subnet_out.IsValid();
}
}
diff --git a/src/netbase.h b/src/netbase.h
index a43f22f240..1da4f5c51d 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -105,24 +105,25 @@ extern DNSLookupFn g_dns_lookup;
* @param name The string representing a host. Could be a name or a numerical
* IP address (IPv6 addresses in their bracketed form are
* allowed).
- * @param[out] vIP The resulting network addresses to which the specified host
- * string resolved.
*
- * @returns Whether or not the specified host string successfully resolved to
- * any resulting network addresses.
+ * @returns The resulting network addresses to which the specified host
+ * string resolved.
*
- * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn)
+ * @see Lookup(const std::string&, uint16_t, bool, unsigned int, DNSLookupFn)
* for additional parameter descriptions.
*/
-bool LookupHost(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
/**
* Resolve a host string to its first corresponding network address.
*
- * @see LookupHost(const std::string&, std::vector<CNetAddr>&, uint16_t, bool, DNSLookupFn)
+ * @returns The resulting network address to which the specified host
+ * string resolved or std::nullopt if host does not resolve to an address.
+ *
+ * @see LookupHost(const std::string&, unsigned int, bool, DNSLookupFn)
* for additional parameter descriptions.
*/
-bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
/**
* Resolve a service string to its corresponding service.
@@ -132,8 +133,6 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL
* disambiguated bracketed form), optionally followed by a uint16_t port
* number. (e.g. example.com:8333 or
* [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
- * @param[out] vAddr The resulting services to which the specified service string
- * resolved.
* @param portDefault The default port for resulting services if not specified
* by the service string.
* @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
@@ -141,18 +140,18 @@ bool LookupHost(const std::string& name, CNetAddr& addr, bool fAllowLookup, DNSL
* @param nMaxSolutions The maximum number of results we want, specifying 0
* means "as many solutions as we get."
*
- * @returns Whether or not the service string successfully resolved to any
- * resulting services.
+ * @returns The resulting services to which the specified service string
+ * resolved.
*/
-bool Lookup(const std::string& name, std::vector<CService>& vAddr, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup);
+std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup);
/**
* Resolve a service string to its first corresponding service.
*
- * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn)
+ * @see Lookup(const std::string&, uint16_t, bool, unsigned int, DNSLookupFn)
* for additional parameter descriptions.
*/
-bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
+std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
/**
* Resolve a service string with a numeric IP to its first corresponding
@@ -160,7 +159,7 @@ bool Lookup(const std::string& name, CService& addr, uint16_t portDefault, bool
*
* @returns The resulting CService if the resolution was successful, [::]:0 otherwise.
*
- * @see Lookup(const std::string&, std::vector<CService>&, uint16_t, bool, unsigned int, DNSLookupFn)
+ * @see Lookup(const std::string&, uint16_t, bool, unsigned int, DNSLookupFn)
* for additional parameter descriptions.
*/
CService LookupNumeric(const std::string& name, uint16_t portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup);
diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp
index 5fb5c8beed..4b296db1b0 100644
--- a/src/node/blockmanager_args.cpp
+++ b/src/node/blockmanager_args.cpp
@@ -4,27 +4,36 @@
#include <node/blockmanager_args.h>
-#include <util/system.h>
+#include <common/args.h>
+#include <node/blockstorage.h>
+#include <tinyformat.h>
+#include <util/result.h>
+#include <util/translation.h>
#include <validation.h>
+#include <cstdint>
+
namespace node {
-std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts)
+util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts)
{
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
int64_t nPruneArg{args.GetIntArg("-prune", opts.prune_target)};
if (nPruneArg < 0) {
- return _("Prune cannot be configured with a negative value.");
+ return util::Error{_("Prune cannot be configured with a negative value.")};
}
uint64_t nPruneTarget{uint64_t(nPruneArg) * 1024 * 1024};
if (nPruneArg == 1) { // manual pruning: -prune=1
nPruneTarget = BlockManager::PRUNE_TARGET_MANUAL;
} else if (nPruneTarget) {
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
- return strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024);
+ return util::Error{strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)};
}
}
opts.prune_target = nPruneTarget;
- return std::nullopt;
+ if (auto value{args.GetBoolArg("-fastprune")}) opts.fast_prune = *value;
+ if (auto value{args.GetBoolArg("-stopafterblockimport")}) opts.stop_after_block_import = *value;
+
+ return {};
}
} // namespace node
diff --git a/src/node/blockmanager_args.h b/src/node/blockmanager_args.h
index e657c6bb45..de9fe83a5c 100644
--- a/src/node/blockmanager_args.h
+++ b/src/node/blockmanager_args.h
@@ -7,14 +7,12 @@
#define BITCOIN_NODE_BLOCKMANAGER_ARGS_H
#include <node/blockstorage.h>
-
-#include <optional>
+#include <util/result.h>
class ArgsManager;
-struct bilingual_str;
namespace node {
-std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts);
+[[nodiscard]] util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Options& opts);
} // namespace node
#endif // BITCOIN_NODE_BLOCKMANAGER_ARGS_H
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 53721b807c..87cd291c7e 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -8,18 +8,18 @@
#include <clientversion.h>
#include <consensus/validation.h>
#include <flatfile.h>
-#include <fs.h>
#include <hash.h>
-#include <logging.h>
#include <kernel/chainparams.h>
+#include <logging.h>
#include <pow.h>
#include <reverse_iterator.h>
#include <shutdown.h>
#include <signet.h>
#include <streams.h>
#include <undo.h>
+#include <util/batchpriority.h>
+#include <util/fs.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <validation.h>
#include <map>
@@ -27,6 +27,7 @@
namespace node {
std::atomic_bool fReindex(false);
+std::atomic_bool g_indexes_ready_to_sync{false};
bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
{
@@ -52,10 +53,6 @@ bool CBlockIndexHeightOnlyComparator::operator()(const CBlockIndex* pa, const CB
return pa->nHeight < pb->nHeight;
}
-static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
-static FlatFileSeq BlockFileSeq();
-static FlatFileSeq UndoFileSeq();
-
std::vector<CBlockIndex*> BlockManager::GetAllBlockIndices()
{
AssertLockHeld(cs_main);
@@ -252,9 +249,9 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
return pindex;
}
-bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
+bool BlockManager::LoadBlockIndex()
{
- if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
+ if (!m_block_tree_db->LoadBlockIndexGuts(GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
return false;
}
@@ -317,9 +314,9 @@ bool BlockManager::WriteBlockIndexDB()
return true;
}
-bool BlockManager::LoadBlockIndexDB(const Consensus::Params& consensus_params)
+bool BlockManager::LoadBlockIndexDB()
{
- if (!LoadBlockIndex(consensus_params)) {
+ if (!LoadBlockIndex()) {
return false;
}
@@ -422,7 +419,7 @@ const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& start_bl
// rev files since they'll be rewritten by the reindex anyway. This ensures that m_blockfile_info
// is in sync with what's actually on disk by the time we start downloading, so that pruning
// works correctly.
-void CleanupBlockRevFiles()
+void BlockManager::CleanupBlockRevFiles() const
{
std::map<std::string, fs::path> mapBlockFiles;
@@ -430,8 +427,7 @@ void CleanupBlockRevFiles()
// Remove the rev files immediately and insert the blk file paths into an
// ordered map keyed by block file index.
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
- const fs::path& blocksdir = gArgs.GetBlocksDirPath();
- for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
+ for (fs::directory_iterator it(m_opts.blocks_dir); it != fs::directory_iterator(); it++) {
const std::string path = fs::PathToString(it->path().filename());
if (fs::is_regular_file(*it) &&
path.length() == 12 &&
@@ -466,7 +462,7 @@ CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
return &m_blockfile_info.at(n);
}
-static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
+bool BlockManager::UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) const
{
// Open history file to append
AutoFile fileout{OpenUndoFile(pos)};
@@ -495,9 +491,9 @@ static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const
return true;
}
-bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
+bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& index) const
{
- const FlatFilePos pos{WITH_LOCK(::cs_main, return pindex->GetUndoPos())};
+ const FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())};
if (pos.IsNull()) {
return error("%s: no undo data available", __func__);
@@ -513,7 +509,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
uint256 hashChecksum;
HashVerifier verifier{filein}; // Use HashVerifier as reserializing may lose data, c.f. commit d342424301013ec47dc146a4beb49d5c9319d80a
try {
- verifier << pindex->pprev->GetBlockHash();
+ verifier << index.pprev->GetBlockHash();
verifier >> blockundo;
filein >> hashChecksum;
} catch (const std::exception& e) {
@@ -569,7 +565,7 @@ uint64_t BlockManager::CalculateCurrentUsage()
return retval;
}
-void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
+void BlockManager::UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const
{
std::error_code ec;
for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
@@ -577,33 +573,33 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
const bool removed_blockfile{fs::remove(BlockFileSeq().FileName(pos), ec)};
const bool removed_undofile{fs::remove(UndoFileSeq().FileName(pos), ec)};
if (removed_blockfile || removed_undofile) {
- LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
+ LogPrint(BCLog::BLOCKSTORAGE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
}
}
}
-static FlatFileSeq BlockFileSeq()
+FlatFileSeq BlockManager::BlockFileSeq() const
{
- return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
+ return FlatFileSeq(m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
}
-static FlatFileSeq UndoFileSeq()
+FlatFileSeq BlockManager::UndoFileSeq() const
{
- return FlatFileSeq(gArgs.GetBlocksDirPath(), "rev", UNDOFILE_CHUNK_SIZE);
+ return FlatFileSeq(m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE);
}
-FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly)
+FILE* BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const
{
return BlockFileSeq().Open(pos, fReadOnly);
}
/** Open an undo file (rev?????.dat) */
-static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly)
+FILE* BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const
{
return UndoFileSeq().Open(pos, fReadOnly);
}
-fs::path GetBlockPosFilename(const FlatFilePos& pos)
+fs::path BlockManager::GetBlockPosFilename(const FlatFilePos& pos) const
{
return BlockFileSeq().FileName(pos);
}
@@ -619,7 +615,18 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
bool finalize_undo = false;
if (!fKnown) {
- while (m_blockfile_info[nFile].nSize + nAddSize >= (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ : MAX_BLOCKFILE_SIZE)) {
+ unsigned int max_blockfile_size{MAX_BLOCKFILE_SIZE};
+ // Use smaller blockfiles in test-only -fastprune mode - but avoid
+ // the possibility of having a block not fit into the block file.
+ if (m_opts.fast_prune) {
+ max_blockfile_size = 0x10000; // 64kiB
+ if (nAddSize >= max_blockfile_size) {
+ // dynamically adjust the blockfile size to be larger than the added size
+ max_blockfile_size = nAddSize + 1;
+ }
+ }
+ assert(nAddSize < max_blockfile_size);
+ while (m_blockfile_info[nFile].nSize + nAddSize >= max_blockfile_size) {
// when the undo file is keeping up with the block file, we want to flush it explicitly
// when it is lagging behind (more blocks arrive than are being connected), we let the
// undo block write case handle it
@@ -635,7 +642,7 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
if ((int)nFile != m_last_blockfile) {
if (!fKnown) {
- LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString());
+ LogPrint(BCLog::BLOCKSTORAGE, "Leaving block file %i: %s\n", m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString());
}
FlushBlockFile(!fKnown, finalize_undo);
m_last_blockfile = nFile;
@@ -685,7 +692,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
return true;
}
-static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart)
+bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart) const
{
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
@@ -708,16 +715,16 @@ static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessa
return true;
}
-bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
+bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)
{
AssertLockHeld(::cs_main);
// Write undo information to disk
- if (pindex->GetUndoPos().IsNull()) {
+ if (block.GetUndoPos().IsNull()) {
FlatFilePos _pos;
- if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) {
+ if (!FindUndoPos(state, block.nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) {
return error("ConnectBlock(): FindUndoPos failed");
}
- if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) {
+ if (!UndoWriteToDisk(blockundo, _pos, block.pprev->GetBlockHash(), GetParams().MessageStart())) {
return AbortNode(state, "Failed to write undo data");
}
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
@@ -725,20 +732,20 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
// in the block file info as below; note that this does not catch the case where the undo writes are keeping up
// with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in
// the FindBlockPos function
- if (_pos.nFile < m_last_blockfile && static_cast<uint32_t>(pindex->nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) {
+ if (_pos.nFile < m_last_blockfile && static_cast<uint32_t>(block.nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) {
FlushUndoFile(_pos.nFile, true);
}
// update nUndoPos in block index
- pindex->nUndoPos = _pos.nPos;
- pindex->nStatus |= BLOCK_HAVE_UNDO;
- m_dirty_blockindex.insert(pindex);
+ block.nUndoPos = _pos.nPos;
+ block.nStatus |= BLOCK_HAVE_UNDO;
+ m_dirty_blockindex.insert(&block);
}
return true;
}
-bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams)
+bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const
{
block.SetNull();
@@ -756,33 +763,33 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
}
// Check the header
- if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
+ if (!CheckProofOfWork(block.GetHash(), block.nBits, GetConsensus())) {
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
}
// Signet only: check block solution
- if (consensusParams.signet_blocks && !CheckSignetBlockSolution(block, consensusParams)) {
+ if (GetConsensus().signet_blocks && !CheckSignetBlockSolution(block, GetConsensus())) {
return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
}
return true;
}
-bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const
{
- const FlatFilePos block_pos{WITH_LOCK(cs_main, return pindex->GetBlockPos())};
+ const FlatFilePos block_pos{WITH_LOCK(cs_main, return index.GetBlockPos())};
- if (!ReadBlockFromDisk(block, block_pos, consensusParams)) {
+ if (!ReadBlockFromDisk(block, block_pos)) {
return false;
}
- if (block.GetHash() != pindex->GetBlockHash()) {
+ if (block.GetHash() != index.GetBlockHash()) {
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
- pindex->ToString(), block_pos.ToString());
+ index.ToString(), block_pos.ToString());
}
return true;
}
-bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start)
+bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start) const
{
FlatFilePos hpos = pos;
hpos.nPos -= 8; // Seek back 8 bytes for meta header
@@ -817,7 +824,7 @@ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, c
return true;
}
-FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp)
+FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const FlatFilePos* dbp)
{
unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION);
FlatFilePos blockPos;
@@ -835,7 +842,7 @@ FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CCha
return FlatFilePos();
}
if (!position_known) {
- if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) {
+ if (!WriteBlockToDisk(block, blockPos, GetParams().MessageStart())) {
AbortNode("Failed to write block");
return FlatFilePos();
}
@@ -860,7 +867,7 @@ public:
}
};
-void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args, const fs::path& mempool_path)
+void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const fs::path& mempool_path)
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::INITIALIZATION_LOAD_BLOCKS);
ScheduleBatchPriority();
@@ -876,10 +883,10 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent;
while (true) {
FlatFilePos pos(nFile, 0);
- if (!fs::exists(GetBlockPosFilename(pos))) {
+ if (!fs::exists(chainman.m_blockman.GetBlockPosFilename(pos))) {
break; // No block files left to reindex
}
- FILE* file = OpenBlockFile(pos, true);
+ FILE* file = chainman.m_blockman.OpenBlockFile(pos, true);
if (!file) {
break; // This error is logged in OpenBlockFile
}
@@ -921,18 +928,18 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
BlockValidationState state;
if (!chainstate->ActivateBestChain(state, nullptr)) {
- LogPrintf("Failed to connect best block (%s)\n", state.ToString());
- StartShutdown();
+ AbortNode(strprintf("Failed to connect best block (%s)", state.ToString()));
return;
}
}
- if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
+ if (chainman.m_blockman.StopAfterBlockImport()) {
LogPrintf("Stopping after block import\n");
StartShutdown();
return;
}
} // End scope of ImportingNow
chainman.ActiveChainstate().LoadMempool(mempool_path);
+ g_indexes_ready_to_sync = true;
}
} // namespace node
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index 5ba0045b8b..a1ebb0df0a 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -7,19 +7,19 @@
#include <attributes.h>
#include <chain.h>
-#include <fs.h>
#include <kernel/blockmanager_opts.h>
+#include <kernel/chainparams.h>
#include <kernel/cs_main.h>
#include <protocol.h>
#include <sync.h>
#include <txdb.h>
+#include <util/fs.h>
#include <atomic>
#include <cstdint>
#include <unordered_map>
#include <vector>
-class ArgsManager;
class BlockValidationState;
class CBlock;
class CBlockFileInfo;
@@ -35,7 +35,6 @@ struct Params;
}
namespace node {
-static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false};
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
@@ -48,6 +47,7 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = CMessageHeader::MESSAGE_START_SIZE + sizeof(unsigned int);
extern std::atomic_bool fReindex;
+extern std::atomic_bool g_indexes_ready_to_sync;
// Because validation code takes pointers to the map's CBlockIndex objects, if
// we ever switch to another associative container, we need to either use a
@@ -81,18 +81,28 @@ class BlockManager
friend ChainstateManager;
private:
+ const CChainParams& GetParams() const { return m_opts.chainparams; }
+ const Consensus::Params& GetConsensus() const { return m_opts.chainparams.GetConsensus(); }
/**
* Load the blocktree off disk and into memory. Populate certain metadata
* per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
* collections like m_dirty_blockindex.
*/
- bool LoadBlockIndex(const Consensus::Params& consensus_params)
+ bool LoadBlockIndex()
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false);
void FlushUndoFile(int block_file, bool finalize = false);
bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown);
bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize);
+ FlatFileSeq BlockFileSeq() const;
+ FlatFileSeq UndoFileSeq() const;
+
+ FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const;
+
+ bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart) const;
+ bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) const;
+
/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height);
@@ -162,7 +172,7 @@ public:
std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
- bool LoadBlockIndexDB(const Consensus::Params& consensus_params) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/**
* Remove any pruned block & undo files that are still on disk.
@@ -184,11 +194,11 @@ public:
/** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n);
- bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
+ bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/** Store block on disk. If dbp is not nullptr, then it provides the known position of the block within a block file on disk. */
- FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp);
+ FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const FlatFilePos* dbp);
/** Whether running in -prune mode. */
[[nodiscard]] bool IsPruneMode() const { return m_prune_mode; }
@@ -199,6 +209,8 @@ public:
[[nodiscard]] bool LoadingBlocks() const { return m_importing || fReindex; }
+ [[nodiscard]] bool StopAfterBlockImport() const { return m_opts.stop_after_block_import; }
+
/** Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage();
@@ -216,28 +228,29 @@ public:
//! Create or update a prune lock identified by its name
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
-};
-void CleanupBlockRevFiles();
+ /** Open a block file (blk?????.dat) */
+ FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false) const;
-/** Open a block file (blk?????.dat) */
-FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false);
-/** Translation to a filesystem path */
-fs::path GetBlockPosFilename(const FlatFilePos& pos);
+ /** Translation to a filesystem path */
+ fs::path GetBlockPosFilename(const FlatFilePos& pos) const;
-/**
- * Actually unlink the specified files
- */
-void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
+ /**
+ * Actually unlink the specified files
+ */
+ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const;
-/** Functions for disk access for blocks */
-bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams);
-bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
-bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start);
+ /** Functions for disk access for blocks */
+ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const;
+ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const;
+ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start) const;
-bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
+ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& index) const;
+
+ void CleanupBlockRevFiles() const;
+};
-void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args, const fs::path& mempool_path);
+void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const fs::path& mempool_path);
} // namespace node
#endif // BITCOIN_NODE_BLOCKSTORAGE_H
diff --git a/src/node/caches.cpp b/src/node/caches.cpp
index 7622a03e19..7403f7ddea 100644
--- a/src/node/caches.cpp
+++ b/src/node/caches.cpp
@@ -4,9 +4,9 @@
#include <node/caches.h>
+#include <common/args.h>
#include <index/txindex.h>
#include <txdb.h>
-#include <util/system.h>
namespace node {
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index cfd3472592..3900d2e620 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -16,6 +16,7 @@
#include <tinyformat.h>
#include <txdb.h>
#include <uint256.h>
+#include <util/fs.h>
#include <util/time.h>
#include <util/translation.h>
#include <validation.h>
@@ -50,7 +51,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (options.prune) {
- CleanupBlockRevFiles();
+ chainman.m_blockman.CleanupBlockRevFiles();
}
}
@@ -206,7 +207,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
} else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) {
LogPrintf("[snapshot] cleaning up unneeded background chainstate, then reinitializing\n");
if (!chainman.ValidatedSnapshotCleanup()) {
- AbortNode("Background chainstate cleanup failed unexpectedly.");
+ return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Background chainstate cleanup failed unexpectedly.")};
}
// Because ValidatedSnapshotCleanup() has torn down chainstates with
@@ -252,7 +253,7 @@ ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const C
"Only rebuild the block database if you are sure that your computer's date and time are correct")};
}
- VerifyDBResult result = CVerifyDB().VerifyDB(
+ VerifyDBResult result = CVerifyDB(chainman.GetNotifications()).VerifyDB(
*chainstate, chainman.GetConsensus(), chainstate->CoinsDB(),
options.check_level,
options.check_blocks);
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index 77240cafe9..2e35035c28 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -42,7 +42,8 @@ struct ChainstateLoadOptions {
//! and exit cleanly in the interrupted case.
enum class ChainstateLoadStatus {
SUCCESS,
- FAILURE,
+ FAILURE, //!< Generic failure which reindexing may fix
+ FAILURE_FATAL, //!< Fatal error which should not prompt to reindex
FAILURE_INCOMPATIBLE_DB,
FAILURE_INSUFFICIENT_DBCACHE,
INTERRUPTED,
diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp
index 9801e6e959..a7f7303348 100644
--- a/src/node/chainstatemanager_args.cpp
+++ b/src/node/chainstatemanager_args.cpp
@@ -5,22 +5,22 @@
#include <node/chainstatemanager_args.h>
#include <arith_uint256.h>
+#include <common/args.h>
#include <kernel/chainstatemanager_opts.h>
#include <node/coins_view_args.h>
#include <node/database_args.h>
#include <tinyformat.h>
#include <uint256.h>
+#include <util/result.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <chrono>
-#include <optional>
#include <string>
namespace node {
-std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts)
+util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts)
{
if (auto value{args.GetBoolArg("-checkblockindex")}) opts.check_block_index = *value;
@@ -28,7 +28,7 @@ std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, Chains
if (auto value{args.GetArg("-minimumchainwork")}) {
if (!IsHexNumber(*value)) {
- return strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), *value);
+ return util::Error{strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), *value)};
}
opts.minimum_chain_work = UintToArith256(uint256S(*value));
}
@@ -37,10 +37,12 @@ std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, Chains
if (auto value{args.GetIntArg("-maxtipage")}) opts.max_tip_age = std::chrono::seconds{*value};
+ if (auto value{args.GetIntArg("-stopatheight")}) opts.stop_at_height = *value;
+
ReadDatabaseArgs(args, opts.block_tree_db);
ReadDatabaseArgs(args, opts.coins_db);
ReadCoinsViewArgs(args, opts.coins_view);
- return std::nullopt;
+ return {};
}
} // namespace node
diff --git a/src/node/chainstatemanager_args.h b/src/node/chainstatemanager_args.h
index 6c46b998f2..701515953e 100644
--- a/src/node/chainstatemanager_args.h
+++ b/src/node/chainstatemanager_args.h
@@ -5,15 +5,13 @@
#ifndef BITCOIN_NODE_CHAINSTATEMANAGER_ARGS_H
#define BITCOIN_NODE_CHAINSTATEMANAGER_ARGS_H
+#include <util/result.h>
#include <validation.h>
-#include <optional>
-
class ArgsManager;
-struct bilingual_str;
namespace node {
-std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts);
+[[nodiscard]] util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts);
} // namespace node
#endif // BITCOIN_NODE_CHAINSTATEMANAGER_ARGS_H
diff --git a/src/node/coins_view_args.cpp b/src/node/coins_view_args.cpp
index 67c9b8dbac..5d55143e83 100644
--- a/src/node/coins_view_args.cpp
+++ b/src/node/coins_view_args.cpp
@@ -4,8 +4,8 @@
#include <node/coins_view_args.h>
+#include <common/args.h>
#include <txdb.h>
-#include <util/system.h>
namespace node {
void ReadCoinsViewArgs(const ArgsManager& args, CoinsViewOptions& options)
diff --git a/src/node/context.cpp b/src/node/context.cpp
index af59ab932b..ca56fa0b86 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -11,6 +11,7 @@
#include <net.h>
#include <net_processing.h>
#include <netgroup.h>
+#include <node/kernel_notifications.h>
#include <policy/fees.h>
#include <scheduler.h>
#include <txmempool.h>
diff --git a/src/node/context.h b/src/node/context.h
index 84f4053c84..91b68fa5bb 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -7,7 +7,9 @@
#include <kernel/context.h>
+#include <atomic>
#include <cassert>
+#include <cstdlib>
#include <functional>
#include <memory>
#include <vector>
@@ -30,6 +32,8 @@ class WalletLoader;
} // namespace interfaces
namespace node {
+class KernelNotifications;
+
//! NodeContext struct containing references to chain state and connection
//! state.
//!
@@ -62,6 +66,8 @@ struct NodeContext {
interfaces::WalletLoader* wallet_loader{nullptr};
std::unique_ptr<CScheduler> scheduler;
std::function<void()> rpc_interruption_point = [] {};
+ std::unique_ptr<KernelNotifications> notifications;
+ std::atomic<int> exit_status{EXIT_SUCCESS};
//! Declare default constructor and destructor that are not inline, so code
//! instantiating the NodeContext struct doesn't need to #include class
diff --git a/src/node/database_args.cpp b/src/node/database_args.cpp
index 2c53b4b47e..aba3c38ff3 100644
--- a/src/node/database_args.cpp
+++ b/src/node/database_args.cpp
@@ -4,8 +4,8 @@
#include <node/database_args.h>
+#include <common/args.h>
#include <dbwrapper.h>
-#include <util/system.h>
namespace node {
void ReadDatabaseArgs(const ArgsManager& args, DBOptions& options)
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index b397661df4..94b607b1de 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -7,6 +7,7 @@
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
+#include <common/args.h>
#include <deploymentstatus.h>
#include <external_signer.h>
#include <index/blockfilterindex.h>
@@ -43,7 +44,6 @@
#include <uint256.h>
#include <univalue.h>
#include <util/check.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -89,10 +89,11 @@ public:
void initLogging() override { InitLogging(args()); }
void initParameterInteraction() override { InitParameterInteraction(args()); }
bilingual_str getWarnings() override { return GetWarnings(true); }
+ int getExitStatus() override { return Assert(m_context)->exit_status.load(); }
uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
{
- if (!AppInitBasicSetup(args())) return false;
+ if (!AppInitBasicSetup(args(), Assert(context())->exit_status)) return false;
if (!AppInitParameterInteraction(args(), /*use_syscall_sandbox=*/false)) return false;
m_context->kernel = std::make_unique<kernel::Context>();
@@ -105,7 +106,10 @@ public:
}
bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override
{
- return AppInitMain(*m_context, tip_info);
+ if (AppInitMain(*m_context, tip_info)) return true;
+ // Error during initialization, set exit status before continue
+ m_context->exit_status.store(EXIT_FAILURE);
+ return false;
}
void appShutdown() override
{
@@ -125,17 +129,17 @@ public:
bool isSettingIgnored(const std::string& name) override
{
bool ignored = false;
- args().LockSettings([&](util::Settings& settings) {
- if (auto* options = util::FindKey(settings.command_line_options, name)) {
+ args().LockSettings([&](common::Settings& settings) {
+ if (auto* options = common::FindKey(settings.command_line_options, name)) {
ignored = !options->empty();
}
});
return ignored;
}
- util::SettingsValue getPersistentSetting(const std::string& name) override { return args().GetPersistentSetting(name); }
- void updateRwSetting(const std::string& name, const util::SettingsValue& value) override
+ common::SettingsValue getPersistentSetting(const std::string& name) override { return args().GetPersistentSetting(name); }
+ void updateRwSetting(const std::string& name, const common::SettingsValue& value) override
{
- args().LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](common::Settings& settings) {
if (value.isNull()) {
settings.rw_settings.erase(name);
} else {
@@ -144,9 +148,9 @@ public:
});
args().WriteSettingsFile();
}
- void forceSetting(const std::string& name, const util::SettingsValue& value) override
+ void forceSetting(const std::string& name, const common::SettingsValue& value) override
{
- args().LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](common::Settings& settings) {
if (value.isNull()) {
settings.forced_settings.erase(name);
} else {
@@ -157,7 +161,7 @@ public:
void resetSettings() override
{
args().WriteSettingsFile(/*errors=*/nullptr, /*backup=*/true);
- args().LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](common::Settings& settings) {
settings.rw_settings.clear();
});
args().WriteSettingsFile();
@@ -239,8 +243,9 @@ public:
std::vector<ExternalSigner> signers = {};
const std::string command = args().GetArg("-signer", "");
if (command == "") return {};
- ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
+ ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString());
std::vector<std::unique_ptr<interfaces::ExternalSigner>> result;
+ result.reserve(signers.size());
for (auto& signer : signers) {
result.emplace_back(std::make_unique<ExternalSignerImpl>(std::move(signer)));
}
@@ -393,7 +398,7 @@ public:
NodeContext* m_context{nullptr};
};
-bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active)
+bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active, const BlockManager& blockman)
{
if (!index) return false;
if (block.m_hash) *block.m_hash = index->GetBlockHash();
@@ -403,10 +408,10 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
if (block.m_locator) { *block.m_locator = GetLocator(index); }
- if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
+ if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active, blockman);
if (block.m_data) {
REVERSE_LOCK(lock);
- if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull();
+ if (!blockman.ReadBlockFromDisk(*block.m_data, *index)) block.m_data->SetNull();
}
block.found = true;
return true;
@@ -556,13 +561,13 @@ public:
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
- return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain());
+ return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain(), chainman().m_blockman);
}
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
const CChain& active = chainman().ActiveChain();
- return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active);
+ return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active, chainman().m_blockman);
}
bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
{
@@ -570,10 +575,10 @@ public:
const CChain& active = chainman().ActiveChain();
if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
- return FillBlock(ancestor, ancestor_out, lock, active);
+ return FillBlock(ancestor, ancestor_out, lock, active, chainman().m_blockman);
}
}
- return FillBlock(nullptr, ancestor_out, lock, active);
+ return FillBlock(nullptr, ancestor_out, lock, active, chainman().m_blockman);
}
bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
{
@@ -581,7 +586,7 @@ public:
const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
- return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain());
+ return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain(), chainman().m_blockman);
}
bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
{
@@ -593,9 +598,9 @@ public:
// Using & instead of && below to avoid short circuiting and leaving
// 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)};
+ return int{FillBlock(ancestor, ancestor_out, lock, active, chainman().m_blockman)} &
+ int{FillBlock(block1, block1_out, lock, active, chainman().m_blockman)} &
+ int{FillBlock(block2, block2_out, lock, active, chainman().m_blockman)};
}
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
double guessVerificationProgress(const uint256& block_hash) override
@@ -743,27 +748,27 @@ public:
RPCRunLater(name, std::move(fn), seconds);
}
int rpcSerializationFlags() override { return RPCSerializationFlags(); }
- util::SettingsValue getSetting(const std::string& name) override
+ common::SettingsValue getSetting(const std::string& name) override
{
return args().GetSetting(name);
}
- std::vector<util::SettingsValue> getSettingsList(const std::string& name) override
+ std::vector<common::SettingsValue> getSettingsList(const std::string& name) override
{
return args().GetSettingsList(name);
}
- util::SettingsValue getRwSetting(const std::string& name) override
+ common::SettingsValue getRwSetting(const std::string& name) override
{
- util::SettingsValue result;
- args().LockSettings([&](const util::Settings& settings) {
- if (const util::SettingsValue* value = util::FindKey(settings.rw_settings, name)) {
+ common::SettingsValue result;
+ args().LockSettings([&](const common::Settings& settings) {
+ if (const common::SettingsValue* value = common::FindKey(settings.rw_settings, name)) {
result = *value;
}
});
return result;
}
- bool updateRwSetting(const std::string& name, const util::SettingsValue& value, bool write) override
+ bool updateRwSetting(const std::string& name, const common::SettingsValue& value, bool write) override
{
- args().LockSettings([&](util::Settings& settings) {
+ args().LockSettings([&](common::Settings& settings) {
if (value.isNull()) {
settings.rw_settings.erase(name);
} else {
diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp
new file mode 100644
index 0000000000..926b157f3b
--- /dev/null
+++ b/src/node/kernel_notifications.cpp
@@ -0,0 +1,75 @@
+// Copyright (c) 2023 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 <node/kernel_notifications.h>
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <common/args.h>
+#include <common/system.h>
+#include <node/interface_ui.h>
+#include <util/strencodings.h>
+#include <util/string.h>
+#include <util/translation.h>
+#include <warnings.h>
+
+#include <cstdint>
+#include <string>
+#include <thread>
+
+static void AlertNotify(const std::string& strMessage)
+{
+ uiInterface.NotifyAlertChanged();
+#if HAVE_SYSTEM
+ std::string strCmd = gArgs.GetArg("-alertnotify", "");
+ if (strCmd.empty()) return;
+
+ // Alert text should be plain ascii coming from a trusted source, but to
+ // be safe we first strip anything not in safeChars, then add single quotes around
+ // the whole string before passing it to the shell:
+ std::string singleQuote("'");
+ std::string safeStatus = SanitizeString(strMessage);
+ safeStatus = singleQuote+safeStatus+singleQuote;
+ ReplaceAll(strCmd, "%s", safeStatus);
+
+ std::thread t(runCommand, strCmd);
+ t.detach(); // thread runs free
+#endif
+}
+
+static void DoWarning(const bilingual_str& warning)
+{
+ static bool fWarned = false;
+ SetMiscWarning(warning);
+ if (!fWarned) {
+ AlertNotify(warning.original);
+ fWarned = true;
+ }
+}
+
+namespace node {
+
+void KernelNotifications::blockTip(SynchronizationState state, CBlockIndex& index)
+{
+ uiInterface.NotifyBlockTip(state, &index);
+}
+
+void KernelNotifications::headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync)
+{
+ uiInterface.NotifyHeaderTip(state, height, timestamp, presync);
+}
+
+void KernelNotifications::progress(const bilingual_str& title, int progress_percent, bool resume_possible)
+{
+ uiInterface.ShowProgress(title.translated, progress_percent, resume_possible);
+}
+
+void KernelNotifications::warning(const bilingual_str& warning)
+{
+ DoWarning(warning);
+}
+
+} // namespace node
diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h
new file mode 100644
index 0000000000..3e665bbf14
--- /dev/null
+++ b/src/node/kernel_notifications.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2023 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_NODE_KERNEL_NOTIFICATIONS_H
+#define BITCOIN_NODE_KERNEL_NOTIFICATIONS_H
+
+#include <kernel/notifications_interface.h>
+
+#include <cstdint>
+#include <string>
+
+class CBlockIndex;
+enum class SynchronizationState;
+struct bilingual_str;
+
+namespace node {
+class KernelNotifications : public kernel::Notifications
+{
+public:
+ void blockTip(SynchronizationState state, CBlockIndex& index) override;
+
+ void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) override;
+
+ void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override;
+
+ void warning(const bilingual_str& warning) override;
+};
+} // namespace node
+
+#endif // BITCOIN_NODE_KERNEL_NOTIFICATIONS_H
diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp
index a0a2e43107..5381902263 100644
--- a/src/node/mempool_args.cpp
+++ b/src/node/mempool_args.cpp
@@ -7,6 +7,7 @@
#include <kernel/mempool_limits.h>
#include <kernel/mempool_options.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <kernel/chainparams.h>
#include <logging.h>
@@ -16,7 +17,6 @@
#include <tinyformat.h>
#include <util/error.h>
#include <util/moneystr.h>
-#include <util/system.h>
#include <util/translation.h>
#include <chrono>
@@ -38,7 +38,7 @@ void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolLimits& mempool_limi
}
}
-std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, MemPoolOptions& mempool_opts)
+util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, MemPoolOptions& mempool_opts)
{
mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio);
@@ -52,7 +52,7 @@ std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, con
if (std::optional<CAmount> inc_relay_fee = ParseMoney(argsman.GetArg("-incrementalrelayfee", ""))) {
mempool_opts.incremental_relay_feerate = CFeeRate{inc_relay_fee.value()};
} else {
- return AmountErrMsg("incrementalrelayfee", argsman.GetArg("-incrementalrelayfee", ""));
+ return util::Error{AmountErrMsg("incrementalrelayfee", argsman.GetArg("-incrementalrelayfee", ""))};
}
}
@@ -61,7 +61,7 @@ std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, con
// High fee check is done afterward in CWallet::Create()
mempool_opts.min_relay_feerate = CFeeRate{min_relay_feerate.value()};
} else {
- return AmountErrMsg("minrelaytxfee", argsman.GetArg("-minrelaytxfee", ""));
+ return util::Error{AmountErrMsg("minrelaytxfee", argsman.GetArg("-minrelaytxfee", ""))};
}
} else if (mempool_opts.incremental_relay_feerate > mempool_opts.min_relay_feerate) {
// Allow only setting incremental fee to control both
@@ -75,7 +75,7 @@ std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, con
if (std::optional<CAmount> parsed = ParseMoney(argsman.GetArg("-dustrelayfee", ""))) {
mempool_opts.dust_relay_feerate = CFeeRate{parsed.value()};
} else {
- return AmountErrMsg("dustrelayfee", argsman.GetArg("-dustrelayfee", ""));
+ return util::Error{AmountErrMsg("dustrelayfee", argsman.GetArg("-dustrelayfee", ""))};
}
}
@@ -89,12 +89,12 @@ std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, con
mempool_opts.require_standard = !argsman.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (!chainparams.IsTestChain() && !mempool_opts.require_standard) {
- return strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString());
+ return util::Error{strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.GetChainTypeString())};
}
mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
ApplyArgsManOptions(argsman, mempool_opts.limits);
- return std::nullopt;
+ return {};
}
diff --git a/src/node/mempool_args.h b/src/node/mempool_args.h
index 52d8b4f265..630fee6421 100644
--- a/src/node/mempool_args.h
+++ b/src/node/mempool_args.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_NODE_MEMPOOL_ARGS_H
#define BITCOIN_NODE_MEMPOOL_ARGS_H
-#include <optional>
+#include <util/result.h>
class ArgsManager;
class CChainParams;
@@ -21,7 +21,7 @@ struct MemPoolOptions;
* @param[in] argsman The ArgsManager in which to check set options.
* @param[in,out] mempool_opts The MemPoolOptions to modify according to \p argsman.
*/
-[[nodiscard]] std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, kernel::MemPoolOptions& mempool_opts);
+[[nodiscard]] util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, kernel::MemPoolOptions& mempool_opts);
#endif // BITCOIN_NODE_MEMPOOL_ARGS_H
diff --git a/src/node/mempool_persist_args.cpp b/src/node/mempool_persist_args.cpp
index 4e775869c6..97ecdd651b 100644
--- a/src/node/mempool_persist_args.cpp
+++ b/src/node/mempool_persist_args.cpp
@@ -4,8 +4,8 @@
#include <node/mempool_persist_args.h>
-#include <fs.h>
-#include <util/system.h>
+#include <common/args.h>
+#include <util/fs.h>
#include <validation.h>
namespace node {
diff --git a/src/node/mempool_persist_args.h b/src/node/mempool_persist_args.h
index f719ec62ab..3b101f0930 100644
--- a/src/node/mempool_persist_args.h
+++ b/src/node/mempool_persist_args.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H
#define BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H
-#include <fs.h>
+#include <util/fs.h>
class ArgsManager;
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index c7bc9a9a3d..aa1a9a155c 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -8,6 +8,7 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
@@ -20,7 +21,6 @@
#include <primitives/transaction.h>
#include <timedata.h>
#include <util/moneystr.h>
-#include <util/system.h>
#include <validation.h>
#include <algorithm>
diff --git a/src/node/miner.h b/src/node/miner.h
index f1ccffff55..70de9e1db0 100644
--- a/src/node/miner.h
+++ b/src/node/miner.h
@@ -14,7 +14,10 @@
#include <optional>
#include <stdint.h>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/tag.hpp>
#include <boost/multi_index_container.hpp>
class ArgsManager;
diff --git a/src/node/mini_miner.cpp b/src/node/mini_miner.cpp
new file mode 100644
index 0000000000..6f253eddfa
--- /dev/null
+++ b/src/node/mini_miner.cpp
@@ -0,0 +1,371 @@
+// Copyright (c) 2023 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 <node/mini_miner.h>
+
+#include <consensus/amount.h>
+#include <policy/feerate.h>
+#include <primitives/transaction.h>
+#include <timedata.h>
+#include <util/check.h>
+#include <util/moneystr.h>
+
+#include <algorithm>
+#include <numeric>
+#include <utility>
+
+namespace node {
+
+MiniMiner::MiniMiner(const CTxMemPool& mempool, const std::vector<COutPoint>& outpoints)
+{
+ LOCK(mempool.cs);
+ // Find which outpoints to calculate bump fees for.
+ // Anything that's spent by the mempool is to-be-replaced
+ // Anything otherwise unavailable just has a bump fee of 0
+ for (const auto& outpoint : outpoints) {
+ if (!mempool.exists(GenTxid::Txid(outpoint.hash))) {
+ // This UTXO is either confirmed or not yet submitted to mempool.
+ // If it's confirmed, no bump fee is required.
+ // If it's not yet submitted, we have no information, so return 0.
+ m_bump_fees.emplace(outpoint, 0);
+ continue;
+ }
+
+ // UXTO is created by transaction in mempool, add to map.
+ // Note: This will either create a missing entry or add the outpoint to an existing entry
+ m_requested_outpoints_by_txid[outpoint.hash].push_back(outpoint);
+
+ if (const auto ptx{mempool.GetConflictTx(outpoint)}) {
+ // This outpoint is already being spent by another transaction in the mempool. We
+ // assume that the caller wants to replace this transaction and its descendants. It
+ // would be unusual for the transaction to have descendants as the wallet won’t normally
+ // attempt to replace transactions with descendants. If the outpoint is from a mempool
+ // transaction, we still need to calculate its ancestors bump fees (added to
+ // m_requested_outpoints_by_txid below), but after removing the to-be-replaced entries.
+ //
+ // Note that the descendants of a transaction include the transaction itself. Also note,
+ // that this is only calculating bump fees. RBF fee rules should be handled separately.
+ CTxMemPool::setEntries descendants;
+ mempool.CalculateDescendants(mempool.GetIter(ptx->GetHash()).value(), descendants);
+ for (const auto& desc_txiter : descendants) {
+ m_to_be_replaced.insert(desc_txiter->GetTx().GetHash());
+ }
+ }
+ }
+
+ // No unconfirmed UTXOs, so nothing mempool-related needs to be calculated.
+ if (m_requested_outpoints_by_txid.empty()) return;
+
+ // Calculate the cluster and construct the entry map.
+ std::vector<uint256> txids_needed;
+ txids_needed.reserve(m_requested_outpoints_by_txid.size());
+ for (const auto& [txid, _]: m_requested_outpoints_by_txid) {
+ txids_needed.push_back(txid);
+ }
+ const auto cluster = mempool.GatherClusters(txids_needed);
+ if (cluster.empty()) {
+ // An empty cluster means that at least one of the transactions is missing from the mempool
+ // (should not be possible given processing above) or DoS limit was hit.
+ m_ready_to_calculate = false;
+ return;
+ }
+
+ // Add every entry to m_entries_by_txid and m_entries, except the ones that will be replaced.
+ for (const auto& txiter : cluster) {
+ if (!m_to_be_replaced.count(txiter->GetTx().GetHash())) {
+ auto [mapiter, success] = m_entries_by_txid.emplace(txiter->GetTx().GetHash(), MiniMinerMempoolEntry(txiter));
+ m_entries.push_back(mapiter);
+ } else {
+ auto outpoints_it = m_requested_outpoints_by_txid.find(txiter->GetTx().GetHash());
+ if (outpoints_it != m_requested_outpoints_by_txid.end()) {
+ // This UTXO is the output of a to-be-replaced transaction. Bump fee is 0; spending
+ // this UTXO is impossible as it will no longer exist after the replacement.
+ for (const auto& outpoint : outpoints_it->second) {
+ m_bump_fees.emplace(outpoint, 0);
+ }
+ m_requested_outpoints_by_txid.erase(outpoints_it);
+ }
+ }
+ }
+
+ // Build the m_descendant_set_by_txid cache.
+ for (const auto& txiter : cluster) {
+ const auto& txid = txiter->GetTx().GetHash();
+ // Cache descendants for future use. Unlike the real mempool, a descendant MiniMinerMempoolEntry
+ // will not exist without its ancestor MiniMinerMempoolEntry, so these sets won't be invalidated.
+ std::vector<MockEntryMap::iterator> cached_descendants;
+ const bool remove{m_to_be_replaced.count(txid) > 0};
+ CTxMemPool::setEntries descendants;
+ mempool.CalculateDescendants(txiter, descendants);
+ Assume(descendants.count(txiter) > 0);
+ for (const auto& desc_txiter : descendants) {
+ const auto txid_desc = desc_txiter->GetTx().GetHash();
+ const bool remove_desc{m_to_be_replaced.count(txid_desc) > 0};
+ auto desc_it{m_entries_by_txid.find(txid_desc)};
+ Assume((desc_it == m_entries_by_txid.end()) == remove_desc);
+ if (remove) Assume(remove_desc);
+ // It's possible that remove=false but remove_desc=true.
+ if (!remove && !remove_desc) {
+ cached_descendants.push_back(desc_it);
+ }
+ }
+ if (remove) {
+ Assume(cached_descendants.empty());
+ } else {
+ m_descendant_set_by_txid.emplace(txid, cached_descendants);
+ }
+ }
+
+ // Release the mempool lock; we now have all the information we need for a subset of the entries
+ // we care about. We will solely operate on the MiniMinerMempoolEntry map from now on.
+ Assume(m_in_block.empty());
+ Assume(m_requested_outpoints_by_txid.size() <= outpoints.size());
+ SanityCheck();
+}
+
+// Compare by min(ancestor feerate, individual feerate), then iterator
+//
+// Under the ancestor-based mining approach, high-feerate children can pay for parents, but high-feerate
+// parents do not incentive inclusion of their children. Therefore the mining algorithm only considers
+// transactions for inclusion on basis of the minimum of their own feerate or their ancestor feerate.
+struct AncestorFeerateComparator
+{
+ template<typename I>
+ bool operator()(const I& a, const I& b) const {
+ auto min_feerate = [](const MiniMinerMempoolEntry& e) -> CFeeRate {
+ const CAmount ancestor_fee{e.GetModFeesWithAncestors()};
+ const int64_t ancestor_size{e.GetSizeWithAncestors()};
+ const CAmount tx_fee{e.GetModifiedFee()};
+ const int64_t tx_size{e.GetTxSize()};
+ // Comparing ancestor feerate with individual feerate:
+ // ancestor_fee / ancestor_size <= tx_fee / tx_size
+ // Avoid division and possible loss of precision by
+ // multiplying both sides by the sizes:
+ return ancestor_fee * tx_size < tx_fee * ancestor_size ?
+ CFeeRate(ancestor_fee, ancestor_size) :
+ CFeeRate(tx_fee, tx_size);
+ };
+ CFeeRate a_feerate{min_feerate(a->second)};
+ CFeeRate b_feerate{min_feerate(b->second)};
+ if (a_feerate != b_feerate) {
+ return a_feerate > b_feerate;
+ }
+ // Use txid as tiebreaker for stable sorting
+ return a->first < b->first;
+ }
+};
+
+void MiniMiner::DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors)
+{
+ Assume(ancestors.size() >= 1);
+ // "Mine" all transactions in this ancestor set.
+ for (auto& anc : ancestors) {
+ Assume(m_in_block.count(anc->first) == 0);
+ m_in_block.insert(anc->first);
+ m_total_fees += anc->second.GetModifiedFee();
+ m_total_vsize += anc->second.GetTxSize();
+ auto it = m_descendant_set_by_txid.find(anc->first);
+ // Each entry’s descendant set includes itself
+ Assume(it != m_descendant_set_by_txid.end());
+ for (auto& descendant : it->second) {
+ // If these fail, we must be double-deducting.
+ Assume(descendant->second.GetModFeesWithAncestors() >= anc->second.GetModifiedFee());
+ Assume(descendant->second.vsize_with_ancestors >= anc->second.GetTxSize());
+ descendant->second.fee_with_ancestors -= anc->second.GetModifiedFee();
+ descendant->second.vsize_with_ancestors -= anc->second.GetTxSize();
+ }
+ }
+ // Delete these entries.
+ for (const auto& anc : ancestors) {
+ m_descendant_set_by_txid.erase(anc->first);
+ // The above loop should have deducted each ancestor's size and fees from each of their
+ // respective descendants exactly once.
+ Assume(anc->second.GetModFeesWithAncestors() == 0);
+ Assume(anc->second.GetSizeWithAncestors() == 0);
+ auto vec_it = std::find(m_entries.begin(), m_entries.end(), anc);
+ Assume(vec_it != m_entries.end());
+ m_entries.erase(vec_it);
+ m_entries_by_txid.erase(anc);
+ }
+}
+
+void MiniMiner::SanityCheck() const
+{
+ // m_entries, m_entries_by_txid, and m_descendant_set_by_txid all same size
+ Assume(m_entries.size() == m_entries_by_txid.size());
+ Assume(m_entries.size() == m_descendant_set_by_txid.size());
+ // Cached ancestor values should be at least as large as the transaction's own fee and size
+ Assume(std::all_of(m_entries.begin(), m_entries.end(), [](const auto& entry) {
+ return entry->second.GetSizeWithAncestors() >= entry->second.GetTxSize() &&
+ entry->second.GetModFeesWithAncestors() >= entry->second.GetModifiedFee();}));
+ // None of the entries should be to-be-replaced transactions
+ Assume(std::all_of(m_to_be_replaced.begin(), m_to_be_replaced.end(),
+ [&](const auto& txid){return m_entries_by_txid.find(txid) == m_entries_by_txid.end();}));
+}
+
+void MiniMiner::BuildMockTemplate(const CFeeRate& target_feerate)
+{
+ while (!m_entries_by_txid.empty()) {
+ // Sort again, since transaction removal may change some m_entries' ancestor feerates.
+ std::sort(m_entries.begin(), m_entries.end(), AncestorFeerateComparator());
+
+ // Pick highest ancestor feerate entry.
+ auto best_iter = m_entries.begin();
+ Assume(best_iter != m_entries.end());
+ const auto ancestor_package_size = (*best_iter)->second.GetSizeWithAncestors();
+ const auto ancestor_package_fee = (*best_iter)->second.GetModFeesWithAncestors();
+ // Stop here. Everything that didn't "make it into the block" has bumpfee.
+ if (ancestor_package_fee < target_feerate.GetFee(ancestor_package_size)) {
+ break;
+ }
+
+ // Calculate ancestors on the fly. This lookup should be fairly cheap, and ancestor sets
+ // change at every iteration, so this is more efficient than maintaining a cache.
+ std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
+ {
+ std::set<MockEntryMap::iterator, IteratorComparator> to_process;
+ to_process.insert(*best_iter);
+ while (!to_process.empty()) {
+ auto iter = to_process.begin();
+ Assume(iter != to_process.end());
+ ancestors.insert(*iter);
+ for (const auto& input : (*iter)->second.GetTx().vin) {
+ if (auto parent_it{m_entries_by_txid.find(input.prevout.hash)}; parent_it != m_entries_by_txid.end()) {
+ if (ancestors.count(parent_it) == 0) {
+ to_process.insert(parent_it);
+ }
+ }
+ }
+ to_process.erase(iter);
+ }
+ }
+ DeleteAncestorPackage(ancestors);
+ SanityCheck();
+ }
+ Assume(m_in_block.empty() || m_total_fees >= target_feerate.GetFee(m_total_vsize));
+ // Do not try to continue building the block template with a different feerate.
+ m_ready_to_calculate = false;
+}
+
+std::map<COutPoint, CAmount> MiniMiner::CalculateBumpFees(const CFeeRate& target_feerate)
+{
+ if (!m_ready_to_calculate) return {};
+ // Build a block template until the target feerate is hit.
+ BuildMockTemplate(target_feerate);
+
+ // Each transaction that "made it into the block" has a bumpfee of 0, i.e. they are part of an
+ // ancestor package with at least the target feerate and don't need to be bumped.
+ for (const auto& txid : m_in_block) {
+ // Not all of the block transactions were necessarily requested.
+ auto it = m_requested_outpoints_by_txid.find(txid);
+ if (it != m_requested_outpoints_by_txid.end()) {
+ for (const auto& outpoint : it->second) {
+ m_bump_fees.emplace(outpoint, 0);
+ }
+ m_requested_outpoints_by_txid.erase(it);
+ }
+ }
+
+ // A transactions and its ancestors will only be picked into a block when
+ // both the ancestor set feerate and the individual feerate meet the target
+ // feerate.
+ //
+ // We had to convince ourselves that after running the mini miner and
+ // picking all eligible transactions into our MockBlockTemplate, there
+ // could still be transactions remaining that have a lower individual
+ // feerate than their ancestor feerate. So here is an example:
+ //
+ // ┌─────────────────┐
+ // │ │
+ // │ Grandparent │
+ // │ 1700 vB │
+ // │ 1700 sats │ Target feerate: 10 s/vB
+ // │ 1 s/vB │ GP Ancestor Set Feerate (ASFR): 1 s/vB
+ // │ │ P1_ASFR: 9.84 s/vB
+ // └──────▲───▲──────┘ P2_ASFR: 2.47 s/vB
+ // │ │ C_ASFR: 10.27 s/vB
+ // ┌───────────────┐ │ │ ┌──────────────┐
+ // │ ├────┘ └────┤ │ ⇒ C_FR < TFR < C_ASFR
+ // │ Parent 1 │ │ Parent 2 │
+ // │ 200 vB │ │ 200 vB │
+ // │ 17000 sats │ │ 3000 sats │
+ // │ 85 s/vB │ │ 15 s/vB │
+ // │ │ │ │
+ // └───────────▲───┘ └───▲──────────┘
+ // │ │
+ // │ ┌───────────┐ │
+ // └────┤ ├────┘
+ // │ Child │
+ // │ 100 vB │
+ // │ 900 sats │
+ // │ 9 s/vB │
+ // │ │
+ // └───────────┘
+ //
+ // We therefore calculate both the bump fee that is necessary to elevate
+ // the individual transaction to the target feerate:
+ // target_feerate × tx_size - tx_fees
+ // and the bump fee that is necessary to bump the entire ancestor set to
+ // the target feerate:
+ // target_feerate × ancestor_set_size - ancestor_set_fees
+ // By picking the maximum from the two, we ensure that a transaction meets
+ // both criteria.
+ for (const auto& [txid, outpoints] : m_requested_outpoints_by_txid) {
+ auto it = m_entries_by_txid.find(txid);
+ Assume(it != m_entries_by_txid.end());
+ if (it != m_entries_by_txid.end()) {
+ Assume(target_feerate.GetFee(it->second.GetSizeWithAncestors()) > std::min(it->second.GetModifiedFee(), it->second.GetModFeesWithAncestors()));
+ CAmount bump_fee_with_ancestors = target_feerate.GetFee(it->second.GetSizeWithAncestors()) - it->second.GetModFeesWithAncestors();
+ CAmount bump_fee_individual = target_feerate.GetFee(it->second.GetTxSize()) - it->second.GetModifiedFee();
+ const CAmount bump_fee{std::max(bump_fee_with_ancestors, bump_fee_individual)};
+ Assume(bump_fee >= 0);
+ for (const auto& outpoint : outpoints) {
+ m_bump_fees.emplace(outpoint, bump_fee);
+ }
+ }
+ }
+ return m_bump_fees;
+}
+
+std::optional<CAmount> MiniMiner::CalculateTotalBumpFees(const CFeeRate& target_feerate)
+{
+ if (!m_ready_to_calculate) return std::nullopt;
+ // Build a block template until the target feerate is hit.
+ BuildMockTemplate(target_feerate);
+
+ // All remaining ancestors that are not part of m_in_block must be bumped, but no other relatives
+ std::set<MockEntryMap::iterator, IteratorComparator> ancestors;
+ std::set<MockEntryMap::iterator, IteratorComparator> to_process;
+ for (const auto& [txid, outpoints] : m_requested_outpoints_by_txid) {
+ // Skip any ancestors that already have a miner score higher than the target feerate
+ // (already "made it" into the block)
+ if (m_in_block.count(txid)) continue;
+ auto iter = m_entries_by_txid.find(txid);
+ if (iter == m_entries_by_txid.end()) continue;
+ to_process.insert(iter);
+ ancestors.insert(iter);
+ }
+
+ std::set<uint256> has_been_processed;
+ while (!to_process.empty()) {
+ auto iter = to_process.begin();
+ const CTransaction& tx = (*iter)->second.GetTx();
+ for (const auto& input : tx.vin) {
+ if (auto parent_it{m_entries_by_txid.find(input.prevout.hash)}; parent_it != m_entries_by_txid.end()) {
+ if (!has_been_processed.count(input.prevout.hash)) {
+ to_process.insert(parent_it);
+ }
+ ancestors.insert(parent_it);
+ }
+ }
+ has_been_processed.insert(tx.GetHash());
+ to_process.erase(iter);
+ }
+ const auto ancestor_package_size = std::accumulate(ancestors.cbegin(), ancestors.cend(), int64_t{0},
+ [](int64_t sum, const auto it) {return sum + it->second.GetTxSize();});
+ const auto ancestor_package_fee = std::accumulate(ancestors.cbegin(), ancestors.cend(), CAmount{0},
+ [](CAmount sum, const auto it) {return sum + it->second.GetModifiedFee();});
+ return target_feerate.GetFee(ancestor_package_size) - ancestor_package_fee;
+}
+} // namespace node
diff --git a/src/node/mini_miner.h b/src/node/mini_miner.h
new file mode 100644
index 0000000000..db07e6d1bf
--- /dev/null
+++ b/src/node/mini_miner.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2022 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_NODE_MINI_MINER_H
+#define BITCOIN_NODE_MINI_MINER_H
+
+#include <txmempool.h>
+
+#include <memory>
+#include <optional>
+#include <stdint.h>
+
+namespace node {
+
+// Container for tracking updates to ancestor feerate as we include ancestors in the "block"
+class MiniMinerMempoolEntry
+{
+ const CAmount fee_individual;
+ const CTransactionRef tx;
+ const int64_t vsize_individual;
+
+// This class must be constructed while holding mempool.cs. After construction, the object's
+// methods can be called without holding that lock.
+public:
+ CAmount fee_with_ancestors;
+ int64_t vsize_with_ancestors;
+ explicit MiniMinerMempoolEntry(CTxMemPool::txiter entry) :
+ fee_individual{entry->GetModifiedFee()},
+ tx{entry->GetSharedTx()},
+ vsize_individual(entry->GetTxSize()),
+ fee_with_ancestors{entry->GetModFeesWithAncestors()},
+ vsize_with_ancestors(entry->GetSizeWithAncestors())
+ { }
+
+ CAmount GetModifiedFee() const { return fee_individual; }
+ CAmount GetModFeesWithAncestors() const { return fee_with_ancestors; }
+ int64_t GetTxSize() const { return vsize_individual; }
+ int64_t GetSizeWithAncestors() const { return vsize_with_ancestors; }
+ const CTransaction& GetTx() const LIFETIMEBOUND { return *tx; }
+};
+
+// Comparator needed for std::set<MockEntryMap::iterator>
+struct IteratorComparator
+{
+ template<typename I>
+ bool operator()(const I& a, const I& b) const
+ {
+ return &(*a) < &(*b);
+ }
+};
+
+/** A minimal version of BlockAssembler. Allows us to run the mining algorithm on a subset of
+ * mempool transactions, ignoring consensus rules, to calculate mining scores. */
+class MiniMiner
+{
+ // When true, a caller may use CalculateBumpFees(). Becomes false if we failed to retrieve
+ // mempool entries (i.e. cluster size too large) or bump fees have already been calculated.
+ bool m_ready_to_calculate{true};
+
+ // Set once per lifetime, fill in during initialization.
+ // txids of to-be-replaced transactions
+ std::set<uint256> m_to_be_replaced;
+
+ // If multiple argument outpoints correspond to the same transaction, cache them together in
+ // a single entry indexed by txid. Then we can just work with txids since all outpoints from
+ // the same tx will have the same bumpfee. Excludes non-mempool transactions.
+ std::map<uint256, std::vector<COutPoint>> m_requested_outpoints_by_txid;
+
+ // What we're trying to calculate.
+ std::map<COutPoint, CAmount> m_bump_fees;
+
+ // The constructed block template
+ std::set<uint256> m_in_block;
+
+ // Information on the current status of the block
+ CAmount m_total_fees{0};
+ int32_t m_total_vsize{0};
+
+ /** Main data structure holding the entries, can be indexed by txid */
+ std::map<uint256, MiniMinerMempoolEntry> m_entries_by_txid;
+ using MockEntryMap = decltype(m_entries_by_txid);
+
+ /** Vector of entries, can be sorted by ancestor feerate. */
+ std::vector<MockEntryMap::iterator> m_entries;
+
+ /** Map of txid to its descendants. Should be inclusive. */
+ std::map<uint256, std::vector<MockEntryMap::iterator>> m_descendant_set_by_txid;
+
+ /** Consider this ancestor package "mined" so remove all these entries from our data structures. */
+ void DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors);
+
+ /** Perform some checks. */
+ void SanityCheck() const;
+
+public:
+ /** Returns true if CalculateBumpFees may be called, false if not. */
+ bool IsReadyToCalculate() const { return m_ready_to_calculate; }
+
+ /** Build a block template until the target feerate is hit. */
+ void BuildMockTemplate(const CFeeRate& target_feerate);
+
+ /** Returns set of txids in the block template if one has been constructed. */
+ std::set<uint256> GetMockTemplateTxids() const { return m_in_block; }
+
+ MiniMiner(const CTxMemPool& mempool, const std::vector<COutPoint>& outpoints);
+
+ /** Construct a new block template and, for each outpoint corresponding to a transaction that
+ * did not make it into the block, calculate the cost of bumping those transactions (and their
+ * ancestors) to the minimum feerate. Returns a map from outpoint to bump fee, or an empty map
+ * if they cannot be calculated. */
+ std::map<COutPoint, CAmount> CalculateBumpFees(const CFeeRate& target_feerate);
+
+ /** Construct a new block template and, calculate the cost of bumping all transactions that did
+ * not make it into the block to the target feerate. Returns the total bump fee, or std::nullopt
+ * if it cannot be calculated. */
+ std::optional<CAmount> CalculateTotalBumpFees(const CFeeRate& target_feerate);
+};
+} // namespace node
+
+#endif // BITCOIN_NODE_MINI_MINER_H
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index c7c8493f0c..026c8084dd 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -122,7 +122,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
return TransactionError::OK;
}
-CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
+CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, uint256& hashBlock, const BlockManager& blockman)
{
if (mempool && !block_index) {
CTransactionRef ptx = mempool->get(hash);
@@ -143,7 +143,7 @@ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMe
}
if (block_index) {
CBlock block;
- if (ReadBlockFromDisk(block, block_index, consensusParams)) {
+ if (blockman.ReadBlockFromDisk(block, *block_index)) {
for (const auto& tx : block.vtx) {
if (tx->GetHash() == hash) {
hashBlock = block_index->GetBlockHash();
diff --git a/src/node/transaction.h b/src/node/transaction.h
index 45f174f13c..168273594c 100644
--- a/src/node/transaction.h
+++ b/src/node/transaction.h
@@ -16,6 +16,7 @@ struct Params;
}
namespace node {
+class BlockManager;
struct NodeContext;
/** Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls.
@@ -53,11 +54,10 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
* @param[in] block_index The block to read from disk, or nullptr
* @param[in] mempool If provided, check mempool for tx
* @param[in] hash The txid
- * @param[in] consensusParams The params
* @param[out] hashBlock The block hash, if the tx was found via -txindex or block_index
* @returns The tx if found, otherwise nullptr
*/
-CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock);
+CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, uint256& hashBlock, const BlockManager& blockman);
} // namespace node
#endif // BITCOIN_NODE_TRANSACTION_H
diff --git a/src/node/txreconciliation.cpp b/src/node/txreconciliation.cpp
index ed04a78cec..d62046daaa 100644
--- a/src/node/txreconciliation.cpp
+++ b/src/node/txreconciliation.cpp
@@ -4,8 +4,9 @@
#include <node/txreconciliation.h>
+#include <common/system.h>
+#include <logging.h>
#include <util/check.h>
-#include <util/system.h>
#include <unordered_map>
#include <variant>
diff --git a/src/node/utxo_snapshot.cpp b/src/node/utxo_snapshot.cpp
index cccf95e552..036a25d0a5 100644
--- a/src/node/utxo_snapshot.cpp
+++ b/src/node/utxo_snapshot.cpp
@@ -4,14 +4,13 @@
#include <node/utxo_snapshot.h>
-#include <fs.h>
#include <logging.h>
#include <streams.h>
#include <sync.h>
#include <tinyformat.h>
#include <txdb.h>
#include <uint256.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <validation.h>
#include <cassert>
@@ -82,10 +81,10 @@ std::optional<uint256> ReadSnapshotBaseBlockhash(fs::path chaindir)
return base_blockhash;
}
-std::optional<fs::path> FindSnapshotChainstateDir()
+std::optional<fs::path> FindSnapshotChainstateDir(const fs::path& data_dir)
{
fs::path possible_dir =
- gArgs.GetDataDirNet() / fs::u8path(strprintf("chainstate%s", SNAPSHOT_CHAINSTATE_SUFFIX));
+ data_dir / fs::u8path(strprintf("chainstate%s", SNAPSHOT_CHAINSTATE_SUFFIX));
if (fs::exists(possible_dir)) {
return possible_dir;
diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h
index c5c018c9e8..a6dd3f3f13 100644
--- a/src/node/utxo_snapshot.h
+++ b/src/node/utxo_snapshot.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_NODE_UTXO_SNAPSHOT_H
#define BITCOIN_NODE_UTXO_SNAPSHOT_H
-#include <fs.h>
#include <kernel/cs_main.h>
#include <serialize.h>
#include <sync.h>
#include <uint256.h>
+#include <util/fs.h>
#include <cstdint>
#include <optional>
@@ -67,7 +67,7 @@ constexpr std::string_view SNAPSHOT_CHAINSTATE_SUFFIX = "_snapshot";
//! Return a path to the snapshot-based chainstate dir, if one exists.
-std::optional<fs::path> FindSnapshotChainstateDir();
+std::optional<fs::path> FindSnapshotChainstateDir(const fs::path& data_dir);
} // namespace node
diff --git a/src/node/validation_cache_args.cpp b/src/node/validation_cache_args.cpp
index 5ea0a8ca0a..ddf24f798d 100644
--- a/src/node/validation_cache_args.cpp
+++ b/src/node/validation_cache_args.cpp
@@ -6,7 +6,7 @@
#include <kernel/validation_cache_sizes.h>
-#include <util/system.h>
+#include <common/args.h>
#include <algorithm>
#include <cstddef>
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index 270212dca5..9a3870d8dc 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -32,8 +32,6 @@ std::optional<OutputType> ParseOutputType(const std::string& type)
return OutputType::BECH32;
} else if (type == OUTPUT_TYPE_STRING_BECH32M) {
return OutputType::BECH32M;
- } else if (type == OUTPUT_TYPE_STRING_UNKNOWN) {
- return OutputType::UNKNOWN;
}
return std::nullopt;
}
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 6f859e2d0d..41f4a4d06b 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -62,7 +62,7 @@ public:
/**
* Return the fee in satoshis for a vsize of 1000 vbytes
*/
- CAmount GetFeePerK() const { return GetFee(1000); }
+ CAmount GetFeePerK() const { return nSatoshisPerK; }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index d244de1bb2..c8f2df781b 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -6,8 +6,8 @@
#include <policy/fees.h>
#include <clientversion.h>
+#include <common/system.h>
#include <consensus/amount.h>
-#include <fs.h>
#include <kernel/mempool_entry.h>
#include <logging.h>
#include <policy/feerate.h>
@@ -18,12 +18,13 @@
#include <sync.h>
#include <tinyformat.h>
#include <uint256.h>
+#include <util/fs.h>
#include <util/serfloat.h>
-#include <util/system.h>
#include <util/time.h>
#include <algorithm>
#include <cassert>
+#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
@@ -527,7 +528,7 @@ bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
}
}
-CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath)
+CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates)
: m_estimation_filepath{estimation_filepath}
{
static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
@@ -545,9 +546,22 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath
shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
- // If the fee estimation file is present, read recorded estimations
AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")};
- if (est_file.IsNull() || !Read(est_file)) {
+
+ // Whenever the fee estimation file is not present return early
+ if (est_file.IsNull()) {
+ LogPrintf("%s is not found. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
+ return;
+ }
+
+ std::chrono::hours file_age = GetFeeEstimatorFileAge();
+ // fee estimate file must not be too old to avoid wrong fee estimates.
+ if (file_age > MAX_FILE_AGE && !read_stale_estimates) {
+ LogPrintf("Fee estimation file %s too old (age=%lld > %lld hours) and will not be used to avoid serving stale estimates.\n", fs::PathToString(m_estimation_filepath), Ticks<std::chrono::hours>(file_age), Ticks<std::chrono::hours>(MAX_FILE_AGE));
+ return;
+ }
+
+ if (!Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
}
@@ -903,10 +917,16 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
void CBlockPolicyEstimator::Flush() {
FlushUnconfirmed();
+ FlushFeeEstimates();
+}
+void CBlockPolicyEstimator::FlushFeeEstimates()
+{
AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "wb")};
if (est_file.IsNull() || !Write(est_file)) {
LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
+ } else {
+ LogPrintf("Flushed fee estimates to %s.\n", fs::PathToString(m_estimation_filepath.filename()));
}
}
@@ -1011,6 +1031,13 @@ void CBlockPolicyEstimator::FlushUnconfirmed()
LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, Ticks<SecondsDouble>(endclear - startclear));
}
+std::chrono::hours CBlockPolicyEstimator::GetFeeEstimatorFileAge()
+{
+ auto file_time = std::filesystem::last_write_time(m_estimation_filepath);
+ auto now = std::filesystem::file_time_type::clock::now();
+ return std::chrono::duration_cast<std::chrono::hours>(now - file_time);
+}
+
static std::set<double> MakeFeeSet(const CFeeRate& min_incremental_fee,
double max_filter_fee_rate,
double fee_filter_spacing)
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 1c24b8c7c3..52761f03ca 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -6,20 +6,33 @@
#define BITCOIN_POLICY_FEES_H
#include <consensus/amount.h>
-#include <fs.h>
#include <policy/feerate.h>
#include <random.h>
#include <sync.h>
#include <threadsafety.h>
#include <uint256.h>
+#include <util/fs.h>
#include <array>
+#include <chrono>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
+
+// How often to flush fee estimates to fee_estimates.dat.
+static constexpr std::chrono::hours FEE_FLUSH_INTERVAL{1};
+
+/** fee_estimates.dat that are more than 60 hours (2.5 days) will not be read,
+ * as the estimates in the file are stale.
+ */
+static constexpr std::chrono::hours MAX_FILE_AGE{60};
+
+// Whether we allow importing a fee_estimates file older than MAX_FILE_AGE.
+static constexpr bool DEFAULT_ACCEPT_STALE_FEE_ESTIMATES{false};
+
class AutoFile;
class CTxMemPoolEntry;
class TxConfirmStats;
@@ -183,7 +196,7 @@ private:
const fs::path m_estimation_filepath;
public:
/** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
- CBlockPolicyEstimator(const fs::path& estimation_filepath);
+ CBlockPolicyEstimator(const fs::path& estimation_filepath, const bool read_stale_estimates);
~CBlockPolicyEstimator();
/** Process all the transactions that have been included in a block */
@@ -239,6 +252,13 @@ public:
void Flush()
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
+ /** Record current fee estimations. */
+ void FlushFeeEstimates()
+ EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
+
+ /** Calculates the age of the file, since last modified */
+ std::chrono::hours GetFeeEstimatorFileAge();
+
private:
mutable Mutex m_cs_fee_estimator;
diff --git a/src/policy/fees_args.cpp b/src/policy/fees_args.cpp
index 1aeb2ab983..988b6d443a 100644
--- a/src/policy/fees_args.cpp
+++ b/src/policy/fees_args.cpp
@@ -4,7 +4,7 @@
#include <policy/fees_args.h>
-#include <util/system.h>
+#include <common/args.h>
namespace {
const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
diff --git a/src/policy/fees_args.h b/src/policy/fees_args.h
index 6b65ce0aa9..ef5cf144af 100644
--- a/src/policy/fees_args.h
+++ b/src/policy/fees_args.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_POLICY_FEES_ARGS_H
#define BITCOIN_POLICY_FEES_ARGS_H
-#include <fs.h>
+#include <util/fs.h>
class ArgsManager;
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 394fb34230..9135cae91c 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -24,7 +24,7 @@ static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000};
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000};
/** The maximum weight for transactions we're willing to relay/mine */
-static constexpr unsigned int MAX_STANDARD_TX_WEIGHT{400000};
+static constexpr int32_t MAX_STANDARD_TX_WEIGHT{400000};
/** The minimum non-witness size for transactions we're willing to relay/mine: one larger than 64 */
static constexpr unsigned int MIN_STANDARD_TX_NONWITNESS_SIZE{65};
/** Maximum number of signature check operations in an IsStandard() P2SH script */
diff --git a/src/protocol.cpp b/src/protocol.cpp
index aa59bae6ff..5ecaabec36 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -5,7 +5,9 @@
#include <protocol.h>
-#include <util/system.h>
+#include <common/system.h>
+
+#include <atomic>
static std::atomic<bool> g_initial_block_download_completed(false);
diff --git a/src/protocol.h b/src/protocol.h
index cbcd400fef..ac4545c311 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -134,7 +134,8 @@ extern const char* GETADDR;
/**
* The mempool message requests the TXIDs of transactions that the receiving
* node has verified as valid but which have not yet appeared in a block.
- * @since protocol version 60002.
+ * @since protocol version 60002 as described by BIP35.
+ * Only available with service bit NODE_BLOOM, see also BIP111.
*/
extern const char* MEMPOOL;
/**
@@ -278,8 +279,6 @@ enum ServiceFlags : uint64_t {
// set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
NODE_NETWORK = (1 << 0),
// NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections.
- // Bitcoin Core nodes used to support this by default, without advertising this bit,
- // but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)
NODE_BLOOM = (1 << 2),
// NODE_WITNESS indicates that a node can be asked for blocks and transactions including
// witness data.
diff --git a/src/psbt.cpp b/src/psbt.cpp
index fe45f2318c..009ed966ed 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -442,6 +442,38 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
return sig_complete;
}
+void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, const int& sighash_type)
+{
+ // Only drop non_witness_utxos if sighash_type != SIGHASH_ANYONECANPAY
+ if ((sighash_type & 0x80) != SIGHASH_ANYONECANPAY) {
+ // Figure out if any non_witness_utxos should be dropped
+ std::vector<unsigned int> to_drop;
+ for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
+ const auto& input = psbtx.inputs.at(i);
+ int wit_ver;
+ std::vector<unsigned char> wit_prog;
+ if (input.witness_utxo.IsNull() || !input.witness_utxo.scriptPubKey.IsWitnessProgram(wit_ver, wit_prog)) {
+ // There's a non-segwit input or Segwit v0, so we cannot drop any witness_utxos
+ to_drop.clear();
+ break;
+ }
+ if (wit_ver == 0) {
+ // Segwit v0, so we cannot drop any non_witness_utxos
+ to_drop.clear();
+ break;
+ }
+ if (input.non_witness_utxo) {
+ to_drop.push_back(i);
+ }
+ }
+
+ // Drop the non_witness_utxos that we can drop
+ for (unsigned int i : to_drop) {
+ psbtx.inputs.at(i).non_witness_utxo = nullptr;
+ }
+ }
+}
+
bool FinalizePSBT(PartiallySignedTransaction& psbtx)
{
// Finalize input signatures -- in case we have partial signatures that add up to a complete
diff --git a/src/psbt.h b/src/psbt.h
index c497584f36..9464b10268 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -1231,6 +1231,9 @@ bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned
**/
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
+/** Reduces the size of the PSBT by dropping unnecessary `non_witness_utxos` (i.e. complete previous transactions) from a psbt when all inputs are segwit v1. */
+void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, const int& sighash_type);
+
/** Counts the unsigned inputs of a PSBT. */
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt);
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index ae5dccfb5a..4866feed67 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -7,6 +7,7 @@
#include <hash.h>
#include <secp256k1.h>
+#include <secp256k1_ellswift.h>
#include <secp256k1_extrakeys.h>
#include <secp256k1_recovery.h>
#include <secp256k1_schnorrsig.h>
@@ -335,6 +336,20 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
return true;
}
+CPubKey EllSwiftPubKey::Decode() const
+{
+ secp256k1_pubkey pubkey;
+ secp256k1_ellswift_decode(secp256k1_context_static, &pubkey, UCharCast(m_pubkey.data()));
+
+ size_t sz = CPubKey::COMPRESSED_SIZE;
+ std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes;
+
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED);
+ assert(sz == vch_bytes.size());
+
+ return CPubKey{vch_bytes.begin(), vch_bytes.end()};
+}
+
void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[0] = nDepth;
memcpy(code+1, vchFingerprint, 4);
diff --git a/src/pubkey.h b/src/pubkey.h
index b3edafea7f..d8d5e3d85b 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -291,6 +291,38 @@ public:
SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
};
+/** An ElligatorSwift-encoded public key. */
+struct EllSwiftPubKey
+{
+private:
+ static constexpr size_t SIZE = 64;
+ std::array<std::byte, SIZE> m_pubkey;
+
+public:
+ /** Construct a new ellswift public key from a given serialization. */
+ EllSwiftPubKey(const std::array<std::byte, SIZE>& ellswift) :
+ m_pubkey(ellswift) {}
+
+ /** Decode to normal compressed CPubKey (for debugging purposes). */
+ CPubKey Decode() const;
+
+ // Read-only access for serialization.
+ const std::byte* data() const { return m_pubkey.data(); }
+ static constexpr size_t size() { return SIZE; }
+ auto begin() const { return m_pubkey.cbegin(); }
+ auto end() const { return m_pubkey.cend(); }
+
+ bool friend operator==(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
+ {
+ return a.m_pubkey == b.m_pubkey;
+ }
+
+ bool friend operator!=(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
+ {
+ return a.m_pubkey != b.m_pubkey;
+ }
+};
+
struct CExtPubKey {
unsigned char version[4];
unsigned char nDepth;
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index e402c51ac4..e4689e4389 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -8,6 +8,7 @@
#include <qt/walletmodel.h>
#include <key_io.h>
+#include <wallet/types.h>
#include <wallet/wallet.h>
#include <algorithm>
@@ -52,17 +53,15 @@ struct AddressTableEntryLessThan
};
/* Determine address type from address purpose */
-static AddressTableEntry::Type translateTransactionType(const QString &strPurpose, bool isMine)
+constexpr AddressTableEntry::Type translateTransactionType(wallet::AddressPurpose purpose, bool isMine)
{
- AddressTableEntry::Type addressType = AddressTableEntry::Hidden;
// "refund" addresses aren't shown, and change addresses aren't returned by getAddresses at all.
- if (strPurpose == "send")
- addressType = AddressTableEntry::Sending;
- else if (strPurpose == "receive")
- addressType = AddressTableEntry::Receiving;
- else if (strPurpose == "unknown" || strPurpose == "") // if purpose not set, guess
- addressType = (isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending);
- return addressType;
+ switch (purpose) {
+ case wallet::AddressPurpose::SEND: return AddressTableEntry::Sending;
+ case wallet::AddressPurpose::RECEIVE: return AddressTableEntry::Receiving;
+ case wallet::AddressPurpose::REFUND: return AddressTableEntry::Hidden;
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
// Private implementation
@@ -85,7 +84,7 @@ public:
continue;
}
AddressTableEntry::Type addressType = translateTransactionType(
- QString::fromStdString(address.purpose), address.is_mine);
+ address.purpose, address.is_mine);
cachedAddressTable.append(AddressTableEntry(addressType,
QString::fromStdString(address.name),
QString::fromStdString(EncodeDestination(address.dest))));
@@ -97,7 +96,7 @@ public:
std::sort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan());
}
- void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status)
+ void updateEntry(const QString &address, const QString &label, bool isMine, wallet::AddressPurpose purpose, int status)
{
// Find address / label in model
QList<AddressTableEntry>::iterator lower = std::lower_bound(
@@ -239,7 +238,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
if(!index.isValid())
return false;
AddressTableEntry *rec = static_cast<AddressTableEntry*>(index.internalPointer());
- std::string strPurpose = (rec->type == AddressTableEntry::Sending ? "send" : "receive");
+ wallet::AddressPurpose purpose = rec->type == AddressTableEntry::Sending ? wallet::AddressPurpose::SEND : wallet::AddressPurpose::RECEIVE;
editStatus = OK;
if(role == Qt::EditRole)
@@ -253,7 +252,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
editStatus = NO_CHANGES;
return false;
}
- walletModel->wallet().setAddressBook(curAddress, value.toString().toStdString(), strPurpose);
+ walletModel->wallet().setAddressBook(curAddress, value.toString().toStdString(), purpose);
} else if(index.column() == Address) {
CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
@@ -282,7 +281,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
// Remove old entry
walletModel->wallet().delAddressBook(curAddress);
// Add new entry with new address
- walletModel->wallet().setAddressBook(newAddress, value.toString().toStdString(), strPurpose);
+ walletModel->wallet().setAddressBook(newAddress, value.toString().toStdString(), purpose);
}
}
return true;
@@ -334,7 +333,7 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex &par
}
void AddressTableModel::updateEntry(const QString &address,
- const QString &label, bool isMine, const QString &purpose, int status)
+ const QString &label, bool isMine, wallet::AddressPurpose purpose, int status)
{
// Update address book model from Bitcoin core
priv->updateEntry(address, label, isMine, purpose, status);
@@ -365,7 +364,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
}
// Add entry
- walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel, "send");
+ walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel, wallet::AddressPurpose::SEND);
}
else if(type == Receive)
{
@@ -416,18 +415,18 @@ QString AddressTableModel::labelForAddress(const QString &address) const
return QString();
}
-QString AddressTableModel::purposeForAddress(const QString &address) const
+std::optional<wallet::AddressPurpose> AddressTableModel::purposeForAddress(const QString &address) const
{
- std::string purpose;
+ wallet::AddressPurpose purpose;
if (getAddressData(address, /* name= */ nullptr, &purpose)) {
- return QString::fromStdString(purpose);
+ return purpose;
}
- return QString();
+ return std::nullopt;
}
bool AddressTableModel::getAddressData(const QString &address,
std::string* name,
- std::string* purpose) const {
+ wallet::AddressPurpose* purpose) const {
CTxDestination destination = DecodeDestination(address.toStdString());
return walletModel->wallet().getAddress(destination, name, /* is_mine= */ nullptr, purpose);
}
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 6cc14654ef..599aa89cad 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_QT_ADDRESSTABLEMODEL_H
#define BITCOIN_QT_ADDRESSTABLEMODEL_H
+#include <optional>
+
#include <QAbstractTableModel>
#include <QStringList>
@@ -16,6 +18,9 @@ class WalletModel;
namespace interfaces {
class Wallet;
}
+namespace wallet {
+enum class AddressPurpose;
+} // namespace wallet
/**
Qt model of the address book in the core. This allows views to access and modify the address book.
@@ -71,7 +76,7 @@ public:
QString labelForAddress(const QString &address) const;
/** Look up purpose for address in address book, if not found return empty string. */
- QString purposeForAddress(const QString &address) const;
+ std::optional<wallet::AddressPurpose> purposeForAddress(const QString &address) const;
/* Look up row index of an address in the model.
Return -1 if not found.
@@ -89,7 +94,7 @@ private:
EditStatus editStatus = OK;
/** Look up address book data given an address string. */
- bool getAddressData(const QString &address, std::string* name, std::string* purpose) const;
+ bool getAddressData(const QString &address, std::string* name, wallet::AddressPurpose* purpose) const;
/** Notify listeners that data changed. */
void emitDataChanged(int index);
@@ -97,7 +102,7 @@ private:
public Q_SLOTS:
/* Update address list from core.
*/
- void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status);
+ void updateEntry(const QString &address, const QString &label, bool isMine, wallet::AddressPurpose purpose, int status);
friend class AddressTablePriv;
};
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 2c413e8b43..8f45af9485 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -9,7 +9,10 @@
#include <qt/bitcoin.h>
#include <chainparams.h>
+#include <node/context.h>
+#include <common/args.h>
#include <common/init.h>
+#include <common/system.h>
#include <init.h>
#include <interfaces/handler.h>
#include <interfaces/init.h>
@@ -31,7 +34,6 @@
#include <uint256.h>
#include <util/exception.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/threadnames.h>
#include <util/translation.h>
#include <validation.h>
@@ -40,6 +42,7 @@
#include <qt/paymentserver.h>
#include <qt/walletcontroller.h>
#include <qt/walletmodel.h>
+#include <wallet/types.h>
#endif // ENABLE_WALLET
#include <boost/signals2/connection.hpp>
@@ -79,6 +82,9 @@ Q_DECLARE_METATYPE(CAmount)
Q_DECLARE_METATYPE(SynchronizationState)
Q_DECLARE_METATYPE(SyncType)
Q_DECLARE_METATYPE(uint256)
+#ifdef ENABLE_WALLET
+Q_DECLARE_METATYPE(wallet::AddressPurpose)
+#endif // ENABLE_WALLET
static void RegisterMetaTypes()
{
@@ -88,7 +94,8 @@ static void RegisterMetaTypes()
qRegisterMetaType<SyncType>();
#ifdef ENABLE_WALLET
qRegisterMetaType<WalletModel*>();
- #endif
+ qRegisterMetaType<wallet::AddressPurpose>();
+ #endif // ENABLE_WALLET
// Register typedefs (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType)
// IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
qRegisterMetaType<CAmount>("CAmount");
@@ -391,9 +398,7 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead
{
qDebug() << __func__ << ": Initialization result: " << success;
- // Set exit result.
- returnValue = success ? EXIT_SUCCESS : EXIT_FAILURE;
- if(success) {
+ if (success) {
delete m_splash;
m_splash = nullptr;
@@ -489,7 +494,7 @@ static void SetupUIArgs(ArgsManager& argsman)
int GuiMain(int argc, char* argv[])
{
#ifdef WIN32
- util::WinCmdLineArgs winArgs;
+ common::WinCmdLineArgs winArgs;
std::tie(argc, argv) = winArgs.get();
#endif
@@ -595,7 +600,7 @@ int GuiMain(int argc, char* argv[])
PaymentServer::ipcParseCommandLine(argc, argv);
#endif
- QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().NetworkIDString()));
+ QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(Params().GetChainType()));
assert(!networkStyle.isNull());
// Allow for separate UI settings for testnets
QApplication::setApplicationName(networkStyle->getAppName());
@@ -647,7 +652,6 @@ int GuiMain(int argc, char* argv[])
app.InitPruneSetting(prune_MiB);
}
- int rv = EXIT_SUCCESS;
try
{
app.createWindow(networkStyle.data());
@@ -660,10 +664,9 @@ int GuiMain(int argc, char* argv[])
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely…").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
#endif
app.exec();
- rv = app.getReturnValue();
} else {
// A dialog with detailed error will have been shown by InitError()
- rv = EXIT_FAILURE;
+ return EXIT_FAILURE;
}
} catch (const std::exception& e) {
PrintExceptionContinue(&e, "Runaway exception");
@@ -672,5 +675,5 @@ int GuiMain(int argc, char* argv[])
PrintExceptionContinue(nullptr, "Runaway exception");
app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated));
}
- return rv;
+ return app.node().getExitStatus();
}
diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h
index 9174e23de6..9622c9d57d 100644
--- a/src/qt/bitcoin.h
+++ b/src/qt/bitcoin.h
@@ -62,9 +62,6 @@ public:
/// Request core initialization
void requestInitialize();
- /// Get process return value
- int getReturnValue() const { return returnValue; }
-
/// Get window identifier of QMainWindow (BitcoinGUI)
WId getMainWinId() const;
@@ -104,7 +101,6 @@ private:
PaymentServer* paymentServer{nullptr};
WalletController* m_wallet_controller{nullptr};
#endif
- int returnValue{0};
const PlatformStyle* platformStyle{nullptr};
std::unique_ptr<QWidget> shutdownWindow;
SplashScreen* m_splash = nullptr;
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 0eae7d3e79..f201d8fa01 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -30,16 +30,17 @@
#include <qt/macdockiconhandler.h>
#endif
-#include <functional>
#include <chain.h>
#include <chainparams.h>
+#include <common/system.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <node/interface_ui.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
+#include <functional>
+
#include <QAction>
#include <QActionGroup>
#include <QApplication>
@@ -689,6 +690,10 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
+ connect(wallet_controller, &WalletController::destroyed, this, [this] {
+ // wallet_controller gets destroyed manually, but it leaves our member copy dangling
+ m_wallet_controller = nullptr;
+ });
auto activity = new LoadWalletsActivity(m_wallet_controller, this);
activity->load();
@@ -701,7 +706,7 @@ WalletController* BitcoinGUI::getWalletController()
void BitcoinGUI::addWallet(WalletModel* walletModel)
{
- if (!walletFrame) return;
+ if (!walletFrame || !m_wallet_controller) return;
WalletView* wallet_view = new WalletView(walletModel, platformStyle, walletFrame);
if (!walletFrame->addView(wallet_view)) return;
@@ -753,7 +758,7 @@ void BitcoinGUI::removeWallet(WalletModel* walletModel)
void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model)
{
- if (!walletFrame) return;
+ if (!walletFrame || !m_wallet_controller) return;
walletFrame->setCurrentWallet(wallet_model);
for (int index = 0; index < m_wallet_selector->count(); ++index) {
if (m_wallet_selector->itemData(index).value<WalletModel*>() == wallet_model) {
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 27aa39a024..71c05768db 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -14,13 +14,22 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring "
"a backup."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"%s failed to validate the -assumeutxo snapshot state. This indicates a "
+"hardware problem, or a bug in the software, or a bad software modification "
+"that allowed an invalid snapshot to be loaded. As a result of this, the node "
+"will shut down and stop using any state that was built on the snapshot, "
+"resetting the chain height from %d to %d. On the next restart, the node will "
+"resume syncing from %d without using any snapshot data. Please report this "
+"incident to %s, including how you obtained the snapshot. The invalid "
+"snapshot chainstate has been left on disk in case it is helpful in "
+"diagnosing the issue that caused this error."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"%s is set very high! Fees this large could be paid on a single transaction."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"%s request to listen on port %u. This port is considered \"bad\" and thus it "
"is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for "
"details and a full list."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"-maxtxfee is set very high! Fees this large could be paid on a single "
-"transaction."),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"-reindex-chainstate option is not compatible with -blockfilterindex. Please "
"temporarily disable blockfilterindex while using -reindex-chainstate, or "
"replace -reindex-chainstate with -reindex to fully rebuild all indexes."),
@@ -90,8 +99,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Failed to rename invalid peers.dat file. Please move or delete it and try "
"again."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -"
-"fallbackfee."),
+"Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable "
+"%s."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"File %s already exists. If you are sure this is what you want, move it out "
"of the way first."),
@@ -99,8 +108,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet "
"forbids connections to IPv4/IPv6"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay "
-"fee of %s to prevent stuck transactions)"),
+"Invalid amount for %s=<amount>: '%s' (must be at least the minrelay fee of "
+"%s to prevent stuck transactions)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Invalid or corrupt peers.dat (%s). If you believe this is a bug, please "
"report it to %s. As a workaround, you can move the file (%s) out of the way "
@@ -186,9 +195,18 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Total length of network version string (%i) exceeds maximum length (%i). "
"Reduce the number or size of uacomments."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Transaction requires one destination of non-0 value, a non-0 feerate, or a "
+"pre-selected input"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"UTXO snapshot failed to validate. Restart to resume normal initial block "
+"download, or try loading a different snapshot."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to replay blocks. You will need to rebuild the database using -"
"reindex-chainstate."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unconfirmed UTXOs are available, but spending them creates a chain of "
+"transactions that will be rejected by the mempool"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n"
"\n"
"The wallet might have been tampered with or created with malicious intent.\n"),
@@ -233,6 +251,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"),
QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"),
QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Block verification was interrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -forcednsseed to true when setting -dnsseed to false."),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -peerblockfilters without -blockfilterindex."),
@@ -255,6 +274,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer version of %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error reading configuration file: %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading next record from wallet database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Cannot extract destination from the generated scriptpubkey"),
@@ -293,10 +313,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -i2psam address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address or hostname: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid P2P permission: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for %s=<amount>: '%s' (must be at least %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for %s=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -%s=<amount>: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -discardfee=<amount>: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid port specified in %s: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid pre-selected input %s"),
@@ -323,11 +342,14 @@ QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to prepare statement t
QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to read database verification error: %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Unexpected application id. Expected %u, got %u"),
QT_TRANSLATE_NOOP("bitcoin-core", "Section [%s] is not recognized."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be read"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Settings file could not be written"),
QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" does not exist"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is a relative path"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is not a directory"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specified blocks directory \"%s\" does not exist."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Specified data directory \"%s\" does not exist."),
QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads…"),
QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "The specified config file %s does not exist"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 8411ec4696..ff7405d139 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -11,11 +11,12 @@
#include <qt/peertablesortproxy.h>
#include <clientversion.h>
+#include <common/args.h>
+#include <common/system.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <net.h>
#include <netbase.h>
-#include <util/system.h>
#include <util/threadnames.h>
#include <util/time.h>
#include <validation.h>
@@ -27,8 +28,8 @@
#include <QThread>
#include <QTimer>
-static int64_t nLastHeaderTipUpdateNotification = 0;
-static int64_t nLastBlockTipUpdateNotification = 0;
+static SteadyClock::time_point g_last_header_tip_update_notification{};
+static SteadyClock::time_point g_last_block_tip_update_notification{};
ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
QObject(parent),
@@ -221,9 +222,9 @@ void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockT
// Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
const bool throttle = (sync_state != SynchronizationState::POST_INIT && synctype == SyncType::BLOCK_SYNC) || sync_state == SynchronizationState::INIT_REINDEX;
- const int64_t now = throttle ? GetTimeMillis() : 0;
- int64_t& nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
- if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) {
+ const auto now{throttle ? SteadyClock::now() : SteadyClock::time_point{}};
+ auto& nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC ? g_last_header_tip_update_notification : g_last_block_tip_update_notification;
+ if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
return;
}
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index e1b1ae12e9..50d3c2e559 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -412,8 +412,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
unsigned int nQuantity = 0;
bool fWitness = false;
- std::vector<COutPoint> vCoinControl;
- m_coin_control.ListSelected(vCoinControl);
+ auto vCoinControl{m_coin_control.ListSelected()};
size_t i = 0;
for (const auto& out : model->wallet().getCoins(vCoinControl)) {
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index 9b3319415d..092a89fa11 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -8,6 +8,8 @@
#include <qt/addresstablemodel.h>
#include <qt/guiutil.h>
+#include <wallet/types.h>
+
#include <QDataWidgetMapper>
#include <QMessageBox>
@@ -137,9 +139,9 @@ QString EditAddressDialog::getDuplicateAddressWarning() const
{
QString dup_address = ui->addressEdit->text();
QString existing_label = model->labelForAddress(dup_address);
- QString existing_purpose = model->purposeForAddress(dup_address);
+ auto existing_purpose = model->purposeForAddress(dup_address);
- if (existing_purpose == "receive" &&
+ if (existing_purpose == wallet::AddressPurpose::RECEIVE &&
(mode == NewSendingAddress || mode == EditSendingAddress)) {
return tr(
"Address \"%1\" already exists as a receiving address with label "
diff --git a/src/qt/forms/psbtoperationsdialog.ui b/src/qt/forms/psbtoperationsdialog.ui
index caae0dab2a..5194826371 100644
--- a/src/qt/forms/psbtoperationsdialog.ui
+++ b/src/qt/forms/psbtoperationsdialog.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>Dialog</string>
+ <string>PSBT Operations</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 83c78d5c18..8d8328aad8 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -12,16 +12,19 @@
#include <base58.h>
#include <chainparams.h>
-#include <fs.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <key_io.h>
+#include <logging.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <protocol.h>
#include <script/script.h>
#include <script/standard.h>
+#include <util/chaintype.h>
#include <util/exception.h>
-#include <util/system.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/time.h>
#ifdef WIN32
@@ -501,12 +504,12 @@ bool LabelOutOfFocusEventFilter::eventFilter(QObject* watched, QEvent* event)
#ifdef WIN32
fs::path static StartupShortcutPath()
{
- std::string chain = gArgs.GetChainName();
- if (chain == CBaseChainParams::MAIN)
+ ChainType chain = gArgs.GetChainType();
+ if (chain == ChainType::MAIN)
return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin.lnk";
- if (chain == CBaseChainParams::TESTNET) // Remove this special case when CBaseChainParams::TESTNET = "testnet4"
+ if (chain == ChainType::TESTNET) // Remove this special case when testnet CBaseChainParams::DataDir() is incremented to "testnet4"
return GetSpecialFolderPath(CSIDL_STARTUP) / "Bitcoin (testnet).lnk";
- return GetSpecialFolderPath(CSIDL_STARTUP) / fs::u8path(strprintf("Bitcoin (%s).lnk", chain));
+ return GetSpecialFolderPath(CSIDL_STARTUP) / fs::u8path(strprintf("Bitcoin (%s).lnk", ChainTypeToString(chain)));
}
bool GetStartOnSystemStartup()
@@ -539,7 +542,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
// Start client minimized
QString strArgs = "-min";
// Set -testnet /-regtest options
- strArgs += QString::fromStdString(strprintf(" -chain=%s", gArgs.GetChainName()));
+ strArgs += QString::fromStdString(strprintf(" -chain=%s", gArgs.GetChainTypeString()));
// Set the path to the shortcut target
psl->SetPath(pszExePath);
@@ -584,10 +587,10 @@ fs::path static GetAutostartDir()
fs::path static GetAutostartFilePath()
{
- std::string chain = gArgs.GetChainName();
- if (chain == CBaseChainParams::MAIN)
+ ChainType chain = gArgs.GetChainType();
+ if (chain == ChainType::MAIN)
return GetAutostartDir() / "bitcoin.desktop";
- return GetAutostartDir() / fs::u8path(strprintf("bitcoin-%s.desktop", chain));
+ return GetAutostartDir() / fs::u8path(strprintf("bitcoin-%s.desktop", ChainTypeToString(chain)));
}
bool GetStartOnSystemStartup()
@@ -627,15 +630,15 @@ bool SetStartOnSystemStartup(bool fAutoStart)
std::ofstream optionFile{GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc};
if (!optionFile.good())
return false;
- std::string chain = gArgs.GetChainName();
+ ChainType chain = gArgs.GetChainType();
// Write a bitcoin.desktop file to the autostart directory:
optionFile << "[Desktop Entry]\n";
optionFile << "Type=Application\n";
- if (chain == CBaseChainParams::MAIN)
+ if (chain == ChainType::MAIN)
optionFile << "Name=Bitcoin\n";
else
- optionFile << strprintf("Name=Bitcoin (%s)\n", chain);
- optionFile << "Exec=" << pszExePath << strprintf(" -min -chain=%s\n", chain);
+ optionFile << strprintf("Name=Bitcoin (%s)\n", ChainTypeToString(chain));
+ optionFile << "Exec=" << pszExePath << strprintf(" -min -chain=%s\n", ChainTypeToString(chain));
optionFile << "Terminal=false\n";
optionFile << "Hidden=false\n";
optionFile.close();
@@ -673,12 +676,17 @@ QString NetworkToQString(Network net)
{
switch (net) {
case NET_UNROUTABLE: return QObject::tr("Unroutable");
- case NET_IPV4: return "IPv4";
- case NET_IPV6: return "IPv6";
- case NET_ONION: return "Onion";
- case NET_I2P: return "I2P";
- case NET_CJDNS: return "CJDNS";
- case NET_INTERNAL: return QObject::tr("Internal");
+ //: Name of IPv4 network in peer info
+ case NET_IPV4: return QObject::tr("IPv4", "network name");
+ //: Name of IPv6 network in peer info
+ case NET_IPV6: return QObject::tr("IPv6", "network name");
+ //: Name of Tor network in peer info
+ case NET_ONION: return QObject::tr("Onion", "network name");
+ //: Name of I2P network in peer info
+ case NET_I2P: return QObject::tr("I2P", "network name");
+ //: Name of CJDNS network in peer info
+ case NET_CJDNS: return QObject::tr("CJDNS", "network name");
+ case NET_INTERNAL: return "Internal"; // should never actually happen
case NET_MAX: assert(false);
} // no default case, so the compiler can warn about missing cases
assert(false);
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 87a323bde9..7f06fdfe37 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -6,10 +6,10 @@
#define BITCOIN_QT_GUIUTIL_H
#include <consensus/amount.h>
-#include <fs.h>
#include <net.h>
#include <netaddress.h>
#include <util/check.h>
+#include <util/fs.h>
#include <QApplication>
#include <QEvent>
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 12aa02340a..f86b167076 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -7,16 +7,18 @@
#endif
#include <chainparams.h>
-#include <fs.h>
#include <qt/intro.h>
#include <qt/forms/ui_intro.h>
+#include <util/chaintype.h>
+#include <util/fs.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
+#include <common/args.h>
#include <interfaces/node.h>
-#include <util/system.h>
+#include <util/fs_helpers.h>
#include <validation.h>
#include <QFileDialog>
@@ -218,7 +220,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB)
{
/* Use selectParams here to guarantee Params() can be used by node interface */
try {
- SelectParams(gArgs.GetChainName());
+ SelectParams(gArgs.GetChainType());
} catch (const std::exception&) {
return false;
}
@@ -318,7 +320,7 @@ void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
void Intro::on_ellipsisButton_clicked()
{
- QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(nullptr, "Choose data directory", ui->dataDirectory->text()));
+ QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(nullptr, tr("Choose data directory"), ui->dataDirectory->text()));
if(!dir.isEmpty())
ui->dataDirectory->setText(dir);
}
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index ebce81b198..644ef5afc2 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -329,7 +329,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>BitcoinApplication</name>
<message>
- <location filename="../bitcoin.cpp" line="+283"/>
+ <location filename="../bitcoin.cpp" line="+267"/>
<source>Settings file %1 might be corrupt or invalid.</source>
<translation type="unfinished"></translation>
</message>
@@ -417,7 +417,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+160"/>
+ <location line="+161"/>
<source>&amp;Minimize</source>
<translation type="unfinished"></translation>
</message>
@@ -427,7 +427,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+395"/>
+ <location line="+407"/>
<source>Network activity disabled.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished"></translation>
@@ -438,7 +438,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1159"/>
+ <location line="-1172"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -533,7 +533,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+119"/>
+ <location line="+120"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
@@ -553,7 +553,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="+459"/>
+ <location line="+471"/>
<source>Syncing Headers (%1%)…</source>
<translation type="unfinished"></translation>
</message>
@@ -578,7 +578,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-832"/>
+ <location line="-845"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -598,7 +598,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+748"/>
+ <location line="+761"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
@@ -646,7 +646,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-817"/>
+ <location line="-830"/>
<source>Ctrl+Q</source>
<translation type="unfinished"></translation>
</message>
@@ -772,7 +772,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+71"/>
+ <location line="+72"/>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Window</translation>
</message>
@@ -792,7 +792,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+260"/>
+ <location line="+272"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
@@ -1429,28 +1429,33 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<location line="+162"/>
<source>%n GB of space available</source>
<translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <numerusform>%n GB of space available</numerusform>
+ <numerusform>%n GB of space available</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+2"/>
<source>(of %n GB needed)</source>
<translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
+ <numerusform>(of %n GB needed)</numerusform>
</translation>
</message>
<message numerus="yes">
<location line="+3"/>
<source>(%n GB needed for full chain)</source>
<translation type="unfinished">
- <numerusform></numerusform>
- <numerusform></numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
+ <numerusform>(%n GB needed for full chain)</numerusform>
</translation>
</message>
<message>
- <location line="+72"/>
+ <location line="+17"/>
+ <source>Choose data directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+55"/>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<translation type="unfinished"></translation>
</message>
@@ -2211,7 +2216,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<name>PSBTOperationsDialog</name>
<message>
<location filename="../forms/psbtoperationsdialog.ui" line="+14"/>
- <source>Dialog</source>
+ <source>PSBT Operations</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -2240,7 +2245,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../psbtoperationsdialog.cpp" line="+61"/>
+ <location filename="../psbtoperationsdialog.cpp" line="+60"/>
<source>Failed to load transaction: %1</source>
<translation type="unfinished"></translation>
</message>
@@ -2498,7 +2503,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+129"/>
+ <location filename="../guiutil.cpp" line="+130"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
@@ -2513,12 +2518,42 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Internal</source>
+ <location line="+2"/>
+ <source>IPv4</source>
+ <comment>network name</comment>
+ <extracomment>Name of IPv4 network in peer info</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+2"/>
+ <source>IPv6</source>
+ <comment>network name</comment>
+ <extracomment>Name of IPv6 network in peer info</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Onion</source>
+ <comment>network name</comment>
+ <extracomment>Name of Tor network in peer info</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>I2P</source>
+ <comment>network name</comment>
+ <extracomment>Name of I2P network in peer info</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>CJDNS</source>
+ <comment>network name</comment>
+ <extracomment>Name of CJDNS network in peer info</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
<source>Inbound</source>
<extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment>
<translation type="unfinished"></translation>
@@ -2660,11 +2695,13 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<location line="+2"/>
+ <location filename="../rpcconsole.cpp" line="+988"/>
<source>%1 kB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+2"/>
+ <location filename="../rpcconsole.cpp" line="+2"/>
<source>%1 MB</source>
<translation type="unfinished"></translation>
</message>
@@ -2674,34 +2711,24 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="-288"/>
+ <location filename="../bitcoin.cpp" line="-281"/>
<source>Do you want to reset settings to default values, or to abort without making changes?</source>
<extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+20"/>
<source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
<extracomment>Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+386"/>
- <source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+9"/>
- <source>Error: Cannot parse configuration file: %1.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+14"/>
+ <location line="+394"/>
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+71"/>
<source>%1 didn&apos;t yet exit safely…</source>
<translation type="unfinished"></translation>
</message>
@@ -2909,7 +2936,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<location line="+68"/>
- <location filename="../rpcconsole.cpp" line="+1155"/>
+ <location filename="../rpcconsole.cpp" line="+165"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -3142,7 +3169,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-202"/>
+ <location filename="../rpcconsole.cpp" line="-203"/>
<source>In:</source>
<translation type="unfinished"></translation>
</message>
@@ -3314,12 +3341,12 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+78"/>
+ <location line="+79"/>
<source>Executing command without any wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+320"/>
+ <location line="+316"/>
<source>Ctrl+I</source>
<translation type="unfinished"></translation>
</message>
@@ -3339,12 +3366,12 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-325"/>
+ <location line="-321"/>
<source>Executing command using &quot;%1&quot; wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-146"/>
+ <location line="-147"/>
<source>Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -3356,7 +3383,7 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+156"/>
+ <location line="+157"/>
<source>Executing…</source>
<extracomment>A console message indicating an entered command is currently being executed.</extracomment>
<translation type="unfinished"></translation>
@@ -3491,7 +3518,47 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+125"/>
+ <location line="+46"/>
+ <source>Base58 (Legacy)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Not recommended due to higher fees and less protection against typos.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Base58 (P2SH-SegWit)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Generates an address compatible with older wallets.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Bech32 (SegWit)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Generates a native segwit address (BIP-173). Some old wallets don&apos;t support it.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Bech32m (Taproot)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+0"/>
+ <source>Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+75"/>
<source>Could not unlock wallet.</source>
<translation type="unfinished"></translation>
</message>
@@ -3644,7 +3711,7 @@ For more information on using this console, type %6.
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+755"/>
+ <location filename="../sendcoinsdialog.cpp" line="+765"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -3831,7 +3898,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-660"/>
+ <location filename="../sendcoinsdialog.cpp" line="-670"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -3913,12 +3980,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+66"/>
+ <location line="+67"/>
<source>To review recipient list click &quot;Show Details…&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+60"/>
+ <location line="+62"/>
<source>Sign failed</source>
<translation type="unfinished"></translation>
</message>
@@ -3929,13 +3996,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+6"/>
<source>External signer failure</source>
<extracomment>&quot;External signer&quot; means using devices such as hardware wallets.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-34"/>
+ <location line="-36"/>
<source>Save Transaction Data</source>
<translation type="unfinished"></translation>
</message>
@@ -3946,17 +4013,18 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+8"/>
<source>PSBT saved</source>
+ <extracomment>Popup message when a PSBT has been saved to a file</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+266"/>
+ <location line="+273"/>
<source>External balance:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-315"/>
+ <location line="-324"/>
<source>or</source>
<translation type="unfinished"></translation>
</message>
@@ -3966,7 +4034,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-30"/>
+ <location line="-31"/>
<source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<extracomment>Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</extracomment>
<translation type="unfinished"></translation>
@@ -3995,7 +4063,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+16"/>
+ <location line="+5"/>
+ <source>%1 kvB</source>
+ <comment>PSBT transaction creation</comment>
+ <extracomment>When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with &quot;virtual size&quot; of the transaction displayed for context</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+12"/>
<source>Not signalling Replace-By-Fee, BIP-125.</source>
<translation type="unfinished"></translation>
</message>
@@ -4005,12 +4080,29 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+99"/>
+ <location line="+24"/>
+ <source>Unsigned Transaction</source>
+ <comment>PSBT copied</comment>
+ <extracomment>Caption of &quot;PSBT has been copied&quot; messagebox</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>The PSBT has been copied to the clipboard. You can also save it.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+29"/>
+ <source>PSBT saved to disk</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+49"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+222"/>
+ <location line="+227"/>
<source>Watch-only balance:</source>
<translation type="unfinished"></translation>
</message>
@@ -4049,8 +4141,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location line="+74"/>
+ <location line="+35"/>
+ <source>%1/kvB</source>
+ <translation type="unfinished"></translation>
+ </message>
<message numerus="yes">
- <location line="+123"/>
+ <location line="+14"/>
<source>Estimated to begin confirmation within %n block(s).</source>
<translation>
<numerusform>Estimated to begin confirmation within %n block.</numerusform>
@@ -4493,17 +4591,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</message>
<message>
<location line="-88"/>
+ <location line="+95"/>
<source>own address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+0"/>
+ <location line="-95"/>
<location line="+69"/>
+ <location line="+28"/>
<source>watch-only</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-67"/>
+ <location line="-95"/>
<source>label</source>
<translation type="unfinished"></translation>
</message>
@@ -4967,7 +5067,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+169"/>
+ <location line="+170"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
@@ -5123,6 +5223,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+0"/>
+ <source>Copied to clipboard</source>
+ <comment>Fee-bump PSBT saved</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+8"/>
<source>Can&apos;t sign transaction.</source>
<translation type="unfinished"></translation>
@@ -5156,7 +5262,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished">Export the data in the current tab to a file</translation>
</message>
<message>
- <location line="+162"/>
+ <location line="+163"/>
<source>Backup Wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -5205,17 +5311,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+15"/>
<source>%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
- <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+15"/>
+ <location line="+16"/>
<source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
<translation type="unfinished"></translation>
</message>
@@ -5280,22 +5381,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+9"/>
<source>File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+9"/>
<source>Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
<translation type="unfinished"></translation>
</message>
@@ -5395,12 +5486,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+9"/>
<source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+10"/>
<source>Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
<translation type="unfinished"></translation>
</message>
@@ -5455,7 +5546,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Cannot resolve -%s address: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -5475,12 +5566,22 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-90"/>
+ <location line="-100"/>
<source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-126"/>
+ <location line="-142"/>
+ <source>%s failed to validate the -assumeutxo snapshot state. This indicates a hardware problem, or a bug in the software, or a bad software modification that allowed an invalid snapshot to be loaded. As a result of this, the node will shut down and stop using any state that was built on the snapshot, resetting the chain height from %d to %d. On the next restart, the node will resume syncing from %d without using any snapshot data. Please report this incident to %s, including how you obtained the snapshot. The invalid snapshot chainstate has been left on disk in case it is helpful in diagnosing the issue that caused this error.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>%s is set very high! Fees this large could be paid on a single transaction.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
<translation type="unfinished"></translation>
</message>
@@ -5525,12 +5626,22 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+3"/>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+3"/>
+ <source>Invalid amount for %s=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+18"/>
<source>Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source>
<translation type="unfinished"></translation>
</message>
@@ -5560,7 +5671,22 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+27"/>
+ <location line="+24"/>
+ <source>Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Unexpected legacy entry in descriptor wallet found. Loading wallet %s
The wallet might have been tampered with or created with malicious intent.
@@ -5594,7 +5720,12 @@ Unable to restore backup of wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+6"/>
+ <source>Block verification was interrupted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+5"/>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished"></translation>
</message>
@@ -5685,6 +5816,11 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
+ <source>Error reading configuration file: %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Error reading from database, shutting down.</source>
<translation type="unfinished"></translation>
</message>
@@ -5875,22 +6011,17 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
- <source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Invalid amount for -discardfee=&lt;amount&gt;: &apos;%s&apos;</source>
+ <source>Invalid amount for %s=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
- <source>Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
+ <source>Invalid amount for %s=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+1"/>
- <source>Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
+ <source>Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -6024,7 +6155,7 @@ Unable to restore backup of wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+3"/>
<source>Signing transaction failed</source>
<translation type="unfinished"></translation>
</message>
@@ -6050,6 +6181,11 @@ Unable to restore backup of wallet.</source>
</message>
<message>
<location line="+1"/>
+ <source>Specified data directory &quot;%s&quot; does not exist.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Starting network threads…</source>
<translation type="unfinished"></translation>
</message>
@@ -6234,12 +6370,12 @@ Unable to restore backup of wallet.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="-514"/>
+ <location line="-44"/>
<source>Settings file could not be read</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+23"/>
+ <location line="+1"/>
<source>Settings file could not be written</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf
index 4920a08d72..d816cea7c4 100644
--- a/src/qt/locale/bitcoin_en.xlf
+++ b/src/qt/locale/bitcoin_en.xlf
@@ -281,609 +281,591 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<group restype="x-trolltech-linguist-context" resname="BitcoinApplication">
<trans-unit id="_msg61">
<source xml:space="preserve">Settings file %1 might be corrupt or invalid.</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
<trans-unit id="_msg62">
<source xml:space="preserve">Runaway exception</source>
- <context-group purpose="location"><context context-type="linenumber">461</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">445</context></context-group>
</trans-unit>
<trans-unit id="_msg63">
<source xml:space="preserve">A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <context-group purpose="location"><context context-type="linenumber">462</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">446</context></context-group>
</trans-unit>
<trans-unit id="_msg64">
<source xml:space="preserve">Internal error</source>
- <context-group purpose="location"><context context-type="linenumber">471</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">455</context></context-group>
</trans-unit>
<trans-unit id="_msg65">
<source xml:space="preserve">An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <context-group purpose="location"><context context-type="linenumber">472</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">456</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
<trans-unit id="_msg66">
<source xml:space="preserve">Do you want to reset settings to default values, or to abort without making changes?</source>
- <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">175</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</note>
</trans-unit>
<trans-unit id="_msg67">
<source xml:space="preserve">A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
- <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</note>
</trans-unit>
<trans-unit id="_msg68">
- <source xml:space="preserve">Error: Specified data directory &quot;%1&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">594</context></context-group>
- </trans-unit>
- <trans-unit id="_msg69">
- <source xml:space="preserve">Error: Cannot parse configuration file: %1.</source>
- <context-group purpose="location"><context context-type="linenumber">603</context></context-group>
- </trans-unit>
- <trans-unit id="_msg70">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">617</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">589</context></context-group>
</trans-unit>
- <trans-unit id="_msg71">
+ <trans-unit id="_msg69">
<source xml:space="preserve">%1 didn&apos;t yet exit safely…</source>
- <context-group purpose="location"><context context-type="linenumber">691</context></context-group>
- </trans-unit>
- </group>
- <group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg72">
- <source xml:space="preserve">Settings file could not be read</source>
- <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
- </trans-unit>
- <trans-unit id="_msg73">
- <source xml:space="preserve">Settings file could not be written</source>
- <context-group purpose="location"><context context-type="linenumber">200</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">660</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bitcoingui.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="BitcoinGUI">
- <trans-unit id="_msg74">
+ <trans-unit id="_msg70">
<source xml:space="preserve">&amp;Overview</source>
<context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
- <trans-unit id="_msg75">
+ <trans-unit id="_msg71">
<source xml:space="preserve">Show general overview of wallet</source>
<context-group purpose="location"><context context-type="linenumber">254</context></context-group>
</trans-unit>
- <trans-unit id="_msg76">
+ <trans-unit id="_msg72">
<source xml:space="preserve">&amp;Transactions</source>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg77">
+ <trans-unit id="_msg73">
<source xml:space="preserve">Browse transaction history</source>
<context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg78">
+ <trans-unit id="_msg74">
<source xml:space="preserve">E&amp;xit</source>
<context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg79">
+ <trans-unit id="_msg75">
<source xml:space="preserve">Quit application</source>
<context-group purpose="location"><context context-type="linenumber">295</context></context-group>
</trans-unit>
- <trans-unit id="_msg80">
+ <trans-unit id="_msg76">
<source xml:space="preserve">&amp;About %1</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg81">
+ <trans-unit id="_msg77">
<source xml:space="preserve">Show information about %1</source>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg82">
+ <trans-unit id="_msg78">
<source xml:space="preserve">About &amp;Qt</source>
<context-group purpose="location"><context context-type="linenumber">302</context></context-group>
</trans-unit>
- <trans-unit id="_msg83">
+ <trans-unit id="_msg79">
<source xml:space="preserve">Show information about Qt</source>
<context-group purpose="location"><context context-type="linenumber">303</context></context-group>
</trans-unit>
- <trans-unit id="_msg84">
+ <trans-unit id="_msg80">
<source xml:space="preserve">Modify configuration options for %1</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg85">
+ <trans-unit id="_msg81">
<source xml:space="preserve">Create a new wallet</source>
<context-group purpose="location"><context context-type="linenumber">350</context></context-group>
</trans-unit>
- <trans-unit id="_msg86">
+ <trans-unit id="_msg82">
<source xml:space="preserve">&amp;Minimize</source>
- <context-group purpose="location"><context context-type="linenumber">510</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
</trans-unit>
- <trans-unit id="_msg87">
+ <trans-unit id="_msg83">
<source xml:space="preserve">Wallet:</source>
- <context-group purpose="location"><context context-type="linenumber">589</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">590</context></context-group>
</trans-unit>
- <trans-unit id="_msg88">
+ <trans-unit id="_msg84">
<source xml:space="preserve">Network activity disabled.</source>
- <context-group purpose="location"><context context-type="linenumber">984</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">997</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip.</note>
</trans-unit>
- <trans-unit id="_msg89">
+ <trans-unit id="_msg85">
<source xml:space="preserve">Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1420</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1433</context></context-group>
</trans-unit>
- <trans-unit id="_msg90">
+ <trans-unit id="_msg86">
<source xml:space="preserve">Send coins to a Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg91">
+ <trans-unit id="_msg87">
<source xml:space="preserve">Backup wallet to another location</source>
<context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg92">
+ <trans-unit id="_msg88">
<source xml:space="preserve">Change the passphrase used for wallet encryption</source>
<context-group purpose="location"><context context-type="linenumber">316</context></context-group>
</trans-unit>
- <trans-unit id="_msg93">
+ <trans-unit id="_msg89">
<source xml:space="preserve">&amp;Send</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg94">
+ <trans-unit id="_msg90">
<source xml:space="preserve">&amp;Receive</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg95">
+ <trans-unit id="_msg91">
<source xml:space="preserve">&amp;Options…</source>
<context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg96">
+ <trans-unit id="_msg92">
<source xml:space="preserve">&amp;Encrypt Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
- <trans-unit id="_msg97">
+ <trans-unit id="_msg93">
<source xml:space="preserve">Encrypt the private keys that belong to your wallet</source>
<context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg98">
+ <trans-unit id="_msg94">
<source xml:space="preserve">&amp;Backup Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">313</context></context-group>
</trans-unit>
- <trans-unit id="_msg99">
+ <trans-unit id="_msg95">
<source xml:space="preserve">&amp;Change Passphrase…</source>
<context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg100">
+ <trans-unit id="_msg96">
<source xml:space="preserve">Sign &amp;message…</source>
<context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg101">
+ <trans-unit id="_msg97">
<source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg102">
+ <trans-unit id="_msg98">
<source xml:space="preserve">&amp;Verify message…</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg103">
+ <trans-unit id="_msg99">
<source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source>
<context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg104">
+ <trans-unit id="_msg100">
<source xml:space="preserve">&amp;Load PSBT from file…</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg105">
+ <trans-unit id="_msg101">
<source xml:space="preserve">Open &amp;URI…</source>
<context-group purpose="location"><context context-type="linenumber">337</context></context-group>
</trans-unit>
- <trans-unit id="_msg106">
+ <trans-unit id="_msg102">
<source xml:space="preserve">Close Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
- <trans-unit id="_msg107">
+ <trans-unit id="_msg103">
<source xml:space="preserve">Create Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">348</context></context-group>
</trans-unit>
- <trans-unit id="_msg108">
+ <trans-unit id="_msg104">
<source xml:space="preserve">Close All Wallets…</source>
<context-group purpose="location"><context context-type="linenumber">358</context></context-group>
</trans-unit>
- <trans-unit id="_msg109">
+ <trans-unit id="_msg105">
<source xml:space="preserve">&amp;File</source>
- <context-group purpose="location"><context context-type="linenumber">477</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">478</context></context-group>
</trans-unit>
- <trans-unit id="_msg110">
+ <trans-unit id="_msg106">
<source xml:space="preserve">&amp;Settings</source>
- <context-group purpose="location"><context context-type="linenumber">497</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">498</context></context-group>
</trans-unit>
- <trans-unit id="_msg111">
+ <trans-unit id="_msg107">
<source xml:space="preserve">&amp;Help</source>
- <context-group purpose="location"><context context-type="linenumber">558</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">559</context></context-group>
</trans-unit>
- <trans-unit id="_msg112">
+ <trans-unit id="_msg108">
<source xml:space="preserve">Tabs toolbar</source>
- <context-group purpose="location"><context context-type="linenumber">569</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">570</context></context-group>
</trans-unit>
- <trans-unit id="_msg113">
+ <trans-unit id="_msg109">
<source xml:space="preserve">Syncing Headers (%1%)…</source>
- <context-group purpose="location"><context context-type="linenumber">1028</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1041</context></context-group>
</trans-unit>
- <trans-unit id="_msg114">
+ <trans-unit id="_msg110">
<source xml:space="preserve">Synchronizing with network…</source>
- <context-group purpose="location"><context context-type="linenumber">1086</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1099</context></context-group>
</trans-unit>
- <trans-unit id="_msg115">
+ <trans-unit id="_msg111">
<source xml:space="preserve">Indexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1091</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1104</context></context-group>
</trans-unit>
- <trans-unit id="_msg116">
+ <trans-unit id="_msg112">
<source xml:space="preserve">Processing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1093</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1106</context></context-group>
</trans-unit>
- <trans-unit id="_msg117">
+ <trans-unit id="_msg113">
<source xml:space="preserve">Connecting to peers…</source>
- <context-group purpose="location"><context context-type="linenumber">1100</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1113</context></context-group>
</trans-unit>
- <trans-unit id="_msg118">
+ <trans-unit id="_msg114">
<source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg119">
+ <trans-unit id="_msg115">
<source xml:space="preserve">Show the list of used sending addresses and labels</source>
<context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg120">
+ <trans-unit id="_msg116">
<source xml:space="preserve">Show the list of used receiving addresses and labels</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg121">
+ <trans-unit id="_msg117">
<source xml:space="preserve">&amp;Command-line options</source>
<context-group purpose="location"><context context-type="linenumber">361</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">1109</context></context-group>
- <trans-unit id="_msg122[0]">
+ <context-group purpose="location"><context context-type="linenumber">1122</context></context-group>
+ <trans-unit id="_msg118[0]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
- <trans-unit id="_msg122[1]">
+ <trans-unit id="_msg118[1]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
</group>
- <trans-unit id="_msg123">
+ <trans-unit id="_msg119">
<source xml:space="preserve">%1 behind</source>
- <context-group purpose="location"><context context-type="linenumber">1132</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1145</context></context-group>
</trans-unit>
- <trans-unit id="_msg124">
+ <trans-unit id="_msg120">
<source xml:space="preserve">Catching up…</source>
- <context-group purpose="location"><context context-type="linenumber">1137</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1150</context></context-group>
</trans-unit>
- <trans-unit id="_msg125">
+ <trans-unit id="_msg121">
<source xml:space="preserve">Last received block was generated %1 ago.</source>
- <context-group purpose="location"><context context-type="linenumber">1156</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1169</context></context-group>
</trans-unit>
- <trans-unit id="_msg126">
+ <trans-unit id="_msg122">
<source xml:space="preserve">Transactions after this will not yet be visible.</source>
- <context-group purpose="location"><context context-type="linenumber">1158</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1171</context></context-group>
</trans-unit>
- <trans-unit id="_msg127">
+ <trans-unit id="_msg123">
<source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">1183</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1196</context></context-group>
</trans-unit>
- <trans-unit id="_msg128">
+ <trans-unit id="_msg124">
<source xml:space="preserve">Warning</source>
- <context-group purpose="location"><context context-type="linenumber">1187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1200</context></context-group>
</trans-unit>
- <trans-unit id="_msg129">
+ <trans-unit id="_msg125">
<source xml:space="preserve">Information</source>
- <context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1204</context></context-group>
</trans-unit>
- <trans-unit id="_msg130">
+ <trans-unit id="_msg126">
<source xml:space="preserve">Up to date</source>
- <context-group purpose="location"><context context-type="linenumber">1113</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1126</context></context-group>
</trans-unit>
- <trans-unit id="_msg131">
+ <trans-unit id="_msg127">
<source xml:space="preserve">Ctrl+Q</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg132">
+ <trans-unit id="_msg128">
<source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source>
<context-group purpose="location"><context context-type="linenumber">322</context></context-group>
</trans-unit>
- <trans-unit id="_msg133">
+ <trans-unit id="_msg129">
<source xml:space="preserve">Load PSBT from &amp;clipboard…</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg134">
+ <trans-unit id="_msg130">
<source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg135">
+ <trans-unit id="_msg131">
<source xml:space="preserve">Node window</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg136">
+ <trans-unit id="_msg132">
<source xml:space="preserve">Open node debugging and diagnostic console</source>
<context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg137">
+ <trans-unit id="_msg133">
<source xml:space="preserve">&amp;Sending addresses</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg138">
+ <trans-unit id="_msg134">
<source xml:space="preserve">&amp;Receiving addresses</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg139">
+ <trans-unit id="_msg135">
<source xml:space="preserve">Open a bitcoin: URI</source>
<context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg140">
+ <trans-unit id="_msg136">
<source xml:space="preserve">Open Wallet</source>
<context-group purpose="location"><context context-type="linenumber">340</context></context-group>
</trans-unit>
- <trans-unit id="_msg141">
+ <trans-unit id="_msg137">
<source xml:space="preserve">Open a wallet</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg142">
+ <trans-unit id="_msg138">
<source xml:space="preserve">Close wallet</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg143">
+ <trans-unit id="_msg139">
<source xml:space="preserve">Restore Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">353</context></context-group>
<note annotates="source" from="developer">Name of the menu item that restores wallet from a backup file.</note>
</trans-unit>
- <trans-unit id="_msg144">
+ <trans-unit id="_msg140">
<source xml:space="preserve">Restore a wallet from a backup file</source>
<context-group purpose="location"><context context-type="linenumber">356</context></context-group>
<note annotates="source" from="developer">Status tip for Restore Wallet menu item</note>
</trans-unit>
- <trans-unit id="_msg145">
+ <trans-unit id="_msg141">
<source xml:space="preserve">Close all wallets</source>
<context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg146">
+ <trans-unit id="_msg142">
<source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<context-group purpose="location"><context context-type="linenumber">363</context></context-group>
</trans-unit>
- <trans-unit id="_msg147">
+ <trans-unit id="_msg143">
<source xml:space="preserve">&amp;Mask values</source>
<context-group purpose="location"><context context-type="linenumber">365</context></context-group>
</trans-unit>
- <trans-unit id="_msg148">
+ <trans-unit id="_msg144">
<source xml:space="preserve">Mask the values in the Overview tab</source>
<context-group purpose="location"><context context-type="linenumber">367</context></context-group>
</trans-unit>
- <trans-unit id="_msg149">
+ <trans-unit id="_msg145">
<source xml:space="preserve">default wallet</source>
<context-group purpose="location"><context context-type="linenumber">398</context></context-group>
</trans-unit>
- <trans-unit id="_msg150">
+ <trans-unit id="_msg146">
<source xml:space="preserve">No wallets available</source>
<context-group purpose="location"><context context-type="linenumber">418</context></context-group>
</trans-unit>
- <trans-unit id="_msg151">
+ <trans-unit id="_msg147">
<source xml:space="preserve">Wallet Data</source>
<context-group purpose="location"><context context-type="linenumber">424</context></context-group>
<note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
- <trans-unit id="_msg152">
+ <trans-unit id="_msg148">
<source xml:space="preserve">Load Wallet Backup</source>
<context-group purpose="location"><context context-type="linenumber">427</context></context-group>
<note annotates="source" from="developer">The title for Restore Wallet File Windows</note>
</trans-unit>
- <trans-unit id="_msg153">
+ <trans-unit id="_msg149">
<source xml:space="preserve">Restore Wallet</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
<note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to restore a wallet.</note>
</trans-unit>
- <trans-unit id="_msg154">
+ <trans-unit id="_msg150">
<source xml:space="preserve">Wallet Name</source>
<context-group purpose="location"><context context-type="linenumber">437</context></context-group>
<note annotates="source" from="developer">Label of the input field where the name of the wallet is entered.</note>
</trans-unit>
- <trans-unit id="_msg155">
+ <trans-unit id="_msg151">
<source xml:space="preserve">&amp;Window</source>
- <context-group purpose="location"><context context-type="linenumber">508</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">509</context></context-group>
</trans-unit>
- <trans-unit id="_msg156">
+ <trans-unit id="_msg152">
<source xml:space="preserve">Ctrl+M</source>
- <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">512</context></context-group>
</trans-unit>
- <trans-unit id="_msg157">
+ <trans-unit id="_msg153">
<source xml:space="preserve">Zoom</source>
- <context-group purpose="location"><context context-type="linenumber">520</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg158">
+ <trans-unit id="_msg154">
<source xml:space="preserve">Main Window</source>
- <context-group purpose="location"><context context-type="linenumber">538</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">539</context></context-group>
</trans-unit>
- <trans-unit id="_msg159">
+ <trans-unit id="_msg155">
<source xml:space="preserve">%1 client</source>
- <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">811</context></context-group>
</trans-unit>
- <trans-unit id="_msg160">
+ <trans-unit id="_msg156">
<source xml:space="preserve">&amp;Hide</source>
- <context-group purpose="location"><context context-type="linenumber">863</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">876</context></context-group>
</trans-unit>
- <trans-unit id="_msg161">
+ <trans-unit id="_msg157">
<source xml:space="preserve">S&amp;how</source>
- <context-group purpose="location"><context context-type="linenumber">864</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">877</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">994</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip.</note>
- <trans-unit id="_msg162[0]">
+ <trans-unit id="_msg158[0]">
<source xml:space="preserve">%n active connection(s) to Bitcoin network.</source>
</trans-unit>
- <trans-unit id="_msg162[1]">
+ <trans-unit id="_msg158[1]">
<source xml:space="preserve">%n active connection(s) to Bitcoin network.</source>
</trans-unit>
</group>
- <trans-unit id="_msg163">
+ <trans-unit id="_msg159">
<source xml:space="preserve">Click for more actions.</source>
- <context-group purpose="location"><context context-type="linenumber">991</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1004</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip. &quot;More actions&quot; are available via the context menu.</note>
</trans-unit>
- <trans-unit id="_msg164">
+ <trans-unit id="_msg160">
<source xml:space="preserve">Show Peers tab</source>
- <context-group purpose="location"><context context-type="linenumber">1008</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1021</context></context-group>
<note annotates="source" from="developer">A context menu item. The &quot;Peers tab&quot; is an element of the &quot;Node window&quot;.</note>
</trans-unit>
- <trans-unit id="_msg165">
+ <trans-unit id="_msg161">
<source xml:space="preserve">Disable network activity</source>
- <context-group purpose="location"><context context-type="linenumber">1016</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1029</context></context-group>
<note annotates="source" from="developer">A context menu item.</note>
</trans-unit>
- <trans-unit id="_msg166">
+ <trans-unit id="_msg162">
<source xml:space="preserve">Enable network activity</source>
- <context-group purpose="location"><context context-type="linenumber">1018</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1031</context></context-group>
<note annotates="source" from="developer">A context menu item. The network activity was disabled previously.</note>
</trans-unit>
- <trans-unit id="_msg167">
+ <trans-unit id="_msg163">
<source xml:space="preserve">Pre-syncing Headers (%1%)…</source>
- <context-group purpose="location"><context context-type="linenumber">1035</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1048</context></context-group>
</trans-unit>
- <trans-unit id="_msg168">
+ <trans-unit id="_msg164">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1184</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1197</context></context-group>
</trans-unit>
- <trans-unit id="_msg169">
+ <trans-unit id="_msg165">
<source xml:space="preserve">Warning: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1201</context></context-group>
</trans-unit>
- <trans-unit id="_msg170">
+ <trans-unit id="_msg166">
<source xml:space="preserve">Date: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1296</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1309</context></context-group>
</trans-unit>
- <trans-unit id="_msg171">
+ <trans-unit id="_msg167">
<source xml:space="preserve">Amount: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1310</context></context-group>
</trans-unit>
- <trans-unit id="_msg172">
+ <trans-unit id="_msg168">
<source xml:space="preserve">Wallet: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1299</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1312</context></context-group>
</trans-unit>
- <trans-unit id="_msg173">
+ <trans-unit id="_msg169">
<source xml:space="preserve">Type: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1301</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1314</context></context-group>
</trans-unit>
- <trans-unit id="_msg174">
+ <trans-unit id="_msg170">
<source xml:space="preserve">Label: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1303</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1316</context></context-group>
</trans-unit>
- <trans-unit id="_msg175">
+ <trans-unit id="_msg171">
<source xml:space="preserve">Address: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1305</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1318</context></context-group>
</trans-unit>
- <trans-unit id="_msg176">
+ <trans-unit id="_msg172">
<source xml:space="preserve">Sent transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1306</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1319</context></context-group>
</trans-unit>
- <trans-unit id="_msg177">
+ <trans-unit id="_msg173">
<source xml:space="preserve">Incoming transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1306</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1319</context></context-group>
</trans-unit>
- <trans-unit id="_msg178">
+ <trans-unit id="_msg174">
<source xml:space="preserve">HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1371</context></context-group>
</trans-unit>
- <trans-unit id="_msg179">
+ <trans-unit id="_msg175">
<source xml:space="preserve">HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1371</context></context-group>
</trans-unit>
- <trans-unit id="_msg180">
+ <trans-unit id="_msg176">
<source xml:space="preserve">Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1371</context></context-group>
</trans-unit>
- <trans-unit id="_msg181">
+ <trans-unit id="_msg177">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1381</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1394</context></context-group>
</trans-unit>
- <trans-unit id="_msg182">
+ <trans-unit id="_msg178">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1389</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1402</context></context-group>
</trans-unit>
- <trans-unit id="_msg183">
+ <trans-unit id="_msg179">
<source xml:space="preserve">Original message:</source>
- <context-group purpose="location"><context context-type="linenumber">1508</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1521</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl">
- <trans-unit id="_msg184">
+ <trans-unit id="_msg180">
<source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source>
- <context-group purpose="location"><context context-type="linenumber">1547</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1560</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg185">
+ <trans-unit id="_msg181">
<source xml:space="preserve">Coin Selection</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg186">
+ <trans-unit id="_msg182">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg187">
+ <trans-unit id="_msg183">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg188">
+ <trans-unit id="_msg184">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg189">
+ <trans-unit id="_msg185">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
- <trans-unit id="_msg190">
+ <trans-unit id="_msg186">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
</trans-unit>
- <trans-unit id="_msg191">
+ <trans-unit id="_msg187">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg192">
+ <trans-unit id="_msg188">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg193">
+ <trans-unit id="_msg189">
<source xml:space="preserve">(un)select all</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg194">
+ <trans-unit id="_msg190">
<source xml:space="preserve">Tree mode</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg195">
+ <trans-unit id="_msg191">
<source xml:space="preserve">List mode</source>
<context-group purpose="location"><context context-type="linenumber">364</context></context-group>
</trans-unit>
- <trans-unit id="_msg196">
+ <trans-unit id="_msg192">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
</trans-unit>
- <trans-unit id="_msg197">
+ <trans-unit id="_msg193">
<source xml:space="preserve">Received with label</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
</trans-unit>
- <trans-unit id="_msg198">
+ <trans-unit id="_msg194">
<source xml:space="preserve">Received with address</source>
<context-group purpose="location"><context context-type="linenumber">430</context></context-group>
</trans-unit>
- <trans-unit id="_msg199">
+ <trans-unit id="_msg195">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
</trans-unit>
- <trans-unit id="_msg200">
+ <trans-unit id="_msg196">
<source xml:space="preserve">Confirmations</source>
<context-group purpose="location"><context context-type="linenumber">440</context></context-group>
</trans-unit>
- <trans-unit id="_msg201">
+ <trans-unit id="_msg197">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
@@ -891,88 +873,88 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../coincontroldialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg202">
+ <trans-unit id="_msg198">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
</trans-unit>
- <trans-unit id="_msg203">
+ <trans-unit id="_msg199">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg204">
+ <trans-unit id="_msg200">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg205">
+ <trans-unit id="_msg201">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg206">
+ <trans-unit id="_msg202">
<source xml:space="preserve">Copy transaction &amp;ID and output index</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg207">
+ <trans-unit id="_msg203">
<source xml:space="preserve">L&amp;ock unspent</source>
<context-group purpose="location"><context context-type="linenumber">63</context></context-group>
</trans-unit>
- <trans-unit id="_msg208">
+ <trans-unit id="_msg204">
<source xml:space="preserve">&amp;Unlock unspent</source>
<context-group purpose="location"><context context-type="linenumber">64</context></context-group>
</trans-unit>
- <trans-unit id="_msg209">
+ <trans-unit id="_msg205">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
</trans-unit>
- <trans-unit id="_msg210">
+ <trans-unit id="_msg206">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg211">
+ <trans-unit id="_msg207">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg212">
+ <trans-unit id="_msg208">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">72</context></context-group>
</trans-unit>
- <trans-unit id="_msg213">
+ <trans-unit id="_msg209">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg214">
+ <trans-unit id="_msg210">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg215">
+ <trans-unit id="_msg211">
<source xml:space="preserve">(%1 locked)</source>
<context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg216">
+ <trans-unit id="_msg212">
<source xml:space="preserve">yes</source>
<context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg217">
+ <trans-unit id="_msg213">
<source xml:space="preserve">no</source>
<context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg218">
+ <trans-unit id="_msg214">
<source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
<context-group purpose="location"><context context-type="linenumber">548</context></context-group>
</trans-unit>
- <trans-unit id="_msg219">
+ <trans-unit id="_msg215">
<source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source>
<context-group purpose="location"><context context-type="linenumber">553</context></context-group>
</trans-unit>
- <trans-unit id="_msg220">
+ <trans-unit id="_msg216">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">600</context></context-group>
<context-group purpose="location"><context context-type="linenumber">654</context></context-group>
</trans-unit>
- <trans-unit id="_msg221">
+ <trans-unit id="_msg217">
<source xml:space="preserve">change from %1 (%2)</source>
<context-group purpose="location"><context context-type="linenumber">647</context></context-group>
</trans-unit>
- <trans-unit id="_msg222">
+ <trans-unit id="_msg218">
<source xml:space="preserve">(change)</source>
<context-group purpose="location"><context context-type="linenumber">648</context></context-group>
</trans-unit>
@@ -980,114 +962,114 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../walletcontroller.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletActivity">
- <trans-unit id="_msg223">
+ <trans-unit id="_msg219">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">244</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of creation of a new wallet.</note>
</trans-unit>
- <trans-unit id="_msg224">
+ <trans-unit id="_msg220">
<source xml:space="preserve">Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
<note annotates="source" from="developer">Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</note>
</trans-unit>
- <trans-unit id="_msg225">
+ <trans-unit id="_msg221">
<source xml:space="preserve">Create wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg226">
+ <trans-unit id="_msg222">
<source xml:space="preserve">Create wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg227">
+ <trans-unit id="_msg223">
<source xml:space="preserve">Can&apos;t list signers</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg228">
+ <trans-unit id="_msg224">
<source xml:space="preserve">Too many external signers found</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="LoadWalletsActivity">
- <trans-unit id="_msg229">
+ <trans-unit id="_msg225">
<source xml:space="preserve">Load Wallets</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being loaded.</note>
</trans-unit>
- <trans-unit id="_msg230">
+ <trans-unit id="_msg226">
<source xml:space="preserve">Loading wallets…</source>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
<note annotates="source" from="developer">Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="OpenWalletActivity">
- <trans-unit id="_msg231">
+ <trans-unit id="_msg227">
<source xml:space="preserve">Open wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg232">
+ <trans-unit id="_msg228">
<source xml:space="preserve">Open wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg233">
+ <trans-unit id="_msg229">
<source xml:space="preserve">default wallet</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg234">
+ <trans-unit id="_msg230">
<source xml:space="preserve">Open Wallet</source>
<context-group purpose="location"><context context-type="linenumber">348</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of opening of a wallet.</note>
</trans-unit>
- <trans-unit id="_msg235">
+ <trans-unit id="_msg231">
<source xml:space="preserve">Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
<note annotates="source" from="developer">Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="RestoreWalletActivity">
- <trans-unit id="_msg236">
+ <trans-unit id="_msg232">
<source xml:space="preserve">Restore Wallet</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being restored.</note>
</trans-unit>
- <trans-unit id="_msg237">
+ <trans-unit id="_msg233">
<source xml:space="preserve">Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
<context-group purpose="location"><context context-type="linenumber">403</context></context-group>
<note annotates="source" from="developer">Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</note>
</trans-unit>
- <trans-unit id="_msg238">
+ <trans-unit id="_msg234">
<source xml:space="preserve">Restore wallet failed</source>
<context-group purpose="location"><context context-type="linenumber">422</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet could not be restored.</note>
</trans-unit>
- <trans-unit id="_msg239">
+ <trans-unit id="_msg235">
<source xml:space="preserve">Restore wallet warning</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet is restored with some warning.</note>
</trans-unit>
- <trans-unit id="_msg240">
+ <trans-unit id="_msg236">
<source xml:space="preserve">Restore wallet message</source>
<context-group purpose="location"><context context-type="linenumber">428</context></context-group>
<note annotates="source" from="developer">Title of message box which is displayed when the wallet is successfully restored.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="WalletController">
- <trans-unit id="_msg241">
+ <trans-unit id="_msg237">
<source xml:space="preserve">Close wallet</source>
<context-group purpose="location"><context context-type="linenumber">84</context></context-group>
</trans-unit>
- <trans-unit id="_msg242">
+ <trans-unit id="_msg238">
<source xml:space="preserve">Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg243">
+ <trans-unit id="_msg239">
<source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg244">
+ <trans-unit id="_msg240">
<source xml:space="preserve">Close all wallets</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg245">
+ <trans-unit id="_msg241">
<source xml:space="preserve">Are you sure you wish to close all wallets?</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
@@ -1095,59 +1077,59 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg246">
+ <trans-unit id="_msg242">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg247">
+ <trans-unit id="_msg243">
<source xml:space="preserve">Wallet Name</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg248">
+ <trans-unit id="_msg244">
<source xml:space="preserve">Wallet</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg249">
+ <trans-unit id="_msg245">
<source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg250">
+ <trans-unit id="_msg246">
<source xml:space="preserve">Encrypt Wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg251">
+ <trans-unit id="_msg247">
<source xml:space="preserve">Advanced Options</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg252">
+ <trans-unit id="_msg248">
<source xml:space="preserve">Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg253">
+ <trans-unit id="_msg249">
<source xml:space="preserve">Disable Private Keys</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg254">
+ <trans-unit id="_msg250">
<source xml:space="preserve">Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg255">
+ <trans-unit id="_msg251">
<source xml:space="preserve">Make Blank Wallet</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg256">
+ <trans-unit id="_msg252">
<source xml:space="preserve">Use descriptors for scriptPubKey management</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg257">
+ <trans-unit id="_msg253">
<source xml:space="preserve">Descriptor Wallet</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg258">
+ <trans-unit id="_msg254">
<source xml:space="preserve">Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
<context-group purpose="location"><context context-type="linenumber">118</context></context-group>
</trans-unit>
- <trans-unit id="_msg259">
+ <trans-unit id="_msg255">
<source xml:space="preserve">External signer</source>
<context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
@@ -1155,15 +1137,15 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../createwalletdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg260">
+ <trans-unit id="_msg256">
<source xml:space="preserve">Create</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg261">
+ <trans-unit id="_msg257">
<source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg262">
+ <trans-unit id="_msg258">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">104</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
@@ -1172,23 +1154,23 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg263">
+ <trans-unit id="_msg259">
<source xml:space="preserve">Edit Address</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg264">
+ <trans-unit id="_msg260">
<source xml:space="preserve">&amp;Label</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg265">
+ <trans-unit id="_msg261">
<source xml:space="preserve">The label associated with this address list entry</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg266">
+ <trans-unit id="_msg262">
<source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source>
<context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg267">
+ <trans-unit id="_msg263">
<source xml:space="preserve">&amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
@@ -1196,35 +1178,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../editaddressdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg268">
+ <trans-unit id="_msg264">
<source xml:space="preserve">New sending address</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg269">
+ <trans-unit id="_msg265">
<source xml:space="preserve">Edit receiving address</source>
<context-group purpose="location"><context context-type="linenumber">30</context></context-group>
</trans-unit>
- <trans-unit id="_msg270">
+ <trans-unit id="_msg266">
<source xml:space="preserve">Edit sending address</source>
<context-group purpose="location"><context context-type="linenumber">34</context></context-group>
</trans-unit>
- <trans-unit id="_msg271">
+ <trans-unit id="_msg267">
<source xml:space="preserve">The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg272">
+ <trans-unit id="_msg268">
<source xml:space="preserve">Address &quot;%1&quot; already exists as a receiving address with label &quot;%2&quot; and so cannot be added as a sending address.</source>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg273">
+ <trans-unit id="_msg269">
<source xml:space="preserve">The entered address &quot;%1&quot; is already in the address book with label &quot;%2&quot;.</source>
<context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg274">
+ <trans-unit id="_msg270">
<source xml:space="preserve">Could not unlock wallet.</source>
<context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
- <trans-unit id="_msg275">
+ <trans-unit id="_msg271">
<source xml:space="preserve">New key generation failed.</source>
<context-group purpose="location"><context context-type="linenumber">126</context></context-group>
</trans-unit>
@@ -1232,90 +1214,94 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../intro.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="FreespaceChecker">
- <trans-unit id="_msg276">
+ <trans-unit id="_msg272">
<source xml:space="preserve">A new data directory will be created.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg277">
+ <trans-unit id="_msg273">
<source xml:space="preserve">name</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg278">
+ <trans-unit id="_msg274">
<source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg279">
+ <trans-unit id="_msg275">
<source xml:space="preserve">Path already exists, and is not a directory.</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg280">
+ <trans-unit id="_msg276">
<source xml:space="preserve">Cannot create data directory here.</source>
<context-group purpose="location"><context context-type="linenumber">107</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg281">
+ <trans-unit id="_msg277">
<source xml:space="preserve">Bitcoin</source>
<context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
- <trans-unit id="_msg282[0]">
+ <trans-unit id="_msg278[0]">
<source xml:space="preserve">%n GB of space available</source>
</trans-unit>
- <trans-unit id="_msg282[1]">
+ <trans-unit id="_msg278[1]">
<source xml:space="preserve">%n GB of space available</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
- <trans-unit id="_msg283[0]">
+ <trans-unit id="_msg279[0]">
<source xml:space="preserve">(of %n GB needed)</source>
</trans-unit>
- <trans-unit id="_msg283[1]">
+ <trans-unit id="_msg279[1]">
<source xml:space="preserve">(of %n GB needed)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
- <trans-unit id="_msg284[0]">
+ <trans-unit id="_msg280[0]">
<source xml:space="preserve">(%n GB needed for full chain)</source>
</trans-unit>
- <trans-unit id="_msg284[1]">
+ <trans-unit id="_msg280[1]">
<source xml:space="preserve">(%n GB needed for full chain)</source>
</trans-unit>
</group>
- <trans-unit id="_msg285">
+ <trans-unit id="_msg281">
+ <source xml:space="preserve">Choose data directory</source>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg282">
<source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg286">
+ <trans-unit id="_msg283">
<source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source>
<context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">388</context></context-group>
<note annotates="source" from="developer">Explanatory text on the capability of the current prune target.</note>
- <trans-unit id="_msg287[0]">
+ <trans-unit id="_msg284[0]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
- <trans-unit id="_msg287[1]">
+ <trans-unit id="_msg284[1]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
</group>
- <trans-unit id="_msg288">
+ <trans-unit id="_msg285">
<source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source>
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg289">
+ <trans-unit id="_msg286">
<source xml:space="preserve">The wallet will also be stored in this directory.</source>
<context-group purpose="location"><context context-type="linenumber">392</context></context-group>
</trans-unit>
- <trans-unit id="_msg290">
+ <trans-unit id="_msg287">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg291">
+ <trans-unit id="_msg288">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">278</context></context-group>
</trans-unit>
@@ -1323,25 +1309,25 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../utilitydialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="HelpMessageDialog">
- <trans-unit id="_msg292">
+ <trans-unit id="_msg289">
<source xml:space="preserve">version</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg293">
+ <trans-unit id="_msg290">
<source xml:space="preserve">About %1</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg294">
+ <trans-unit id="_msg291">
<source xml:space="preserve">Command-line options</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="ShutdownWindow">
- <trans-unit id="_msg295">
+ <trans-unit id="_msg292">
<source xml:space="preserve">%1 is shutting down…</source>
<context-group purpose="location"><context context-type="linenumber">145</context></context-group>
</trans-unit>
- <trans-unit id="_msg296">
+ <trans-unit id="_msg293">
<source xml:space="preserve">Do not shut down the computer until this window disappears.</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -1349,47 +1335,47 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg297">
+ <trans-unit id="_msg294">
<source xml:space="preserve">Welcome</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg298">
+ <trans-unit id="_msg295">
<source xml:space="preserve">Welcome to %1.</source>
<context-group purpose="location"><context context-type="linenumber">23</context></context-group>
</trans-unit>
- <trans-unit id="_msg299">
+ <trans-unit id="_msg296">
<source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg300">
+ <trans-unit id="_msg297">
<source xml:space="preserve">Limit block chain storage to</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg301">
+ <trans-unit id="_msg298">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg302">
+ <trans-unit id="_msg299">
<source xml:space="preserve"> GB</source>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg303">
+ <trans-unit id="_msg300">
<source xml:space="preserve">This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg304">
+ <trans-unit id="_msg301">
<source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
<context-group purpose="location"><context context-type="linenumber">206</context></context-group>
</trans-unit>
- <trans-unit id="_msg305">
+ <trans-unit id="_msg302">
<source xml:space="preserve">If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg306">
+ <trans-unit id="_msg303">
<source xml:space="preserve">Use the default data directory</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg307">
+ <trans-unit id="_msg304">
<source xml:space="preserve">Use a custom data directory:</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
@@ -1397,54 +1383,54 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg308">
+ <trans-unit id="_msg305">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg309">
+ <trans-unit id="_msg306">
<source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet&apos;s balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
<context-group purpose="location"><context context-type="linenumber">133</context></context-group>
</trans-unit>
- <trans-unit id="_msg310">
+ <trans-unit id="_msg307">
<source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg311">
+ <trans-unit id="_msg308">
<source xml:space="preserve">Number of blocks left</source>
<context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg312">
+ <trans-unit id="_msg309">
<source xml:space="preserve">Unknown…</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg313">
+ <trans-unit id="_msg310">
<source xml:space="preserve">calculating…</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg314">
+ <trans-unit id="_msg311">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">235</context></context-group>
</trans-unit>
- <trans-unit id="_msg315">
+ <trans-unit id="_msg312">
<source xml:space="preserve">Progress</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg316">
+ <trans-unit id="_msg313">
<source xml:space="preserve">Progress increase per hour</source>
<context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg317">
+ <trans-unit id="_msg314">
<source xml:space="preserve">Estimated time left until synced</source>
<context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg318">
+ <trans-unit id="_msg315">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg319">
+ <trans-unit id="_msg316">
<source xml:space="preserve">Esc</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
@@ -1452,21 +1438,21 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../modaloverlay.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg320">
+ <trans-unit id="_msg317">
<source xml:space="preserve">%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg321">
+ <trans-unit id="_msg318">
<source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg322">
+ <trans-unit id="_msg319">
<source xml:space="preserve">Unknown. Pre-syncing Headers (%1, %2%)…</source>
<context-group purpose="location"><context context-type="linenumber">163</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg323">
+ <trans-unit id="_msg320">
<source xml:space="preserve">unknown</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
@@ -1474,15 +1460,15 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OpenURIDialog">
- <trans-unit id="_msg324">
+ <trans-unit id="_msg321">
<source xml:space="preserve">Open bitcoin URI</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg325">
+ <trans-unit id="_msg322">
<source xml:space="preserve">URI:</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg326">
+ <trans-unit id="_msg323">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
<note annotates="source" from="developer">Tooltip text for button that allows you to paste an address that is in your clipboard.</note>
@@ -1491,310 +1477,310 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg327">
+ <trans-unit id="_msg324">
<source xml:space="preserve">Options</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg328">
+ <trans-unit id="_msg325">
<source xml:space="preserve">&amp;Main</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg329">
+ <trans-unit id="_msg326">
<source xml:space="preserve">Automatically start %1 after logging in to the system.</source>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg330">
+ <trans-unit id="_msg327">
<source xml:space="preserve">&amp;Start %1 on system login</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg331">
+ <trans-unit id="_msg328">
<source xml:space="preserve">Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg332">
+ <trans-unit id="_msg329">
<source xml:space="preserve">Size of &amp;database cache</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg333">
+ <trans-unit id="_msg330">
<source xml:space="preserve">Number of script &amp;verification threads</source>
<context-group purpose="location"><context context-type="linenumber">157</context></context-group>
</trans-unit>
- <trans-unit id="_msg334">
+ <trans-unit id="_msg331">
<source xml:space="preserve">Full path to a %1 compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
<context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg335">
+ <trans-unit id="_msg332">
<source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<context-group purpose="location"><context context-type="linenumber">388</context></context-group>
<context-group purpose="location"><context context-type="linenumber">575</context></context-group>
</trans-unit>
- <trans-unit id="_msg336">
+ <trans-unit id="_msg333">
<source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
<context-group purpose="location"><context context-type="linenumber">457</context></context-group>
<context-group purpose="location"><context context-type="linenumber">480</context></context-group>
<context-group purpose="location"><context context-type="linenumber">503</context></context-group>
</trans-unit>
- <trans-unit id="_msg337">
+ <trans-unit id="_msg334">
<source xml:space="preserve">Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
<context-group purpose="location"><context context-type="linenumber">672</context></context-group>
</trans-unit>
- <trans-unit id="_msg338">
+ <trans-unit id="_msg335">
<source xml:space="preserve">Options set in this dialog are overridden by the command line:</source>
<context-group purpose="location"><context context-type="linenumber">899</context></context-group>
</trans-unit>
- <trans-unit id="_msg339">
+ <trans-unit id="_msg336">
<source xml:space="preserve">Open the %1 configuration file from the working directory.</source>
<context-group purpose="location"><context context-type="linenumber">944</context></context-group>
</trans-unit>
- <trans-unit id="_msg340">
+ <trans-unit id="_msg337">
<source xml:space="preserve">Open Configuration File</source>
<context-group purpose="location"><context context-type="linenumber">947</context></context-group>
</trans-unit>
- <trans-unit id="_msg341">
+ <trans-unit id="_msg338">
<source xml:space="preserve">Reset all client options to default.</source>
<context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg342">
+ <trans-unit id="_msg339">
<source xml:space="preserve">&amp;Reset Options</source>
<context-group purpose="location"><context context-type="linenumber">960</context></context-group>
</trans-unit>
- <trans-unit id="_msg343">
+ <trans-unit id="_msg340">
<source xml:space="preserve">&amp;Network</source>
<context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg344">
+ <trans-unit id="_msg341">
<source xml:space="preserve">Prune &amp;block storage to</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg345">
+ <trans-unit id="_msg342">
<source xml:space="preserve">GB</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg346">
+ <trans-unit id="_msg343">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg347">
+ <trans-unit id="_msg344">
<source xml:space="preserve">Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</note>
</trans-unit>
- <trans-unit id="_msg348">
+ <trans-unit id="_msg345">
<source xml:space="preserve">MiB</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg349">
+ <trans-unit id="_msg346">
<source xml:space="preserve">Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</note>
</trans-unit>
- <trans-unit id="_msg350">
+ <trans-unit id="_msg347">
<source xml:space="preserve">(0 = auto, &lt;0 = leave that many cores free)</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg351">
+ <trans-unit id="_msg348">
<source xml:space="preserve">This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that enables the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg352">
+ <trans-unit id="_msg349">
<source xml:space="preserve">Enable R&amp;PC server</source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
<note annotates="source" from="developer">An Options window setting to enable the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg353">
+ <trans-unit id="_msg350">
<source xml:space="preserve">W&amp;allet</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg354">
+ <trans-unit id="_msg351">
<source xml:space="preserve">Whether to set subtract fee from amount as default or not.</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg355">
+ <trans-unit id="_msg352">
<source xml:space="preserve">Subtract &amp;fee from amount by default</source>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
<note annotates="source" from="developer">An Options window setting to set subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg356">
+ <trans-unit id="_msg353">
<source xml:space="preserve">Expert</source>
<context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg357">
+ <trans-unit id="_msg354">
<source xml:space="preserve">Enable coin &amp;control features</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg358">
+ <trans-unit id="_msg355">
<source xml:space="preserve">If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg359">
+ <trans-unit id="_msg356">
<source xml:space="preserve">&amp;Spend unconfirmed change</source>
<context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg360">
+ <trans-unit id="_msg357">
<source xml:space="preserve">Enable &amp;PSBT controls</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<note annotates="source" from="developer">An options window setting to enable PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg361">
+ <trans-unit id="_msg358">
<source xml:space="preserve">Whether to show PSBT controls.</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
<note annotates="source" from="developer">Tooltip text for options window setting that enables PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg362">
+ <trans-unit id="_msg359">
<source xml:space="preserve">External Signer (e.g. hardware wallet)</source>
<context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg363">
+ <trans-unit id="_msg360">
<source xml:space="preserve">&amp;External signer script path</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg364">
+ <trans-unit id="_msg361">
<source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg365">
+ <trans-unit id="_msg362">
<source xml:space="preserve">Map port using &amp;UPnP</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg366">
+ <trans-unit id="_msg363">
<source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
<context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg367">
+ <trans-unit id="_msg364">
<source xml:space="preserve">Map port using NA&amp;T-PMP</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg368">
+ <trans-unit id="_msg365">
<source xml:space="preserve">Accept connections from outside.</source>
<context-group purpose="location"><context context-type="linenumber">341</context></context-group>
</trans-unit>
- <trans-unit id="_msg369">
+ <trans-unit id="_msg366">
<source xml:space="preserve">Allow incomin&amp;g connections</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg370">
+ <trans-unit id="_msg367">
<source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg371">
+ <trans-unit id="_msg368">
<source xml:space="preserve">&amp;Connect through SOCKS5 proxy (default proxy):</source>
<context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg372">
+ <trans-unit id="_msg369">
<source xml:space="preserve">Proxy &amp;IP:</source>
<context-group purpose="location"><context context-type="linenumber">363</context></context-group>
<context-group purpose="location"><context context-type="linenumber">550</context></context-group>
</trans-unit>
- <trans-unit id="_msg373">
+ <trans-unit id="_msg370">
<source xml:space="preserve">&amp;Port:</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
<context-group purpose="location"><context context-type="linenumber">582</context></context-group>
</trans-unit>
- <trans-unit id="_msg374">
+ <trans-unit id="_msg371">
<source xml:space="preserve">Port of the proxy (e.g. 9050)</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
<context-group purpose="location"><context context-type="linenumber">607</context></context-group>
</trans-unit>
- <trans-unit id="_msg375">
+ <trans-unit id="_msg372">
<source xml:space="preserve">Used for reaching peers via:</source>
<context-group purpose="location"><context context-type="linenumber">444</context></context-group>
</trans-unit>
- <trans-unit id="_msg376">
+ <trans-unit id="_msg373">
<source xml:space="preserve">IPv4</source>
<context-group purpose="location"><context context-type="linenumber">467</context></context-group>
</trans-unit>
- <trans-unit id="_msg377">
+ <trans-unit id="_msg374">
<source xml:space="preserve">IPv6</source>
<context-group purpose="location"><context context-type="linenumber">490</context></context-group>
</trans-unit>
- <trans-unit id="_msg378">
+ <trans-unit id="_msg375">
<source xml:space="preserve">Tor</source>
<context-group purpose="location"><context context-type="linenumber">513</context></context-group>
</trans-unit>
- <trans-unit id="_msg379">
+ <trans-unit id="_msg376">
<source xml:space="preserve">&amp;Window</source>
<context-group purpose="location"><context context-type="linenumber">643</context></context-group>
</trans-unit>
- <trans-unit id="_msg380">
+ <trans-unit id="_msg377">
<source xml:space="preserve">Show the icon in the system tray.</source>
<context-group purpose="location"><context context-type="linenumber">649</context></context-group>
</trans-unit>
- <trans-unit id="_msg381">
+ <trans-unit id="_msg378">
<source xml:space="preserve">&amp;Show tray icon</source>
<context-group purpose="location"><context context-type="linenumber">652</context></context-group>
</trans-unit>
- <trans-unit id="_msg382">
+ <trans-unit id="_msg379">
<source xml:space="preserve">Show only a tray icon after minimizing the window.</source>
<context-group purpose="location"><context context-type="linenumber">662</context></context-group>
</trans-unit>
- <trans-unit id="_msg383">
+ <trans-unit id="_msg380">
<source xml:space="preserve">&amp;Minimize to the tray instead of the taskbar</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg384">
+ <trans-unit id="_msg381">
<source xml:space="preserve">M&amp;inimize on close</source>
<context-group purpose="location"><context context-type="linenumber">675</context></context-group>
</trans-unit>
- <trans-unit id="_msg385">
+ <trans-unit id="_msg382">
<source xml:space="preserve">&amp;Display</source>
<context-group purpose="location"><context context-type="linenumber">696</context></context-group>
</trans-unit>
- <trans-unit id="_msg386">
+ <trans-unit id="_msg383">
<source xml:space="preserve">User Interface &amp;language:</source>
<context-group purpose="location"><context context-type="linenumber">704</context></context-group>
</trans-unit>
- <trans-unit id="_msg387">
+ <trans-unit id="_msg384">
<source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source>
<context-group purpose="location"><context context-type="linenumber">717</context></context-group>
</trans-unit>
- <trans-unit id="_msg388">
+ <trans-unit id="_msg385">
<source xml:space="preserve">&amp;Unit to show amounts in:</source>
<context-group purpose="location"><context context-type="linenumber">728</context></context-group>
</trans-unit>
- <trans-unit id="_msg389">
+ <trans-unit id="_msg386">
<source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg390">
+ <trans-unit id="_msg387">
<source xml:space="preserve">Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<context-group purpose="location"><context context-type="linenumber">752</context></context-group>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg391">
+ <trans-unit id="_msg388">
<source xml:space="preserve">&amp;Third-party transaction URLs</source>
<context-group purpose="location"><context context-type="linenumber">755</context></context-group>
</trans-unit>
- <trans-unit id="_msg392">
+ <trans-unit id="_msg389">
<source xml:space="preserve">Whether to show coin control features or not.</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg393">
+ <trans-unit id="_msg390">
<source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
</trans-unit>
- <trans-unit id="_msg394">
+ <trans-unit id="_msg391">
<source xml:space="preserve">Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
<context-group purpose="location"><context context-type="linenumber">541</context></context-group>
</trans-unit>
- <trans-unit id="_msg395">
+ <trans-unit id="_msg392">
<source xml:space="preserve">Monospaced font in the Overview tab:</source>
<context-group purpose="location"><context context-type="linenumber">777</context></context-group>
</trans-unit>
- <trans-unit id="_msg396">
+ <trans-unit id="_msg393">
<source xml:space="preserve">embedded &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">785</context></context-group>
</trans-unit>
- <trans-unit id="_msg397">
+ <trans-unit id="_msg394">
<source xml:space="preserve">closest matching &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">834</context></context-group>
</trans-unit>
- <trans-unit id="_msg398">
+ <trans-unit id="_msg395">
<source xml:space="preserve">&amp;OK</source>
<context-group purpose="location"><context context-type="linenumber">1040</context></context-group>
</trans-unit>
- <trans-unit id="_msg399">
+ <trans-unit id="_msg396">
<source xml:space="preserve">&amp;Cancel</source>
<context-group purpose="location"><context context-type="linenumber">1053</context></context-group>
</trans-unit>
@@ -1802,71 +1788,71 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg400">
+ <trans-unit id="_msg397">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg401">
+ <trans-unit id="_msg398">
<source xml:space="preserve">default</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg402">
+ <trans-unit id="_msg399">
<source xml:space="preserve">none</source>
<context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg403">
+ <trans-unit id="_msg400">
<source xml:space="preserve">Confirm options reset</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up window shown when the user has chosen to reset options.</note>
</trans-unit>
- <trans-unit id="_msg404">
+ <trans-unit id="_msg401">
<source xml:space="preserve">Client restart required to activate changes.</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
<note annotates="source" from="developer">Text explaining that the settings changed will not come into effect until the client is restarted.</note>
</trans-unit>
- <trans-unit id="_msg405">
+ <trans-unit id="_msg402">
<source xml:space="preserve">Current settings will be backed up at &quot;%1&quot;.</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
<note annotates="source" from="developer">Text explaining to the user that the client&apos;s current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location&apos;s path.</note>
</trans-unit>
- <trans-unit id="_msg406">
+ <trans-unit id="_msg403">
<source xml:space="preserve">Client will be shut down. Do you want to proceed?</source>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
<note annotates="source" from="developer">Text asking the user to confirm if they would like to proceed with a client shutdown.</note>
</trans-unit>
- <trans-unit id="_msg407">
+ <trans-unit id="_msg404">
<source xml:space="preserve">Configuration options</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up box that allows opening up of configuration file.</note>
</trans-unit>
- <trans-unit id="_msg408">
+ <trans-unit id="_msg405">
<source xml:space="preserve">The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source>
<context-group purpose="location"><context context-type="linenumber">322</context></context-group>
<note annotates="source" from="developer">Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</note>
</trans-unit>
- <trans-unit id="_msg409">
+ <trans-unit id="_msg406">
<source xml:space="preserve">Continue</source>
<context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg410">
+ <trans-unit id="_msg407">
<source xml:space="preserve">Cancel</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg411">
+ <trans-unit id="_msg408">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg412">
+ <trans-unit id="_msg409">
<source xml:space="preserve">The configuration file could not be opened.</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg413">
+ <trans-unit id="_msg410">
<source xml:space="preserve">This change would require a client restart.</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg414">
+ <trans-unit id="_msg411">
<source xml:space="preserve">The supplied proxy address is invalid.</source>
<context-group purpose="location"><context context-type="linenumber">403</context></context-group>
</trans-unit>
@@ -1874,7 +1860,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsModel">
- <trans-unit id="_msg415">
+ <trans-unit id="_msg412">
<source xml:space="preserve">Could not read setting &quot;%1&quot;, %2.</source>
<context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
@@ -1882,76 +1868,76 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg416">
+ <trans-unit id="_msg413">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg417">
+ <trans-unit id="_msg414">
<source xml:space="preserve">The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
<context-group purpose="location"><context context-type="linenumber">411</context></context-group>
</trans-unit>
- <trans-unit id="_msg418">
+ <trans-unit id="_msg415">
<source xml:space="preserve">Watch-only:</source>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg419">
+ <trans-unit id="_msg416">
<source xml:space="preserve">Available:</source>
<context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg420">
+ <trans-unit id="_msg417">
<source xml:space="preserve">Your current spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg421">
+ <trans-unit id="_msg418">
<source xml:space="preserve">Pending:</source>
<context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg422">
+ <trans-unit id="_msg419">
<source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg423">
+ <trans-unit id="_msg420">
<source xml:space="preserve">Immature:</source>
<context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg424">
+ <trans-unit id="_msg421">
<source xml:space="preserve">Mined balance that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg425">
+ <trans-unit id="_msg422">
<source xml:space="preserve">Balances</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg426">
+ <trans-unit id="_msg423">
<source xml:space="preserve">Total:</source>
<context-group purpose="location"><context context-type="linenumber">200</context></context-group>
</trans-unit>
- <trans-unit id="_msg427">
+ <trans-unit id="_msg424">
<source xml:space="preserve">Your current total balance</source>
<context-group purpose="location"><context context-type="linenumber">249</context></context-group>
</trans-unit>
- <trans-unit id="_msg428">
+ <trans-unit id="_msg425">
<source xml:space="preserve">Your current balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg429">
+ <trans-unit id="_msg426">
<source xml:space="preserve">Spendable:</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg430">
+ <trans-unit id="_msg427">
<source xml:space="preserve">Recent transactions</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
</trans-unit>
- <trans-unit id="_msg431">
+ <trans-unit id="_msg428">
<source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg432">
+ <trans-unit id="_msg429">
<source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg433">
+ <trans-unit id="_msg430">
<source xml:space="preserve">Current total balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
@@ -1959,7 +1945,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../overviewpage.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg434">
+ <trans-unit id="_msg431">
<source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
<context-group purpose="location"><context context-type="linenumber">184</context></context-group>
</trans-unit>
@@ -1967,27 +1953,27 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg435">
- <source xml:space="preserve">Dialog</source>
+ <trans-unit id="_msg432">
+ <source xml:space="preserve">PSBT Operations</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg436">
+ <trans-unit id="_msg433">
<source xml:space="preserve">Sign Tx</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg437">
+ <trans-unit id="_msg434">
<source xml:space="preserve">Broadcast Tx</source>
<context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
- <trans-unit id="_msg438">
+ <trans-unit id="_msg435">
<source xml:space="preserve">Copy to Clipboard</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg439">
+ <trans-unit id="_msg436">
<source xml:space="preserve">Save…</source>
<context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg440">
+ <trans-unit id="_msg437">
<source xml:space="preserve">Close</source>
<context-group purpose="location"><context context-type="linenumber">136</context></context-group>
</trans-unit>
@@ -1995,146 +1981,146 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg441">
+ <trans-unit id="_msg438">
<source xml:space="preserve">Failed to load transaction: %1</source>
- <context-group purpose="location"><context context-type="linenumber">61</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg442">
+ <trans-unit id="_msg439">
<source xml:space="preserve">Failed to sign transaction: %1</source>
- <context-group purpose="location"><context context-type="linenumber">86</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg443">
+ <trans-unit id="_msg440">
<source xml:space="preserve">Cannot sign inputs while wallet is locked.</source>
- <context-group purpose="location"><context context-type="linenumber">94</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">93</context></context-group>
</trans-unit>
- <trans-unit id="_msg444">
+ <trans-unit id="_msg441">
<source xml:space="preserve">Could not sign any more inputs.</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg445">
+ <trans-unit id="_msg442">
<source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source>
- <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg446">
+ <trans-unit id="_msg443">
<source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source>
- <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg447">
+ <trans-unit id="_msg444">
<source xml:space="preserve">Unknown error processing transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">113</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">112</context></context-group>
</trans-unit>
- <trans-unit id="_msg448">
+ <trans-unit id="_msg445">
<source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source>
- <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg449">
+ <trans-unit id="_msg446">
<source xml:space="preserve">Transaction broadcast failed: %1</source>
- <context-group purpose="location"><context context-type="linenumber">126</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
- <trans-unit id="_msg450">
+ <trans-unit id="_msg447">
<source xml:space="preserve">PSBT copied to clipboard.</source>
- <context-group purpose="location"><context context-type="linenumber">135</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg451">
+ <trans-unit id="_msg448">
<source xml:space="preserve">Save Transaction Data</source>
- <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">157</context></context-group>
</trans-unit>
- <trans-unit id="_msg452">
+ <trans-unit id="_msg449">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
- <context-group purpose="location"><context context-type="linenumber">160</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">159</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg453">
+ <trans-unit id="_msg450">
<source xml:space="preserve">PSBT saved to disk.</source>
- <context-group purpose="location"><context context-type="linenumber">167</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
- <trans-unit id="_msg454">
+ <trans-unit id="_msg451">
<source xml:space="preserve"> * Sends %1 to %2</source>
- <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">182</context></context-group>
</trans-unit>
- <trans-unit id="_msg455">
+ <trans-unit id="_msg452">
<source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source>
- <context-group purpose="location"><context context-type="linenumber">193</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg456">
+ <trans-unit id="_msg453">
<source xml:space="preserve">Pays transaction fee: </source>
- <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg457">
+ <trans-unit id="_msg454">
<source xml:space="preserve">Total Amount</source>
- <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
</trans-unit>
- <trans-unit id="_msg458">
+ <trans-unit id="_msg455">
<source xml:space="preserve">or</source>
- <context-group purpose="location"><context context-type="linenumber">210</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
</trans-unit>
- <trans-unit id="_msg459">
+ <trans-unit id="_msg456">
<source xml:space="preserve">Transaction has %1 unsigned inputs.</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg460">
+ <trans-unit id="_msg457">
<source xml:space="preserve">Transaction is missing some information about inputs.</source>
- <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg461">
+ <trans-unit id="_msg458">
<source xml:space="preserve">Transaction still needs signature(s).</source>
- <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
</trans-unit>
- <trans-unit id="_msg462">
+ <trans-unit id="_msg459">
<source xml:space="preserve">(But no wallet is loaded.)</source>
- <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg463">
+ <trans-unit id="_msg460">
<source xml:space="preserve">(But this wallet cannot sign transactions.)</source>
- <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg464">
+ <trans-unit id="_msg461">
<source xml:space="preserve">(But this wallet does not have the right keys.)</source>
- <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg465">
+ <trans-unit id="_msg462">
<source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg466">
+ <trans-unit id="_msg463">
<source xml:space="preserve">Transaction status is unknown.</source>
- <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../paymentserver.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PaymentServer">
- <trans-unit id="_msg467">
+ <trans-unit id="_msg464">
<source xml:space="preserve">Payment request error</source>
<context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg468">
+ <trans-unit id="_msg465">
<source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source>
<context-group purpose="location"><context context-type="linenumber">150</context></context-group>
</trans-unit>
- <trans-unit id="_msg469">
+ <trans-unit id="_msg466">
<source xml:space="preserve">URI handling</source>
<context-group purpose="location"><context context-type="linenumber">198</context></context-group>
<context-group purpose="location"><context context-type="linenumber">214</context></context-group>
<context-group purpose="location"><context context-type="linenumber">220</context></context-group>
<context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg470">
+ <trans-unit id="_msg467">
<source xml:space="preserve">&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
<context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg471">
+ <trans-unit id="_msg468">
<source xml:space="preserve">Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it&apos;s strongly recommended that any merchant instructions to switch wallets be ignored.
If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
<context-group purpose="location"><context context-type="linenumber">215</context></context-group>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg472">
+ <trans-unit id="_msg469">
<source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
<context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg473">
+ <trans-unit id="_msg470">
<source xml:space="preserve">Payment request file handling</source>
<context-group purpose="location"><context context-type="linenumber">237</context></context-group>
</trans-unit>
@@ -2142,52 +2128,52 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../peertablemodel.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg474">
+ <trans-unit id="_msg471">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">112</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the peer&apos;s User Agent string.</note>
</trans-unit>
- <trans-unit id="_msg475">
+ <trans-unit id="_msg472">
<source xml:space="preserve">Ping</source>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the current latency of the connection with the peer.</note>
</trans-unit>
- <trans-unit id="_msg476">
+ <trans-unit id="_msg473">
<source xml:space="preserve">Peer</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains a unique number used to identify a connection.</note>
</trans-unit>
- <trans-unit id="_msg477">
+ <trans-unit id="_msg474">
<source xml:space="preserve">Age</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</note>
</trans-unit>
- <trans-unit id="_msg478">
+ <trans-unit id="_msg475">
<source xml:space="preserve">Direction</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the direction the peer connection was initiated from.</note>
</trans-unit>
- <trans-unit id="_msg479">
+ <trans-unit id="_msg476">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">106</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</note>
</trans-unit>
- <trans-unit id="_msg480">
+ <trans-unit id="_msg477">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">109</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have received from the peer.</note>
</trans-unit>
- <trans-unit id="_msg481">
+ <trans-unit id="_msg478">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">91</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</note>
</trans-unit>
- <trans-unit id="_msg482">
+ <trans-unit id="_msg479">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which describes the type of peer connection. The &quot;type&quot; describes why the connection exists.</note>
</trans-unit>
- <trans-unit id="_msg483">
+ <trans-unit id="_msg480">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which states the network the peer connected through.</note>
@@ -2196,12 +2182,12 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../peertablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg484">
+ <trans-unit id="_msg481">
<source xml:space="preserve">Inbound</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
<note annotates="source" from="developer">An Inbound Connection from a Peer.</note>
</trans-unit>
- <trans-unit id="_msg485">
+ <trans-unit id="_msg482">
<source xml:space="preserve">Outbound</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
<note annotates="source" from="developer">An Outbound Connection to a Peer.</note>
@@ -2210,7 +2196,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../bitcoinunits.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg486">
+ <trans-unit id="_msg483">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">197</context></context-group>
</trans-unit>
@@ -2218,194 +2204,222 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../guiutil.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg487">
+ <trans-unit id="_msg484">
<source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source>
- <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">130</context></context-group>
</trans-unit>
- <trans-unit id="_msg488">
+ <trans-unit id="_msg485">
<source xml:space="preserve">Ctrl+W</source>
- <context-group purpose="location"><context context-type="linenumber">417</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">418</context></context-group>
</trans-unit>
- <trans-unit id="_msg489">
+ <trans-unit id="_msg486">
<source xml:space="preserve">Unroutable</source>
- <context-group purpose="location"><context context-type="linenumber">674</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">675</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg487">
+ <source xml:space="preserve">IPv4</source>
+ <context-group purpose="location"><context context-type="linenumber">677</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group>
+ <note annotates="source" from="developer">Name of IPv4 network in peer info</note>
+ </trans-unit>
+ <trans-unit id="_msg488">
+ <source xml:space="preserve">IPv6</source>
+ <context-group purpose="location"><context context-type="linenumber">679</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group>
+ <note annotates="source" from="developer">Name of IPv6 network in peer info</note>
+ </trans-unit>
+ <trans-unit id="_msg489">
+ <source xml:space="preserve">Onion</source>
+ <context-group purpose="location"><context context-type="linenumber">681</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group>
+ <note annotates="source" from="developer">Name of Tor network in peer info</note>
</trans-unit>
<trans-unit id="_msg490">
- <source xml:space="preserve">Internal</source>
- <context-group purpose="location"><context context-type="linenumber">680</context></context-group>
+ <source xml:space="preserve">I2P</source>
+ <context-group purpose="location"><context context-type="linenumber">683</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group>
+ <note annotates="source" from="developer">Name of I2P network in peer info</note>
</trans-unit>
<trans-unit id="_msg491">
+ <source xml:space="preserve">CJDNS</source>
+ <context-group purpose="location"><context context-type="linenumber">685</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">network name</context></context-group>
+ <note annotates="source" from="developer">Name of CJDNS network in peer info</note>
+ </trans-unit>
+ <trans-unit id="_msg492">
<source xml:space="preserve">Inbound</source>
- <context-group purpose="location"><context context-type="linenumber">693</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">699</context></context-group>
<note annotates="source" from="developer">An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</note>
</trans-unit>
- <trans-unit id="_msg492">
+ <trans-unit id="_msg493">
<source xml:space="preserve">Outbound</source>
- <context-group purpose="location"><context context-type="linenumber">696</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">702</context></context-group>
<note annotates="source" from="developer">An outbound connection to a peer. An outbound connection is a connection initiated by us.</note>
</trans-unit>
- <trans-unit id="_msg493">
+ <trans-unit id="_msg494">
<source xml:space="preserve">Full Relay</source>
- <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">707</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays all network information.</note>
</trans-unit>
- <trans-unit id="_msg494">
+ <trans-unit id="_msg495">
<source xml:space="preserve">Block Relay</source>
- <context-group purpose="location"><context context-type="linenumber">704</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">710</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg495">
+ <trans-unit id="_msg496">
<source xml:space="preserve">Manual</source>
- <context-group purpose="location"><context context-type="linenumber">706</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">712</context></context-group>
<note annotates="source" from="developer">Peer connection type established manually through one of several methods.</note>
</trans-unit>
- <trans-unit id="_msg496">
+ <trans-unit id="_msg497">
<source xml:space="preserve">Feeler</source>
- <context-group purpose="location"><context context-type="linenumber">708</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">714</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that tests the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg497">
+ <trans-unit id="_msg498">
<source xml:space="preserve">Address Fetch</source>
- <context-group purpose="location"><context context-type="linenumber">710</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">716</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that solicits known addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg498">
- <source xml:space="preserve">%1 d</source>
- <context-group purpose="location"><context context-type="linenumber">723</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">735</context></context-group>
- </trans-unit>
<trans-unit id="_msg499">
- <source xml:space="preserve">%1 h</source>
- <context-group purpose="location"><context context-type="linenumber">724</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">736</context></context-group>
+ <source xml:space="preserve">%1 d</source>
+ <context-group purpose="location"><context context-type="linenumber">729</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
<trans-unit id="_msg500">
- <source xml:space="preserve">%1 m</source>
- <context-group purpose="location"><context context-type="linenumber">725</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">737</context></context-group>
+ <source xml:space="preserve">%1 h</source>
+ <context-group purpose="location"><context context-type="linenumber">730</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">742</context></context-group>
</trans-unit>
<trans-unit id="_msg501">
- <source xml:space="preserve">%1 s</source>
- <context-group purpose="location"><context context-type="linenumber">727</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">738</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">764</context></context-group>
+ <source xml:space="preserve">%1 m</source>
+ <context-group purpose="location"><context context-type="linenumber">731</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">743</context></context-group>
</trans-unit>
<trans-unit id="_msg502">
- <source xml:space="preserve">None</source>
- <context-group purpose="location"><context context-type="linenumber">752</context></context-group>
+ <source xml:space="preserve">%1 s</source>
+ <context-group purpose="location"><context context-type="linenumber">733</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">744</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">770</context></context-group>
</trans-unit>
<trans-unit id="_msg503">
- <source xml:space="preserve">N/A</source>
+ <source xml:space="preserve">None</source>
<context-group purpose="location"><context context-type="linenumber">758</context></context-group>
</trans-unit>
<trans-unit id="_msg504">
+ <source xml:space="preserve">N/A</source>
+ <context-group purpose="location"><context context-type="linenumber">764</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg505">
<source xml:space="preserve">%1 ms</source>
- <context-group purpose="location"><context context-type="linenumber">759</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">777</context></context-group>
- <trans-unit id="_msg505[0]">
+ <context-group purpose="location"><context context-type="linenumber">783</context></context-group>
+ <trans-unit id="_msg506[0]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
- <trans-unit id="_msg505[1]">
+ <trans-unit id="_msg506[1]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">781</context></context-group>
- <trans-unit id="_msg506[0]">
+ <context-group purpose="location"><context context-type="linenumber">787</context></context-group>
+ <trans-unit id="_msg507[0]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
- <trans-unit id="_msg506[1]">
+ <trans-unit id="_msg507[1]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">785</context></context-group>
- <trans-unit id="_msg507[0]">
+ <context-group purpose="location"><context context-type="linenumber">791</context></context-group>
+ <trans-unit id="_msg508[0]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
- <trans-unit id="_msg507[1]">
+ <trans-unit id="_msg508[1]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">789</context></context-group>
- <trans-unit id="_msg508[0]">
+ <context-group purpose="location"><context context-type="linenumber">795</context></context-group>
+ <trans-unit id="_msg509[0]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
- <trans-unit id="_msg508[1]">
+ <trans-unit id="_msg509[1]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">793</context></context-group>
<context-group purpose="location"><context context-type="linenumber">799</context></context-group>
- <trans-unit id="_msg509[0]">
+ <context-group purpose="location"><context context-type="linenumber">805</context></context-group>
+ <trans-unit id="_msg510[0]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
- <trans-unit id="_msg509[1]">
+ <trans-unit id="_msg510[1]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg510">
+ <trans-unit id="_msg511">
<source xml:space="preserve">%1 and %2</source>
- <context-group purpose="location"><context context-type="linenumber">799</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">805</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">799</context></context-group>
- <trans-unit id="_msg511[0]">
+ <context-group purpose="location"><context context-type="linenumber">805</context></context-group>
+ <trans-unit id="_msg512[0]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
- <trans-unit id="_msg511[1]">
+ <trans-unit id="_msg512[1]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg512">
+ <trans-unit id="_msg513">
<source xml:space="preserve">%1 B</source>
- <context-group purpose="location"><context context-type="linenumber">807</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">813</context></context-group>
</trans-unit>
- <trans-unit id="_msg513">
+ <trans-unit id="_msg514">
<source xml:space="preserve">%1 kB</source>
- <context-group purpose="location"><context context-type="linenumber">809</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">815</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">988</context></context-group>
</trans-unit>
- <trans-unit id="_msg514">
+ <trans-unit id="_msg515">
<source xml:space="preserve">%1 MB</source>
- <context-group purpose="location"><context context-type="linenumber">811</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">817</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">990</context></context-group>
</trans-unit>
- <trans-unit id="_msg515">
+ <trans-unit id="_msg516">
<source xml:space="preserve">%1 GB</source>
- <context-group purpose="location"><context context-type="linenumber">813</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">819</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../qrimagewidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QRImageWidget">
- <trans-unit id="_msg516">
+ <trans-unit id="_msg517">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">30</context></context-group>
</trans-unit>
- <trans-unit id="_msg517">
+ <trans-unit id="_msg518">
<source xml:space="preserve">&amp;Copy Image</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg518">
+ <trans-unit id="_msg519">
<source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg519">
+ <trans-unit id="_msg520">
<source xml:space="preserve">Error encoding URI into QR Code.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg520">
+ <trans-unit id="_msg521">
<source xml:space="preserve">QR code support not available.</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg521">
+ <trans-unit id="_msg522">
<source xml:space="preserve">Save QR Code</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg522">
+ <trans-unit id="_msg523">
<source xml:space="preserve">PNG Image</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
<note annotates="source" from="developer">Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</note>
@@ -2414,7 +2428,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg523">
+ <trans-unit id="_msg524">
<source xml:space="preserve">N/A</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
@@ -2455,291 +2469,291 @@ If you are receiving this error you should request the merchant provide a BIP21
<context-group purpose="location"><context context-type="linenumber">1662</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg524">
+ <trans-unit id="_msg525">
<source xml:space="preserve">Client version</source>
<context-group purpose="location"><context context-type="linenumber">65</context></context-group>
</trans-unit>
- <trans-unit id="_msg525">
+ <trans-unit id="_msg526">
<source xml:space="preserve">&amp;Information</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg526">
+ <trans-unit id="_msg527">
<source xml:space="preserve">General</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg527">
+ <trans-unit id="_msg528">
<source xml:space="preserve">Datadir</source>
<context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
- <trans-unit id="_msg528">
+ <trans-unit id="_msg529">
<source xml:space="preserve">To specify a non-default location of the data directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg529">
+ <trans-unit id="_msg530">
<source xml:space="preserve">Blocksdir</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg530">
+ <trans-unit id="_msg531">
<source xml:space="preserve">To specify a non-default location of the blocks directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg531">
+ <trans-unit id="_msg532">
<source xml:space="preserve">Startup time</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg532">
+ <trans-unit id="_msg533">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1093</context></context-group>
</trans-unit>
- <trans-unit id="_msg533">
+ <trans-unit id="_msg534">
<source xml:space="preserve">Name</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg534">
+ <trans-unit id="_msg535">
<source xml:space="preserve">Number of connections</source>
<context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg535">
+ <trans-unit id="_msg536">
<source xml:space="preserve">Block chain</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg536">
+ <trans-unit id="_msg537">
<source xml:space="preserve">Memory Pool</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg537">
+ <trans-unit id="_msg538">
<source xml:space="preserve">Current number of transactions</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg538">
+ <trans-unit id="_msg539">
<source xml:space="preserve">Memory usage</source>
<context-group purpose="location"><context context-type="linenumber">349</context></context-group>
</trans-unit>
- <trans-unit id="_msg539">
+ <trans-unit id="_msg540">
<source xml:space="preserve">Wallet: </source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
- <trans-unit id="_msg540">
+ <trans-unit id="_msg541">
<source xml:space="preserve">(none)</source>
<context-group purpose="location"><context context-type="linenumber">454</context></context-group>
</trans-unit>
- <trans-unit id="_msg541">
+ <trans-unit id="_msg542">
<source xml:space="preserve">&amp;Reset</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg542">
+ <trans-unit id="_msg543">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">745</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1453</context></context-group>
</trans-unit>
- <trans-unit id="_msg543">
+ <trans-unit id="_msg544">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">825</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1430</context></context-group>
</trans-unit>
- <trans-unit id="_msg544">
+ <trans-unit id="_msg545">
<source xml:space="preserve">&amp;Peers</source>
<context-group purpose="location"><context context-type="linenumber">866</context></context-group>
</trans-unit>
- <trans-unit id="_msg545">
+ <trans-unit id="_msg546">
<source xml:space="preserve">Banned peers</source>
<context-group purpose="location"><context context-type="linenumber">942</context></context-group>
</trans-unit>
- <trans-unit id="_msg546">
+ <trans-unit id="_msg547">
<source xml:space="preserve">Select a peer to view detailed information.</source>
<context-group purpose="location"><context context-type="linenumber">1010</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1155</context></context-group>
</trans-unit>
- <trans-unit id="_msg547">
+ <trans-unit id="_msg548">
<source xml:space="preserve">Version</source>
<context-group purpose="location"><context context-type="linenumber">1116</context></context-group>
</trans-unit>
- <trans-unit id="_msg548">
+ <trans-unit id="_msg549">
<source xml:space="preserve">Whether we relay transactions to this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
</trans-unit>
- <trans-unit id="_msg549">
+ <trans-unit id="_msg550">
<source xml:space="preserve">Transaction Relay</source>
<context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
</trans-unit>
- <trans-unit id="_msg550">
+ <trans-unit id="_msg551">
<source xml:space="preserve">Starting Block</source>
<context-group purpose="location"><context context-type="linenumber">1240</context></context-group>
</trans-unit>
- <trans-unit id="_msg551">
+ <trans-unit id="_msg552">
<source xml:space="preserve">Synced Headers</source>
<context-group purpose="location"><context context-type="linenumber">1263</context></context-group>
</trans-unit>
- <trans-unit id="_msg552">
+ <trans-unit id="_msg553">
<source xml:space="preserve">Synced Blocks</source>
<context-group purpose="location"><context context-type="linenumber">1286</context></context-group>
</trans-unit>
- <trans-unit id="_msg553">
+ <trans-unit id="_msg554">
<source xml:space="preserve">Last Transaction</source>
<context-group purpose="location"><context context-type="linenumber">1361</context></context-group>
</trans-unit>
- <trans-unit id="_msg554">
+ <trans-unit id="_msg555">
<source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source>
<context-group purpose="location"><context context-type="linenumber">1571</context></context-group>
</trans-unit>
- <trans-unit id="_msg555">
+ <trans-unit id="_msg556">
<source xml:space="preserve">Mapped AS</source>
<context-group purpose="location"><context context-type="linenumber">1574</context></context-group>
</trans-unit>
- <trans-unit id="_msg556">
+ <trans-unit id="_msg557">
<source xml:space="preserve">Whether we relay addresses to this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1597</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg557">
+ <trans-unit id="_msg558">
<source xml:space="preserve">Address Relay</source>
<context-group purpose="location"><context context-type="linenumber">1600</context></context-group>
<note annotates="source" from="developer">Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg558">
+ <trans-unit id="_msg559">
<source xml:space="preserve">The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
<context-group purpose="location"><context context-type="linenumber">1623</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg559">
+ <trans-unit id="_msg560">
<source xml:space="preserve">The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
<context-group purpose="location"><context context-type="linenumber">1649</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg560">
+ <trans-unit id="_msg561">
<source xml:space="preserve">Addresses Processed</source>
<context-group purpose="location"><context context-type="linenumber">1626</context></context-group>
<note annotates="source" from="developer">Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg561">
+ <trans-unit id="_msg562">
<source xml:space="preserve">Addresses Rate-Limited</source>
<context-group purpose="location"><context context-type="linenumber">1652</context></context-group>
<note annotates="source" from="developer">Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg562">
+ <trans-unit id="_msg563">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1139</context></context-group>
</trans-unit>
- <trans-unit id="_msg563">
+ <trans-unit id="_msg564">
<source xml:space="preserve">Node window</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg564">
+ <trans-unit id="_msg565">
<source xml:space="preserve">Current block height</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg565">
+ <trans-unit id="_msg566">
<source xml:space="preserve">Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<context-group purpose="location"><context context-type="linenumber">397</context></context-group>
</trans-unit>
- <trans-unit id="_msg566">
+ <trans-unit id="_msg567">
<source xml:space="preserve">Decrease font size</source>
<context-group purpose="location"><context context-type="linenumber">475</context></context-group>
</trans-unit>
- <trans-unit id="_msg567">
+ <trans-unit id="_msg568">
<source xml:space="preserve">Increase font size</source>
<context-group purpose="location"><context context-type="linenumber">495</context></context-group>
</trans-unit>
- <trans-unit id="_msg568">
+ <trans-unit id="_msg569">
<source xml:space="preserve">Permissions</source>
<context-group purpose="location"><context context-type="linenumber">1041</context></context-group>
</trans-unit>
- <trans-unit id="_msg569">
+ <trans-unit id="_msg570">
<source xml:space="preserve">The direction and type of peer connection: %1</source>
<context-group purpose="location"><context context-type="linenumber">1064</context></context-group>
</trans-unit>
- <trans-unit id="_msg570">
+ <trans-unit id="_msg571">
<source xml:space="preserve">Direction/Type</source>
<context-group purpose="location"><context context-type="linenumber">1067</context></context-group>
</trans-unit>
- <trans-unit id="_msg571">
+ <trans-unit id="_msg572">
<source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
<context-group purpose="location"><context context-type="linenumber">1090</context></context-group>
</trans-unit>
- <trans-unit id="_msg572">
+ <trans-unit id="_msg573">
<source xml:space="preserve">Services</source>
<context-group purpose="location"><context context-type="linenumber">1162</context></context-group>
</trans-unit>
- <trans-unit id="_msg573">
+ <trans-unit id="_msg574">
<source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source>
<context-group purpose="location"><context context-type="linenumber">1214</context></context-group>
</trans-unit>
- <trans-unit id="_msg574">
+ <trans-unit id="_msg575">
<source xml:space="preserve">High Bandwidth</source>
<context-group purpose="location"><context context-type="linenumber">1217</context></context-group>
</trans-unit>
- <trans-unit id="_msg575">
+ <trans-unit id="_msg576">
<source xml:space="preserve">Connection Time</source>
<context-group purpose="location"><context context-type="linenumber">1309</context></context-group>
</trans-unit>
- <trans-unit id="_msg576">
+ <trans-unit id="_msg577">
<source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1332</context></context-group>
</trans-unit>
- <trans-unit id="_msg577">
+ <trans-unit id="_msg578">
<source xml:space="preserve">Last Block</source>
<context-group purpose="location"><context context-type="linenumber">1335</context></context-group>
</trans-unit>
- <trans-unit id="_msg578">
+ <trans-unit id="_msg579">
<source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Last Transaction field in the peer details area.</note>
</trans-unit>
- <trans-unit id="_msg579">
+ <trans-unit id="_msg580">
<source xml:space="preserve">Last Send</source>
<context-group purpose="location"><context context-type="linenumber">1384</context></context-group>
</trans-unit>
- <trans-unit id="_msg580">
+ <trans-unit id="_msg581">
<source xml:space="preserve">Last Receive</source>
<context-group purpose="location"><context context-type="linenumber">1407</context></context-group>
</trans-unit>
- <trans-unit id="_msg581">
+ <trans-unit id="_msg582">
<source xml:space="preserve">Ping Time</source>
<context-group purpose="location"><context context-type="linenumber">1476</context></context-group>
</trans-unit>
- <trans-unit id="_msg582">
+ <trans-unit id="_msg583">
<source xml:space="preserve">The duration of a currently outstanding ping.</source>
<context-group purpose="location"><context context-type="linenumber">1499</context></context-group>
</trans-unit>
- <trans-unit id="_msg583">
+ <trans-unit id="_msg584">
<source xml:space="preserve">Ping Wait</source>
<context-group purpose="location"><context context-type="linenumber">1502</context></context-group>
</trans-unit>
- <trans-unit id="_msg584">
+ <trans-unit id="_msg585">
<source xml:space="preserve">Min Ping</source>
<context-group purpose="location"><context context-type="linenumber">1525</context></context-group>
</trans-unit>
- <trans-unit id="_msg585">
+ <trans-unit id="_msg586">
<source xml:space="preserve">Time Offset</source>
<context-group purpose="location"><context context-type="linenumber">1548</context></context-group>
</trans-unit>
- <trans-unit id="_msg586">
+ <trans-unit id="_msg587">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg587">
+ <trans-unit id="_msg588">
<source xml:space="preserve">&amp;Open</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
</trans-unit>
- <trans-unit id="_msg588">
+ <trans-unit id="_msg589">
<source xml:space="preserve">&amp;Console</source>
<context-group purpose="location"><context context-type="linenumber">426</context></context-group>
</trans-unit>
- <trans-unit id="_msg589">
+ <trans-unit id="_msg590">
<source xml:space="preserve">&amp;Network Traffic</source>
<context-group purpose="location"><context context-type="linenumber">613</context></context-group>
</trans-unit>
- <trans-unit id="_msg590">
+ <trans-unit id="_msg591">
<source xml:space="preserve">Totals</source>
<context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg591">
+ <trans-unit id="_msg592">
<source xml:space="preserve">Debug log file</source>
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg592">
+ <trans-unit id="_msg593">
<source xml:space="preserve">Clear console</source>
<context-group purpose="location"><context context-type="linenumber">515</context></context-group>
</trans-unit>
@@ -2747,139 +2761,139 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../rpcconsole.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg593">
+ <trans-unit id="_msg594">
<source xml:space="preserve">In:</source>
- <context-group purpose="location"><context context-type="linenumber">953</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">952</context></context-group>
</trans-unit>
- <trans-unit id="_msg594">
+ <trans-unit id="_msg595">
<source xml:space="preserve">Out:</source>
- <context-group purpose="location"><context context-type="linenumber">954</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">953</context></context-group>
</trans-unit>
- <trans-unit id="_msg595">
+ <trans-unit id="_msg596">
<source xml:space="preserve">Inbound: initiated by peer</source>
- <context-group purpose="location"><context context-type="linenumber">496</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
<note annotates="source" from="developer">Explanatory text for an inbound peer connection.</note>
</trans-unit>
- <trans-unit id="_msg596">
+ <trans-unit id="_msg597">
<source xml:space="preserve">Outbound Full Relay: default</source>
- <context-group purpose="location"><context context-type="linenumber">500</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">499</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</note>
</trans-unit>
- <trans-unit id="_msg597">
+ <trans-unit id="_msg598">
<source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source>
- <context-group purpose="location"><context context-type="linenumber">503</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">502</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg598">
+ <trans-unit id="_msg599">
<source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
- <context-group purpose="location"><context context-type="linenumber">508</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">507</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</note>
</trans-unit>
- <trans-unit id="_msg599">
+ <trans-unit id="_msg600">
<source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source>
- <context-group purpose="location"><context context-type="linenumber">514</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">513</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg600">
+ <trans-unit id="_msg601">
<source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source>
- <context-group purpose="location"><context context-type="linenumber">517</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">516</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg601">
+ <trans-unit id="_msg602">
<source xml:space="preserve">we selected the peer for high bandwidth relay</source>
- <context-group purpose="location"><context context-type="linenumber">521</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">520</context></context-group>
</trans-unit>
- <trans-unit id="_msg602">
+ <trans-unit id="_msg603">
<source xml:space="preserve">the peer selected us for high bandwidth relay</source>
- <context-group purpose="location"><context context-type="linenumber">522</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg603">
+ <trans-unit id="_msg604">
<source xml:space="preserve">no high bandwidth relay selected</source>
- <context-group purpose="location"><context context-type="linenumber">523</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">522</context></context-group>
</trans-unit>
- <trans-unit id="_msg604">
+ <trans-unit id="_msg605">
<source xml:space="preserve">Ctrl++</source>
- <context-group purpose="location"><context context-type="linenumber">536</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">535</context></context-group>
<note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg605">
+ <trans-unit id="_msg606">
<source xml:space="preserve">Ctrl+=</source>
- <context-group purpose="location"><context context-type="linenumber">538</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">537</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg606">
+ <trans-unit id="_msg607">
<source xml:space="preserve">Ctrl+-</source>
- <context-group purpose="location"><context context-type="linenumber">542</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">541</context></context-group>
<note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg607">
+ <trans-unit id="_msg608">
<source xml:space="preserve">Ctrl+_</source>
- <context-group purpose="location"><context context-type="linenumber">544</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">543</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg608">
+ <trans-unit id="_msg609">
<source xml:space="preserve">&amp;Copy address</source>
- <context-group purpose="location"><context context-type="linenumber">695</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">694</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the address of a peer.</note>
</trans-unit>
- <trans-unit id="_msg609">
+ <trans-unit id="_msg610">
<source xml:space="preserve">&amp;Disconnect</source>
- <context-group purpose="location"><context context-type="linenumber">699</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">698</context></context-group>
</trans-unit>
- <trans-unit id="_msg610">
+ <trans-unit id="_msg611">
<source xml:space="preserve">1 &amp;hour</source>
- <context-group purpose="location"><context context-type="linenumber">700</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">699</context></context-group>
</trans-unit>
- <trans-unit id="_msg611">
+ <trans-unit id="_msg612">
<source xml:space="preserve">1 d&amp;ay</source>
- <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">700</context></context-group>
</trans-unit>
- <trans-unit id="_msg612">
+ <trans-unit id="_msg613">
<source xml:space="preserve">1 &amp;week</source>
- <context-group purpose="location"><context context-type="linenumber">702</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
</trans-unit>
- <trans-unit id="_msg613">
+ <trans-unit id="_msg614">
<source xml:space="preserve">1 &amp;year</source>
- <context-group purpose="location"><context context-type="linenumber">703</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">702</context></context-group>
</trans-unit>
- <trans-unit id="_msg614">
+ <trans-unit id="_msg615">
<source xml:space="preserve">&amp;Copy IP/Netmask</source>
- <context-group purpose="location"><context context-type="linenumber">729</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">728</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer&apos;s IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</note>
</trans-unit>
- <trans-unit id="_msg615">
+ <trans-unit id="_msg616">
<source xml:space="preserve">&amp;Unban</source>
- <context-group purpose="location"><context context-type="linenumber">733</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">732</context></context-group>
</trans-unit>
- <trans-unit id="_msg616">
+ <trans-unit id="_msg617">
<source xml:space="preserve">Network activity disabled</source>
- <context-group purpose="location"><context context-type="linenumber">957</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">956</context></context-group>
</trans-unit>
- <trans-unit id="_msg617">
+ <trans-unit id="_msg618">
<source xml:space="preserve">Executing command without any wallet</source>
<context-group purpose="location"><context context-type="linenumber">1035</context></context-group>
</trans-unit>
- <trans-unit id="_msg618">
+ <trans-unit id="_msg619">
<source xml:space="preserve">Ctrl+I</source>
- <context-group purpose="location"><context context-type="linenumber">1355</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1351</context></context-group>
</trans-unit>
- <trans-unit id="_msg619">
+ <trans-unit id="_msg620">
<source xml:space="preserve">Ctrl+T</source>
- <context-group purpose="location"><context context-type="linenumber">1356</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1352</context></context-group>
</trans-unit>
- <trans-unit id="_msg620">
+ <trans-unit id="_msg621">
<source xml:space="preserve">Ctrl+N</source>
- <context-group purpose="location"><context context-type="linenumber">1357</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1353</context></context-group>
</trans-unit>
- <trans-unit id="_msg621">
+ <trans-unit id="_msg622">
<source xml:space="preserve">Ctrl+P</source>
- <context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1354</context></context-group>
</trans-unit>
- <trans-unit id="_msg622">
+ <trans-unit id="_msg623">
<source xml:space="preserve">Executing command using &quot;%1&quot; wallet</source>
<context-group purpose="location"><context context-type="linenumber">1033</context></context-group>
</trans-unit>
- <trans-unit id="_msg623">
+ <trans-unit id="_msg624">
<source xml:space="preserve">Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -2887,19 +2901,19 @@ Type %5 for an overview of available commands.
For more information on using this console, type %6.
%7WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.%8</source>
- <context-group purpose="location"><context context-type="linenumber">887</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">886</context></context-group>
<note annotates="source" from="developer">RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</note>
</trans-unit>
- <trans-unit id="_msg624">
+ <trans-unit id="_msg625">
<source xml:space="preserve">Executing…</source>
<context-group purpose="location"><context context-type="linenumber">1043</context></context-group>
<note annotates="source" from="developer">A console message indicating an entered command is currently being executed.</note>
</trans-unit>
- <trans-unit id="_msg625">
+ <trans-unit id="_msg626">
<source xml:space="preserve">(peer: %1)</source>
<context-group purpose="location"><context context-type="linenumber">1161</context></context-group>
</trans-unit>
- <trans-unit id="_msg626">
+ <trans-unit id="_msg627">
<source xml:space="preserve">via %1</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
@@ -2907,31 +2921,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../rpcconsole.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg627">
+ <trans-unit id="_msg628">
<source xml:space="preserve">Yes</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg628">
+ <trans-unit id="_msg629">
<source xml:space="preserve">No</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg629">
+ <trans-unit id="_msg630">
<source xml:space="preserve">To</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg630">
+ <trans-unit id="_msg631">
<source xml:space="preserve">From</source>
<context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg631">
+ <trans-unit id="_msg632">
<source xml:space="preserve">Ban for</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg632">
+ <trans-unit id="_msg633">
<source xml:space="preserve">Never</source>
<context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
- <trans-unit id="_msg633">
+ <trans-unit id="_msg634">
<source xml:space="preserve">Unknown</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
@@ -2939,72 +2953,72 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg634">
+ <trans-unit id="_msg635">
<source xml:space="preserve">&amp;Amount:</source>
<context-group purpose="location"><context context-type="linenumber">37</context></context-group>
</trans-unit>
- <trans-unit id="_msg635">
+ <trans-unit id="_msg636">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg636">
+ <trans-unit id="_msg637">
<source xml:space="preserve">&amp;Message:</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg637">
+ <trans-unit id="_msg638">
<source xml:space="preserve">An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg638">
+ <trans-unit id="_msg639">
<source xml:space="preserve">An optional label to associate with the new receiving address.</source>
<context-group purpose="location"><context context-type="linenumber">80</context></context-group>
</trans-unit>
- <trans-unit id="_msg639">
+ <trans-unit id="_msg640">
<source xml:space="preserve">Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg640">
+ <trans-unit id="_msg641">
<source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<context-group purpose="location"><context context-type="linenumber">34</context></context-group>
<context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg641">
+ <trans-unit id="_msg642">
<source xml:space="preserve">An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg642">
+ <trans-unit id="_msg643">
<source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg643">
+ <trans-unit id="_msg644">
<source xml:space="preserve">&amp;Create new receiving address</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg644">
+ <trans-unit id="_msg645">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg645">
+ <trans-unit id="_msg646">
<source xml:space="preserve">Clear</source>
<context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
- <trans-unit id="_msg646">
+ <trans-unit id="_msg647">
<source xml:space="preserve">Requested payments history</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg647">
+ <trans-unit id="_msg648">
<source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg648">
+ <trans-unit id="_msg649">
<source xml:space="preserve">Show</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
- <trans-unit id="_msg649">
+ <trans-unit id="_msg650">
<source xml:space="preserve">Remove the selected entries from the list</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg650">
+ <trans-unit id="_msg651">
<source xml:space="preserve">Remove</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
@@ -3012,31 +3026,63 @@ For more information on using this console, type %6.
</body></file>
<file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg651">
+ <trans-unit id="_msg652">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">46</context></context-group>
</trans-unit>
- <trans-unit id="_msg652">
+ <trans-unit id="_msg653">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg653">
+ <trans-unit id="_msg654">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg654">
+ <trans-unit id="_msg655">
<source xml:space="preserve">Copy &amp;message</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg655">
+ <trans-unit id="_msg656">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg656">
+ <trans-unit id="_msg657">
+ <source xml:space="preserve">Base58 (Legacy)</source>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg658">
+ <source xml:space="preserve">Not recommended due to higher fees and less protection against typos.</source>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg659">
+ <source xml:space="preserve">Base58 (P2SH-SegWit)</source>
+ <context-group purpose="location"><context context-type="linenumber">97</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg660">
+ <source xml:space="preserve">Generates an address compatible with older wallets.</source>
+ <context-group purpose="location"><context context-type="linenumber">97</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg661">
+ <source xml:space="preserve">Bech32 (SegWit)</source>
+ <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg662">
+ <source xml:space="preserve">Generates a native segwit address (BIP-173). Some old wallets don&apos;t support it.</source>
+ <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg663">
+ <source xml:space="preserve">Bech32m (Taproot)</source>
+ <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg664">
+ <source xml:space="preserve">Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.</source>
+ <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg665">
<source xml:space="preserve">Could not unlock wallet.</source>
<context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg657">
+ <trans-unit id="_msg666">
<source xml:space="preserve">Could not generate new %1 address</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
@@ -3044,51 +3090,51 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg658">
+ <trans-unit id="_msg667">
<source xml:space="preserve">Request payment to …</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg659">
+ <trans-unit id="_msg668">
<source xml:space="preserve">Address:</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg660">
+ <trans-unit id="_msg669">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">119</context></context-group>
</trans-unit>
- <trans-unit id="_msg661">
+ <trans-unit id="_msg670">
<source xml:space="preserve">Label:</source>
<context-group purpose="location"><context context-type="linenumber">148</context></context-group>
</trans-unit>
- <trans-unit id="_msg662">
+ <trans-unit id="_msg671">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg663">
+ <trans-unit id="_msg672">
<source xml:space="preserve">Wallet:</source>
<context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
- <trans-unit id="_msg664">
+ <trans-unit id="_msg673">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg665">
+ <trans-unit id="_msg674">
<source xml:space="preserve">Copy &amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg666">
+ <trans-unit id="_msg675">
<source xml:space="preserve">&amp;Verify</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg667">
+ <trans-unit id="_msg676">
<source xml:space="preserve">Verify this address on e.g. a hardware wallet screen</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg668">
+ <trans-unit id="_msg677">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg669">
+ <trans-unit id="_msg678">
<source xml:space="preserve">Payment information</source>
<context-group purpose="location"><context context-type="linenumber">39</context></context-group>
</trans-unit>
@@ -3096,7 +3142,7 @@ For more information on using this console, type %6.
</body></file>
<file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg670">
+ <trans-unit id="_msg679">
<source xml:space="preserve">Request payment to %1</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
@@ -3104,31 +3150,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel">
- <trans-unit id="_msg671">
+ <trans-unit id="_msg680">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg672">
+ <trans-unit id="_msg681">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg673">
+ <trans-unit id="_msg682">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg674">
+ <trans-unit id="_msg683">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg675">
+ <trans-unit id="_msg684">
<source xml:space="preserve">(no message)</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg676">
+ <trans-unit id="_msg685">
<source xml:space="preserve">(no amount requested)</source>
<context-group purpose="location"><context context-type="linenumber">87</context></context-group>
</trans-unit>
- <trans-unit id="_msg677">
+ <trans-unit id="_msg686">
<source xml:space="preserve">Requested</source>
<context-group purpose="location"><context context-type="linenumber">130</context></context-group>
</trans-unit>
@@ -3136,154 +3182,154 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg678">
+ <trans-unit id="_msg687">
<source xml:space="preserve">Send Coins</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">755</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg679">
+ <trans-unit id="_msg688">
<source xml:space="preserve">Coin Control Features</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg680">
+ <trans-unit id="_msg689">
<source xml:space="preserve">automatically selected</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg681">
+ <trans-unit id="_msg690">
<source xml:space="preserve">Insufficient funds!</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg682">
+ <trans-unit id="_msg691">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg683">
+ <trans-unit id="_msg692">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg684">
+ <trans-unit id="_msg693">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg685">
+ <trans-unit id="_msg694">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">391</context></context-group>
</trans-unit>
- <trans-unit id="_msg686">
+ <trans-unit id="_msg695">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">442</context></context-group>
</trans-unit>
- <trans-unit id="_msg687">
+ <trans-unit id="_msg696">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">474</context></context-group>
</trans-unit>
- <trans-unit id="_msg688">
+ <trans-unit id="_msg697">
<source xml:space="preserve">If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
<context-group purpose="location"><context context-type="linenumber">518</context></context-group>
</trans-unit>
- <trans-unit id="_msg689">
+ <trans-unit id="_msg698">
<source xml:space="preserve">Custom change address</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg690">
+ <trans-unit id="_msg699">
<source xml:space="preserve">Transaction Fee:</source>
<context-group purpose="location"><context context-type="linenumber">727</context></context-group>
</trans-unit>
- <trans-unit id="_msg691">
+ <trans-unit id="_msg700">
<source xml:space="preserve">Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg692">
+ <trans-unit id="_msg701">
<source xml:space="preserve">Warning: Fee estimation is currently not possible.</source>
<context-group purpose="location"><context context-type="linenumber">774</context></context-group>
</trans-unit>
- <trans-unit id="_msg693">
+ <trans-unit id="_msg702">
<source xml:space="preserve">per kilobyte</source>
<context-group purpose="location"><context context-type="linenumber">856</context></context-group>
</trans-unit>
- <trans-unit id="_msg694">
+ <trans-unit id="_msg703">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">803</context></context-group>
</trans-unit>
- <trans-unit id="_msg695">
+ <trans-unit id="_msg704">
<source xml:space="preserve">Recommended:</source>
<context-group purpose="location"><context context-type="linenumber">915</context></context-group>
</trans-unit>
- <trans-unit id="_msg696">
+ <trans-unit id="_msg705">
<source xml:space="preserve">Custom:</source>
<context-group purpose="location"><context context-type="linenumber">945</context></context-group>
</trans-unit>
- <trans-unit id="_msg697">
+ <trans-unit id="_msg706">
<source xml:space="preserve">Send to multiple recipients at once</source>
<context-group purpose="location"><context context-type="linenumber">1160</context></context-group>
</trans-unit>
- <trans-unit id="_msg698">
+ <trans-unit id="_msg707">
<source xml:space="preserve">Add &amp;Recipient</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
- <trans-unit id="_msg699">
+ <trans-unit id="_msg708">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">1143</context></context-group>
</trans-unit>
- <trans-unit id="_msg700">
+ <trans-unit id="_msg709">
<source xml:space="preserve">Inputs…</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg701">
+ <trans-unit id="_msg710">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">343</context></context-group>
</trans-unit>
- <trans-unit id="_msg702">
+ <trans-unit id="_msg711">
<source xml:space="preserve">Choose…</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg703">
+ <trans-unit id="_msg712">
<source xml:space="preserve">Hide transaction fee settings</source>
<context-group purpose="location"><context context-type="linenumber">800</context></context-group>
</trans-unit>
- <trans-unit id="_msg704">
+ <trans-unit id="_msg713">
<source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction&apos;s virtual size.
Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100 satoshis per kvB&quot; for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
<context-group purpose="location"><context context-type="linenumber">851</context></context-group>
</trans-unit>
- <trans-unit id="_msg705">
+ <trans-unit id="_msg714">
<source xml:space="preserve">When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
<context-group purpose="location"><context context-type="linenumber">886</context></context-group>
</trans-unit>
- <trans-unit id="_msg706">
+ <trans-unit id="_msg715">
<source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source>
<context-group purpose="location"><context context-type="linenumber">889</context></context-group>
</trans-unit>
- <trans-unit id="_msg707">
+ <trans-unit id="_msg716">
<source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source>
<context-group purpose="location"><context context-type="linenumber">994</context></context-group>
</trans-unit>
- <trans-unit id="_msg708">
+ <trans-unit id="_msg717">
<source xml:space="preserve">Confirmation time target:</source>
<context-group purpose="location"><context context-type="linenumber">1020</context></context-group>
</trans-unit>
- <trans-unit id="_msg709">
+ <trans-unit id="_msg718">
<source xml:space="preserve">Enable Replace-By-Fee</source>
<context-group purpose="location"><context context-type="linenumber">1078</context></context-group>
</trans-unit>
- <trans-unit id="_msg710">
+ <trans-unit id="_msg719">
<source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction&apos;s fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
<context-group purpose="location"><context context-type="linenumber">1081</context></context-group>
</trans-unit>
- <trans-unit id="_msg711">
+ <trans-unit id="_msg720">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">1146</context></context-group>
</trans-unit>
- <trans-unit id="_msg712">
+ <trans-unit id="_msg721">
<source xml:space="preserve">Balance:</source>
<context-group purpose="location"><context context-type="linenumber">1201</context></context-group>
</trans-unit>
- <trans-unit id="_msg713">
+ <trans-unit id="_msg722">
<source xml:space="preserve">Confirm the send action</source>
<context-group purpose="location"><context context-type="linenumber">1117</context></context-group>
</trans-unit>
- <trans-unit id="_msg714">
+ <trans-unit id="_msg723">
<source xml:space="preserve">S&amp;end</source>
<context-group purpose="location"><context context-type="linenumber">1120</context></context-group>
</trans-unit>
@@ -3291,278 +3337,304 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg715">
+ <trans-unit id="_msg724">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg716">
+ <trans-unit id="_msg725">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg717">
+ <trans-unit id="_msg726">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg718">
+ <trans-unit id="_msg727">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg719">
+ <trans-unit id="_msg728">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg720">
+ <trans-unit id="_msg729">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg721">
+ <trans-unit id="_msg730">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg722">
+ <trans-unit id="_msg731">
<source xml:space="preserve">%1 (%2 blocks)</source>
<context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg723">
+ <trans-unit id="_msg732">
<source xml:space="preserve">Sign on device</source>
<context-group purpose="location"><context context-type="linenumber">205</context></context-group>
<note annotates="source" from="developer">&quot;device&quot; usually means a hardware wallet.</note>
</trans-unit>
- <trans-unit id="_msg724">
+ <trans-unit id="_msg733">
<source xml:space="preserve">Connect your hardware wallet first.</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg725">
+ <trans-unit id="_msg734">
<source xml:space="preserve">Set external signer script path in Options -&gt; Wallet</source>
<context-group purpose="location"><context context-type="linenumber">212</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg726">
+ <trans-unit id="_msg735">
<source xml:space="preserve">Cr&amp;eate Unsigned</source>
<context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg727">
+ <trans-unit id="_msg736">
<source xml:space="preserve">Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg728">
+ <trans-unit id="_msg737">
<source xml:space="preserve"> from wallet &apos;%1&apos;</source>
<context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg729">
+ <trans-unit id="_msg738">
<source xml:space="preserve">%1 to &apos;%2&apos;</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg730">
+ <trans-unit id="_msg739">
<source xml:space="preserve">%1 to %2</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg731">
+ <trans-unit id="_msg740">
<source xml:space="preserve">To review recipient list click &quot;Show Details…&quot;</source>
- <context-group purpose="location"><context context-type="linenumber">390</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">391</context></context-group>
</trans-unit>
- <trans-unit id="_msg732">
+ <trans-unit id="_msg741">
<source xml:space="preserve">Sign failed</source>
- <context-group purpose="location"><context context-type="linenumber">450</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">453</context></context-group>
</trans-unit>
- <trans-unit id="_msg733">
+ <trans-unit id="_msg742">
<source xml:space="preserve">External signer not found</source>
- <context-group purpose="location"><context context-type="linenumber">455</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">458</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg734">
+ <trans-unit id="_msg743">
<source xml:space="preserve">External signer failure</source>
- <context-group purpose="location"><context context-type="linenumber">460</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">464</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg735">
+ <trans-unit id="_msg744">
<source xml:space="preserve">Save Transaction Data</source>
- <context-group purpose="location"><context context-type="linenumber">426</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">428</context></context-group>
</trans-unit>
- <trans-unit id="_msg736">
+ <trans-unit id="_msg745">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
- <context-group purpose="location"><context context-type="linenumber">428</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">430</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg737">
+ <trans-unit id="_msg746">
<source xml:space="preserve">PSBT saved</source>
- <context-group purpose="location"><context context-type="linenumber">435</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">438</context></context-group>
+ <note annotates="source" from="developer">Popup message when a PSBT has been saved to a file</note>
</trans-unit>
- <trans-unit id="_msg738">
+ <trans-unit id="_msg747">
<source xml:space="preserve">External balance:</source>
- <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">711</context></context-group>
</trans-unit>
- <trans-unit id="_msg739">
+ <trans-unit id="_msg748">
<source xml:space="preserve">or</source>
- <context-group purpose="location"><context context-type="linenumber">386</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">387</context></context-group>
</trans-unit>
- <trans-unit id="_msg740">
+ <trans-unit id="_msg749">
<source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
- <context-group purpose="location"><context context-type="linenumber">368</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">369</context></context-group>
</trans-unit>
- <trans-unit id="_msg741">
+ <trans-unit id="_msg750">
<source xml:space="preserve">Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<context-group purpose="location"><context context-type="linenumber">338</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</note>
</trans-unit>
- <trans-unit id="_msg742">
+ <trans-unit id="_msg751">
<source xml:space="preserve">Do you want to create this transaction?</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
<note annotates="source" from="developer">Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</note>
</trans-unit>
- <trans-unit id="_msg743">
+ <trans-unit id="_msg752">
<source xml:space="preserve">Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<context-group purpose="location"><context context-type="linenumber">343</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</note>
</trans-unit>
- <trans-unit id="_msg744">
+ <trans-unit id="_msg753">
<source xml:space="preserve">Please, review your transaction.</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
<note annotates="source" from="developer">Text to prompt a user to review the details of the transaction they are attempting to send.</note>
</trans-unit>
- <trans-unit id="_msg745">
+ <trans-unit id="_msg754">
<source xml:space="preserve">Transaction fee</source>
<context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg746">
+ <trans-unit id="_msg755">
+ <source xml:space="preserve">%1 kvB</source>
+ <context-group purpose="location"><context context-type="linenumber">359</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">PSBT transaction creation</context></context-group>
+ <note annotates="source" from="developer">When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with &quot;virtual size&quot; of the transaction displayed for context</note>
+ </trans-unit>
+ <trans-unit id="_msg756">
<source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source>
- <context-group purpose="location"><context context-type="linenumber">370</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">371</context></context-group>
</trans-unit>
- <trans-unit id="_msg747">
+ <trans-unit id="_msg757">
<source xml:space="preserve">Total Amount</source>
- <context-group purpose="location"><context context-type="linenumber">383</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">384</context></context-group>
</trans-unit>
- <trans-unit id="_msg748">
+ <trans-unit id="_msg758">
+ <source xml:space="preserve">Unsigned Transaction</source>
+ <context-group purpose="location"><context context-type="linenumber">408</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">PSBT copied</context></context-group>
+ <note annotates="source" from="developer">Caption of &quot;PSBT has been copied&quot; messagebox</note>
+ </trans-unit>
+ <trans-unit id="_msg759">
+ <source xml:space="preserve">The PSBT has been copied to the clipboard. You can also save it.</source>
+ <context-group purpose="location"><context context-type="linenumber">409</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg760">
+ <source xml:space="preserve">PSBT saved to disk</source>
+ <context-group purpose="location"><context context-type="linenumber">438</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg761">
<source xml:space="preserve">Confirm send coins</source>
- <context-group purpose="location"><context context-type="linenumber">482</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">487</context></context-group>
</trans-unit>
- <trans-unit id="_msg749">
+ <trans-unit id="_msg762">
<source xml:space="preserve">Watch-only balance:</source>
- <context-group purpose="location"><context context-type="linenumber">704</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">714</context></context-group>
</trans-unit>
- <trans-unit id="_msg750">
+ <trans-unit id="_msg763">
<source xml:space="preserve">The recipient address is not valid. Please recheck.</source>
- <context-group purpose="location"><context context-type="linenumber">728</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">738</context></context-group>
</trans-unit>
- <trans-unit id="_msg751">
+ <trans-unit id="_msg764">
<source xml:space="preserve">The amount to pay must be larger than 0.</source>
- <context-group purpose="location"><context context-type="linenumber">731</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg752">
+ <trans-unit id="_msg765">
<source xml:space="preserve">The amount exceeds your balance.</source>
- <context-group purpose="location"><context context-type="linenumber">734</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">744</context></context-group>
</trans-unit>
- <trans-unit id="_msg753">
+ <trans-unit id="_msg766">
<source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source>
- <context-group purpose="location"><context context-type="linenumber">737</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">747</context></context-group>
</trans-unit>
- <trans-unit id="_msg754">
+ <trans-unit id="_msg767">
<source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source>
- <context-group purpose="location"><context context-type="linenumber">740</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">750</context></context-group>
</trans-unit>
- <trans-unit id="_msg755">
+ <trans-unit id="_msg768">
<source xml:space="preserve">Transaction creation failed!</source>
- <context-group purpose="location"><context context-type="linenumber">743</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">753</context></context-group>
</trans-unit>
- <trans-unit id="_msg756">
+ <trans-unit id="_msg769">
<source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source>
- <context-group purpose="location"><context context-type="linenumber">747</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">757</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg770">
+ <source xml:space="preserve">%1/kvB</source>
+ <context-group purpose="location"><context context-type="linenumber">831</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">866</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">870</context></context-group>
- <trans-unit id="_msg757[0]">
+ <context-group purpose="location"><context context-type="linenumber">880</context></context-group>
+ <trans-unit id="_msg771[0]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
- <trans-unit id="_msg757[1]">
+ <trans-unit id="_msg771[1]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
</group>
- <trans-unit id="_msg758">
+ <trans-unit id="_msg772">
<source xml:space="preserve">Warning: Invalid Bitcoin address</source>
- <context-group purpose="location"><context context-type="linenumber">971</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">981</context></context-group>
</trans-unit>
- <trans-unit id="_msg759">
+ <trans-unit id="_msg773">
<source xml:space="preserve">Warning: Unknown change address</source>
- <context-group purpose="location"><context context-type="linenumber">976</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">986</context></context-group>
</trans-unit>
- <trans-unit id="_msg760">
+ <trans-unit id="_msg774">
<source xml:space="preserve">Confirm custom change address</source>
- <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">989</context></context-group>
</trans-unit>
- <trans-unit id="_msg761">
+ <trans-unit id="_msg775">
<source xml:space="preserve">The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
- <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">989</context></context-group>
</trans-unit>
- <trans-unit id="_msg762">
+ <trans-unit id="_msg776">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">1000</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1010</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsEntry">
- <trans-unit id="_msg763">
+ <trans-unit id="_msg777">
<source xml:space="preserve">A&amp;mount:</source>
<context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg764">
+ <trans-unit id="_msg778">
<source xml:space="preserve">Pay &amp;To:</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg765">
+ <trans-unit id="_msg779">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
- <trans-unit id="_msg766">
+ <trans-unit id="_msg780">
<source xml:space="preserve">Choose previously used address</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg767">
+ <trans-unit id="_msg781">
<source xml:space="preserve">The Bitcoin address to send the payment to</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg768">
+ <trans-unit id="_msg782">
<source xml:space="preserve">Alt+A</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg769">
+ <trans-unit id="_msg783">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg770">
+ <trans-unit id="_msg784">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg771">
+ <trans-unit id="_msg785">
<source xml:space="preserve">Remove this entry</source>
<context-group purpose="location"><context context-type="linenumber">106</context></context-group>
</trans-unit>
- <trans-unit id="_msg772">
+ <trans-unit id="_msg786">
<source xml:space="preserve">The amount to send in the selected unit</source>
<context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
- <trans-unit id="_msg773">
+ <trans-unit id="_msg787">
<source xml:space="preserve">The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg774">
+ <trans-unit id="_msg788">
<source xml:space="preserve">S&amp;ubtract fee from amount</source>
<context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg775">
+ <trans-unit id="_msg789">
<source xml:space="preserve">Use available balance</source>
<context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg776">
+ <trans-unit id="_msg790">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg777">
+ <trans-unit id="_msg791">
<source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source>
<context-group purpose="location"><context context-type="linenumber">141</context></context-group>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg778">
+ <trans-unit id="_msg792">
<source xml:space="preserve">A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
@@ -3570,11 +3642,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendConfirmationDialog">
- <trans-unit id="_msg779">
+ <trans-unit id="_msg793">
<source xml:space="preserve">Send</source>
<context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg780">
+ <trans-unit id="_msg794">
<source xml:space="preserve">Create Unsigned</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -3582,105 +3654,105 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg781">
+ <trans-unit id="_msg795">
<source xml:space="preserve">Signatures - Sign / Verify a Message</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg782">
+ <trans-unit id="_msg796">
<source xml:space="preserve">&amp;Sign Message</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg783">
+ <trans-unit id="_msg797">
<source xml:space="preserve">You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg784">
+ <trans-unit id="_msg798">
<source xml:space="preserve">The Bitcoin address to sign the message with</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg785">
+ <trans-unit id="_msg799">
<source xml:space="preserve">Choose previously used address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg786">
+ <trans-unit id="_msg800">
<source xml:space="preserve">Alt+A</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg787">
+ <trans-unit id="_msg801">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg788">
+ <trans-unit id="_msg802">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg789">
+ <trans-unit id="_msg803">
<source xml:space="preserve">Enter the message you want to sign here</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
- <trans-unit id="_msg790">
+ <trans-unit id="_msg804">
<source xml:space="preserve">Signature</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg791">
+ <trans-unit id="_msg805">
<source xml:space="preserve">Copy the current signature to the system clipboard</source>
<context-group purpose="location"><context context-type="linenumber">140</context></context-group>
</trans-unit>
- <trans-unit id="_msg792">
+ <trans-unit id="_msg806">
<source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">161</context></context-group>
</trans-unit>
- <trans-unit id="_msg793">
+ <trans-unit id="_msg807">
<source xml:space="preserve">Sign &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">164</context></context-group>
</trans-unit>
- <trans-unit id="_msg794">
+ <trans-unit id="_msg808">
<source xml:space="preserve">Reset all sign message fields</source>
<context-group purpose="location"><context context-type="linenumber">178</context></context-group>
</trans-unit>
- <trans-unit id="_msg795">
+ <trans-unit id="_msg809">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
<context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg796">
+ <trans-unit id="_msg810">
<source xml:space="preserve">&amp;Verify Message</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg797">
+ <trans-unit id="_msg811">
<source xml:space="preserve">Enter the receiver&apos;s address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
<context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg798">
+ <trans-unit id="_msg812">
<source xml:space="preserve">The Bitcoin address the message was signed with</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg799">
+ <trans-unit id="_msg813">
<source xml:space="preserve">The signed message to verify</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg800">
+ <trans-unit id="_msg814">
<source xml:space="preserve">The signature given when the message was signed</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
<context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg801">
+ <trans-unit id="_msg815">
<source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg802">
+ <trans-unit id="_msg816">
<source xml:space="preserve">Verify &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg803">
+ <trans-unit id="_msg817">
<source xml:space="preserve">Reset all verify message fields</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg804">
+ <trans-unit id="_msg818">
<source xml:space="preserve">Click &quot;Sign Message&quot; to generate signature</source>
<context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
@@ -3688,61 +3760,61 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg805">
+ <trans-unit id="_msg819">
<source xml:space="preserve">The entered address is invalid.</source>
<context-group purpose="location"><context context-type="linenumber">119</context></context-group>
<context-group purpose="location"><context context-type="linenumber">218</context></context-group>
</trans-unit>
- <trans-unit id="_msg806">
+ <trans-unit id="_msg820">
<source xml:space="preserve">Please check the address and try again.</source>
<context-group purpose="location"><context context-type="linenumber">119</context></context-group>
<context-group purpose="location"><context context-type="linenumber">126</context></context-group>
<context-group purpose="location"><context context-type="linenumber">219</context></context-group>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg807">
+ <trans-unit id="_msg821">
<source xml:space="preserve">The entered address does not refer to a key.</source>
<context-group purpose="location"><context context-type="linenumber">126</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg808">
+ <trans-unit id="_msg822">
<source xml:space="preserve">Wallet unlock was cancelled.</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg809">
+ <trans-unit id="_msg823">
<source xml:space="preserve">No error</source>
<context-group purpose="location"><context context-type="linenumber">145</context></context-group>
</trans-unit>
- <trans-unit id="_msg810">
+ <trans-unit id="_msg824">
<source xml:space="preserve">Private key for the entered address is not available.</source>
<context-group purpose="location"><context context-type="linenumber">148</context></context-group>
</trans-unit>
- <trans-unit id="_msg811">
+ <trans-unit id="_msg825">
<source xml:space="preserve">Message signing failed.</source>
<context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg812">
+ <trans-unit id="_msg826">
<source xml:space="preserve">Message signed.</source>
<context-group purpose="location"><context context-type="linenumber">163</context></context-group>
</trans-unit>
- <trans-unit id="_msg813">
+ <trans-unit id="_msg827">
<source xml:space="preserve">The signature could not be decoded.</source>
<context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg814">
+ <trans-unit id="_msg828">
<source xml:space="preserve">Please check the signature and try again.</source>
<context-group purpose="location"><context context-type="linenumber">233</context></context-group>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg815">
+ <trans-unit id="_msg829">
<source xml:space="preserve">The signature did not match the message digest.</source>
<context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg816">
+ <trans-unit id="_msg830">
<source xml:space="preserve">Message verification failed.</source>
<context-group purpose="location"><context context-type="linenumber">245</context></context-group>
</trans-unit>
- <trans-unit id="_msg817">
+ <trans-unit id="_msg831">
<source xml:space="preserve">Message verified.</source>
<context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
@@ -3750,11 +3822,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../splashscreen.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SplashScreen">
- <trans-unit id="_msg818">
+ <trans-unit id="_msg832">
<source xml:space="preserve">(press q to shutdown and continue later)</source>
<context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg819">
+ <trans-unit id="_msg833">
<source xml:space="preserve">press q to shutdown</source>
<context-group purpose="location"><context context-type="linenumber">178</context></context-group>
</trans-unit>
@@ -3762,7 +3834,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget">
- <trans-unit id="_msg820">
+ <trans-unit id="_msg834">
<source xml:space="preserve">kB/s</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
@@ -3770,82 +3842,84 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondesc.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDesc">
- <trans-unit id="_msg821">
+ <trans-unit id="_msg835">
<source xml:space="preserve">conflicted with a transaction with %1 confirmations</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</note>
</trans-unit>
- <trans-unit id="_msg822">
+ <trans-unit id="_msg836">
<source xml:space="preserve">0/unconfirmed, in memory pool</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg823">
+ <trans-unit id="_msg837">
<source xml:space="preserve">0/unconfirmed, not in memory pool</source>
<context-group purpose="location"><context context-type="linenumber">55</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg824">
+ <trans-unit id="_msg838">
<source xml:space="preserve">abandoned</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</note>
</trans-unit>
- <trans-unit id="_msg825">
+ <trans-unit id="_msg839">
<source xml:space="preserve">%1/unconfirmed</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</note>
</trans-unit>
- <trans-unit id="_msg826">
+ <trans-unit id="_msg840">
<source xml:space="preserve">%1 confirmations</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
<note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</note>
</trans-unit>
- <trans-unit id="_msg827">
+ <trans-unit id="_msg841">
<source xml:space="preserve">Status</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg828">
+ <trans-unit id="_msg842">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg829">
+ <trans-unit id="_msg843">
<source xml:space="preserve">Source</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg830">
+ <trans-unit id="_msg844">
<source xml:space="preserve">Generated</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg831">
+ <trans-unit id="_msg845">
<source xml:space="preserve">From</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg832">
+ <trans-unit id="_msg846">
<source xml:space="preserve">unknown</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg833">
+ <trans-unit id="_msg847">
<source xml:space="preserve">To</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
<context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg834">
+ <trans-unit id="_msg848">
<source xml:space="preserve">own address</source>
<context-group purpose="location"><context context-type="linenumber">156</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg835">
+ <trans-unit id="_msg849">
<source xml:space="preserve">watch-only</source>
<context-group purpose="location"><context context-type="linenumber">156</context></context-group>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
- <trans-unit id="_msg836">
+ <trans-unit id="_msg850">
<source xml:space="preserve">label</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg837">
+ <trans-unit id="_msg851">
<source xml:space="preserve">Credit</source>
<context-group purpose="location"><context context-type="linenumber">194</context></context-group>
<context-group purpose="location"><context context-type="linenumber">206</context></context-group>
@@ -3855,98 +3929,98 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">196</context></context-group>
- <trans-unit id="_msg838[0]">
+ <trans-unit id="_msg852[0]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
- <trans-unit id="_msg838[1]">
+ <trans-unit id="_msg852[1]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg839">
+ <trans-unit id="_msg853">
<source xml:space="preserve">not accepted</source>
<context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg840">
+ <trans-unit id="_msg854">
<source xml:space="preserve">Debit</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
<context-group purpose="location"><context context-type="linenumber">347</context></context-group>
</trans-unit>
- <trans-unit id="_msg841">
+ <trans-unit id="_msg855">
<source xml:space="preserve">Total debit</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg842">
+ <trans-unit id="_msg856">
<source xml:space="preserve">Total credit</source>
<context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg843">
+ <trans-unit id="_msg857">
<source xml:space="preserve">Transaction fee</source>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg844">
+ <trans-unit id="_msg858">
<source xml:space="preserve">Net amount</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg845">
+ <trans-unit id="_msg859">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">302</context></context-group>
<context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg846">
+ <trans-unit id="_msg860">
<source xml:space="preserve">Comment</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg847">
+ <trans-unit id="_msg861">
<source xml:space="preserve">Transaction ID</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg848">
+ <trans-unit id="_msg862">
<source xml:space="preserve">Transaction total size</source>
<context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg849">
+ <trans-unit id="_msg863">
<source xml:space="preserve">Transaction virtual size</source>
<context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg850">
+ <trans-unit id="_msg864">
<source xml:space="preserve">Output index</source>
<context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg851">
+ <trans-unit id="_msg865">
<source xml:space="preserve"> (Certificate was not verified)</source>
<context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg852">
+ <trans-unit id="_msg866">
<source xml:space="preserve">Merchant</source>
<context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg853">
+ <trans-unit id="_msg867">
<source xml:space="preserve">Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
<context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg854">
+ <trans-unit id="_msg868">
<source xml:space="preserve">Debug information</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg855">
+ <trans-unit id="_msg869">
<source xml:space="preserve">Transaction</source>
<context-group purpose="location"><context context-type="linenumber">352</context></context-group>
</trans-unit>
- <trans-unit id="_msg856">
+ <trans-unit id="_msg870">
<source xml:space="preserve">Inputs</source>
<context-group purpose="location"><context context-type="linenumber">355</context></context-group>
</trans-unit>
- <trans-unit id="_msg857">
+ <trans-unit id="_msg871">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg858">
+ <trans-unit id="_msg872">
<source xml:space="preserve">true</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg859">
+ <trans-unit id="_msg873">
<source xml:space="preserve">false</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
@@ -3955,7 +4029,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg860">
+ <trans-unit id="_msg874">
<source xml:space="preserve">This pane shows a detailed description of the transaction</source>
<context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
@@ -3963,7 +4037,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg861">
+ <trans-unit id="_msg875">
<source xml:space="preserve">Details for %1</source>
<context-group purpose="location"><context context-type="linenumber">18</context></context-group>
</trans-unit>
@@ -3971,99 +4045,99 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionTableModel">
- <trans-unit id="_msg862">
+ <trans-unit id="_msg876">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg863">
+ <trans-unit id="_msg877">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg864">
+ <trans-unit id="_msg878">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg865">
+ <trans-unit id="_msg879">
<source xml:space="preserve">Unconfirmed</source>
<context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg866">
+ <trans-unit id="_msg880">
<source xml:space="preserve">Abandoned</source>
<context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg867">
+ <trans-unit id="_msg881">
<source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg868">
+ <trans-unit id="_msg882">
<source xml:space="preserve">Confirmed (%1 confirmations)</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg869">
+ <trans-unit id="_msg883">
<source xml:space="preserve">Conflicted</source>
<context-group purpose="location"><context context-type="linenumber">329</context></context-group>
</trans-unit>
- <trans-unit id="_msg870">
+ <trans-unit id="_msg884">
<source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source>
<context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg871">
+ <trans-unit id="_msg885">
<source xml:space="preserve">Generated but not accepted</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg872">
+ <trans-unit id="_msg886">
<source xml:space="preserve">Received with</source>
<context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg873">
+ <trans-unit id="_msg887">
<source xml:space="preserve">Received from</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg874">
+ <trans-unit id="_msg888">
<source xml:space="preserve">Sent to</source>
<context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg875">
+ <trans-unit id="_msg889">
<source xml:space="preserve">Payment to yourself</source>
<context-group purpose="location"><context context-type="linenumber">381</context></context-group>
</trans-unit>
- <trans-unit id="_msg876">
+ <trans-unit id="_msg890">
<source xml:space="preserve">Mined</source>
<context-group purpose="location"><context context-type="linenumber">383</context></context-group>
</trans-unit>
- <trans-unit id="_msg877">
+ <trans-unit id="_msg891">
<source xml:space="preserve">watch-only</source>
<context-group purpose="location"><context context-type="linenumber">411</context></context-group>
</trans-unit>
- <trans-unit id="_msg878">
+ <trans-unit id="_msg892">
<source xml:space="preserve">(n/a)</source>
<context-group purpose="location"><context context-type="linenumber">427</context></context-group>
</trans-unit>
- <trans-unit id="_msg879">
+ <trans-unit id="_msg893">
<source xml:space="preserve">(no label)</source>
<context-group purpose="location"><context context-type="linenumber">634</context></context-group>
</trans-unit>
- <trans-unit id="_msg880">
+ <trans-unit id="_msg894">
<source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source>
<context-group purpose="location"><context context-type="linenumber">673</context></context-group>
</trans-unit>
- <trans-unit id="_msg881">
+ <trans-unit id="_msg895">
<source xml:space="preserve">Date and time that the transaction was received.</source>
<context-group purpose="location"><context context-type="linenumber">675</context></context-group>
</trans-unit>
- <trans-unit id="_msg882">
+ <trans-unit id="_msg896">
<source xml:space="preserve">Type of transaction.</source>
<context-group purpose="location"><context context-type="linenumber">677</context></context-group>
</trans-unit>
- <trans-unit id="_msg883">
+ <trans-unit id="_msg897">
<source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source>
<context-group purpose="location"><context context-type="linenumber">679</context></context-group>
</trans-unit>
- <trans-unit id="_msg884">
+ <trans-unit id="_msg898">
<source xml:space="preserve">User-defined intent/purpose of the transaction.</source>
<context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg885">
+ <trans-unit id="_msg899">
<source xml:space="preserve">Amount removed from or added to balance.</source>
<context-group purpose="location"><context context-type="linenumber">683</context></context-group>
</trans-unit>
@@ -4071,206 +4145,206 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactionview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionView">
- <trans-unit id="_msg886">
+ <trans-unit id="_msg900">
<source xml:space="preserve">All</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
<context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
- <trans-unit id="_msg887">
+ <trans-unit id="_msg901">
<source xml:space="preserve">Today</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg888">
+ <trans-unit id="_msg902">
<source xml:space="preserve">This week</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
</trans-unit>
- <trans-unit id="_msg889">
+ <trans-unit id="_msg903">
<source xml:space="preserve">This month</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg890">
+ <trans-unit id="_msg904">
<source xml:space="preserve">Last month</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg891">
+ <trans-unit id="_msg905">
<source xml:space="preserve">This year</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg892">
+ <trans-unit id="_msg906">
<source xml:space="preserve">Received with</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg893">
+ <trans-unit id="_msg907">
<source xml:space="preserve">Sent to</source>
<context-group purpose="location"><context context-type="linenumber">92</context></context-group>
</trans-unit>
- <trans-unit id="_msg894">
+ <trans-unit id="_msg908">
<source xml:space="preserve">To yourself</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg895">
+ <trans-unit id="_msg909">
<source xml:space="preserve">Mined</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg896">
+ <trans-unit id="_msg910">
<source xml:space="preserve">Other</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg897">
+ <trans-unit id="_msg911">
<source xml:space="preserve">Enter address, transaction id, or label to search</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg898">
+ <trans-unit id="_msg912">
<source xml:space="preserve">Min amount</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg899">
+ <trans-unit id="_msg913">
<source xml:space="preserve">Range…</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg900">
+ <trans-unit id="_msg914">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">169</context></context-group>
</trans-unit>
- <trans-unit id="_msg901">
+ <trans-unit id="_msg915">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg902">
+ <trans-unit id="_msg916">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">171</context></context-group>
</trans-unit>
- <trans-unit id="_msg903">
+ <trans-unit id="_msg917">
<source xml:space="preserve">Copy transaction &amp;ID</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg904">
+ <trans-unit id="_msg918">
<source xml:space="preserve">Copy &amp;raw transaction</source>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg905">
+ <trans-unit id="_msg919">
<source xml:space="preserve">Copy full transaction &amp;details</source>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
</trans-unit>
- <trans-unit id="_msg906">
+ <trans-unit id="_msg920">
<source xml:space="preserve">&amp;Show transaction details</source>
<context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg907">
+ <trans-unit id="_msg921">
<source xml:space="preserve">Increase transaction &amp;fee</source>
<context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg908">
+ <trans-unit id="_msg922">
<source xml:space="preserve">A&amp;bandon transaction</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg909">
+ <trans-unit id="_msg923">
<source xml:space="preserve">&amp;Edit address label</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
- <trans-unit id="_msg910">
+ <trans-unit id="_msg924">
<source xml:space="preserve">Show in %1</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
<note annotates="source" from="developer">Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</note>
</trans-unit>
- <trans-unit id="_msg911">
+ <trans-unit id="_msg925">
<source xml:space="preserve">Export Transaction History</source>
<context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg912">
+ <trans-unit id="_msg926">
<source xml:space="preserve">Comma separated file</source>
<context-group purpose="location"><context context-type="linenumber">362</context></context-group>
<note annotates="source" from="developer">Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</note>
</trans-unit>
- <trans-unit id="_msg913">
+ <trans-unit id="_msg927">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
</trans-unit>
- <trans-unit id="_msg914">
+ <trans-unit id="_msg928">
<source xml:space="preserve">Watch-only</source>
<context-group purpose="location"><context context-type="linenumber">373</context></context-group>
</trans-unit>
- <trans-unit id="_msg915">
+ <trans-unit id="_msg929">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg916">
+ <trans-unit id="_msg930">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg917">
+ <trans-unit id="_msg931">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg918">
+ <trans-unit id="_msg932">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
</trans-unit>
- <trans-unit id="_msg919">
+ <trans-unit id="_msg933">
<source xml:space="preserve">ID</source>
<context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg920">
+ <trans-unit id="_msg934">
<source xml:space="preserve">Exporting Failed</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg921">
+ <trans-unit id="_msg935">
<source xml:space="preserve">There was an error trying to save the transaction history to %1.</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg922">
+ <trans-unit id="_msg936">
<source xml:space="preserve">Exporting Successful</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg923">
+ <trans-unit id="_msg937">
<source xml:space="preserve">The transaction history was successfully saved to %1.</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg924">
+ <trans-unit id="_msg938">
<source xml:space="preserve">Range:</source>
- <context-group purpose="location"><context context-type="linenumber">555</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">556</context></context-group>
</trans-unit>
- <trans-unit id="_msg925">
+ <trans-unit id="_msg939">
<source xml:space="preserve">to</source>
- <context-group purpose="location"><context context-type="linenumber">563</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">564</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletframe.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletFrame">
- <trans-unit id="_msg926">
+ <trans-unit id="_msg940">
<source xml:space="preserve">No wallet has been loaded.
Go to File &gt; Open Wallet to load a wallet.
- OR -</source>
<context-group purpose="location"><context context-type="linenumber">45</context></context-group>
</trans-unit>
- <trans-unit id="_msg927">
+ <trans-unit id="_msg941">
<source xml:space="preserve">Create a new wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg928">
+ <trans-unit id="_msg942">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
<context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
- <trans-unit id="_msg929">
+ <trans-unit id="_msg943">
<source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg930">
+ <trans-unit id="_msg944">
<source xml:space="preserve">Load Transaction Data</source>
<context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg931">
+ <trans-unit id="_msg945">
<source xml:space="preserve">Partially Signed Transaction (*.psbt)</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg932">
+ <trans-unit id="_msg946">
<source xml:space="preserve">PSBT file must be smaller than 100 MiB</source>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
</trans-unit>
- <trans-unit id="_msg933">
+ <trans-unit id="_msg947">
<source xml:space="preserve">Unable to decode PSBT</source>
<context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
@@ -4278,68 +4352,73 @@ Go to File &gt; Open Wallet to load a wallet.
</body></file>
<file original="../walletmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletModel">
- <trans-unit id="_msg934">
+ <trans-unit id="_msg948">
<source xml:space="preserve">Send Coins</source>
<context-group purpose="location"><context context-type="linenumber">228</context></context-group>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg935">
+ <trans-unit id="_msg949">
<source xml:space="preserve">Fee bump error</source>
<context-group purpose="location"><context context-type="linenumber">489</context></context-group>
<context-group purpose="location"><context context-type="linenumber">544</context></context-group>
<context-group purpose="location"><context context-type="linenumber">559</context></context-group>
<context-group purpose="location"><context context-type="linenumber">564</context></context-group>
</trans-unit>
- <trans-unit id="_msg936">
+ <trans-unit id="_msg950">
<source xml:space="preserve">Increasing transaction fee failed</source>
<context-group purpose="location"><context context-type="linenumber">489</context></context-group>
</trans-unit>
- <trans-unit id="_msg937">
+ <trans-unit id="_msg951">
<source xml:space="preserve">Do you want to increase the fee?</source>
<context-group purpose="location"><context context-type="linenumber">496</context></context-group>
<note annotates="source" from="developer">Asks a user if they would like to manually increase the fee of a transaction that has already been created.</note>
</trans-unit>
- <trans-unit id="_msg938">
+ <trans-unit id="_msg952">
<source xml:space="preserve">Current fee:</source>
<context-group purpose="location"><context context-type="linenumber">500</context></context-group>
</trans-unit>
- <trans-unit id="_msg939">
+ <trans-unit id="_msg953">
<source xml:space="preserve">Increase:</source>
<context-group purpose="location"><context context-type="linenumber">504</context></context-group>
</trans-unit>
- <trans-unit id="_msg940">
+ <trans-unit id="_msg954">
<source xml:space="preserve">New fee:</source>
<context-group purpose="location"><context context-type="linenumber">508</context></context-group>
</trans-unit>
- <trans-unit id="_msg941">
+ <trans-unit id="_msg955">
<source xml:space="preserve">Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
<context-group purpose="location"><context context-type="linenumber">516</context></context-group>
</trans-unit>
- <trans-unit id="_msg942">
+ <trans-unit id="_msg956">
<source xml:space="preserve">Confirm fee bump</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg943">
+ <trans-unit id="_msg957">
<source xml:space="preserve">Can&apos;t draft transaction.</source>
<context-group purpose="location"><context context-type="linenumber">544</context></context-group>
</trans-unit>
- <trans-unit id="_msg944">
+ <trans-unit id="_msg958">
<source xml:space="preserve">PSBT copied</source>
<context-group purpose="location"><context context-type="linenumber">551</context></context-group>
</trans-unit>
- <trans-unit id="_msg945">
+ <trans-unit id="_msg959">
+ <source xml:space="preserve">Copied to clipboard</source>
+ <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
+ <context-group><context context-type="x-gettext-msgctxt">Fee-bump PSBT saved</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg960">
<source xml:space="preserve">Can&apos;t sign transaction.</source>
<context-group purpose="location"><context context-type="linenumber">559</context></context-group>
</trans-unit>
- <trans-unit id="_msg946">
+ <trans-unit id="_msg961">
<source xml:space="preserve">Could not commit transaction</source>
<context-group purpose="location"><context context-type="linenumber">564</context></context-group>
</trans-unit>
- <trans-unit id="_msg947">
+ <trans-unit id="_msg962">
<source xml:space="preserve">Can&apos;t display address</source>
<context-group purpose="location"><context context-type="linenumber">578</context></context-group>
</trans-unit>
- <trans-unit id="_msg948">
+ <trans-unit id="_msg963">
<source xml:space="preserve">default wallet</source>
<context-group purpose="location"><context context-type="linenumber">596</context></context-group>
</trans-unit>
@@ -4347,879 +4426,911 @@ Go to File &gt; Open Wallet to load a wallet.
</body></file>
<file original="../walletview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletView">
- <trans-unit id="_msg949">
+ <trans-unit id="_msg964">
<source xml:space="preserve">&amp;Export</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg950">
+ <trans-unit id="_msg965">
<source xml:space="preserve">Export the data in the current tab to a file</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg951">
+ <trans-unit id="_msg966">
<source xml:space="preserve">Backup Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
- <trans-unit id="_msg952">
+ <trans-unit id="_msg967">
<source xml:space="preserve">Wallet Data</source>
- <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
<note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
- <trans-unit id="_msg953">
+ <trans-unit id="_msg968">
<source xml:space="preserve">Backup Failed</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg954">
+ <trans-unit id="_msg969">
<source xml:space="preserve">There was an error trying to save the wallet data to %1.</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg955">
+ <trans-unit id="_msg970">
<source xml:space="preserve">Backup Successful</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg956">
+ <trans-unit id="_msg971">
<source xml:space="preserve">The wallet data was successfully saved to %1.</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg957">
+ <trans-unit id="_msg972">
<source xml:space="preserve">Cancel</source>
- <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg958">
+ <trans-unit id="_msg973">
<source xml:space="preserve">The %s developers</source>
<context-group purpose="location"><context context-type="linenumber">12</context></context-group>
</trans-unit>
- <trans-unit id="_msg959">
+ <trans-unit id="_msg974">
<source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
<context-group purpose="location"><context context-type="linenumber">13</context></context-group>
</trans-unit>
- <trans-unit id="_msg960">
+ <trans-unit id="_msg975">
<source xml:space="preserve">%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any peer will connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
- <context-group purpose="location"><context context-type="linenumber">16</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">28</context></context-group>
</trans-unit>
- <trans-unit id="_msg961">
- <source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">20</context></context-group>
- </trans-unit>
- <trans-unit id="_msg962">
+ <trans-unit id="_msg976">
<source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
- <context-group purpose="location"><context context-type="linenumber">35</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">44</context></context-group>
</trans-unit>
- <trans-unit id="_msg963">
+ <trans-unit id="_msg977">
<source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">38</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg964">
+ <trans-unit id="_msg978">
<source xml:space="preserve">Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
- <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg965">
+ <trans-unit id="_msg979">
<source xml:space="preserve">Disk space for %s may not accommodate the block files. Approximately %u GB of data will be stored in this directory.</source>
- <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">56</context></context-group>
</trans-unit>
- <trans-unit id="_msg966">
+ <trans-unit id="_msg980">
<source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source>
- <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg967">
+ <trans-unit id="_msg981">
<source xml:space="preserve">Error loading wallet. Wallet requires blocks to be downloaded, and software does not currently support loading wallets while blocks are being downloaded out of order when using assumeutxo snapshots. Wallet should be able to load successfully after node sync reaches height %s</source>
- <context-group purpose="location"><context context-type="linenumber">56</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">65</context></context-group>
</trans-unit>
- <trans-unit id="_msg968">
+ <trans-unit id="_msg982">
<source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
- <context-group purpose="location"><context context-type="linenumber">61</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg969">
+ <trans-unit id="_msg983">
<source xml:space="preserve">Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">64</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg970">
+ <trans-unit id="_msg984">
<source xml:space="preserve">Error: Dumpfile format record is incorrect. Got &quot;%s&quot;, expected &quot;format&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">70</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg971">
+ <trans-unit id="_msg985">
<source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got &quot;%s&quot;, expected &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">72</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">81</context></context-group>
</trans-unit>
- <trans-unit id="_msg972">
+ <trans-unit id="_msg986">
<source xml:space="preserve">Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
- <context-group purpose="location"><context context-type="linenumber">74</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg973">
+ <trans-unit id="_msg987">
<source xml:space="preserve">Error: Legacy wallets only support the &quot;legacy&quot;, &quot;p2sh-segwit&quot;, and &quot;bech32&quot; address types</source>
- <context-group purpose="location"><context context-type="linenumber">80</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
- <trans-unit id="_msg974">
+ <trans-unit id="_msg988">
<source xml:space="preserve">Error: Unable to produce descriptors for this legacy wallet. Make sure to provide the wallet&apos;s passphrase if it is encrypted.</source>
- <context-group purpose="location"><context context-type="linenumber">86</context></context-group>
- </trans-unit>
- <trans-unit id="_msg975">
- <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <context-group purpose="location"><context context-type="linenumber">92</context></context-group>
- </trans-unit>
- <trans-unit id="_msg976">
- <source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg977">
- <source xml:space="preserve">Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
+ <trans-unit id="_msg989">
+ <source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
+ <context-group purpose="location"><context context-type="linenumber">104</context></context-group>
</trans-unit>
- <trans-unit id="_msg978">
+ <trans-unit id="_msg990">
<source xml:space="preserve">Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
- <context-group purpose="location"><context context-type="linenumber">104</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">113</context></context-group>
</trans-unit>
- <trans-unit id="_msg979">
+ <trans-unit id="_msg991">
<source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
- <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
</trans-unit>
- <trans-unit id="_msg980">
+ <trans-unit id="_msg992">
<source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg981">
+ <trans-unit id="_msg993">
<source xml:space="preserve">No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg982">
+ <trans-unit id="_msg994">
<source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">116</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
- <trans-unit id="_msg983">
+ <trans-unit id="_msg995">
<source xml:space="preserve">Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
- <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">141</context></context-group>
</trans-unit>
- <trans-unit id="_msg984">
+ <trans-unit id="_msg996">
<source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source>
- <context-group purpose="location"><context context-type="linenumber">135</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg985">
+ <trans-unit id="_msg997">
<source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">147</context></context-group>
</trans-unit>
- <trans-unit id="_msg986">
+ <trans-unit id="_msg998">
<source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
- <context-group purpose="location"><context context-type="linenumber">140</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg987">
+ <trans-unit id="_msg999">
<source xml:space="preserve">Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
- <context-group purpose="location"><context context-type="linenumber">143</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg988">
+ <trans-unit id="_msg1000">
<source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
- <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">155</context></context-group>
</trans-unit>
- <trans-unit id="_msg989">
+ <trans-unit id="_msg1001">
<source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
- <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
</trans-unit>
- <trans-unit id="_msg990">
+ <trans-unit id="_msg1002">
<source xml:space="preserve">The block index db contains a legacy &apos;txindex&apos;. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
- <context-group purpose="location"><context context-type="linenumber">157</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
- <trans-unit id="_msg991">
+ <trans-unit id="_msg1003">
<source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source>
- <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg992">
+ <trans-unit id="_msg1004">
<source xml:space="preserve">This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
- <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
</trans-unit>
- <trans-unit id="_msg993">
+ <trans-unit id="_msg1005">
<source xml:space="preserve">This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
- <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg994">
+ <trans-unit id="_msg1006">
<source xml:space="preserve">This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
- <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
</trans-unit>
- <trans-unit id="_msg995">
+ <trans-unit id="_msg1007">
<source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">189</context></context-group>
</trans-unit>
- <trans-unit id="_msg996">
+ <trans-unit id="_msg1008">
<source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source>
- <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg997">
+ <trans-unit id="_msg1009">
<source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
- <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg998">
+ <trans-unit id="_msg1010">
<source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <context-group purpose="location"><context context-type="linenumber">188</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
</trans-unit>
- <trans-unit id="_msg999">
+ <trans-unit id="_msg1011">
<source xml:space="preserve">Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
- <trans-unit id="_msg1000">
+ <trans-unit id="_msg1012">
<source xml:space="preserve">Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
- <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
</trans-unit>
- <trans-unit id="_msg1001">
+ <trans-unit id="_msg1013">
<source xml:space="preserve">Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
- <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg1002">
+ <trans-unit id="_msg1014">
<source xml:space="preserve">Warning: Dumpfile wallet format &quot;%s&quot; does not match command line specified format &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg1003">
+ <trans-unit id="_msg1015">
<source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
</trans-unit>
- <trans-unit id="_msg1004">
+ <trans-unit id="_msg1016">
<source xml:space="preserve">Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
</trans-unit>
- <trans-unit id="_msg1005">
+ <trans-unit id="_msg1017">
<source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg1006">
+ <trans-unit id="_msg1018">
<source xml:space="preserve">You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
- <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
</trans-unit>
- <trans-unit id="_msg1007">
+ <trans-unit id="_msg1019">
<source xml:space="preserve">%s is set very high!</source>
- <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg1008">
+ <trans-unit id="_msg1020">
<source xml:space="preserve">-maxmempool must be at least %d MB</source>
- <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
</trans-unit>
- <trans-unit id="_msg1009">
+ <trans-unit id="_msg1021">
<source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source>
- <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
- <trans-unit id="_msg1010">
+ <trans-unit id="_msg1022">
<source xml:space="preserve">Cannot resolve -%s address: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
</trans-unit>
- <trans-unit id="_msg1011">
+ <trans-unit id="_msg1023">
<source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
- <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
</trans-unit>
- <trans-unit id="_msg1012">
+ <trans-unit id="_msg1024">
<source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source>
- <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg1013">
+ <trans-unit id="_msg1025">
<source xml:space="preserve">Cannot write to data directory &apos;%s&apos;; check permissions.</source>
- <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
</trans-unit>
- <trans-unit id="_msg1014">
+ <trans-unit id="_msg1026">
<source xml:space="preserve">The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg1015">
+ <trans-unit id="_msg1027">
+ <source xml:space="preserve">%s failed to validate the -assumeutxo snapshot state. This indicates a hardware problem, or a bug in the software, or a bad software modification that allowed an invalid snapshot to be loaded. As a result of this, the node will shut down and stop using any state that was built on the snapshot, resetting the chain height from %d to %d. On the next restart, the node will resume syncing from %d without using any snapshot data. Please report this incident to %s, including how you obtained the snapshot. The invalid snapshot chainstate has been left on disk in case it is helpful in diagnosing the issue that caused this error.</source>
+ <context-group purpose="location"><context context-type="linenumber">16</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1028">
+ <source xml:space="preserve">%s is set very high! Fees this large could be paid on a single transaction.</source>
+ <context-group purpose="location"><context context-type="linenumber">26</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1029">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
- <context-group purpose="location"><context context-type="linenumber">23</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg1016">
+ <trans-unit id="_msg1030">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
- <context-group purpose="location"><context context-type="linenumber">27</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg1017">
+ <trans-unit id="_msg1031">
<source xml:space="preserve">-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
- <context-group purpose="location"><context context-type="linenumber">31</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">40</context></context-group>
</trans-unit>
- <trans-unit id="_msg1018">
+ <trans-unit id="_msg1032">
<source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
- <context-group purpose="location"><context context-type="linenumber">40</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg1019">
+ <trans-unit id="_msg1033">
<source xml:space="preserve">Error loading %s: External signer wallet being loaded without external signer support compiled</source>
- <context-group purpose="location"><context context-type="linenumber">53</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">62</context></context-group>
</trans-unit>
- <trans-unit id="_msg1020">
+ <trans-unit id="_msg1034">
<source xml:space="preserve">Error: Address book data in wallet cannot be identified to belong to migrated wallets</source>
- <context-group purpose="location"><context context-type="linenumber">67</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg1021">
+ <trans-unit id="_msg1035">
<source xml:space="preserve">Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source>
- <context-group purpose="location"><context context-type="linenumber">77</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg1022">
+ <trans-unit id="_msg1036">
<source xml:space="preserve">Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source>
- <context-group purpose="location"><context context-type="linenumber">83</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">92</context></context-group>
</trans-unit>
- <trans-unit id="_msg1023">
+ <trans-unit id="_msg1037">
<source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
- <context-group purpose="location"><context context-type="linenumber">89</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg1024">
+ <trans-unit id="_msg1038">
+ <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s.</source>
+ <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1039">
<source xml:space="preserve">Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source>
- <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">107</context></context-group>
</trans-unit>
- <trans-unit id="_msg1025">
+ <trans-unit id="_msg1040">
+ <source xml:space="preserve">Invalid amount for %s=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
+ <context-group purpose="location"><context context-type="linenumber">110</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1041">
<source xml:space="preserve">Outbound connections restricted to CJDNS (-onlynet=cjdns) but -cjdnsreachable is not provided</source>
- <context-group purpose="location"><context context-type="linenumber">119</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
- <trans-unit id="_msg1026">
+ <trans-unit id="_msg1042">
<source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source>
- <context-group purpose="location"><context context-type="linenumber">122</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">131</context></context-group>
</trans-unit>
- <trans-unit id="_msg1027">
+ <trans-unit id="_msg1043">
<source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source>
- <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg1028">
+ <trans-unit id="_msg1044">
<source xml:space="preserve">Outbound connections restricted to i2p (-onlynet=i2p) but -i2psam is not provided</source>
- <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
</trans-unit>
- <trans-unit id="_msg1029">
+ <trans-unit id="_msg1045">
<source xml:space="preserve">The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet&apos;s UTXOs</source>
- <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg1030">
+ <trans-unit id="_msg1046">
<source xml:space="preserve">The preselected coins total amount does not cover the transaction target. Please allow other inputs to be automatically selected or include more coins manually</source>
- <context-group purpose="location"><context context-type="linenumber">164</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg1031">
+ <trans-unit id="_msg1047">
+ <source xml:space="preserve">Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input</source>
+ <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1048">
+ <source xml:space="preserve">UTXO snapshot failed to validate. Restart to resume normal initial block download, or try loading a different snapshot.</source>
+ <context-group purpose="location"><context context-type="linenumber">200</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1049">
+ <source xml:space="preserve">Unconfirmed UTXOs are available, but spending them creates a chain of transactions that will be rejected by the mempool</source>
+ <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1050">
<source xml:space="preserve">Unexpected legacy entry in descriptor wallet found. Loading wallet %s
The wallet might have been tampered with or created with malicious intent.
</source>
- <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
</trans-unit>
- <trans-unit id="_msg1032">
+ <trans-unit id="_msg1051">
<source xml:space="preserve">Unrecognized descriptor found. Loading wallet %s
The wallet might had been created on a newer version.
Please try running the latest software version.
</source>
- <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg1033">
+ <trans-unit id="_msg1052">
<source xml:space="preserve">Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=&lt;category&gt;:&lt;loglevel&gt;. Valid categories: %s. Valid loglevels: %s.</source>
- <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg1034">
+ <trans-unit id="_msg1053">
<source xml:space="preserve">
Unable to cleanup failed migration</source>
- <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
</trans-unit>
- <trans-unit id="_msg1035">
+ <trans-unit id="_msg1054">
<source xml:space="preserve">
Unable to restore backup of wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg1036">
+ <trans-unit id="_msg1055">
+ <source xml:space="preserve">Block verification was interrupted</source>
+ <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1056">
<source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
</trans-unit>
- <trans-unit id="_msg1037">
+ <trans-unit id="_msg1057">
<source xml:space="preserve">Copyright (C) %i-%i</source>
- <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg1038">
+ <trans-unit id="_msg1058">
<source xml:space="preserve">Corrupted block database detected</source>
- <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg1039">
+ <trans-unit id="_msg1059">
<source xml:space="preserve">Could not find asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg1040">
+ <trans-unit id="_msg1060">
<source xml:space="preserve">Could not parse asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg1041">
+ <trans-unit id="_msg1061">
<source xml:space="preserve">Disk space is too low!</source>
- <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
</trans-unit>
- <trans-unit id="_msg1042">
+ <trans-unit id="_msg1062">
<source xml:space="preserve">Do you want to rebuild the block database now?</source>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
</trans-unit>
- <trans-unit id="_msg1043">
+ <trans-unit id="_msg1063">
<source xml:space="preserve">Done loading</source>
- <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg1044">
+ <trans-unit id="_msg1064">
<source xml:space="preserve">Dump file %s does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg1045">
+ <trans-unit id="_msg1065">
<source xml:space="preserve">Error creating %s</source>
- <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg1046">
+ <trans-unit id="_msg1066">
<source xml:space="preserve">Error initializing block database</source>
- <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg1047">
+ <trans-unit id="_msg1067">
<source xml:space="preserve">Error initializing wallet database environment %s!</source>
- <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
</trans-unit>
- <trans-unit id="_msg1048">
+ <trans-unit id="_msg1068">
<source xml:space="preserve">Error loading %s</source>
- <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg1049">
+ <trans-unit id="_msg1069">
<source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source>
- <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg1050">
+ <trans-unit id="_msg1070">
<source xml:space="preserve">Error loading %s: Wallet corrupted</source>
- <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg1051">
+ <trans-unit id="_msg1071">
<source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source>
- <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg1052">
+ <trans-unit id="_msg1072">
<source xml:space="preserve">Error loading block database</source>
- <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg1053">
+ <trans-unit id="_msg1073">
<source xml:space="preserve">Error opening block database</source>
- <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
</trans-unit>
- <trans-unit id="_msg1054">
+ <trans-unit id="_msg1074">
+ <source xml:space="preserve">Error reading configuration file: %s</source>
+ <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1075">
<source xml:space="preserve">Error reading from database, shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
</trans-unit>
- <trans-unit id="_msg1055">
+ <trans-unit id="_msg1076">
<source xml:space="preserve">Error reading next record from wallet database</source>
- <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg1056">
+ <trans-unit id="_msg1077">
<source xml:space="preserve">Error: Cannot extract destination from the generated scriptpubkey</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg1057">
+ <trans-unit id="_msg1078">
<source xml:space="preserve">Error: Could not add watchonly tx to watchonly wallet</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
</trans-unit>
- <trans-unit id="_msg1058">
+ <trans-unit id="_msg1079">
<source xml:space="preserve">Error: Could not delete watchonly transactions</source>
- <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg1059">
+ <trans-unit id="_msg1080">
<source xml:space="preserve">Error: Couldn&apos;t create cursor into database</source>
- <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg1060">
+ <trans-unit id="_msg1081">
<source xml:space="preserve">Error: Disk space is low for %s</source>
- <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg1061">
+ <trans-unit id="_msg1082">
<source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
- <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg1062">
+ <trans-unit id="_msg1083">
<source xml:space="preserve">Error: Failed to create new watchonly wallet</source>
- <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
</trans-unit>
- <trans-unit id="_msg1063">
+ <trans-unit id="_msg1084">
<source xml:space="preserve">Error: Got key that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
- <trans-unit id="_msg1064">
+ <trans-unit id="_msg1085">
<source xml:space="preserve">Error: Got value that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
</trans-unit>
- <trans-unit id="_msg1065">
+ <trans-unit id="_msg1086">
<source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source>
- <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg1066">
+ <trans-unit id="_msg1087">
<source xml:space="preserve">Error: Missing checksum</source>
- <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg1067">
+ <trans-unit id="_msg1088">
<source xml:space="preserve">Error: No %s addresses available.</source>
- <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
</trans-unit>
- <trans-unit id="_msg1068">
+ <trans-unit id="_msg1089">
<source xml:space="preserve">Error: Not all watchonly txs could be deleted</source>
- <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
</trans-unit>
- <trans-unit id="_msg1069">
+ <trans-unit id="_msg1090">
<source xml:space="preserve">Error: This wallet already uses SQLite</source>
- <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
</trans-unit>
- <trans-unit id="_msg1070">
+ <trans-unit id="_msg1091">
<source xml:space="preserve">Error: This wallet is already a descriptor wallet</source>
- <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg1071">
+ <trans-unit id="_msg1092">
<source xml:space="preserve">Error: Unable to begin reading all records in the database</source>
- <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">295</context></context-group>
</trans-unit>
- <trans-unit id="_msg1072">
+ <trans-unit id="_msg1093">
<source xml:space="preserve">Error: Unable to make a backup of your wallet</source>
- <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg1073">
+ <trans-unit id="_msg1094">
<source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source>
- <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">297</context></context-group>
</trans-unit>
- <trans-unit id="_msg1074">
+ <trans-unit id="_msg1095">
<source xml:space="preserve">Error: Unable to read all records in the database</source>
- <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg1075">
+ <trans-unit id="_msg1096">
<source xml:space="preserve">Error: Unable to remove watchonly address book data</source>
- <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg1076">
+ <trans-unit id="_msg1097">
<source xml:space="preserve">Error: Unable to write record to new wallet</source>
- <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">300</context></context-group>
</trans-unit>
- <trans-unit id="_msg1077">
+ <trans-unit id="_msg1098">
<source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source>
- <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
- <trans-unit id="_msg1078">
+ <trans-unit id="_msg1099">
<source xml:space="preserve">Failed to rescan the wallet during initialization</source>
- <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
</trans-unit>
- <trans-unit id="_msg1079">
+ <trans-unit id="_msg1100">
<source xml:space="preserve">Failed to verify database</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">303</context></context-group>
</trans-unit>
- <trans-unit id="_msg1080">
+ <trans-unit id="_msg1101">
<source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
- <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg1081">
+ <trans-unit id="_msg1102">
<source xml:space="preserve">Ignoring duplicate -wallet %s.</source>
- <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg1082">
+ <trans-unit id="_msg1103">
<source xml:space="preserve">Importing…</source>
- <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg1083">
+ <trans-unit id="_msg1104">
<source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source>
- <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg1084">
+ <trans-unit id="_msg1105">
<source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg1085">
+ <trans-unit id="_msg1106">
<source xml:space="preserve">Input not found or already spent</source>
- <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg1086">
+ <trans-unit id="_msg1107">
<source xml:space="preserve">Insufficient dbcache for block verification</source>
- <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
- <trans-unit id="_msg1087">
+ <trans-unit id="_msg1108">
<source xml:space="preserve">Insufficient funds</source>
- <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg1088">
+ <trans-unit id="_msg1109">
<source xml:space="preserve">Invalid -i2psam address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg1089">
+ <trans-unit id="_msg1110">
<source xml:space="preserve">Invalid -onion address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
</trans-unit>
- <trans-unit id="_msg1090">
+ <trans-unit id="_msg1111">
<source xml:space="preserve">Invalid -proxy address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg1091">
+ <trans-unit id="_msg1112">
<source xml:space="preserve">Invalid P2P permission: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">295</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1092">
- <source xml:space="preserve">Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg1093">
- <source xml:space="preserve">Invalid amount for -discardfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">297</context></context-group>
+ <trans-unit id="_msg1113">
+ <source xml:space="preserve">Invalid amount for %s=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
+ <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
</trans-unit>
- <trans-unit id="_msg1094">
- <source xml:space="preserve">Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
+ <trans-unit id="_msg1114">
+ <source xml:space="preserve">Invalid amount for %s=&lt;amount&gt;: &apos;%s&apos;</source>
+ <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
- <trans-unit id="_msg1095">
- <source xml:space="preserve">Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
- <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
+ <trans-unit id="_msg1115">
+ <source xml:space="preserve">Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
+ <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg1096">
+ <trans-unit id="_msg1116">
<source xml:space="preserve">Invalid netmask specified in -whitelist: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">300</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg1097">
+ <trans-unit id="_msg1117">
<source xml:space="preserve">Invalid port specified in %s: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
- <trans-unit id="_msg1098">
+ <trans-unit id="_msg1118">
<source xml:space="preserve">Invalid pre-selected input %s</source>
- <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg1099">
+ <trans-unit id="_msg1119">
<source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">303</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
</trans-unit>
- <trans-unit id="_msg1100">
+ <trans-unit id="_msg1120">
<source xml:space="preserve">Loading P2P addresses…</source>
- <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg1101">
+ <trans-unit id="_msg1121">
<source xml:space="preserve">Loading banlist…</source>
- <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg1102">
+ <trans-unit id="_msg1122">
<source xml:space="preserve">Loading block index…</source>
- <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg1103">
+ <trans-unit id="_msg1123">
<source xml:space="preserve">Loading wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg1104">
+ <trans-unit id="_msg1124">
<source xml:space="preserve">Missing amount</source>
- <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg1105">
+ <trans-unit id="_msg1125">
<source xml:space="preserve">Missing solving data for estimating transaction size</source>
- <context-group purpose="location"><context context-type="linenumber">309</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg1106">
+ <trans-unit id="_msg1126">
<source xml:space="preserve">Need to specify a port with -whitebind: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
</trans-unit>
- <trans-unit id="_msg1107">
+ <trans-unit id="_msg1127">
<source xml:space="preserve">No addresses available</source>
- <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
</trans-unit>
- <trans-unit id="_msg1108">
+ <trans-unit id="_msg1128">
<source xml:space="preserve">Not enough file descriptors available.</source>
- <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg1109">
+ <trans-unit id="_msg1129">
<source xml:space="preserve">Not found pre-selected input %s</source>
- <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg1110">
+ <trans-unit id="_msg1130">
<source xml:space="preserve">Not solvable pre-selected input %s</source>
- <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg1111">
+ <trans-unit id="_msg1131">
<source xml:space="preserve">Prune cannot be configured with a negative value.</source>
- <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg1112">
+ <trans-unit id="_msg1132">
<source xml:space="preserve">Prune mode is incompatible with -txindex.</source>
- <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg1113">
+ <trans-unit id="_msg1133">
<source xml:space="preserve">Pruning blockstore…</source>
- <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg1114">
+ <trans-unit id="_msg1134">
<source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source>
- <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
</trans-unit>
- <trans-unit id="_msg1115">
+ <trans-unit id="_msg1135">
<source xml:space="preserve">Replaying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg1116">
+ <trans-unit id="_msg1136">
<source xml:space="preserve">Rescanning…</source>
- <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg1117">
+ <trans-unit id="_msg1137">
<source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">340</context></context-group>
</trans-unit>
- <trans-unit id="_msg1118">
+ <trans-unit id="_msg1138">
<source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">341</context></context-group>
</trans-unit>
- <trans-unit id="_msg1119">
+ <trans-unit id="_msg1139">
<source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source>
- <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg1120">
+ <trans-unit id="_msg1140">
<source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
- <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">343</context></context-group>
</trans-unit>
- <trans-unit id="_msg1121">
+ <trans-unit id="_msg1141">
<source xml:space="preserve">Section [%s] is not recognized.</source>
- <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg1122">
+ <trans-unit id="_msg1142">
<source xml:space="preserve">Signing transaction failed</source>
- <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">347</context></context-group>
</trans-unit>
- <trans-unit id="_msg1123">
+ <trans-unit id="_msg1143">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
</trans-unit>
- <trans-unit id="_msg1124">
+ <trans-unit id="_msg1144">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is a relative path</source>
- <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">349</context></context-group>
</trans-unit>
- <trans-unit id="_msg1125">
+ <trans-unit id="_msg1145">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is not a directory</source>
- <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
</trans-unit>
- <trans-unit id="_msg1126">
+ <trans-unit id="_msg1146">
<source xml:space="preserve">Specified blocks directory &quot;%s&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg1127">
+ <trans-unit id="_msg1147">
+ <source xml:space="preserve">Specified data directory &quot;%s&quot; does not exist.</source>
+ <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1148">
<source xml:space="preserve">Starting network threads…</source>
- <context-group purpose="location"><context context-type="linenumber">331</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">353</context></context-group>
</trans-unit>
- <trans-unit id="_msg1128">
+ <trans-unit id="_msg1149">
<source xml:space="preserve">The source code is available from %s.</source>
- <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg1129">
+ <trans-unit id="_msg1150">
<source xml:space="preserve">The specified config file %s does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">355</context></context-group>
</trans-unit>
- <trans-unit id="_msg1130">
+ <trans-unit id="_msg1151">
<source xml:space="preserve">The transaction amount is too small to pay the fee</source>
- <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
</trans-unit>
- <trans-unit id="_msg1131">
+ <trans-unit id="_msg1152">
<source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source>
- <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">357</context></context-group>
</trans-unit>
- <trans-unit id="_msg1132">
+ <trans-unit id="_msg1153">
<source xml:space="preserve">This is experimental software.</source>
- <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">358</context></context-group>
</trans-unit>
- <trans-unit id="_msg1133">
+ <trans-unit id="_msg1154">
<source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg1134">
+ <trans-unit id="_msg1155">
<source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">360</context></context-group>
</trans-unit>
- <trans-unit id="_msg1135">
+ <trans-unit id="_msg1156">
<source xml:space="preserve">Transaction amount too small</source>
- <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">361</context></context-group>
</trans-unit>
- <trans-unit id="_msg1136">
+ <trans-unit id="_msg1157">
<source xml:space="preserve">Transaction amounts must not be negative</source>
- <context-group purpose="location"><context context-type="linenumber">340</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">362</context></context-group>
</trans-unit>
- <trans-unit id="_msg1137">
+ <trans-unit id="_msg1158">
<source xml:space="preserve">Transaction change output index out of range</source>
- <context-group purpose="location"><context context-type="linenumber">341</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">363</context></context-group>
</trans-unit>
- <trans-unit id="_msg1138">
+ <trans-unit id="_msg1159">
<source xml:space="preserve">Transaction has too long of a mempool chain</source>
- <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">364</context></context-group>
</trans-unit>
- <trans-unit id="_msg1139">
+ <trans-unit id="_msg1160">
<source xml:space="preserve">Transaction must have at least one recipient</source>
- <context-group purpose="location"><context context-type="linenumber">343</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">365</context></context-group>
</trans-unit>
- <trans-unit id="_msg1140">
+ <trans-unit id="_msg1161">
<source xml:space="preserve">Transaction needs a change address, but we can&apos;t generate it.</source>
- <context-group purpose="location"><context context-type="linenumber">344</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">366</context></context-group>
</trans-unit>
- <trans-unit id="_msg1141">
+ <trans-unit id="_msg1162">
<source xml:space="preserve">Transaction too large</source>
- <context-group purpose="location"><context context-type="linenumber">345</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">367</context></context-group>
</trans-unit>
- <trans-unit id="_msg1142">
+ <trans-unit id="_msg1163">
<source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: &apos;%s&apos; MiB</source>
- <context-group purpose="location"><context context-type="linenumber">346</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">368</context></context-group>
</trans-unit>
- <trans-unit id="_msg1143">
+ <trans-unit id="_msg1164">
<source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">347</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">369</context></context-group>
</trans-unit>
- <trans-unit id="_msg1144">
+ <trans-unit id="_msg1165">
<source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">370</context></context-group>
</trans-unit>
- <trans-unit id="_msg1145">
+ <trans-unit id="_msg1166">
<source xml:space="preserve">Unable to create the PID file &apos;%s&apos;: %s</source>
- <context-group purpose="location"><context context-type="linenumber">349</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">371</context></context-group>
</trans-unit>
- <trans-unit id="_msg1146">
+ <trans-unit id="_msg1167">
<source xml:space="preserve">Unable to find UTXO for external input</source>
- <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">372</context></context-group>
</trans-unit>
- <trans-unit id="_msg1147">
+ <trans-unit id="_msg1168">
<source xml:space="preserve">Unable to generate initial keys</source>
- <context-group purpose="location"><context context-type="linenumber">351</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">373</context></context-group>
</trans-unit>
- <trans-unit id="_msg1148">
+ <trans-unit id="_msg1169">
<source xml:space="preserve">Unable to generate keys</source>
- <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg1149">
+ <trans-unit id="_msg1170">
<source xml:space="preserve">Unable to open %s for writing</source>
- <context-group purpose="location"><context context-type="linenumber">353</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg1150">
+ <trans-unit id="_msg1171">
<source xml:space="preserve">Unable to parse -maxuploadtarget: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">354</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg1151">
+ <trans-unit id="_msg1172">
<source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source>
- <context-group purpose="location"><context context-type="linenumber">355</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">377</context></context-group>
</trans-unit>
- <trans-unit id="_msg1152">
+ <trans-unit id="_msg1173">
<source xml:space="preserve">Unable to unload the wallet before migrating</source>
- <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg1153">
+ <trans-unit id="_msg1174">
<source xml:space="preserve">Unknown -blockfilterindex value %s.</source>
- <context-group purpose="location"><context context-type="linenumber">357</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg1154">
+ <trans-unit id="_msg1175">
<source xml:space="preserve">Unknown address type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">358</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg1155">
+ <trans-unit id="_msg1176">
<source xml:space="preserve">Unknown change type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">359</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">381</context></context-group>
</trans-unit>
- <trans-unit id="_msg1156">
+ <trans-unit id="_msg1177">
<source xml:space="preserve">Unknown network specified in -onlynet: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">360</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg1157">
+ <trans-unit id="_msg1178">
<source xml:space="preserve">Unknown new rules activated (versionbit %i)</source>
- <context-group purpose="location"><context context-type="linenumber">361</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">383</context></context-group>
</trans-unit>
- <trans-unit id="_msg1158">
+ <trans-unit id="_msg1179">
<source xml:space="preserve">Unsupported global logging level -loglevel=%s. Valid values: %s.</source>
- <context-group purpose="location"><context context-type="linenumber">362</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">384</context></context-group>
</trans-unit>
- <trans-unit id="_msg1159">
+ <trans-unit id="_msg1180">
<source xml:space="preserve">Unsupported logging category %s=%s.</source>
- <context-group purpose="location"><context context-type="linenumber">363</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">385</context></context-group>
</trans-unit>
- <trans-unit id="_msg1160">
+ <trans-unit id="_msg1181">
<source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source>
- <context-group purpose="location"><context context-type="linenumber">364</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg1161">
+ <trans-unit id="_msg1182">
<source xml:space="preserve">Verifying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">365</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">387</context></context-group>
</trans-unit>
- <trans-unit id="_msg1162">
+ <trans-unit id="_msg1183">
<source xml:space="preserve">Verifying wallet(s)…</source>
- <context-group purpose="location"><context context-type="linenumber">366</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">388</context></context-group>
</trans-unit>
- <trans-unit id="_msg1163">
+ <trans-unit id="_msg1184">
<source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source>
- <context-group purpose="location"><context context-type="linenumber">367</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">389</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1185">
+ <source xml:space="preserve">Settings file could not be read</source>
+ <context-group purpose="location"><context context-type="linenumber">345</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1186">
+ <source xml:space="preserve">Settings file could not be written</source>
+ <context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
</group>
</body></file>
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index b789e6a958..b6314f5533 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -6,21 +6,21 @@
#include <qt/guiconstants.h>
-#include <chainparamsbase.h>
#include <tinyformat.h>
+#include <util/chaintype.h>
#include <QApplication>
static const struct {
- const char *networkId;
+ const ChainType networkId;
const char *appName;
const int iconColorHueShift;
const int iconColorSaturationReduction;
} network_styles[] = {
- {"main", QAPP_APP_NAME_DEFAULT, 0, 0},
- {"test", QAPP_APP_NAME_TESTNET, 70, 30},
- {"signet", QAPP_APP_NAME_SIGNET, 35, 15},
- {"regtest", QAPP_APP_NAME_REGTEST, 160, 30},
+ {ChainType::MAIN, QAPP_APP_NAME_DEFAULT, 0, 0},
+ {ChainType::TESTNET, QAPP_APP_NAME_TESTNET, 70, 30},
+ {ChainType::SIGNET, QAPP_APP_NAME_SIGNET, 35, 15},
+ {ChainType::REGTEST, QAPP_APP_NAME_REGTEST, 160, 30},
};
// titleAddText needs to be const char* for tr()
@@ -77,9 +77,9 @@ NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift,
trayAndWindowIcon = QIcon(pixmap.scaled(QSize(256,256)));
}
-const NetworkStyle* NetworkStyle::instantiate(const std::string& networkId)
+const NetworkStyle* NetworkStyle::instantiate(const ChainType networkId)
{
- std::string titleAddText = networkId == CBaseChainParams::MAIN ? "" : strprintf("[%s]", networkId);
+ std::string titleAddText = networkId == ChainType::MAIN ? "" : strprintf("[%s]", ChainTypeToString(networkId));
for (const auto& network_style : network_styles) {
if (networkId == network_style.networkId) {
return new NetworkStyle(
diff --git a/src/qt/networkstyle.h b/src/qt/networkstyle.h
index a73e3e2625..dd2aee3eb3 100644
--- a/src/qt/networkstyle.h
+++ b/src/qt/networkstyle.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_QT_NETWORKSTYLE_H
#define BITCOIN_QT_NETWORKSTYLE_H
+#include <util/chaintype.h>
+
#include <QIcon>
#include <QPixmap>
#include <QString>
@@ -14,7 +16,7 @@ class NetworkStyle
{
public:
/** Get style associated with provided network id, or 0 if not known */
- static const NetworkStyle* instantiate(const std::string& networkId);
+ static const NetworkStyle* instantiate(const ChainType networkId);
const QString &getAppName() const { return appName; }
const QIcon &getAppIcon() const { return appIcon; }
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 6dec4b2e42..512fce473d 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -15,11 +15,11 @@
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
+#include <common/system.h>
#include <interfaces/node.h>
-#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
#include <netbase.h>
-#include <txdb.h> // for -dbcache defaults
-#include <util/system.h>
+#include <txdb.h>
+#include <validation.h>
#include <chrono>
@@ -406,9 +406,8 @@ void OptionsDialog::updateProxyValidationState()
void OptionsDialog::updateDefaultProxyNets()
{
- CNetAddr ui_proxy_netaddr;
- LookupHost(ui->proxyIp->text().toStdString(), ui_proxy_netaddr, /*fAllowLookup=*/false);
- const CService ui_proxy{ui_proxy_netaddr, ui->proxyPort->text().toUShort()};
+ const std::optional<CNetAddr> ui_proxy_netaddr{LookupHost(ui->proxyIp->text().toStdString(), /*fAllowLookup=*/false)};
+ const CService ui_proxy{ui_proxy_netaddr.value_or(CNetAddr{}), ui->proxyPort->text().toUShort()};
Proxy proxy;
bool has_proxy;
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index bee8fafddc..c1563fe1e2 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -12,14 +12,14 @@
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <mapport.h>
#include <net.h>
#include <netbase.h>
-#include <txdb.h> // for -dbcache defaults
+#include <txdb.h> // for -dbcache defaults
#include <util/string.h>
-#include <util/system.h>
-#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
+#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
#include <wallet/wallet.h> // For DEFAULT_SPEND_ZEROCONF_CHANGE
#include <QDebug>
@@ -60,7 +60,7 @@ static const char* SettingName(OptionsModel::OptionID option)
}
/** Call node.updateRwSetting() with Bitcoin 22.x workaround. */
-static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID option, const std::string& suffix, const util::SettingsValue& value)
+static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID option, const std::string& suffix, const common::SettingsValue& value)
{
if (value.isNum() &&
(option == OptionsModel::DatabaseCache ||
@@ -81,14 +81,14 @@ static void UpdateRwSetting(interfaces::Node& node, OptionsModel::OptionID optio
}
//! Convert enabled/size values to bitcoin -prune setting.
-static util::SettingsValue PruneSetting(bool prune_enabled, int prune_size_gb)
+static common::SettingsValue PruneSetting(bool prune_enabled, int prune_size_gb)
{
assert(!prune_enabled || prune_size_gb >= 1); // PruneSizeGB and ParsePruneSizeGB never return less
return prune_enabled ? PruneGBtoMiB(prune_size_gb) : 0;
}
//! Get pruning enabled value to show in GUI from bitcoin -prune setting.
-static bool PruneEnabled(const util::SettingsValue& prune_setting)
+static bool PruneEnabled(const common::SettingsValue& prune_setting)
{
// -prune=1 setting is manual pruning mode, so disabled for purposes of the gui
return SettingToInt(prune_setting, 0) > 1;
@@ -96,7 +96,7 @@ static bool PruneEnabled(const util::SettingsValue& prune_setting)
//! Get pruning size value to show in GUI from bitcoin -prune setting. If
//! pruning is not enabled, just show default recommended pruning size (2GB).
-static int PruneSizeGB(const util::SettingsValue& prune_setting)
+static int PruneSizeGB(const common::SettingsValue& prune_setting)
{
int value = SettingToInt(prune_setting, 0);
return value > 1 ? PruneMiBtoGB(value) : DEFAULT_PRUNE_TARGET_GB;
@@ -311,8 +311,8 @@ static QString GetDefaultProxyAddress()
void OptionsModel::SetPruneTargetGB(int prune_target_gb)
{
- const util::SettingsValue cur_value = node().getPersistentSetting("prune");
- const util::SettingsValue new_value = PruneSetting(prune_target_gb > 0, prune_target_gb);
+ const common::SettingsValue cur_value = node().getPersistentSetting("prune");
+ const common::SettingsValue new_value = PruneSetting(prune_target_gb > 0, prune_target_gb);
// Force setting to take effect. It is still safe to change the value at
// this point because this function is only called after the intro screen is
@@ -331,7 +331,7 @@ void OptionsModel::SetPruneTargetGB(int prune_target_gb)
// Keep previous pruning size, if pruning was disabled.
if (PruneEnabled(cur_value)) {
- UpdateRwSetting(node(), Prune, "-prev", PruneEnabled(new_value) ? util::SettingsValue{} : cur_value);
+ UpdateRwSetting(node(), Prune, "-prev", PruneEnabled(new_value) ? common::SettingsValue{} : cur_value);
}
}
@@ -457,7 +457,7 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con
bool OptionsModel::setOption(OptionID option, const QVariant& value, const std::string& suffix)
{
auto changed = [&] { return value.isValid() && value != getOption(option, suffix); };
- auto update = [&](const util::SettingsValue& value) { return UpdateRwSetting(node(), option, suffix, value); };
+ auto update = [&](const common::SettingsValue& value) { return UpdateRwSetting(node(), option, suffix, value); };
bool successful = true; /* set to false on parse error */
QSettings settings;
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 3f9d1b040b..592e591edb 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -13,11 +13,11 @@
#include <qt/optionsmodel.h>
#include <chainparams.h>
+#include <common/args.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <node/interface_ui.h>
#include <policy/policy.h>
-#include <util/system.h>
#include <wallet/wallet.h>
#include <cstdlib>
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 17a65be0fe..fe52e11157 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -5,7 +5,6 @@
#include <qt/psbtoperationsdialog.h>
#include <core_io.h>
-#include <fs.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <node/psbt.h>
@@ -14,6 +13,7 @@
#include <qt/forms/ui_psbtoperationsdialog.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
+#include <util/fs.h>
#include <util/strencodings.h>
#include <fstream>
@@ -31,7 +31,6 @@ PSBTOperationsDialog::PSBTOperationsDialog(
m_client_model(client_model)
{
m_ui->setupUi(this);
- setWindowTitle("PSBT Operations");
connect(m_ui->signTransactionButton, &QPushButton::clicked, this, &PSBTOperationsDialog::signTransaction);
connect(m_ui->broadcastTransactionButton, &QPushButton::clicked, this, &PSBTOperationsDialog::broadcastTransaction);
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 22eb642ecd..be7741e8a8 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -93,11 +93,11 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
ui->addressType->setItemData(index, tooltip, Qt::ToolTipRole);
if (model->wallet().getDefaultAddressType() == type) ui->addressType->setCurrentIndex(index);
};
- add_address_type(OutputType::LEGACY, "Base58 (Legacy)", "Not recommended due to higher fees and less protection against typos.");
- add_address_type(OutputType::P2SH_SEGWIT, "Base58 (P2SH-SegWit)", "Generates an address compatible with older wallets.");
- add_address_type(OutputType::BECH32, "Bech32 (SegWit)", "Generates a native segwit address (BIP-173). Some old wallets don't support it.");
+ add_address_type(OutputType::LEGACY, tr("Base58 (Legacy)"), tr("Not recommended due to higher fees and less protection against typos."));
+ add_address_type(OutputType::P2SH_SEGWIT, tr("Base58 (P2SH-SegWit)"), tr("Generates an address compatible with older wallets."));
+ add_address_type(OutputType::BECH32, tr("Bech32 (SegWit)"), tr("Generates a native segwit address (BIP-173). Some old wallets don't support it."));
if (model->wallet().taprootEnabled()) {
- add_address_type(OutputType::BECH32M, "Bech32m (Taproot)", "Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited.");
+ add_address_type(OutputType::BECH32M, tr("Bech32m (Taproot)"), tr("Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited."));
}
// Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 0e712062af..90aae0219e 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -10,6 +10,7 @@
#include <qt/forms/ui_debugwindow.h>
#include <chainparams.h>
+#include <common/system.h>
#include <interfaces/node.h>
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
@@ -21,7 +22,6 @@
#include <rpc/server.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/threadnames.h>
#include <univalue.h>
@@ -249,7 +249,7 @@ bool RPCConsole::RPCParseCommandLine(interfaces::Node* node, std::string &strRes
subelement = lastResult[parsed.value()];
}
else if (lastResult.isObject())
- subelement = find_value(lastResult, curarg);
+ subelement = lastResult.find_value(curarg);
else
throw std::runtime_error("Invalid result query"); //no array or object: abort
lastResult = subelement;
@@ -448,8 +448,8 @@ void RPCExecutor::request(const QString &command, const WalletModel* wallet_mode
{
try // Nice formatting for standard-format error
{
- int code = find_value(objError, "code").getInt<int>();
- std::string message = find_value(objError, "message").get_str();
+ int code = objError.find_value("code").getInt<int>();
+ std::string message = objError.find_value("message").get_str();
Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
}
catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
@@ -744,7 +744,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
ui->dataDir->setText(model->dataDir());
ui->blocksDir->setText(model->blocksDir());
ui->startupTime->setText(model->formatClientStartupTime());
- ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
+ ui->networkName->setText(QString::fromStdString(Params().GetChainTypeString()));
//Setup autocomplete and attach it
QStringList wordList;
@@ -984,10 +984,11 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage)
{
ui->mempoolNumberTxs->setText(QString::number(numberOfTxs));
- if (dynUsage < 1000000)
- ui->mempoolSize->setText(QString::number(dynUsage/1000.0, 'f', 2) + " KB");
- else
- ui->mempoolSize->setText(QString::number(dynUsage/1000000.0, 'f', 2) + " MB");
+ if (dynUsage < 1000000) {
+ ui->mempoolSize->setText(QObject::tr("%1 kB").arg(dynUsage / 1000.0, 0, 'f', 2));
+ } else {
+ ui->mempoolSize->setText(QObject::tr("%1 MB").arg(dynUsage / 1000000.0, 0, 'f', 2));
+ }
}
void RPCConsole::on_lineEdit_returnPressed()
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 89dd0ada62..48f7fb6ad1 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -355,7 +355,8 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa
question_string.append("</b>");
// append transaction size
- question_string.append(" (" + QString::number((double)m_current_transaction->getTransactionSize() / 1000) + " kB): ");
+ //: When reviewing a newly created PSBT (via Send flow), the transaction fee is shown, with "virtual size" of the transaction displayed for context
+ question_string.append(" (" + tr("%1 kvB", "PSBT transaction creation").arg((double)m_current_transaction->getTransactionSize() / 1000, 0, 'g', 3) + "): ");
// append transaction fee value
question_string.append("<span style='color:#aa0000; font-weight:bold;'>");
@@ -402,9 +403,10 @@ void SendCoinsDialog::presentPSBT(PartiallySignedTransaction& psbtx)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
- QMessageBox msgBox;
- msgBox.setText("Unsigned Transaction");
- msgBox.setInformativeText("The PSBT has been copied to the clipboard. You can also save it.");
+ QMessageBox msgBox(this);
+ //: Caption of "PSBT has been copied" messagebox
+ msgBox.setText(tr("Unsigned Transaction", "PSBT copied"));
+ msgBox.setInformativeText(tr("The PSBT has been copied to the clipboard. You can also save it."));
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard);
msgBox.setDefaultButton(QMessageBox::Discard);
switch (msgBox.exec()) {
@@ -432,7 +434,8 @@ void SendCoinsDialog::presentPSBT(PartiallySignedTransaction& psbtx)
std::ofstream out{filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary};
out << ssTx.str();
out.close();
- Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION);
+ //: Popup message when a PSBT has been saved to a file
+ Q_EMIT message(tr("PSBT saved"), tr("PSBT saved to disk"), CClientUIInterface::MSG_INFORMATION);
break;
}
case QMessageBox::Discard:
@@ -452,12 +455,14 @@ bool SendCoinsDialog::signWithExternalSigner(PartiallySignedTransaction& psbtx,
}
if (err == TransactionError::EXTERNAL_SIGNER_NOT_FOUND) {
//: "External signer" means using devices such as hardware wallets.
- QMessageBox::critical(nullptr, tr("External signer not found"), "External signer not found");
+ const QString msg = tr("External signer not found");
+ QMessageBox::critical(nullptr, msg, msg);
return false;
}
if (err == TransactionError::EXTERNAL_SIGNER_FAILED) {
//: "External signer" means using devices such as hardware wallets.
- QMessageBox::critical(nullptr, tr("External signer failure"), "External signer failure");
+ const QString msg = tr("External signer failure");
+ QMessageBox::critical(nullptr, msg, msg);
return false;
}
if (err != TransactionError::OK) {
@@ -596,10 +601,15 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
entry->clear();
entry->setFocus();
ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
- qApp->processEvents();
- QScrollBar* bar = ui->scrollArea->verticalScrollBar();
- if(bar)
- bar->setSliderPosition(bar->maximum());
+
+ // Scroll to the newly added entry on a QueuedConnection because Qt doesn't
+ // adjust the scroll area and scrollbar immediately when the widget is added.
+ // Invoking on a DirectConnection will only scroll to the second-to-last entry.
+ QMetaObject::invokeMethod(ui->scrollArea, [this] {
+ if (ui->scrollArea->verticalScrollBar()) {
+ ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->maximum());
+ }
+ }, Qt::QueuedConnection);
updateTabsAndLabels();
return entry;
@@ -781,8 +791,13 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
// Include watch-only for wallets without private key
m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner();
+ // Same behavior as send: if we have selected coins, only obtain their available balance.
+ // Copy to avoid modifying the member's data.
+ CCoinControl coin_control = *m_coin_control;
+ coin_control.m_allow_other_inputs = !coin_control.HasSelected();
+
// Calculate available amount to send.
- CAmount amount = model->getAvailableBalance(m_coin_control.get());
+ CAmount amount = model->getAvailableBalance(&coin_control);
for (int i = 0; i < ui->entries->count(); ++i) {
SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if (e && !e->isHidden() && e != entry) {
@@ -818,7 +833,7 @@ void SendCoinsDialog::updateFeeMinimizedLabel()
if (ui->radioSmartFee->isChecked())
ui->labelFeeMinimized->setText(ui->labelSmartFee->text());
else {
- ui->labelFeeMinimized->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value()) + "/kvB");
+ ui->labelFeeMinimized->setText(tr("%1/kvB").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), ui->customFee->value())));
}
}
@@ -853,7 +868,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
FeeReason reason;
CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, *m_coin_control, &returned_target, &reason));
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kvB");
+ ui->labelSmartFee->setText(tr("%1/kvB").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK())));
if (reason == FeeReason::FALLBACK) {
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 2fcdf5b32a..ac05cd98e5 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -49,6 +49,9 @@ public:
void pasteEntry(const SendCoinsRecipient &rv);
bool handlePaymentRequest(const SendCoinsRecipient &recipient);
+ // Only used for testing-purposes
+ wallet::CCoinControl* getCoinControl() { return m_coin_control.get(); }
+
public Q_SLOTS:
void clear();
void reject() override;
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 096f8a0ded..8872f8be32 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -9,13 +9,13 @@
#include <qt/splashscreen.h>
#include <clientversion.h>
+#include <common/system.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
#include <qt/guiutil.h>
#include <qt/networkstyle.h>
#include <qt/walletmodel.h>
-#include <util/system.h>
#include <util/translation.h>
#include <functional>
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index d005e08d14..f17a6b7f74 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -19,6 +19,7 @@
#include <key.h>
#include <key_io.h>
#include <wallet/wallet.h>
+#include <wallet/test/util.h>
#include <walletinitinterface.h>
#include <chrono>
@@ -31,7 +32,7 @@
using wallet::AddWallet;
using wallet::CWallet;
-using wallet::CreateMockWalletDatabase;
+using wallet::CreateMockableWalletDatabase;
using wallet::RemoveWallet;
using wallet::WALLET_FLAG_DESCRIPTORS;
using wallet::WalletContext;
@@ -75,7 +76,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
test.m_node.wallet_loader = wallet_loader.get();
node.setContext(&test.m_node);
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
wallet->LoadWallet();
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
{
@@ -113,8 +114,8 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
{
LOCK(wallet->cs_wallet);
- wallet->SetAddressBook(r_key_dest, r_label.toStdString(), "receive");
- wallet->SetAddressBook(s_key_dest, s_label.toStdString(), "send");
+ wallet->SetAddressBook(r_key_dest, r_label.toStdString(), wallet::AddressPurpose::RECEIVE);
+ wallet->SetAddressBook(s_key_dest, s_label.toStdString(), wallet::AddressPurpose::SEND);
}
auto check_addbook_size = [&wallet](int expected_size) {
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
index 000bbe65be..e918e84184 100644
--- a/src/qt/test/apptests.cpp
+++ b/src/qt/test/apptests.cpp
@@ -73,7 +73,7 @@ void AppTests::appTests()
qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
m_app.parameterSetup();
QVERIFY(m_app.createOptionsModel(/*resetSettings=*/true));
- QScopedPointer<const NetworkStyle> style(NetworkStyle::instantiate(Params().NetworkIDString()));
+ QScopedPointer<const NetworkStyle> style(NetworkStyle::instantiate(Params().GetChainType()));
m_app.setupPlatformStyle();
m_app.createWindow(style.data());
connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests);
diff --git a/src/qt/test/optiontests.cpp b/src/qt/test/optiontests.cpp
index dc7c8928c5..e5a5179d87 100644
--- a/src/qt/test/optiontests.cpp
+++ b/src/qt/test/optiontests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <init.h>
#include <qt/bitcoin.h>
#include <qt/guiutil.h>
#include <qt/test/optiontests.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <QSettings>
#include <QTest>
@@ -18,13 +18,13 @@
OptionTests::OptionTests(interfaces::Node& node) : m_node(node)
{
- gArgs.LockSettings([&](util::Settings& s) { m_previous_settings = s; });
+ gArgs.LockSettings([&](common::Settings& s) { m_previous_settings = s; });
}
void OptionTests::init()
{
// reset args
- gArgs.LockSettings([&](util::Settings& s) { s = m_previous_settings; });
+ gArgs.LockSettings([&](common::Settings& s) { s = m_previous_settings; });
gArgs.ClearPathCache();
}
@@ -76,14 +76,14 @@ void OptionTests::integerGetArgBug()
// Test regression https://github.com/bitcoin/bitcoin/issues/24457. Ensure
// that setting integer prune value doesn't cause an exception to be thrown
// in the OptionsModel constructor
- gArgs.LockSettings([&](util::Settings& settings) {
+ gArgs.LockSettings([&](common::Settings& settings) {
settings.forced_settings.erase("prune");
settings.rw_settings["prune"] = 3814;
});
gArgs.WriteSettingsFile();
bilingual_str error;
QVERIFY(OptionsModel{m_node}.Init(error));
- gArgs.LockSettings([&](util::Settings& settings) {
+ gArgs.LockSettings([&](common::Settings& settings) {
settings.rw_settings.erase("prune");
});
gArgs.WriteSettingsFile();
@@ -95,7 +95,7 @@ void OptionTests::parametersInteraction()
// It was fixed via https://github.com/bitcoin-core/gui/pull/568.
// With fListen=false in ~/.config/Bitcoin/Bitcoin-Qt.conf and all else left as default,
// bitcoin-qt should set both -listen and -listenonion to false and start successfully.
- gArgs.LockSettings([&](util::Settings& s) {
+ gArgs.LockSettings([&](common::Settings& s) {
s.forced_settings.erase("listen");
s.forced_settings.erase("listenonion");
});
diff --git a/src/qt/test/optiontests.h b/src/qt/test/optiontests.h
index 0c458c97a6..2d7b94933f 100644
--- a/src/qt/test/optiontests.h
+++ b/src/qt/test/optiontests.h
@@ -5,9 +5,9 @@
#ifndef BITCOIN_QT_TEST_OPTIONTESTS_H
#define BITCOIN_QT_TEST_OPTIONTESTS_H
+#include <common/settings.h>
#include <qt/optionsmodel.h>
#include <univalue.h>
-#include <util/settings.h>
#include <QObject>
@@ -26,7 +26,7 @@ private Q_SLOTS:
private:
interfaces::Node& m_node;
- util::Settings m_previous_settings;
+ common::Settings m_previous_settings;
};
#endif // BITCOIN_QT_TEST_OPTIONTESTS_H
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index 669a05fe0f..72e8055425 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -4,12 +4,12 @@
#include <qt/test/rpcnestedtests.h>
+#include <common/system.h>
#include <interfaces/node.h>
-#include <rpc/server.h>
#include <qt/rpcconsole.h>
+#include <rpc/server.h>
#include <test/util/setup_common.h>
#include <univalue.h>
-#include <util/system.h>
#include <QTest>
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 2d069f76a0..e45fc1ced8 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -14,6 +14,7 @@
#include <qt/test/rpcnestedtests.h>
#include <qt/test/uritests.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#ifdef ENABLE_WALLET
#include <qt/test/addressbooktests.h>
@@ -57,7 +58,7 @@ int main(int argc, char* argv[])
//
// All tests must use their own testing setup (if needed).
fs::create_directories([] {
- BasicTestingSetup dummy{CBaseChainParams::REGTEST};
+ BasicTestingSetup dummy{ChainType::REGTEST};
return gArgs.GetDataDirNet() / "blocks";
}());
@@ -70,6 +71,9 @@ int main(int argc, char* argv[])
gArgs.ForceSetArg("-upnp", "0");
gArgs.ForceSetArg("-natpmp", "0");
+ std::string error;
+ if (!gArgs.ReadConfigFiles(error, true)) QWARN(error.c_str());
+
// Prefer the "minimal" platform for the test instead of the normal default
// platform ("xcb", "windows", or "cocoa") so tests can't unintentionally
// interfere with any background GUIs and don't require extra resources.
diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp
index c5ed20d967..d91b90fbba 100644
--- a/src/qt/test/util.cpp
+++ b/src/qt/test/util.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 <qt/test/util.h>
+
#include <chrono>
#include <QApplication>
diff --git a/src/qt/test/util.h b/src/qt/test/util.h
index 13170c89ea..a1788ca74e 100644
--- a/src/qt/test/util.h
+++ b/src/qt/test/util.h
@@ -7,6 +7,8 @@
#include <chrono>
+#include <qglobal.h>
+
QT_BEGIN_NAMESPACE
class QString;
QT_END_NAMESPACE
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 62f2019438..5f789e400e 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -5,6 +5,7 @@
#include <qt/test/wallettests.h>
#include <qt/test/util.h>
+#include <wallet/coincontrol.h>
#include <interfaces/chain.h>
#include <interfaces/node.h>
#include <key_io.h>
@@ -25,6 +26,7 @@
#include <qt/walletmodel.h>
#include <test/util/setup_common.h>
#include <validation.h>
+#include <wallet/test/util.h>
#include <wallet/wallet.h>
#include <chrono>
@@ -34,6 +36,8 @@
#include <QAction>
#include <QApplication>
#include <QCheckBox>
+#include <QClipboard>
+#include <QObject>
#include <QPushButton>
#include <QTimer>
#include <QVBoxLayout>
@@ -43,9 +47,10 @@
using wallet::AddWallet;
using wallet::CWallet;
-using wallet::CreateMockWalletDatabase;
+using wallet::CreateMockableWalletDatabase;
using wallet::RemoveWallet;
using wallet::WALLET_FLAG_DESCRIPTORS;
+using wallet::WALLET_FLAG_DISABLE_PRIVATE_KEYS;
using wallet::WalletContext;
using wallet::WalletDescriptor;
using wallet::WalletRescanReserver;
@@ -53,14 +58,14 @@ using wallet::WalletRescanReserver;
namespace
{
//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
-void ConfirmSend(QString* text = nullptr, bool cancel = false)
+void ConfirmSend(QString* text = nullptr, QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
{
- QTimer::singleShot(0, [text, cancel]() {
+ QTimer::singleShot(0, [text, confirm_type]() {
for (QWidget* widget : QApplication::topLevelWidgets()) {
if (widget->inherits("SendConfirmationDialog")) {
SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
if (text) *text = dialog->text();
- QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
+ QAbstractButton* button = dialog->button(confirm_type);
button->setEnabled(true);
button->click();
}
@@ -69,7 +74,8 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false)
}
//! Send coins to address and return txid.
-uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
+uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf,
+ QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
{
QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
@@ -83,7 +89,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& hash, ChangeType status) {
if (status == CT_NEW) txid = hash;
}));
- ConfirmSend();
+ ConfirmSend(/*text=*/nullptr, confirm_type);
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
assert(invoked);
return txid;
@@ -121,7 +127,7 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st
action->setEnabled(true);
QString text;
if (expectError.empty()) {
- ConfirmSend(&text, cancel);
+ ConfirmSend(&text, cancel ? QMessageBox::Cancel : QMessageBox::Yes);
} else {
ConfirmMessage(&text, 0ms);
}
@@ -136,6 +142,119 @@ void CompareBalance(WalletModel& walletModel, CAmount expected_balance, QLabel*
QCOMPARE(balance_label_to_check->text().trimmed(), balanceComparison);
}
+// Verify the 'useAvailableBalance' functionality. With and without manually selected coins.
+// Case 1: No coin control selected coins.
+// 'useAvailableBalance' should fill the amount edit box with the total available balance
+// Case 2: With coin control selected coins.
+// 'useAvailableBalance' should fill the amount edit box with the sum of the selected coins values.
+void VerifyUseAvailableBalance(SendCoinsDialog& sendCoinsDialog, const WalletModel& walletModel)
+{
+ // Verify first entry amount and "useAvailableBalance" button
+ QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
+ QVERIFY(entries->count() == 1); // only one entry
+ SendCoinsEntry* send_entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
+ QVERIFY(send_entry->getValue().amount == 0);
+ // Now click "useAvailableBalance", check updated balance (the entire wallet balance should be set)
+ Q_EMIT send_entry->useAvailableBalance(send_entry);
+ QVERIFY(send_entry->getValue().amount == walletModel.getCachedBalance().balance);
+
+ // Now manually select two coins and click on "useAvailableBalance". Then check updated balance
+ // (only the sum of the selected coins should be set).
+ int COINS_TO_SELECT = 2;
+ auto coins = walletModel.wallet().listCoins();
+ CAmount sum_selected_coins = 0;
+ int selected = 0;
+ QVERIFY(coins.size() == 1); // context check, coins received only on one destination
+ for (const auto& [outpoint, tx_out] : coins.begin()->second) {
+ sendCoinsDialog.getCoinControl()->Select(outpoint);
+ sum_selected_coins += tx_out.txout.nValue;
+ if (++selected == COINS_TO_SELECT) break;
+ }
+ QVERIFY(selected == COINS_TO_SELECT);
+
+ // Now that we have 2 coins selected, "useAvailableBalance" should update the balance label only with
+ // the sum of them.
+ Q_EMIT send_entry->useAvailableBalance(send_entry);
+ QVERIFY(send_entry->getValue().amount == sum_selected_coins);
+}
+
+void SyncUpWallet(const std::shared_ptr<CWallet>& wallet, interfaces::Node& node)
+{
+ WalletRescanReserver reserver(*wallet);
+ reserver.reserve();
+ CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/false);
+ QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
+ QCOMPARE(result.last_scanned_block, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
+ QVERIFY(result.last_failed_block.IsNull());
+}
+
+std::shared_ptr<CWallet> SetupLegacyWatchOnlyWallet(interfaces::Node& node, TestChain100Setup& test)
+{
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
+ wallet->LoadWallet();
+ {
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ wallet->SetupLegacyScriptPubKeyMan();
+ // Add watched key
+ CPubKey pubKey = test.coinbaseKey.GetPubKey();
+ bool import_keys = wallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , /*key_origins=*/{}, /*add_keypool=*/false, /*internal=*/false, /*timestamp=*/1);
+ assert(import_keys);
+ wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
+ }
+ SyncUpWallet(wallet, node);
+ return wallet;
+}
+
+std::shared_ptr<CWallet> SetupDescriptorsWallet(interfaces::Node& node, TestChain100Setup& test)
+{
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ // Add the coinbase key
+ FlatSigningProvider provider;
+ std::string error;
+ std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
+ assert(desc);
+ WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
+ if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
+ CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type);
+ wallet->SetAddressBook(dest, "", wallet::AddressPurpose::RECEIVE);
+ wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
+ SyncUpWallet(wallet, node);
+ wallet->SetBroadcastTransactions(true);
+ return wallet;
+}
+
+struct MiniGUI {
+public:
+ SendCoinsDialog sendCoinsDialog;
+ TransactionView transactionView;
+ OptionsModel optionsModel;
+ std::unique_ptr<ClientModel> clientModel;
+ std::unique_ptr<WalletModel> walletModel;
+
+ MiniGUI(interfaces::Node& node, const PlatformStyle* platformStyle) : sendCoinsDialog(platformStyle), transactionView(platformStyle), optionsModel(node) {
+ bilingual_str error;
+ QVERIFY(optionsModel.Init(error));
+ clientModel = std::make_unique<ClientModel>(node, &optionsModel);
+ }
+
+ void initModelForWallet(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet, const PlatformStyle* platformStyle)
+ {
+ WalletContext& context = *node.walletLoader().context();
+ AddWallet(context, wallet);
+ walletModel = std::make_unique<WalletModel>(interfaces::MakeWallet(context, wallet), *clientModel, platformStyle);
+ RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
+ sendCoinsDialog.setModel(walletModel.get());
+ transactionView.setModel(walletModel.get());
+ }
+
+};
+
//! Simple qt wallet tests.
//
// Test widgets can be debugged interactively calling show() on them and
@@ -149,69 +268,31 @@ void CompareBalance(WalletModel& walletModel, CAmount expected_balance, QLabel*
// QT_QPA_PLATFORM=xcb src/qt/test/test_bitcoin-qt # Linux
// QT_QPA_PLATFORM=windows src/qt/test/test_bitcoin-qt # Windows
// QT_QPA_PLATFORM=cocoa src/qt/test/test_bitcoin-qt # macOS
-void TestGUI(interfaces::Node& node)
+void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
{
- // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
- TestChain100Setup test;
- for (int i = 0; i < 5; ++i) {
- test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
- }
- auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
- test.m_node.wallet_loader = wallet_loader.get();
- node.setContext(&test.m_node);
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- {
- LOCK(wallet->cs_wallet);
- wallet->SetupDescriptorScriptPubKeyMans();
-
- // Add the coinbase key
- FlatSigningProvider provider;
- std::string error;
- std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(test.coinbaseKey) + ")", provider, error, /* require_checksum=*/ false);
- assert(desc);
- WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
- if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
- CTxDestination dest = GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet->m_default_address_type);
- wallet->SetAddressBook(dest, "", "receive");
- wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
- }
- {
- WalletRescanReserver reserver(*wallet);
- reserver.reserve();
- CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/false);
- QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
- QCOMPARE(result.last_scanned_block, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
- QVERIFY(result.last_failed_block.IsNull());
- }
- wallet->SetBroadcastTransactions(true);
-
// Create widgets for sending coins and listing transactions.
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
- SendCoinsDialog sendCoinsDialog(platformStyle.get());
- TransactionView transactionView(platformStyle.get());
- OptionsModel optionsModel(node);
- bilingual_str error;
- QVERIFY(optionsModel.Init(error));
- ClientModel clientModel(node, &optionsModel);
- WalletContext& context = *node.walletLoader().context();
- AddWallet(context, wallet);
- WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get());
- RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
- sendCoinsDialog.setModel(&walletModel);
- transactionView.setModel(&walletModel);
+ MiniGUI mini_gui(node, platformStyle.get());
+ mini_gui.initModelForWallet(node, wallet, platformStyle.get());
+ WalletModel& walletModel = *mini_gui.walletModel;
+ SendCoinsDialog& sendCoinsDialog = mini_gui.sendCoinsDialog;
+ TransactionView& transactionView = mini_gui.transactionView;
// Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
walletModel.pollBalanceChanged();
// Check balance in send dialog
CompareBalance(walletModel, walletModel.wallet().getBalance(), sendCoinsDialog.findChild<QLabel*>("labelBalance"));
+ // Check 'UseAvailableBalance' functionality
+ VerifyUseAvailableBalance(sendCoinsDialog, walletModel);
+
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105);
uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
+ // Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
+ qApp->processEvents();
QCOMPARE(transactionTableModel->rowCount({}), 107);
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
@@ -311,6 +392,76 @@ void TestGUI(interfaces::Node& node)
QCOMPARE(walletModel.wallet().getAddressReceiveRequests().size(), size_t{0});
}
+void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
+{
+ const std::shared_ptr<CWallet>& wallet = SetupLegacyWatchOnlyWallet(node, test);
+
+ // Create widgets and init models
+ std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
+ MiniGUI mini_gui(node, platformStyle.get());
+ mini_gui.initModelForWallet(node, wallet, platformStyle.get());
+ WalletModel& walletModel = *mini_gui.walletModel;
+ SendCoinsDialog& sendCoinsDialog = mini_gui.sendCoinsDialog;
+
+ // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
+ walletModel.pollBalanceChanged();
+ // Check balance in send dialog
+ CompareBalance(walletModel, walletModel.wallet().getBalances().watch_only_balance,
+ sendCoinsDialog.findChild<QLabel*>("labelBalance"));
+
+ // Set change address
+ sendCoinsDialog.getCoinControl()->destChange = GetDestinationForKey(test.coinbaseKey.GetPubKey(), OutputType::LEGACY);
+
+ // Time to reject "save" PSBT dialog ('SendCoins' locks the main thread until the dialog receives the event).
+ QTimer timer;
+ timer.setInterval(500);
+ QObject::connect(&timer, &QTimer::timeout, [&](){
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("QMessageBox")) {
+ QMessageBox* dialog = qobject_cast<QMessageBox*>(widget);
+ QAbstractButton* button = dialog->button(QMessageBox::Discard);
+ button->setEnabled(true);
+ button->click();
+ timer.stop();
+ break;
+ }
+ }
+ });
+ timer.start(500);
+
+ // Send tx and verify PSBT copied to the clipboard.
+ SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Save);
+ const std::string& psbt_string = QApplication::clipboard()->text().toStdString();
+ QVERIFY(!psbt_string.empty());
+
+ // Decode psbt
+ std::optional<std::vector<unsigned char>> decoded_psbt = DecodeBase64(psbt_string);
+ QVERIFY(decoded_psbt);
+ PartiallySignedTransaction psbt;
+ std::string err;
+ QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
+}
+
+void TestGUI(interfaces::Node& node)
+{
+ // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
+ TestChain100Setup test;
+ for (int i = 0; i < 5; ++i) {
+ test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
+ }
+ auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
+ test.m_node.wallet_loader = wallet_loader.get();
+ node.setContext(&test.m_node);
+
+ // "Full" GUI tests, use descriptor wallet
+ const std::shared_ptr<CWallet>& desc_wallet = SetupDescriptorsWallet(node, test);
+ TestGUI(node, desc_wallet);
+
+ // Legacy watch-only wallet test
+ // Verify PSBT creation.
+ TestGUIWatchOnly(node, test);
+}
+
} // namespace
void WalletTests::walletTests()
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 08789c1048..fb6f2cb464 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -68,8 +68,8 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *)
painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h);
// decide what order of magnitude we are
- int base = floor(log10(fMax));
- float val = pow(10.0f, base);
+ int base = std::floor(std::log10(fMax));
+ float val = std::pow(10.0f, base);
const QString units = tr("kB/s");
const float yMarginText = 2.0;
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 2ced44241f..fa110cfbc9 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -13,14 +13,14 @@
#include <qt/paymentserver.h>
#include <qt/transactionrecord.h>
+#include <common/system.h>
#include <consensus/consensus.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
#include <key_io.h>
#include <policy/policy.h>
-#include <util/system.h>
#include <validation.h>
-#include <wallet/ismine.h>
+#include <wallet/types.h>
#include <stdint.h>
#include <string>
@@ -248,9 +248,9 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += GUIUtil::HtmlEscape(name) + " ";
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE)
- strHTML += " (own address)";
+ strHTML += " (" + tr("own address") + ")";
else if(toSelf & ISMINE_WATCH_ONLY)
- strHTML += " (watch-only)";
+ strHTML += " (" + tr("watch-only") + ")";
strHTML += "<br>";
}
}
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 5f981ea250..1d2f6484fb 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -7,7 +7,7 @@
#include <chain.h>
#include <interfaces/wallet.h>
#include <key_io.h>
-#include <wallet/ismine.h>
+#include <wallet/types.h>
#include <stdint.h>
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index eb2ab12a66..f43b993628 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -13,8 +13,8 @@
#include <qt/guiutil.h>
#include <clientversion.h>
+#include <common/args.h>
#include <init.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <cstdio>
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 43411370a2..7a8a053900 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -4,7 +4,6 @@
#include <qt/walletframe.h>
-#include <fs.h>
#include <node/interface_ui.h>
#include <psbt.h>
#include <qt/guiutil.h>
@@ -12,7 +11,8 @@
#include <qt/psbtoperationsdialog.h>
#include <qt/walletmodel.h>
#include <qt/walletview.h>
-#include <util/system.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <cassert>
#include <fstream>
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3c69d46b7e..ee3327530c 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -18,12 +18,12 @@
#include <qt/sendcoinsdialog.h>
#include <qt/transactiontablemodel.h>
+#include <common/args.h> // for GetBoolArg
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <key_io.h>
#include <node/interface_ui.h>
#include <psbt.h>
-#include <util/system.h> // for GetBoolArg
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/wallet.h> // for CRecipient
@@ -138,7 +138,7 @@ void WalletModel::updateTransaction()
}
void WalletModel::updateAddressBook(const QString &address, const QString &label,
- bool isMine, const QString &purpose, int status)
+ bool isMine, wallet::AddressPurpose purpose, int status)
{
if(addressTableModel)
addressTableModel->updateEntry(address, label, isMine, purpose, status);
@@ -280,11 +280,11 @@ void WalletModel::sendCoins(WalletModelTransaction& transaction)
if (!m_wallet->getAddress(
dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr))
{
- m_wallet->setAddressBook(dest, strLabel, "send");
+ m_wallet->setAddressBook(dest, strLabel, wallet::AddressPurpose::SEND);
}
else if (name != strLabel)
{
- m_wallet->setAddressBook(dest, strLabel, ""); // "" means don't change purpose
+ m_wallet->setAddressBook(dest, strLabel, {}); // {} means don't change purpose
}
}
}
@@ -377,18 +377,17 @@ static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
static void NotifyAddressBookChanged(WalletModel *walletmodel,
const CTxDestination &address, const std::string &label, bool isMine,
- const std::string &purpose, ChangeType status)
+ wallet::AddressPurpose purpose, ChangeType status)
{
QString strAddress = QString::fromStdString(EncodeDestination(address));
QString strLabel = QString::fromStdString(label);
- QString strPurpose = QString::fromStdString(purpose);
- qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status);
+ qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + QString::number(static_cast<uint8_t>(purpose)) + " status=" + QString::number(status);
bool invoked = QMetaObject::invokeMethod(walletmodel, "updateAddressBook",
Q_ARG(QString, strAddress),
Q_ARG(QString, strLabel),
Q_ARG(bool, isMine),
- Q_ARG(QString, strPurpose),
+ Q_ARG(wallet::AddressPurpose, purpose),
Q_ARG(int, status));
assert(invoked);
}
@@ -548,7 +547,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
- Q_EMIT message(tr("PSBT copied"), "Copied to clipboard", CClientUIInterface::MSG_INFORMATION);
+ Q_EMIT message(tr("PSBT copied"), tr("Copied to clipboard", "Fee-bump PSBT saved"), CClientUIInterface::MSG_INFORMATION);
return true;
}
@@ -613,5 +612,17 @@ uint256 WalletModel::getLastBlockProcessed() const
CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
{
- return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance;
+ // No selected coins, return the cached balance
+ if (!control || !control->HasSelected()) {
+ const interfaces::WalletBalances& balances = getCachedBalance();
+ CAmount available_balance = balances.balance;
+ // if wallet private keys are disabled, this is a watch-only wallet
+ // so, let's include the watch-only balance.
+ if (balances.have_watch_only && m_wallet->privateKeysDisabled()) {
+ available_balance += balances.watch_only_balance;
+ }
+ return available_balance;
+ }
+ // Fetch balance from the wallet, taking into account the selected coins
+ return wallet().getAvailableBalance(*control);
}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 17a39349f3..4f75d41404 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -236,7 +236,7 @@ public Q_SLOTS:
/* New transaction, or transaction changed status */
void updateTransaction();
/* New, updated or removed address book entry */
- void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status);
+ void updateAddressBook(const QString &address, const QString &label, bool isMine, wallet::AddressPurpose purpose, int status);
/* Watch-only added */
void updateWatchOnlyFlag(bool fHaveWatchonly);
/* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */
diff --git a/src/random.cpp b/src/random.cpp
index f4c51574cc..39ceae4206 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -28,14 +28,10 @@
#include <sys/time.h>
#endif
-#ifdef HAVE_SYS_GETRANDOM
-#include <sys/syscall.h>
-#include <linux/random.h>
-#endif
-#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
-#include <unistd.h>
+#if defined(HAVE_GETRANDOM) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
#include <sys/random.h>
#endif
+
#ifdef HAVE_SYSCTL_ARND
#include <sys/sysctl.h>
#endif
@@ -252,7 +248,7 @@ static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration du
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
* compatible way to get cryptographic randomness on UNIX-ish platforms.
*/
-static void GetDevURandom(unsigned char *ent32)
+[[maybe_unused]] static void GetDevURandom(unsigned char *ent32)
{
int f = open("/dev/urandom", O_RDONLY);
if (f == -1) {
@@ -285,23 +281,14 @@ void GetOSRand(unsigned char *ent32)
RandFailure();
}
CryptReleaseContext(hProvider, 0);
-#elif defined(HAVE_SYS_GETRANDOM)
+#elif defined(HAVE_GETRANDOM)
/* Linux. From the getrandom(2) man page:
* "If the urandom source has been initialized, reads of up to 256 bytes
* will always return as many bytes as requested and will not be
* interrupted by signals."
*/
- int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
- if (rv != NUM_OS_RANDOM_BYTES) {
- if (rv < 0 && errno == ENOSYS) {
- /* Fallback for kernel <3.17: the return value will be -1 and errno
- * ENOSYS if the syscall is not available, in that case fall back
- * to /dev/urandom.
- */
- GetDevURandom(ent32);
- } else {
- RandFailure();
- }
+ if (getrandom(ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
+ RandFailure();
}
#elif defined(__OpenBSD__)
/* OpenBSD. From the arc4random(3) man page:
@@ -311,16 +298,10 @@ void GetOSRand(unsigned char *ent32)
The function call is always successful.
*/
arc4random_buf(ent32, NUM_OS_RANDOM_BYTES);
- // Silence a compiler warning about unused function.
- (void)GetDevURandom;
#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
- /* getentropy() is available on macOS 10.12 and later.
- */
if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
RandFailure();
}
- // Silence a compiler warning about unused function.
- (void)GetDevURandom;
#elif defined(HAVE_SYSCTL_ARND)
/* FreeBSD, NetBSD and similar. It is possible for the call to return less
* bytes than requested, so need to read in a loop.
@@ -334,8 +315,6 @@ void GetOSRand(unsigned char *ent32)
}
have += len;
} while (have < NUM_OS_RANDOM_BYTES);
- // Silence a compiler warning about unused function.
- (void)GetDevURandom;
#else
/* Fall back to /dev/urandom if there is no specific method implemented to
* get system entropy for this OS.
@@ -620,6 +599,12 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
return ret;
}
+void FastRandomContext::fillrand(Span<std::byte> output)
+{
+ if (requires_seed) RandomSeed();
+ rng.Keystream(UCharCast(output.data()), output.size());
+}
+
FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0)
{
rng.SetKey32(seed.begin());
diff --git a/src/random.h b/src/random.h
index 49c0dff5bf..50f56ed911 100644
--- a/src/random.h
+++ b/src/random.h
@@ -213,6 +213,9 @@ public:
/** Generate random bytes. */
std::vector<unsigned char> randbytes(size_t len);
+ /** Fill a byte Span with random bytes. */
+ void fillrand(Span<std::byte> output);
+
/** Generate a random 32-bit integer. */
uint32_t rand32() noexcept { return randbits(32); }
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index 3e4d5a587d..581612bccf 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -24,11 +24,12 @@
#include <thread>
#include <vector>
+#include <sys/types.h> // must go before a number of other headers
+
#ifdef WIN32
#include <windows.h>
#include <winreg.h>
#else
-#include <sys/types.h> // must go before a number of other headers
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/resource.h>
diff --git a/src/rest.cpp b/src/rest.cpp
index fa119ddfb7..ba149c1a9e 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -24,8 +24,8 @@
#include <streams.h>
#include <sync.h>
#include <txmempool.h>
+#include <util/any.h>
#include <util/check.h>
-#include <util/system.h>
#include <validation.h>
#include <version.h>
@@ -36,7 +36,6 @@
using node::GetTransaction;
using node::NodeContext;
-using node::ReadBlockFromDisk;
static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
static constexpr unsigned int MAX_REST_HEADERS_RESULTS = 2000;
@@ -200,7 +199,11 @@ static bool rest_headers(const std::any& context,
} else if (path.size() == 1) {
// new path with query parameter: /rest/headers/<hash>?count=<count>
hashStr = path[0];
- raw_count = req->GetQueryParameter("count").value_or("5");
+ try {
+ raw_count = req->GetQueryParameter("count").value_or("5");
+ } catch (const std::runtime_error& e) {
+ return RESTERR(req, HTTP_BAD_REQUEST, e.what());
+ }
} else {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>");
}
@@ -307,7 +310,7 @@ static bool rest_block(const std::any& context,
}
- if (!ReadBlockFromDisk(block, pblockindex, chainman.GetParams().GetConsensus())) {
+ if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
@@ -371,7 +374,11 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const
} else if (uri_parts.size() == 2) {
// new path with query parameter: /rest/blockfilterheaders/<filtertype>/<blockhash>?count=<count>
raw_blockhash = uri_parts[1];
- raw_count = req->GetQueryParameter("count").value_or("5");
+ try {
+ raw_count = req->GetQueryParameter("count").value_or("5");
+ } catch (const std::runtime_error& e) {
+ return RESTERR(req, HTTP_BAD_REQUEST, e.what());
+ }
} else {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<blockhash>.<ext>?count=<count>");
}
@@ -620,7 +627,7 @@ static bool rest_deploymentinfo(const std::any& context, HTTPRequest* req, const
return RESTERR(req, HTTP_BAD_REQUEST, "Block not found");
}
- jsonRequest.params.pushKV("blockhash", hash_str);
+ jsonRequest.params.push_back(hash_str);
}
req->WriteHeader("Content-Type", "application/json");
@@ -652,11 +659,21 @@ static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::s
case RESTResponseFormat::JSON: {
std::string str_json;
if (param == "contents") {
- const std::string raw_verbose{req->GetQueryParameter("verbose").value_or("true")};
+ std::string raw_verbose;
+ try {
+ raw_verbose = req->GetQueryParameter("verbose").value_or("true");
+ } catch (const std::runtime_error& e) {
+ return RESTERR(req, HTTP_BAD_REQUEST, e.what());
+ }
if (raw_verbose != "true" && raw_verbose != "false") {
return RESTERR(req, HTTP_BAD_REQUEST, "The \"verbose\" query parameter must be either \"true\" or \"false\".");
}
- const std::string raw_mempool_sequence{req->GetQueryParameter("mempool_sequence").value_or("false")};
+ std::string raw_mempool_sequence;
+ try {
+ raw_mempool_sequence = req->GetQueryParameter("mempool_sequence").value_or("false");
+ } catch (const std::runtime_error& e) {
+ return RESTERR(req, HTTP_BAD_REQUEST, e.what());
+ }
if (raw_mempool_sequence != "true" && raw_mempool_sequence != "false") {
return RESTERR(req, HTTP_BAD_REQUEST, "The \"mempool_sequence\" query parameter must be either \"true\" or \"false\".");
}
@@ -698,7 +715,7 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string
const NodeContext* const node = GetNodeContext(context, req);
if (!node) return false;
uint256 hashBlock = uint256();
- const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, node->mempool.get(), hash, Params().GetConsensus(), hashBlock);
+ const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, node->mempool.get(), hash, hashBlock, node->chainman->m_blockman);
if (!tx) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 1a9b265fbe..ee3237638e 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -9,13 +9,13 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/params.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <deploymentinfo.h>
#include <deploymentstatus.h>
-#include <fs.h>
#include <hash.h>
#include <index/blockfilterindex.h>
#include <index/coinstatsindex.h>
@@ -39,8 +39,8 @@
#include <undo.h>
#include <univalue.h>
#include <util/check.h>
+#include <util/fs.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -58,9 +58,7 @@ using kernel::CoinStatsHashType;
using node::BlockManager;
using node::NodeContext;
-using node::ReadBlockFromDisk;
using node::SnapshotMetadata;
-using node::UndoReadFromDisk;
struct CUpdatedBlock
{
@@ -183,7 +181,7 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
CBlockUndo blockUndo;
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
- const bool have_undo{is_not_pruned && UndoReadFromDisk(blockUndo, blockindex)};
+ const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, *blockindex)};
for (size_t i = 0; i < block.vtx.size(); ++i) {
const CTransactionRef& tx = block.vtx.at(i);
@@ -430,7 +428,7 @@ static RPCHelpMan getblockfrompeer()
"getblockfrompeer",
"Attempt to fetch block from a given peer.\n\n"
"We must have the header for this block, e.g. using submitheader.\n"
- "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n"
+ "Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"
"Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
"When a peer does not respond with a block, we will disconnect.\n"
"Note: The block could be re-pruned as soon as it is received.\n\n"
@@ -587,7 +585,7 @@ static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblocki
}
}
- if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
+ if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
// Block not found on disk. This could be because we have the block
// header in our index but not yet have the block or did not accept the
// block. Or if the block was pruned right after we released the lock above.
@@ -611,7 +609,7 @@ static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblo
}
}
- if (!UndoReadFromDisk(blockUndo, pblockindex)) {
+ if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
}
@@ -1125,7 +1123,7 @@ static RPCHelpMan verifychain()
LOCK(cs_main);
Chainstate& active_chainstate = chainman.ActiveChainstate();
- return CVerifyDB().VerifyDB(
+ return CVerifyDB(chainman.GetNotifications()).VerifyDB(
active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
},
};
@@ -1256,7 +1254,7 @@ RPCHelpMan getblockchaininfo()
const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
const int height{tip.nHeight};
UniValue obj(UniValue::VOBJ);
- obj.pushKV("chain", chainman.GetParams().NetworkIDString());
+ obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
obj.pushKV("blocks", height);
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
@@ -2325,6 +2323,7 @@ static RPCHelpMan scanblocks()
{RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
{RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
}},
+ {RPCResult::Type::BOOL, "completed", "true if the scan process was not aborted"}
}},
RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::NUM, "progress", "Approximate percent complete"},
@@ -2362,8 +2361,7 @@ static RPCHelpMan scanblocks()
// set the abort flag
g_scanfilter_should_abort_scan = true;
return true;
- }
- else if (request.params[0].get_str() == "start") {
+ } else if (request.params[0].get_str() == "start") {
BlockFiltersScanReserver reserver;
if (!reserver.reserve()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
@@ -2387,27 +2385,28 @@ static RPCHelpMan scanblocks()
ChainstateManager& chainman = EnsureChainman(node);
// set the start-height
- const CBlockIndex* block = nullptr;
+ const CBlockIndex* start_index = nullptr;
const CBlockIndex* stop_block = nullptr;
{
LOCK(cs_main);
CChain& active_chain = chainman.ActiveChain();
- block = active_chain.Genesis();
- stop_block = active_chain.Tip();
+ start_index = active_chain.Genesis();
+ stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
if (!request.params[2].isNull()) {
- block = active_chain[request.params[2].getInt<int>()];
- if (!block) {
+ start_index = active_chain[request.params[2].getInt<int>()];
+ if (!start_index) {
throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
}
}
if (!request.params[3].isNull()) {
stop_block = active_chain[request.params[3].getInt<int>()];
- if (!stop_block || stop_block->nHeight < block->nHeight) {
+ if (!stop_block || stop_block->nHeight < start_index->nHeight) {
throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
}
}
}
- CHECK_NONFATAL(block);
+ CHECK_NONFATAL(start_index);
+ CHECK_NONFATAL(stop_block);
// loop through the scan objects, add scripts to the needle_set
GCSFilter::ElementSet needle_set;
@@ -2420,64 +2419,64 @@ static RPCHelpMan scanblocks()
}
UniValue blocks(UniValue::VARR);
const int amount_per_chunk = 10000;
- const CBlockIndex* start_index = block; // for remembering the start of a blockfilter range
std::vector<BlockFilter> filters;
- const CBlockIndex* start_block = block; // for progress reporting
- const int total_blocks_to_process = stop_block->nHeight - start_block->nHeight;
+ int start_block_height = start_index->nHeight; // for progress reporting
+ const int total_blocks_to_process = stop_block->nHeight - start_block_height;
g_scanfilter_should_abort_scan = false;
g_scanfilter_progress = 0;
- g_scanfilter_progress_height = start_block->nHeight;
+ g_scanfilter_progress_height = start_block_height;
+ bool completed = true;
- while (block) {
+ const CBlockIndex* end_range = nullptr;
+ do {
node.rpc_interruption_point(); // allow a clean shutdown
if (g_scanfilter_should_abort_scan) {
- LogPrintf("scanblocks RPC aborted at height %d.\n", block->nHeight);
+ completed = false;
break;
}
- const CBlockIndex* next = nullptr;
- {
- LOCK(cs_main);
- CChain& active_chain = chainman.ActiveChain();
- next = active_chain.Next(block);
- if (block == stop_block) next = nullptr;
- }
- if (start_index->nHeight + amount_per_chunk == block->nHeight || next == nullptr) {
- LogPrint(BCLog::RPC, "Fetching blockfilters from height %d to height %d.\n", start_index->nHeight, block->nHeight);
- if (index->LookupFilterRange(start_index->nHeight, block, filters)) {
- for (const BlockFilter& filter : filters) {
- // compare the elements-set with each filter
- if (filter.GetFilter().MatchAny(needle_set)) {
- if (filter_false_positives) {
- // Double check the filter matches by scanning the block
- const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
-
- if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
- continue;
- }
- }
- blocks.push_back(filter.GetBlockHash().GetHex());
- LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex());
+ // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
+ int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
+ end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
+ WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
+ stop_block;
+
+ if (index->LookupFilterRange(start_block, end_range, filters)) {
+ for (const BlockFilter& filter : filters) {
+ // compare the elements-set with each filter
+ if (filter.GetFilter().MatchAny(needle_set)) {
+ if (filter_false_positives) {
+ // Double check the filter matches by scanning the block
+ const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
+
+ if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
+ continue;
+ }
}
+
+ blocks.push_back(filter.GetBlockHash().GetHex());
}
}
- start_index = block;
-
- // update progress
- int blocks_processed = block->nHeight - start_block->nHeight;
- if (total_blocks_to_process > 0) { // avoid division by zero
- g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
- } else {
- g_scanfilter_progress = 100;
- }
- g_scanfilter_progress_height = block->nHeight;
}
- block = next;
- }
- ret.pushKV("from_height", start_block->nHeight);
- ret.pushKV("to_height", g_scanfilter_progress_height.load());
+ start_index = end_range;
+
+ // update progress
+ int blocks_processed = end_range->nHeight - start_block_height;
+ if (total_blocks_to_process > 0) { // avoid division by zero
+ g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
+ } else {
+ g_scanfilter_progress = 100;
+ }
+ g_scanfilter_progress_height = end_range->nHeight;
+
+ // Finish if we reached the stop block
+ } while (start_index != stop_block);
+
+ ret.pushKV("from_height", start_block_height);
+ ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here
ret.pushKV("relevant_blocks", blocks);
+ ret.pushKV("completed", completed);
}
else {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 9ccb87b78a..0a86085db0 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -7,9 +7,9 @@
#include <consensus/amount.h>
#include <core_io.h>
-#include <fs.h>
#include <streams.h>
#include <sync.h>
+#include <util/fs.h>
#include <validation.h>
#include <any>
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4459dd71aa..5f58eef1db 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <rpc/client.h>
#include <tinyformat.h>
-#include <util/system.h>
#include <set>
#include <stdint.h>
@@ -101,6 +101,11 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listunspent", 2, "addresses" },
{ "listunspent", 3, "include_unsafe" },
{ "listunspent", 4, "query_options" },
+ { "listunspent", 4, "minimumAmount" },
+ { "listunspent", 4, "maximumAmount" },
+ { "listunspent", 4, "maximumCount" },
+ { "listunspent", 4, "minimumSumAmount" },
+ { "listunspent", 4, "include_immature_coinbase" },
{ "getblock", 1, "verbosity" },
{ "getblock", 1, "verbose" },
{ "getblockheader", 1, "verbose" },
@@ -124,15 +129,45 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "submitpackage", 0, "package" },
{ "combinerawtransaction", 0, "txs" },
{ "fundrawtransaction", 1, "options" },
+ { "fundrawtransaction", 1, "add_inputs"},
+ { "fundrawtransaction", 1, "include_unsafe"},
+ { "fundrawtransaction", 1, "minconf"},
+ { "fundrawtransaction", 1, "maxconf"},
+ { "fundrawtransaction", 1, "changePosition"},
+ { "fundrawtransaction", 1, "includeWatching"},
+ { "fundrawtransaction", 1, "lockUnspents"},
+ { "fundrawtransaction", 1, "fee_rate"},
+ { "fundrawtransaction", 1, "feeRate"},
+ { "fundrawtransaction", 1, "subtractFeeFromOutputs"},
+ { "fundrawtransaction", 1, "input_weights"},
+ { "fundrawtransaction", 1, "conf_target"},
+ { "fundrawtransaction", 1, "replaceable"},
+ { "fundrawtransaction", 1, "solving_data"},
{ "fundrawtransaction", 2, "iswitness" },
{ "walletcreatefundedpsbt", 0, "inputs" },
{ "walletcreatefundedpsbt", 1, "outputs" },
{ "walletcreatefundedpsbt", 2, "locktime" },
{ "walletcreatefundedpsbt", 3, "options" },
+ { "walletcreatefundedpsbt", 3, "add_inputs"},
+ { "walletcreatefundedpsbt", 3, "include_unsafe"},
+ { "walletcreatefundedpsbt", 3, "minconf"},
+ { "walletcreatefundedpsbt", 3, "maxconf"},
+ { "walletcreatefundedpsbt", 3, "changePosition"},
+ { "walletcreatefundedpsbt", 3, "includeWatching"},
+ { "walletcreatefundedpsbt", 3, "lockUnspents"},
+ { "walletcreatefundedpsbt", 3, "fee_rate"},
+ { "walletcreatefundedpsbt", 3, "feeRate"},
+ { "walletcreatefundedpsbt", 3, "subtractFeeFromOutputs"},
+ { "walletcreatefundedpsbt", 3, "conf_target"},
+ { "walletcreatefundedpsbt", 3, "replaceable"},
+ { "walletcreatefundedpsbt", 3, "solving_data"},
{ "walletcreatefundedpsbt", 4, "bip32derivs" },
{ "walletprocesspsbt", 1, "sign" },
{ "walletprocesspsbt", 3, "bip32derivs" },
{ "walletprocesspsbt", 4, "finalize" },
+ { "descriptorprocesspsbt", 1, "descriptors"},
+ { "descriptorprocesspsbt", 3, "bip32derivs" },
+ { "descriptorprocesspsbt", 4, "finalize" },
{ "createpsbt", 0, "inputs" },
{ "createpsbt", 1, "outputs" },
{ "createpsbt", 2, "locktime" },
@@ -154,18 +189,49 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "send", 1, "conf_target" },
{ "send", 3, "fee_rate"},
{ "send", 4, "options" },
+ { "send", 4, "add_inputs"},
+ { "send", 4, "include_unsafe"},
+ { "send", 4, "minconf"},
+ { "send", 4, "maxconf"},
+ { "send", 4, "add_to_wallet"},
+ { "send", 4, "change_position"},
+ { "send", 4, "fee_rate"},
+ { "send", 4, "include_watching"},
+ { "send", 4, "inputs"},
+ { "send", 4, "locktime"},
+ { "send", 4, "lock_unspents"},
+ { "send", 4, "psbt"},
+ { "send", 4, "subtract_fee_from_outputs"},
+ { "send", 4, "conf_target"},
+ { "send", 4, "replaceable"},
+ { "send", 4, "solving_data"},
{ "sendall", 0, "recipients" },
{ "sendall", 1, "conf_target" },
{ "sendall", 3, "fee_rate"},
{ "sendall", 4, "options" },
+ { "sendall", 4, "add_to_wallet"},
+ { "sendall", 4, "fee_rate"},
+ { "sendall", 4, "include_watching"},
+ { "sendall", 4, "inputs"},
+ { "sendall", 4, "locktime"},
+ { "sendall", 4, "lock_unspents"},
+ { "sendall", 4, "psbt"},
+ { "sendall", 4, "send_max"},
+ { "sendall", 4, "minconf"},
+ { "sendall", 4, "maxconf"},
+ { "sendall", 4, "conf_target"},
+ { "sendall", 4, "replaceable"},
+ { "sendall", 4, "solving_data"},
{ "simulaterawtransaction", 0, "rawtxs" },
{ "simulaterawtransaction", 1, "options" },
+ { "simulaterawtransaction", 1, "include_watchonly"},
{ "importprivkey", 2, "rescan" },
{ "importaddress", 2, "rescan" },
{ "importaddress", 3, "p2sh" },
{ "importpubkey", 2, "rescan" },
{ "importmulti", 0, "requests" },
{ "importmulti", 1, "options" },
+ { "importmulti", 1, "rescan" },
{ "importdescriptors", 0, "requests" },
{ "listdescriptors", 0, "private" },
{ "verifychain", 0, "checklevel" },
@@ -189,7 +255,15 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getmempooldescendants", 1, "verbose" },
{ "gettxspendingprevout", 0, "outputs" },
{ "bumpfee", 1, "options" },
+ { "bumpfee", 1, "conf_target"},
+ { "bumpfee", 1, "fee_rate"},
+ { "bumpfee", 1, "replaceable"},
+ { "bumpfee", 1, "outputs"},
{ "psbtbumpfee", 1, "options" },
+ { "psbtbumpfee", 1, "conf_target"},
+ { "psbtbumpfee", 1, "fee_rate"},
+ { "psbtbumpfee", 1, "replaceable"},
+ { "psbtbumpfee", 1, "outputs"},
{ "logging", 0, "include" },
{ "logging", 1, "exclude" },
{ "disconnectnode", 1, "nodeid" },
@@ -223,6 +297,14 @@ static const CRPCConvertParam vRPCConvertParams[] =
};
// clang-format on
+/** Parse string to UniValue or throw runtime_error if string contains invalid JSON */
+static UniValue Parse(std::string_view raw)
+{
+ UniValue parsed;
+ if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
+ return parsed;
+}
+
class CRPCConvertTable
{
private:
@@ -235,13 +317,13 @@ public:
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
{
- return members.count({method, param_idx}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
+ return members.count({method, param_idx}) > 0 ? Parse(arg_value) : arg_value;
}
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
{
- return membersByName.count({method, param_name}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
+ return membersByName.count({method, param_name}) > 0 ? Parse(arg_value) : arg_value;
}
};
@@ -255,16 +337,6 @@ CRPCConvertTable::CRPCConvertTable()
static CRPCConvertTable rpcCvtTable;
-/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
- * as well as objects and arrays.
- */
-UniValue ParseNonRFCJSONValue(std::string_view raw)
-{
- UniValue parsed;
- if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
- return parsed;
-}
-
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
UniValue params(UniValue::VARR);
@@ -299,10 +371,10 @@ UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<s
}
if (!positional_args.empty()) {
- // Use __pushKV instead of pushKV to avoid overwriting an explicit
+ // Use pushKVEnd instead of pushKV to avoid overwriting an explicit
// "args" value with an implicit one. Let the RPC server handle the
// request as given.
- params.__pushKV("args", positional_args);
+ params.pushKVEnd("args", positional_args);
}
return params;
diff --git a/src/rpc/client.h b/src/rpc/client.h
index 3c5c4fc4d6..b67cd27fdf 100644
--- a/src/rpc/client.h
+++ b/src/rpc/client.h
@@ -17,9 +17,4 @@ UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::s
/** Convert named arguments to command-specific RPC representation */
UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<std::string>& strParams);
-/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
- * as well as objects and arrays.
- */
-UniValue ParseNonRFCJSONValue(std::string_view raw);
-
#endif // BITCOIN_RPC_CLIENT_H
diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp
index f5a6913572..310eec5f15 100644
--- a/src/rpc/external_signer.cpp
+++ b/src/rpc/external_signer.cpp
@@ -2,12 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <chainparamsbase.h>
+#include <common/args.h>
+#include <common/system.h>
#include <external_signer.h>
+#include <rpc/protocol.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <util/strencodings.h>
-#include <rpc/protocol.h>
#include <string>
#include <vector>
@@ -41,7 +42,7 @@ static RPCHelpMan enumeratesigners()
{
const std::string command = gArgs.GetArg("-signer", "");
if (command == "") throw JSONRPCError(RPC_MISC_ERROR, "Error: restart bitcoind with -signer=<cmd>");
- const std::string chain = gArgs.GetChainName();
+ const std::string chain = gArgs.GetChainTypeString();
UniValue signers_res = UniValue::VARR;
try {
std::vector<ExternalSigner> signers;
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 3a69e2d8a2..11d2874961 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -9,7 +9,6 @@
#include <chainparams.h>
#include <core_io.h>
-#include <fs.h>
#include <kernel/mempool_entry.h>
#include <node/mempool_persist_args.h>
#include <policy/rbf.h>
@@ -21,6 +20,7 @@
#include <script/standard.h>
#include <txmempool.h>
#include <univalue.h>
+#include <util/fs.h>
#include <util/moneystr.h>
#include <util/time.h>
@@ -351,8 +351,8 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempoo
entryToJSON(pool, info, e);
// Mempool has unique entries so there is no advantage in using
// UniValue::pushKV, which checks if the key already exists in O(N).
- // UniValue::__pushKV is used instead which currently is O(1).
- o.__pushKV(hash.ToString(), info);
+ // UniValue::pushKVEnd is used instead which currently is O(1).
+ o.pushKVEnd(hash.ToString(), info);
}
return o;
} else {
@@ -638,7 +638,7 @@ static RPCHelpMan gettxspendingprevout()
}, /*fAllowNull=*/false, /*fStrict=*/true);
const uint256 txid(ParseHashO(o, "txid"));
- const int nOutput{find_value(o, "vout").getInt<int>()};
+ const int nOutput{o.find_value("vout").getInt<int>()};
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index d55e20ba5e..074cecadd2 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -5,6 +5,7 @@
#include <chain.h>
#include <chainparams.h>
+#include <common/system.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
@@ -32,7 +33,6 @@
#include <univalue.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -435,7 +435,7 @@ static RPCHelpMan getmininginfo()
obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip()));
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
- obj.pushKV("chain", chainman.GetParams().NetworkIDString());
+ obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
obj.pushKV("warnings", GetWarnings(false).original);
return obj;
},
@@ -480,6 +480,40 @@ static RPCHelpMan prioritisetransaction()
};
}
+static RPCHelpMan getprioritisedtransactions()
+{
+ return RPCHelpMan{"getprioritisedtransactions",
+ "Returns a map of all user-created (see prioritisetransaction) fee deltas by txid, and whether the tx is present in mempool.",
+ {},
+ RPCResult{
+ RPCResult::Type::OBJ_DYN, "prioritisation-map", "prioritisation keyed by txid",
+ {
+ {RPCResult::Type::OBJ, "txid", "", {
+ {RPCResult::Type::NUM, "fee_delta", "transaction fee delta in satoshis"},
+ {RPCResult::Type::BOOL, "in_mempool", "whether this transaction is currently in mempool"},
+ }}
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getprioritisedtransactions", "")
+ + HelpExampleRpc("getprioritisedtransactions", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+ {
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ CTxMemPool& mempool = EnsureMemPool(node);
+ UniValue rpc_result{UniValue::VOBJ};
+ for (const auto& delta_info : mempool.GetPrioritisedTransactions()) {
+ UniValue result_inner{UniValue::VOBJ};
+ result_inner.pushKV("fee_delta", delta_info.delta);
+ result_inner.pushKV("in_mempool", delta_info.in_mempool);
+ rpc_result.pushKV(delta_info.txid.GetHex(), result_inner);
+ }
+ return rpc_result;
+ },
+ };
+}
+
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
static UniValue BIP22ValidationResult(const BlockValidationState& state)
@@ -612,7 +646,7 @@ static RPCHelpMan getblocktemplate()
if (!request.params[0].isNull())
{
const UniValue& oparam = request.params[0].get_obj();
- const UniValue& modeval = find_value(oparam, "mode");
+ const UniValue& modeval = oparam.find_value("mode");
if (modeval.isStr())
strMode = modeval.get_str();
else if (modeval.isNull())
@@ -621,11 +655,11 @@ static RPCHelpMan getblocktemplate()
}
else
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
- lpval = find_value(oparam, "longpollid");
+ lpval = oparam.find_value("longpollid");
if (strMode == "proposal")
{
- const UniValue& dataval = find_value(oparam, "data");
+ const UniValue& dataval = oparam.find_value("data");
if (!dataval.isStr())
throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
@@ -652,7 +686,7 @@ static RPCHelpMan getblocktemplate()
return BIP22ValidationResult(state);
}
- const UniValue& aClientRules = find_value(oparam, "rules");
+ const UniValue& aClientRules = oparam.find_value("rules");
if (aClientRules.isArray()) {
for (unsigned int i = 0; i < aClientRules.size(); ++i) {
const UniValue& v = aClientRules[i];
@@ -1048,6 +1082,7 @@ void RegisterMiningRPCCommands(CRPCTable& t)
{"mining", &getnetworkhashps},
{"mining", &getmininginfo},
{"mining", &prioritisetransaction},
+ {"mining", &getprioritisedtransactions},
{"mining", &getblocktemplate},
{"mining", &submitblock},
{"mining", &submitheader},
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 7ffa777ef4..a2a46ef32f 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -21,6 +21,7 @@
#include <rpc/util.h>
#include <sync.h>
#include <timedata.h>
+#include <util/chaintype.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
@@ -354,7 +355,7 @@ static RPCHelpMan addconnection()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- if (Params().NetworkIDString() != CBaseChainParams::REGTEST) {
+ if (Params().GetChainType() != ChainType::REGTEST) {
throw std::runtime_error("addconnection is for regression testing (-regtest mode) only.");
}
@@ -512,15 +513,15 @@ static RPCHelpMan getaddednodeinfo()
static RPCHelpMan getnettotals()
{
return RPCHelpMan{"getnettotals",
- "\nReturns information about network traffic, including bytes in, bytes out,\n"
- "and current time.\n",
- {},
+ "Returns information about network traffic, including bytes in, bytes out,\n"
+ "and current system time.",
+ {},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"},
{RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"},
- {RPCResult::Type::NUM_TIME, "timemillis", "Current " + UNIX_EPOCH_TIME + " in milliseconds"},
+ {RPCResult::Type::NUM_TIME, "timemillis", "Current system " + UNIX_EPOCH_TIME + " in milliseconds"},
{RPCResult::Type::OBJ, "uploadtarget", "",
{
{RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"},
@@ -544,7 +545,7 @@ static RPCHelpMan getnettotals()
UniValue obj(UniValue::VOBJ);
obj.pushKV("totalbytesrecv", connman.GetTotalBytesRecv());
obj.pushKV("totalbytessent", connman.GetTotalBytesSent());
- obj.pushKV("timemillis", GetTimeMillis());
+ obj.pushKV("timemillis", TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()));
UniValue outboundLimit(UniValue::VOBJ);
outboundLimit.pushKV("timeframe", count_seconds(connman.GetMaxOutboundTimeframe()));
@@ -712,9 +713,10 @@ static RPCHelpMan setban()
isSubnet = true;
if (!isSubnet) {
- CNetAddr resolved;
- LookupHost(request.params[0].get_str(), resolved, false);
- netAddr = resolved;
+ const std::optional<CNetAddr> addr{LookupHost(request.params[0].get_str(), false)};
+ if (addr.has_value()) {
+ netAddr = addr.value();
+ }
}
else
LookupSubNet(request.params[0].get_str(), subNet);
@@ -942,11 +944,11 @@ static RPCHelpMan addpeeraddress()
const bool tried{request.params[2].isNull() ? false : request.params[2].get_bool()};
UniValue obj(UniValue::VOBJ);
- CNetAddr net_addr;
+ std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)};
bool success{false};
- if (LookupHost(addr_string, net_addr, false)) {
- CService service{net_addr, port};
+ if (net_addr.has_value()) {
+ CService service{net_addr.value(), port};
CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
address.nTime = Now<NodeSeconds>();
// The source address is set equal to the address. This is equivalent to the peer
diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp
index 5918bc6e38..45d46d223b 100644
--- a/src/rpc/node.cpp
+++ b/src/rpc/node.cpp
@@ -19,9 +19,9 @@
#include <rpc/util.h>
#include <scheduler.h>
#include <univalue.h>
+#include <util/any.h>
#include <util/check.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <stdint.h>
#ifdef HAVE_MALLOC_INFO
@@ -163,7 +163,7 @@ static RPCHelpMan getmemoryinfo()
{
{"mode", RPCArg::Type::STR, RPCArg::Default{"stats"}, "determines what kind of information is returned.\n"
" - \"stats\" returns general statistics about memory usage in the daemon.\n"
- " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."},
+ " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc)."},
},
{
RPCResult{"mode \"stats\"",
diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp
index bb04f58424..990ec3ab0c 100644
--- a/src/rpc/output_script.cpp
+++ b/src/rpc/output_script.cpp
@@ -162,7 +162,7 @@ static RPCHelpMan createmultisig()
// Only warns if the user has explicitly chosen an address type we cannot generate
warnings.push_back("Unable to make chosen address type, please ensure no uncompressed public keys are present.");
}
- if (!warnings.empty()) result.pushKV("warnings", warnings);
+ PushWarnings(warnings, result);
return result;
},
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 21d49fda9d..eb0200ccf5 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -51,8 +51,6 @@ using node::FindCoins;
using node::GetTransaction;
using node::NodeContext;
using node::PSBTAnalysis;
-using node::ReadBlockFromDisk;
-using node::UndoReadFromDisk;
static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry,
Chainstate& active_chainstate, const CTxUndo* txundo = nullptr,
@@ -172,6 +170,93 @@ static std::vector<RPCArg> CreateTxDoc()
};
}
+// Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors.
+// Optionally, sign the inputs that we can using information from the descriptors.
+PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std::any& context, const HidingSigningProvider& provider, int sighash_type, bool finalize)
+{
+ // Unserialize the transactions
+ PartiallySignedTransaction psbtx;
+ std::string error;
+ if (!DecodeBase64PSBT(psbtx, psbt_string, error)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
+ }
+
+ if (g_txindex) g_txindex->BlockUntilSyncedToCurrentChain();
+ const NodeContext& node = EnsureAnyNodeContext(context);
+
+ // If we can't find the corresponding full transaction for all of our inputs,
+ // this will be used to find just the utxos for the segwit inputs for which
+ // the full transaction isn't found
+ std::map<COutPoint, Coin> coins;
+
+ // Fetch previous transactions:
+ // First, look in the txindex and the mempool
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& psbt_input = psbtx.inputs.at(i);
+ const CTxIn& tx_in = psbtx.tx->vin.at(i);
+
+ // The `non_witness_utxo` is the whole previous transaction
+ if (psbt_input.non_witness_utxo) continue;
+
+ CTransactionRef tx;
+
+ // Look in the txindex
+ if (g_txindex) {
+ uint256 block_hash;
+ g_txindex->FindTx(tx_in.prevout.hash, block_hash, tx);
+ }
+ // If we still don't have it look in the mempool
+ if (!tx) {
+ tx = node.mempool->get(tx_in.prevout.hash);
+ }
+ if (tx) {
+ psbt_input.non_witness_utxo = tx;
+ } else {
+ coins[tx_in.prevout]; // Create empty map entry keyed by prevout
+ }
+ }
+
+ // If we still haven't found all of the inputs, look for the missing ones in the utxo set
+ if (!coins.empty()) {
+ FindCoins(node, coins);
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& input = psbtx.inputs.at(i);
+
+ // If there are still missing utxos, add them if they were found in the utxo set
+ if (!input.non_witness_utxo) {
+ const CTxIn& tx_in = psbtx.tx->vin.at(i);
+ const Coin& coin = coins.at(tx_in.prevout);
+ if (!coin.out.IsNull() && IsSegWitOutput(provider, coin.out.scriptPubKey)) {
+ input.witness_utxo = coin.out;
+ }
+ }
+ }
+ }
+
+ const PrecomputedTransactionData& txdata = PrecomputePSBTData(psbtx);
+
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ if (PSBTInputSigned(psbtx.inputs.at(i))) {
+ continue;
+ }
+
+ // Update script/keypath information using descriptor data.
+ // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures.
+ // We only actually care about those if our signing provider doesn't hide private
+ // information, as is the case with `descriptorprocesspsbt`
+ SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize);
+ }
+
+ // Update script/keypath information using descriptor data.
+ for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
+ UpdatePSBTOutput(provider, psbtx, i);
+ }
+
+ RemoveUnnecessaryTransactions(psbtx, /*sighash_type=*/1);
+
+ return psbtx;
+}
+
static RPCHelpMan getrawtransaction()
{
return RPCHelpMan{
@@ -277,7 +362,7 @@ static RPCHelpMan getrawtransaction()
}
uint256 hash_block;
- const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), hash, chainman.GetConsensus(), hash_block);
+ const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), hash, hash_block, chainman.m_blockman);
if (!tx) {
std::string errmsg;
if (blockindex) {
@@ -321,7 +406,7 @@ static RPCHelpMan getrawtransaction()
if (tx->IsCoinBase() ||
!blockindex || is_block_pruned ||
- !(UndoReadFromDisk(blockUndo, blockindex) && ReadBlockFromDisk(block, blockindex, Params().GetConsensus()))) {
+ !(chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex) && chainman.m_blockman.ReadBlockFromDisk(block, *blockindex))) {
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result;
}
@@ -1580,7 +1665,7 @@ static RPCHelpMan converttopsbt()
static RPCHelpMan utxoupdatepsbt()
{
return RPCHelpMan{"utxoupdatepsbt",
- "\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n",
+ "\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
{"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of either strings or objects", {
@@ -1599,13 +1684,6 @@ static RPCHelpMan utxoupdatepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- // Unserialize the transactions
- PartiallySignedTransaction psbtx;
- std::string error;
- if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
- }
-
// Parse descriptors, if any.
FlatSigningProvider provider;
if (!request.params[1].isNull()) {
@@ -1614,53 +1692,14 @@ static RPCHelpMan utxoupdatepsbt()
EvalDescriptorStringOrObject(descs[i], provider);
}
}
- // We don't actually need private keys further on; hide them as a precaution.
- HidingSigningProvider public_provider(&provider, /*hide_secret=*/true, /*hide_origin=*/false);
-
- // Fetch previous transactions (inputs):
- CCoinsView viewDummy;
- CCoinsViewCache view(&viewDummy);
- {
- NodeContext& node = EnsureAnyNodeContext(request.context);
- const CTxMemPool& mempool = EnsureMemPool(node);
- ChainstateManager& chainman = EnsureChainman(node);
- LOCK2(cs_main, mempool.cs);
- CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip();
- CCoinsViewMemPool viewMempool(&viewChain, mempool);
- view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
-
- for (const CTxIn& txin : psbtx.tx->vin) {
- view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
- }
-
- view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
- }
-
- // Fill the inputs
- const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- PSBTInput& input = psbtx.inputs.at(i);
-
- if (input.non_witness_utxo || !input.witness_utxo.IsNull()) {
- continue;
- }
-
- const Coin& coin = view.AccessCoin(psbtx.tx->vin[i].prevout);
-
- if (IsSegWitOutput(provider, coin.out.scriptPubKey)) {
- input.witness_utxo = coin.out;
- }
-
- // 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=*/1);
- }
- // Update script/keypath information using descriptor data.
- for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
- UpdatePSBTOutput(public_provider, psbtx, i);
- }
+ // We don't actually need private keys further on; hide them as a precaution.
+ const PartiallySignedTransaction& psbtx = ProcessPSBT(
+ request.params[0].get_str(),
+ request.context,
+ HidingSigningProvider(&provider, /*hide_secret=*/true, /*hide_origin=*/false),
+ /*sighash_type=*/SIGHASH_ALL,
+ /*finalize=*/false);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
@@ -1879,6 +1918,82 @@ static RPCHelpMan analyzepsbt()
};
}
+RPCHelpMan descriptorprocesspsbt()
+{
+ return RPCHelpMan{"descriptorprocesspsbt",
+ "\nUpdate all segwit inputs in a PSBT with information from output descriptors, the UTXO set or the mempool. \n"
+ "Then, sign the inputs we are able to with information from the output descriptors. ",
+ {
+ {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
+ {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of either strings or objects", {
+ {"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", {
+ {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
+ {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"},
+ }},
+ }},
+ {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT for Taproot, ALL otherwise"}, "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
+ " \"DEFAULT\"\n"
+ " \"ALL\"\n"
+ " \"NONE\"\n"
+ " \"SINGLE\"\n"
+ " \"ALL|ANYONECANPAY\"\n"
+ " \"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, "", "",
+ {
+ {RPCResult::Type::STR, "psbt", "The base64-encoded partially signed transaction"},
+ {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("descriptorprocesspsbt", "\"psbt\" \"[\\\"descriptor1\\\", \\\"descriptor2\\\"]\"") +
+ HelpExampleCli("descriptorprocesspsbt", "\"psbt\" \"[{\\\"desc\\\":\\\"mydescriptor\\\", \\\"range\\\":21}]\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ // Add descriptor information to a signing provider
+ FlatSigningProvider provider;
+
+ auto descs = request.params[1].get_array();
+ for (size_t i = 0; i < descs.size(); ++i) {
+ EvalDescriptorStringOrObject(descs[i], provider, /*expand_priv=*/true);
+ }
+
+ int sighash_type = ParseSighashString(request.params[2]);
+ bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
+ bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool();
+
+ const PartiallySignedTransaction& psbtx = ProcessPSBT(
+ request.params[0].get_str(),
+ request.context,
+ HidingSigningProvider(&provider, /*hide_secret=*/false, !bip32derivs),
+ sighash_type,
+ finalize);
+
+ // Check whether or not all of the inputs are now signed
+ bool complete = true;
+ for (const auto& input : psbtx.inputs) {
+ complete &= PSBTInputSigned(input);
+ }
+
+ CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
+ ssTx << psbtx;
+
+ UniValue result(UniValue::VOBJ);
+
+ result.pushKV("psbt", EncodeBase64(ssTx));
+ result.pushKV("complete", complete);
+
+ return result;
+},
+ };
+}
+
void RegisterRawTransactionRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
@@ -1894,6 +2009,7 @@ void RegisterRawTransactionRPCCommands(CRPCTable& t)
{"rawtransactions", &createpsbt},
{"rawtransactions", &converttopsbt},
{"rawtransactions", &utxoupdatepsbt},
+ {"rawtransactions", &descriptorprocesspsbt},
{"rawtransactions", &joinpsbts},
{"rawtransactions", &analyzepsbt},
};
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 3ba930f84f..3a6fa39e4d 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -36,7 +36,7 @@ void AddInputs(CMutableTransaction& rawTx, const UniValue& inputs_in, std::optio
uint256 txid = ParseHashO(o, "txid");
- const UniValue& vout_v = find_value(o, "vout");
+ const UniValue& vout_v = o.find_value("vout");
if (!vout_v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.getInt<int>();
@@ -54,7 +54,7 @@ void AddInputs(CMutableTransaction& rawTx, const UniValue& inputs_in, std::optio
}
// set the sequence number if passed in the parameters object
- const UniValue& sequenceObj = find_value(o, "sequence");
+ const UniValue& sequenceObj = o.find_value("sequence");
if (sequenceObj.isNum()) {
int64_t seqNr64 = sequenceObj.getInt<int64_t>();
if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) {
@@ -187,7 +187,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
uint256 txid = ParseHashO(prevOut, "txid");
- int nOut = find_value(prevOut, "vout").getInt<int>();
+ int nOut = prevOut.find_value("vout").getInt<int>();
if (nOut < 0) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative");
}
@@ -208,7 +208,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
newcoin.out.scriptPubKey = scriptPubKey;
newcoin.out.nValue = MAX_MONEY;
if (prevOut.exists("amount")) {
- newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
+ newcoin.out.nValue = AmountFromValue(prevOut.find_value("amount"));
}
newcoin.nHeight = 1;
coins[out] = std::move(newcoin);
@@ -223,8 +223,8 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
{"redeemScript", UniValueType(UniValue::VSTR)},
{"witnessScript", UniValueType(UniValue::VSTR)},
}, true);
- UniValue rs = find_value(prevOut, "redeemScript");
- UniValue ws = find_value(prevOut, "witnessScript");
+ const UniValue& rs{prevOut.find_value("redeemScript")};
+ const UniValue& ws{prevOut.find_value("witnessScript")};
if (rs.isNull() && ws.isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript/witnessScript");
}
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index b6ef1909c9..4c67da8b70 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -5,11 +5,13 @@
#include <rpc/request.h>
-#include <fs.h>
+#include <util/fs.h>
+#include <common/args.h>
+#include <logging.h>
#include <random.h>
#include <rpc/protocol.h>
-#include <util/system.h>
+#include <util/fs_helpers.h>
#include <util/strencodings.h>
#include <fstream>
@@ -86,7 +88,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
/** the umask determines what permissions are used to create this file -
- * these are set to 0077 in util/system.cpp.
+ * these are set to 0077 in common/system.cpp.
*/
std::ofstream file;
fs::path filepath_tmp = GetAuthCookieFile(true);
@@ -163,10 +165,10 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
const UniValue& request = valRequest.get_obj();
// Parse id now so errors from here on will have the id
- id = find_value(request, "id");
+ id = request.find_value("id");
// Parse method
- UniValue valMethod = find_value(request, "method");
+ const UniValue& valMethod{request.find_value("method")};
if (valMethod.isNull())
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
if (!valMethod.isStr())
@@ -179,7 +181,7 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
// Parse params
- UniValue valParams = find_value(request, "params");
+ const UniValue& valParams{request.find_value("params")};
if (valParams.isArray() || valParams.isObject())
params = valParams;
else if (valParams.isNull())
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 44d7e2676b..daf751111f 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -5,12 +5,14 @@
#include <rpc/server.h>
+#include <common/args.h>
+#include <common/system.h>
+#include <logging.h>
#include <rpc/util.h>
#include <shutdown.h>
#include <sync.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <boost/signals2/signal.hpp>
@@ -83,6 +85,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
std::string category;
std::set<intptr_t> setDone;
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
+ vCommands.reserve(mapCommands.size());
for (const auto& entry : mapCommands)
vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
@@ -389,7 +392,7 @@ std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
* Process named arguments into a vector of positional arguments, based on the
* passed-in specification for the RPC call's arguments.
*/
-static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
+static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::pair<std::string, bool>>& argNames)
{
JSONRPCRequest out = in;
out.params = UniValue(UniValue::VARR);
@@ -414,7 +417,9 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
// "args" parameter, if present.
int hole = 0;
int initial_hole_size = 0;
- for (const std::string &argNamePattern: argNames) {
+ const std::string* initial_param = nullptr;
+ UniValue options{UniValue::VOBJ};
+ for (const auto& [argNamePattern, named_only]: argNames) {
std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
auto fr = argsIn.end();
for (const std::string & argName : vargNames) {
@@ -423,7 +428,22 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
break;
}
}
- if (fr != argsIn.end()) {
+
+ // Handle named-only parameters by pushing them into a temporary options
+ // object, and then pushing the accumulated options as the next
+ // positional argument.
+ if (named_only) {
+ if (fr != argsIn.end()) {
+ if (options.exists(fr->first)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + fr->first + " specified multiple times");
+ }
+ options.pushKVEnd(fr->first, *fr->second);
+ argsIn.erase(fr);
+ }
+ continue;
+ }
+
+ if (!options.empty() || fr != argsIn.end()) {
for (int i = 0; i < hole; ++i) {
// Fill hole between specified parameters with JSON nulls,
// but not at the end (for backwards compatibility with calls
@@ -431,12 +451,26 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
out.params.push_back(UniValue());
}
hole = 0;
- out.params.push_back(*fr->second);
- argsIn.erase(fr);
+ if (!initial_param) initial_param = &argNamePattern;
} else {
hole += 1;
if (out.params.empty()) initial_hole_size = hole;
}
+
+ // If named input parameter "fr" is present, push it onto out.params. If
+ // options are present, push them onto out.params. If both are present,
+ // throw an error.
+ if (fr != argsIn.end()) {
+ if (!options.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + fr->first + " conflicts with parameter " + options.getKeys().front());
+ }
+ out.params.push_back(*fr->second);
+ argsIn.erase(fr);
+ }
+ if (!options.empty()) {
+ out.params.push_back(std::move(options));
+ options = UniValue{UniValue::VOBJ};
+ }
}
// If leftover "args" param was found, use it as a source of positional
// arguments and add named arguments after. This is a convenience for
@@ -444,9 +478,8 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
// arguments as described in doc/JSON-RPC-interface.md#parameter-passing
auto positional_args{argsIn.extract("args")};
if (positional_args && positional_args.mapped()->isArray()) {
- const bool has_named_arguments{initial_hole_size < (int)argNames.size()};
- if (initial_hole_size < (int)positional_args.mapped()->size() && has_named_arguments) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + argNames[initial_hole_size] + " specified twice both as positional and named argument");
+ if (initial_hole_size < (int)positional_args.mapped()->size() && initial_param) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + *initial_param + " specified twice both as positional and named argument");
}
// Assign positional_args to out.params and append named_args after.
UniValue named_args{std::move(out.params)};
@@ -513,6 +546,7 @@ static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& req
std::vector<std::string> CRPCTable::listCommands() const
{
std::vector<std::string> commandList;
+ commandList.reserve(mapCommands.size());
for (const auto& i : mapCommands) commandList.emplace_back(i.first);
return commandList;
}
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 01e8556050..24658ddb8b 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -95,7 +95,7 @@ public:
using Actor = std::function<bool(const JSONRPCRequest& request, UniValue& result, bool last_handler)>;
//! Constructor taking Actor callback supporting multiple handlers.
- CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::string> args, intptr_t unique_id)
+ CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::pair<std::string, bool>> args, intptr_t unique_id)
: category(std::move(category)), name(std::move(name)), actor(std::move(actor)), argNames(std::move(args)),
unique_id(unique_id)
{
@@ -115,7 +115,16 @@ public:
std::string category;
std::string name;
Actor actor;
- std::vector<std::string> argNames;
+ //! List of method arguments and whether they are named-only. Incoming RPC
+ //! requests contain a "params" field that can either be an array containing
+ //! unnamed arguments or an object containing named arguments. The
+ //! "argNames" vector is used in the latter case to transform the params
+ //! object into an array. Each argument in "argNames" gets mapped to a
+ //! unique position in the array, based on the order it is listed, unless
+ //! the argument is a named-only argument with argNames[x].second set to
+ //! true. Named-only arguments are combined into a JSON object that is
+ //! appended after other arguments, see transformNamedArguments for details.
+ std::vector<std::pair<std::string, bool>> argNames;
intptr_t unique_id;
};
diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp
index 7a708ec813..1d4afb3758 100644
--- a/src/rpc/server_util.cpp
+++ b/src/rpc/server_util.cpp
@@ -4,13 +4,14 @@
#include <rpc/server_util.h>
+#include <common/args.h>
#include <net_processing.h>
#include <node/context.h>
#include <policy/fees.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <txmempool.h>
-#include <util/system.h>
+#include <util/any.h>
#include <validation.h>
#include <any>
diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp
index 24b5d04115..d74959cecc 100644
--- a/src/rpc/txoutproof.cpp
+++ b/src/rpc/txoutproof.cpp
@@ -18,7 +18,6 @@
#include <validation.h>
using node::GetTransaction;
-using node::ReadBlockFromDisk;
static RPCHelpMan gettxoutproof()
{
@@ -85,7 +84,7 @@ static RPCHelpMan gettxoutproof()
}
if (pblockindex == nullptr) {
- const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), chainman.GetConsensus(), hashBlock);
+ const CTransactionRef tx = GetTransaction(/*block_index=*/nullptr, /*mempool=*/nullptr, *setTxids.begin(), hashBlock, chainman.m_blockman);
if (!tx || hashBlock.IsNull()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
}
@@ -98,7 +97,7 @@ static RPCHelpMan gettxoutproof()
}
CBlock block;
- if (!ReadBlockFromDisk(block, pblockindex, chainman.GetConsensus())) {
+ if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
}
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index a1020c3b2b..19e14f88df 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <clientversion.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <key_io.h>
#include <outputtype.h>
@@ -13,7 +14,6 @@
#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <tuple>
@@ -37,7 +37,7 @@ void RPCTypeCheckObj(const UniValue& o,
bool fStrict)
{
for (const auto& t : typesExpected) {
- const UniValue& v = find_value(o, t.first);
+ const UniValue& v = o.find_value(t.first);
if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
@@ -81,7 +81,7 @@ uint256 ParseHashV(const UniValue& v, std::string strName)
}
uint256 ParseHashO(const UniValue& o, std::string strKey)
{
- return ParseHashV(find_value(o, strKey), strKey);
+ return ParseHashV(o.find_value(strKey), strKey);
}
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
{
@@ -94,7 +94,7 @@ std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
}
std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
{
- return ParseHexV(find_value(o, strKey), strKey);
+ return ParseHexV(o.find_value(strKey), strKey);
}
namespace {
@@ -389,7 +389,8 @@ struct Sections {
case RPCArg::Type::NUM:
case RPCArg::Type::AMOUNT:
case RPCArg::Type::RANGE:
- case RPCArg::Type::BOOL: {
+ case RPCArg::Type::BOOL:
+ case RPCArg::Type::OBJ_NAMED_PARAMS: {
if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
if (arg.m_opts.type_str.size() != 0 && push_name) {
@@ -485,12 +486,32 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
m_results{std::move(results)},
m_examples{std::move(examples)}
{
- std::set<std::string> named_args;
+ // Map of parameter names and types just used to check whether the names are
+ // unique. Parameter names always need to be unique, with the exception that
+ // there can be pairs of POSITIONAL and NAMED parameters with the same name.
+ enum ParamType { POSITIONAL = 1, NAMED = 2, NAMED_ONLY = 4 };
+ std::map<std::string, int> param_names;
+
for (const auto& arg : m_args) {
std::vector<std::string> names = SplitString(arg.m_names, '|');
// Should have unique named arguments
for (const std::string& name : names) {
- CHECK_NONFATAL(named_args.insert(name).second);
+ auto& param_type = param_names[name];
+ CHECK_NONFATAL(!(param_type & POSITIONAL));
+ CHECK_NONFATAL(!(param_type & NAMED_ONLY));
+ param_type |= POSITIONAL;
+ }
+ if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {
+ for (const auto& inner : arg.m_inner) {
+ std::vector<std::string> inner_names = SplitString(inner.m_names, '|');
+ for (const std::string& inner_name : inner_names) {
+ auto& param_type = param_names[inner_name];
+ CHECK_NONFATAL(!(param_type & POSITIONAL) || inner.m_opts.also_positional);
+ CHECK_NONFATAL(!(param_type & NAMED));
+ CHECK_NONFATAL(!(param_type & NAMED_ONLY));
+ param_type |= inner.m_opts.also_positional ? NAMED : NAMED_ONLY;
+ }
+ }
}
// Default value type should match argument type only when defined
if (arg.m_fallback.index() == 2) {
@@ -605,11 +626,17 @@ bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
return num_required_args <= num_args && num_args <= m_args.size();
}
-std::vector<std::string> RPCHelpMan::GetArgNames() const
+std::vector<std::pair<std::string, bool>> RPCHelpMan::GetArgNames() const
{
- std::vector<std::string> ret;
+ std::vector<std::pair<std::string, bool>> ret;
+ ret.reserve(m_args.size());
for (const auto& arg : m_args) {
- ret.emplace_back(arg.m_names);
+ if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {
+ for (const auto& inner : arg.m_inner) {
+ ret.emplace_back(inner.m_names, /*named_only=*/true);
+ }
+ }
+ ret.emplace_back(arg.m_names, /*named_only=*/false);
}
return ret;
}
@@ -641,20 +668,31 @@ std::string RPCHelpMan::ToString() const
// Arguments
Sections sections;
+ Sections named_only_sections;
for (size_t i{0}; i < m_args.size(); ++i) {
const auto& arg = m_args.at(i);
if (arg.m_opts.hidden) break; // Any arg that follows is also hidden
- if (i == 0) ret += "\nArguments:\n";
-
// Push named argument name and description
sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true));
sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());
// Recursively push nested args
sections.Push(arg);
+
+ // Push named-only argument sections
+ if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {
+ for (const auto& arg_inner : arg.m_inner) {
+ named_only_sections.PushSection({arg_inner.GetFirstName(), arg_inner.ToDescriptionString(/*is_named_arg=*/true)});
+ named_only_sections.Push(arg_inner);
+ }
+ }
}
+
+ if (!sections.m_sections.empty()) ret += "\nArguments:\n";
ret += sections.ToString();
+ if (!named_only_sections.m_sections.empty()) ret += "\nNamed Arguments:\n";
+ ret += named_only_sections.ToString();
// Result
ret += m_results.ToDescriptionString();
@@ -668,17 +706,30 @@ std::string RPCHelpMan::ToString() const
UniValue RPCHelpMan::GetArgMap() const
{
UniValue arr{UniValue::VARR};
+
+ auto push_back_arg_info = [&arr](const std::string& rpc_name, int pos, const std::string& arg_name, const RPCArg::Type& type) {
+ UniValue map{UniValue::VARR};
+ map.push_back(rpc_name);
+ map.push_back(pos);
+ map.push_back(arg_name);
+ map.push_back(type == RPCArg::Type::STR ||
+ type == RPCArg::Type::STR_HEX);
+ arr.push_back(map);
+ };
+
for (int i{0}; i < int(m_args.size()); ++i) {
const auto& arg = m_args.at(i);
std::vector<std::string> arg_names = SplitString(arg.m_names, '|');
for (const auto& arg_name : arg_names) {
- UniValue map{UniValue::VARR};
- map.push_back(m_name);
- map.push_back(i);
- map.push_back(arg_name);
- map.push_back(arg.m_type == RPCArg::Type::STR ||
- arg.m_type == RPCArg::Type::STR_HEX);
- arr.push_back(map);
+ push_back_arg_info(m_name, i, arg_name, arg.m_type);
+ if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {
+ for (const auto& inner : arg.m_inner) {
+ std::vector<std::string> inner_names = SplitString(inner.m_names, '|');
+ for (const std::string& inner_name : inner_names) {
+ push_back_arg_info(m_name, i, inner_name, inner.m_type);
+ }
+ }
+ }
}
}
return arr;
@@ -707,6 +758,7 @@ static std::optional<UniValue::VType> ExpectedType(RPCArg::Type type)
return UniValue::VBOOL;
}
case Type::OBJ:
+ case Type::OBJ_NAMED_PARAMS:
case Type::OBJ_USER_KEYS: {
return UniValue::VOBJ;
}
@@ -732,12 +784,12 @@ UniValue RPCArg::MatchesType(const UniValue& request) const
std::string RPCArg::GetFirstName() const
{
- return m_names.substr(0, m_names.find("|"));
+ return m_names.substr(0, m_names.find('|'));
}
std::string RPCArg::GetName() const
{
- CHECK_NONFATAL(std::string::npos == m_names.find("|"));
+ CHECK_NONFATAL(std::string::npos == m_names.find('|'));
return m_names;
}
@@ -780,6 +832,7 @@ std::string RPCArg::ToDescriptionString(bool is_named_arg) const
break;
}
case Type::OBJ:
+ case Type::OBJ_NAMED_PARAMS:
case Type::OBJ_USER_KEYS: {
ret += "json object";
break;
@@ -808,6 +861,7 @@ std::string RPCArg::ToDescriptionString(bool is_named_arg) const
} // no default case, so the compiler can warn about missing cases
}
ret += ")";
+ if (m_type == Type::OBJ_NAMED_PARAMS) ret += " Options object that can be used to pass named arguments, listed below.";
ret += m_description.empty() ? "" : " " + m_description;
return ret;
}
@@ -1053,6 +1107,7 @@ std::string RPCArg::ToStringObj(const bool oneline) const
}
return res + "...]";
case Type::OBJ:
+ case Type::OBJ_NAMED_PARAMS:
case Type::OBJ_USER_KEYS:
// Currently unused, so avoid writing dead code
NONFATAL_UNREACHABLE();
@@ -1076,6 +1131,7 @@ std::string RPCArg::ToString(const bool oneline) const
return GetFirstName();
}
case Type::OBJ:
+ case Type::OBJ_NAMED_PARAMS:
case Type::OBJ_USER_KEYS: {
const std::string res = Join(m_inner, ",", [&](const RPCArg& i) { return i.ToStringObj(oneline); });
if (m_type == Type::OBJ) {
@@ -1125,17 +1181,17 @@ std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value)
return {low, high};
}
-std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider)
+std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider, const bool expand_priv)
{
std::string desc_str;
std::pair<int64_t, int64_t> range = {0, 1000};
if (scanobject.isStr()) {
desc_str = scanobject.get_str();
} else if (scanobject.isObject()) {
- UniValue desc_uni = find_value(scanobject, "desc");
+ const UniValue& desc_uni{scanobject.find_value("desc")};
if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
desc_str = desc_uni.get_str();
- UniValue range_uni = find_value(scanobject, "range");
+ const UniValue& range_uni{scanobject.find_value("range")};
if (!range_uni.isNull()) {
range = ParseDescriptorRange(range_uni);
}
@@ -1158,6 +1214,9 @@ std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, Fl
if (!desc->Expand(i, provider, scripts, provider)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
}
+ if (expand_priv) {
+ desc->ExpandPrivate(/*pos=*/i, provider, /*out=*/provider);
+ }
std::move(scripts.begin(), scripts.end(), std::back_inserter(ret));
}
return ret;
@@ -1173,3 +1232,26 @@ UniValue GetServicesNames(ServiceFlags services)
return servicesNames;
}
+
+/** Convert a vector of bilingual strings to a UniValue::VARR containing their original untranslated values. */
+[[nodiscard]] static UniValue BilingualStringsToUniValue(const std::vector<bilingual_str>& bilingual_strings)
+{
+ CHECK_NONFATAL(!bilingual_strings.empty());
+ UniValue result{UniValue::VARR};
+ for (const auto& s : bilingual_strings) {
+ result.push_back(s.original);
+ }
+ return result;
+}
+
+void PushWarnings(const UniValue& warnings, UniValue& obj)
+{
+ if (warnings.empty()) return;
+ obj.pushKV("warnings", warnings);
+}
+
+void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj)
+{
+ if (warnings.empty()) return;
+ obj.pushKV("warnings", BilingualStringsToUniValue(warnings));
+}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index e3783c8f76..4cba5a9818 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -110,7 +110,7 @@ UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_s
std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value);
/** Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range of 1000. */
-std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider);
+std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider, const bool expand_priv = false);
/** Returns, given services flags, a list of humanly readable (known) network services */
UniValue GetServicesNames(ServiceFlags services);
@@ -130,6 +130,15 @@ struct RPCArgOptions {
std::string oneline_description{}; //!< Should be empty unless it is supposed to override the auto-generated summary line
std::vector<std::string> type_str{}; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_opts.type_str.at(0) will override the type of the value in a key-value pair, m_opts.type_str.at(1) will override the type in the argument description.
bool hidden{false}; //!< For testing only
+ bool also_positional{false}; //!< If set allows a named-parameter field in an OBJ_NAMED_PARAM options object
+ //!< to have the same name as a top-level parameter. By default the RPC
+ //!< framework disallows this, because if an RPC request passes the value by
+ //!< name, it is assigned to top-level parameter position, not to the options
+ //!< position, defeating the purpose of using OBJ_NAMED_PARAMS instead OBJ for
+ //!< that option. But sometimes it makes sense to allow less-commonly used
+ //!< options to be passed by name only, and more commonly used options to be
+ //!< passed by name or position, so the RPC framework allows this as long as
+ //!< methods set the also_positional flag and read values from both positions.
};
struct RPCArg {
@@ -139,6 +148,13 @@ struct RPCArg {
STR,
NUM,
BOOL,
+ OBJ_NAMED_PARAMS, //!< Special type that behaves almost exactly like
+ //!< OBJ, defining an options object with a list of
+ //!< pre-defined keys. The only difference between OBJ
+ //!< and OBJ_NAMED_PARAMS is that OBJ_NAMED_PARMS
+ //!< also allows the keys to be passed as top-level
+ //!< named parameters, as a more convenient way to pass
+ //!< options to the RPC method without nesting them.
OBJ_USER_KEYS, //!< Special type where the user must set the keys e.g. to define multiple addresses; as opposed to e.g. an options object where the keys are predefined
AMOUNT, //!< Special type representing a floating point amount (can be either NUM or STR)
STR_HEX, //!< Special type that is a STR with only hex chars
@@ -183,7 +199,7 @@ struct RPCArg {
m_description{std::move(description)},
m_opts{std::move(opts)}
{
- CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ && type != Type::OBJ_USER_KEYS);
+ CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ && type != Type::OBJ_NAMED_PARAMS && type != Type::OBJ_USER_KEYS);
}
RPCArg(
@@ -200,7 +216,7 @@ struct RPCArg {
m_description{std::move(description)},
m_opts{std::move(opts)}
{
- CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ || type == Type::OBJ_USER_KEYS);
+ CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ || type == Type::OBJ_NAMED_PARAMS || type == Type::OBJ_USER_KEYS);
}
bool IsOptional() const;
@@ -369,7 +385,8 @@ public:
UniValue GetArgMap() const;
/** If the supplied number of args is neither too small nor too high */
bool IsValidNumArgs(size_t num_args) const;
- std::vector<std::string> GetArgNames() const;
+ //! Return list of arguments and whether they are named-only.
+ std::vector<std::pair<std::string, bool>> GetArgNames() const;
const std::string m_name;
@@ -381,4 +398,13 @@ private:
const RPCExamples m_examples;
};
+/**
+ * Push warning messages to an RPC "warnings" field as a JSON array of strings.
+ *
+ * @param[in] warnings Warning messages to push.
+ * @param[out] obj UniValue object to push the warnings array object to.
+ */
+void PushWarnings(const UniValue& warnings, UniValue& obj);
+void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj);
+
#endif // BITCOIN_RPC_UTIL_H
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 857fee1818..b8ade1684a 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -12,10 +12,10 @@
#include <script/standard.h>
#include <uint256.h>
+#include <common/args.h>
#include <span.h>
#include <util/bip32.h>
#include <util/spanparsing.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <util/vector.h>
@@ -197,7 +197,9 @@ public:
/** Get the descriptor string form including private data (if available in arg). */
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
- /** Get the descriptor string form with the xpub at the last hardened derivation */
+ /** Get the descriptor string form with the xpub at the last hardened derivation,
+ * and always use h for hardened derivation.
+ */
virtual bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache = nullptr) const = 0;
/** Derive a private key, if private data is available in arg. */
@@ -208,14 +210,15 @@ class OriginPubkeyProvider final : public PubkeyProvider
{
KeyOriginInfo m_origin;
std::unique_ptr<PubkeyProvider> m_provider;
+ bool m_apostrophe;
- std::string OriginString() const
+ std::string OriginString(bool normalized=false) const
{
- return HexStr(m_origin.fingerprint) + FormatHDKeypath(m_origin.path);
+ return HexStr(m_origin.fingerprint) + FormatHDKeypath(m_origin.path, /*apostrophe=*/!normalized && m_apostrophe);
}
public:
- OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)) {}
+ OriginPubkeyProvider(uint32_t exp_index, KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider, bool apostrophe) : PubkeyProvider(exp_index), m_origin(std::move(info)), m_provider(std::move(provider)), m_apostrophe(apostrophe) {}
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
{
if (!m_provider->GetPubKey(pos, arg, key, info, read_cache, write_cache)) return false;
@@ -242,9 +245,9 @@ public:
// and append that to our own origin string.
if (sub[0] == '[') {
sub = sub.substr(9);
- ret = "[" + OriginString() + std::move(sub);
+ ret = "[" + OriginString(/*normalized=*/true) + std::move(sub);
} else {
- ret = "[" + OriginString() + "]" + std::move(sub);
+ ret = "[" + OriginString(/*normalized=*/true) + "]" + std::move(sub);
}
return true;
}
@@ -312,6 +315,8 @@ class BIP32PubkeyProvider final : public PubkeyProvider
CExtPubKey m_root_extkey;
KeyPath m_path;
DeriveType m_derive;
+ // Whether ' or h is used in harded derivation
+ bool m_apostrophe;
bool GetExtKey(const SigningProvider& arg, CExtKey& ret) const
{
@@ -348,7 +353,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
}
public:
- BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
+ BIP32PubkeyProvider(uint32_t exp_index, const CExtPubKey& extkey, KeyPath path, DeriveType derive, bool apostrophe) : PubkeyProvider(exp_index), m_root_extkey(extkey), m_path(std::move(path)), m_derive(derive), m_apostrophe(apostrophe) {}
bool IsRange() const override { return m_derive != DeriveType::NO; }
size_t GetSize() const override { return 33; }
bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key_out, KeyOriginInfo& final_info_out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override
@@ -416,31 +421,36 @@ public:
return true;
}
- std::string ToString() const override
+ std::string ToString(bool normalized) const
{
- std::string ret = EncodeExtPubKey(m_root_extkey) + FormatHDKeypath(m_path);
+ const bool use_apostrophe = !normalized && m_apostrophe;
+ std::string ret = EncodeExtPubKey(m_root_extkey) + FormatHDKeypath(m_path, /*apostrophe=*/use_apostrophe);
if (IsRange()) {
ret += "/*";
- if (m_derive == DeriveType::HARDENED) ret += '\'';
+ if (m_derive == DeriveType::HARDENED) ret += use_apostrophe ? '\'' : 'h';
}
return ret;
}
+ std::string ToString() const override
+ {
+ return ToString(/*normalized=*/false);
+ }
bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
{
CExtKey key;
if (!GetExtKey(arg, key)) return false;
- out = EncodeExtKey(key) + FormatHDKeypath(m_path);
+ out = EncodeExtKey(key) + FormatHDKeypath(m_path, /*apostrophe=*/m_apostrophe);
if (IsRange()) {
out += "/*";
- if (m_derive == DeriveType::HARDENED) out += '\'';
+ if (m_derive == DeriveType::HARDENED) out += m_apostrophe ? '\'' : 'h';
}
return true;
}
bool ToNormalizedString(const SigningProvider& arg, std::string& out, const DescriptorCache* cache) const override
{
- // For hardened derivation type, just return the typical string, nothing to normalize
if (m_derive == DeriveType::HARDENED) {
- out = ToString();
+ out = ToString(/*normalized=*/true);
+
return true;
}
// Step backwards to find the last hardened step in the path
@@ -830,6 +840,7 @@ protected:
std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript>, FlatSigningProvider&) const override {
CScript ret;
std::vector<XOnlyPubKey> xkeys;
+ xkeys.reserve(keys.size());
for (const auto& key : keys) xkeys.emplace_back(key);
if (m_sorted) std::sort(xkeys.begin(), xkeys.end());
ret << ToByteVector(xkeys[0]) << OP_CHECKSIG;
@@ -1048,15 +1059,27 @@ enum class ParseScriptContext {
P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf)
};
-/** Parse a key path, being passed a split list of elements (the first element is ignored). */
-[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error)
+/**
+ * Parse a key path, being passed a split list of elements (the first element is ignored).
+ *
+ * @param[in] split BIP32 path string, using either ' or h for hardened derivation
+ * @param[out] out the key path
+ * @param[out] apostrophe only updated if hardened derivation is found
+ * @param[out] error parsing error message
+ * @returns false if parsing failed
+ **/
+[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, bool& apostrophe, std::string& error)
{
for (size_t i = 1; i < split.size(); ++i) {
Span<const char> elem = split[i];
bool hardened = false;
- if (elem.size() > 0 && (elem[elem.size() - 1] == '\'' || elem[elem.size() - 1] == 'h')) {
- elem = elem.first(elem.size() - 1);
- hardened = true;
+ if (elem.size() > 0) {
+ const char last = elem[elem.size() - 1];
+ if (last == '\'' || last == 'h') {
+ elem = elem.first(elem.size() - 1);
+ hardened = true;
+ apostrophe = last == '\'';
+ }
}
uint32_t p;
if (!ParseUInt32(std::string(elem.begin(), elem.end()), &p)) {
@@ -1072,7 +1095,7 @@ enum class ParseScriptContext {
}
/** Parse a public key that excludes origin information. */
-std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error)
+std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out, bool& apostrophe, std::string& error)
{
using namespace spanparsing;
@@ -1129,15 +1152,16 @@ std::unique_ptr<PubkeyProvider> ParsePubkeyInner(uint32_t key_exp_index, const S
split.pop_back();
type = DeriveType::UNHARDENED;
} else if (split.back() == Span{"*'"}.first(2) || split.back() == Span{"*h"}.first(2)) {
+ apostrophe = split.back() == Span{"*'"}.first(2);
split.pop_back();
type = DeriveType::HARDENED;
}
- if (!ParseKeyPath(split, path, error)) return nullptr;
+ if (!ParseKeyPath(split, path, apostrophe, error)) return nullptr;
if (extkey.key.IsValid()) {
extpubkey = extkey.Neuter();
out.keys.emplace(extpubkey.pubkey.GetID(), extkey.key);
}
- return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type);
+ return std::make_unique<BIP32PubkeyProvider>(key_exp_index, extpubkey, std::move(path), type, apostrophe);
}
/** Parse a public key including origin information (if enabled). */
@@ -1150,7 +1174,11 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
error = "Multiple ']' characters found for a single pubkey";
return nullptr;
}
- if (origin_split.size() == 1) return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, error);
+ // This is set if either the origin or path suffix contains a hardened derivation.
+ bool apostrophe = false;
+ if (origin_split.size() == 1) {
+ return ParsePubkeyInner(key_exp_index, origin_split[0], ctx, out, apostrophe, error);
+ }
if (origin_split[0].empty() || origin_split[0][0] != '[') {
error = strprintf("Key origin start '[ character expected but not found, got '%c' instead",
origin_split[0].empty() ? /** empty, implies split char */ ']' : origin_split[0][0]);
@@ -1171,10 +1199,10 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(uint32_t key_exp_index, const Span<c
static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes");
assert(fpr_bytes.size() == 4);
std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
- if (!ParseKeyPath(slash_split, info.path, error)) return nullptr;
- auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, error);
+ if (!ParseKeyPath(slash_split, info.path, apostrophe, error)) return nullptr;
+ auto provider = ParsePubkeyInner(key_exp_index, origin_split[1], ctx, out, apostrophe, error);
if (!provider) return nullptr;
- return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider));
+ return std::make_unique<OriginPubkeyProvider>(key_exp_index, std::move(info), std::move(provider), apostrophe);
}
std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptContext, const SigningProvider& provider)
@@ -1182,7 +1210,7 @@ std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptCo
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, false);
KeyOriginInfo info;
if (provider.GetKeyOrigin(pubkey.GetID(), info)) {
- return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
+ return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider), /*apostrophe=*/false);
}
return key_provider;
}
@@ -1195,7 +1223,7 @@ std::unique_ptr<PubkeyProvider> InferXOnlyPubkey(const XOnlyPubKey& xkey, ParseS
std::unique_ptr<PubkeyProvider> key_provider = std::make_unique<ConstPubkeyProvider>(0, pubkey, true);
KeyOriginInfo info;
if (provider.GetKeyOriginByXOnly(xkey, info)) {
- return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider));
+ return std::make_unique<OriginPubkeyProvider>(0, std::move(info), std::move(key_provider), /*apostrophe=*/false);
}
return key_provider;
}
diff --git a/src/script/miniscript.h b/src/script/miniscript.h
index bb42bf3c92..7c1a87a7dc 100644
--- a/src/script/miniscript.h
+++ b/src/script/miniscript.h
@@ -1194,7 +1194,7 @@ public:
case Fragment::OR_I:
return subs[0] || subs[1];
case Fragment::THRESH:
- return std::count(subs.begin(), subs.end(), true) >= node.k;
+ return static_cast<uint32_t>(std::count(subs.begin(), subs.end(), true)) >= node.k;
default: // wrappers
assert(subs.size() == 1);
return subs[0];
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index fef3601887..7c6c282cc4 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -5,10 +5,11 @@
#include <script/sigcache.h>
+#include <common/system.h>
+#include <logging.h>
#include <pubkey.h>
#include <random.h>
#include <uint256.h>
-#include <util/system.h>
#include <cuckoocache.h>
diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml
index 0b904a4e38..5a00b65a33 100644
--- a/src/secp256k1/.cirrus.yml
+++ b/src/secp256k1/.cirrus.yml
@@ -21,6 +21,7 @@ env:
ECDH: no
RECOVERY: no
SCHNORRSIG: no
+ ELLSWIFT: no
### test options
SECP256K1_TEST_ITERS:
BENCH: yes
@@ -74,12 +75,12 @@ task:
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128}
- - env: {WIDEMUL: int128_struct}
- - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
+ - env: {WIDEMUL: int128_struct, ELLSWIFT: yes}
+ - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- - env: {WIDEMUL: int128, ASM: x86_64}
+ - env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes}
- env: { RECOVERY: yes, SCHNORRSIG: yes}
- env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
@@ -154,6 +155,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
<< : *MERGE_BASE
test_script:
@@ -173,10 +175,11 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
matrix:
- env: {}
- - env: {EXPERIMENTAL: yes, ASM: arm}
+ - env: {EXPERIMENTAL: yes, ASM: arm32}
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -193,6 +196,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
<< : *MERGE_BASE
test_script:
@@ -210,6 +214,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
<< : *MERGE_BASE
test_script:
@@ -247,6 +252,7 @@ task:
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
# This will detect some MinGW-w64 tools but then make will need only
@@ -286,6 +292,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
CTIMETESTS: no
matrix:
- name: "Valgrind (memcheck)"
@@ -361,6 +368,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
+ ELLSWIFT: yes
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
@@ -397,13 +405,13 @@ task:
- PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
configure_script:
- '%x64_NATIVE_TOOLS%'
- - cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
+ - cmake -E env CFLAGS="/WX" cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
build_script:
- '%x64_NATIVE_TOOLS%'
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
check_script:
- '%x64_NATIVE_TOOLS%'
- - ctest --test-dir build -j 5
+ - ctest -C RelWithDebInfo --test-dir build -j 5
- build\src\RelWithDebInfo\bench_ecmult.exe
- build\src\RelWithDebInfo\bench_internal.exe
- build\src\RelWithDebInfo\bench.exe
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index bc7e499de7..574902b8b5 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -59,5 +59,7 @@ build-aux/compile
build-aux/test-driver
libsecp256k1.pc
+### CMake
+/CMakeUserPresets.json
# Default CMake build directory.
/build
diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md
index 7f43843641..8e31edc6ee 100644
--- a/src/secp256k1/CHANGELOG.md
+++ b/src/secp256k1/CHANGELOG.md
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.3.2] - 2023-05-13
+We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
+
+#### Security
+ - Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1.
+
+#### Fixed
+ - Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far.
+
+#### Changed
+ - Various improvements and changes to CMake builds. CMake builds remain experimental.
+ - Made API versioning consistent with GNU Autotools builds.
+ - Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library.
+ - Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts.
+ - Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake).
+
+#### ABI Compatibility
+The ABI is compatible with versions 0.3.0 and 0.3.1.
+
+## [0.3.1] - 2023-04-10
+We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`.
+
+#### Security
+ - Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14.
+
+#### Added
+ - Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases.
+
+#### Changed
+ - Increased minimum required CMake version to 3.13. CMake builds remain experimental.
+
+#### ABI Compatibility
+The ABI is compatible with version 0.3.0.
+
## [0.3.0] - 2023-03-08
#### Added
@@ -25,7 +59,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
#### ABI Compatibility
-
Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions.
## [0.2.0] - 2022-12-12
@@ -45,7 +78,6 @@ Due to changes in the API regarding `secp256k1_context_static` described above,
- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
#### ABI Compatibility
-
Since this is the first release, we do not compare application binary interfaces.
However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
@@ -55,7 +87,9 @@ This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
Therefore, this version number does not uniquely identify a set of source files.
-[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...HEAD
+[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD
+[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2
+[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93
diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt
index 5c8aad6fcc..3107eb3bf1 100644
--- a/src/secp256k1/CMakeLists.txt
+++ b/src/secp256k1/CMakeLists.txt
@@ -1,16 +1,33 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.13)
-if(CMAKE_VERSION VERSION_GREATER 3.14)
+if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
# MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction.
cmake_policy(SET CMP0091 NEW)
# MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.
cmake_policy(SET CMP0092 NEW)
endif()
-# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
-# the API. All changes in experimental modules are treated as
-# backwards-compatible and therefore at most increase the minor version.
-project(libsecp256k1 VERSION 0.3.0 LANGUAGES C)
+project(libsecp256k1
+ # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
+ # the API. All changes in experimental modules are treated as
+ # backwards-compatible and therefore at most increase the minor version.
+ VERSION 0.3.3
+ DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
+ HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
+ LANGUAGES C
+)
+
+if(CMAKE_VERSION VERSION_LESS 3.21)
+ get_directory_property(parent_directory PARENT_DIRECTORY)
+ if(parent_directory)
+ set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ else()
+ set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
+ endif()
+ unset(parent_directory)
+endif()
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
@@ -18,7 +35,7 @@ project(libsecp256k1 VERSION 0.3.0 LANGUAGES C)
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2)
-set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
+set(${PROJECT_NAME}_LIB_VERSION_REVISION 3)
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
set(CMAKE_C_STANDARD 90)
@@ -26,36 +43,42 @@ set(CMAKE_C_EXTENSIONS OFF)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
-# We do not use CMake's BUILD_SHARED_LIBS option.
-option(SECP256K1_BUILD_SHARED "Build shared library." ON)
-option(SECP256K1_BUILD_STATIC "Build static library." ON)
-if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC)
- message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.")
+option(BUILD_SHARED_LIBS "Build shared libraries." ON)
+option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
+if(SECP256K1_DISABLE_SHARED)
+ set(BUILD_SHARED_LIBS OFF)
endif()
+option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
+
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
if(SECP256K1_ENABLE_MODULE_ECDH)
- add_definitions(-DENABLE_MODULE_ECDH=1)
+ add_compile_definitions(ENABLE_MODULE_ECDH=1)
endif()
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
if(SECP256K1_ENABLE_MODULE_RECOVERY)
- add_definitions(-DENABLE_MODULE_RECOVERY=1)
+ add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
endif()
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
- add_definitions(-DENABLE_MODULE_SCHNORRSIG=1)
+ add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
endif()
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- add_definitions(-DENABLE_MODULE_EXTRAKEYS=1)
+ add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
+endif()
+
+option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
+if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
+ add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
endif()
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
- add_definitions(-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1)
+ add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
endif()
set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]")
@@ -65,7 +88,7 @@ check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO")
set(SECP256K1_ECMULT_WINDOW_SIZE 15)
endif()
-add_definitions(-DECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
+add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]")
set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8)
@@ -73,29 +96,35 @@ check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS)
if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO")
set(SECP256K1_ECMULT_GEN_PREC_BITS 4)
endif()
-add_definitions(-DECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
+add_compile_definitions(ECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
- add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1)
+ add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1)
endif()
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
-set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]")
-set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm")
+set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
+set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
check_string_option_value(SECP256K1_ASM)
-if(SECP256K1_ASM STREQUAL "arm")
+if(SECP256K1_ASM STREQUAL "arm32")
enable_language(ASM)
- add_definitions(-DUSE_EXTERNAL_ASM=1)
+ include(CheckArm32Assembly)
+ check_arm32_assembly()
+ if(HAVE_ARM32_ASM)
+ add_compile_definitions(USE_EXTERNAL_ASM=1)
+ else()
+ message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
+ endif()
elseif(SECP256K1_ASM)
- include(Check64bitAssembly)
- check_64bit_assembly()
- if(HAS_64BIT_ASM)
+ include(CheckX86_64Assembly)
+ check_x86_64_assembly()
+ if(HAVE_X86_64_ASM)
set(SECP256K1_ASM "x86_64")
- add_definitions(-DUSE_ASM_X86_64=1)
+ add_compile_definitions(USE_ASM_X86_64=1)
elseif(SECP256K1_ASM STREQUAL "AUTO")
set(SECP256K1_ASM "OFF")
else()
@@ -105,8 +134,8 @@ endif()
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
if(NOT SECP256K1_EXPERIMENTAL)
- if(SECP256K1_ASM STREQUAL "arm")
- message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
+ if(SECP256K1_ASM STREQUAL "arm32")
+ message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
endif()
endif()
@@ -118,7 +147,7 @@ if(SECP256K1_VALGRIND)
if(Valgrind_FOUND)
set(SECP256K1_VALGRIND ON)
include_directories(${Valgrind_INCLUDE_DIR})
- add_definitions(-DVALGRIND)
+ add_compile_definitions(VALGRIND)
elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
set(SECP256K1_VALGRIND OFF)
else()
@@ -147,7 +176,7 @@ else()
endif()
# Define custom "Coverage" build type.
-set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage -Wno-unused-parameter" CACHE STRING
+set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING
"Flags used by the C compiler during \"Coverage\" builds."
FORCE
)
@@ -165,49 +194,53 @@ mark_as_advanced(
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)
-if(CMAKE_CONFIGURATION_TYPES)
- set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage")
-endif()
-
-get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE)
-if(cached_cmake_build_type)
+get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+set(default_build_type "RelWithDebInfo")
+if(is_multi_config)
+ set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
+ "Supported configuration types."
+ FORCE
+ )
+else()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
- STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage"
+ STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
)
+ if(NOT CMAKE_BUILD_TYPE)
+ message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
+ set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
+ "Choose the type of build."
+ FORCE
+ )
+ endif()
endif()
-set(default_build_type "RelWithDebInfo")
-if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
- message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
- set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
-endif()
-
-include(TryAddCompileOption)
+include(TryAppendCFlags)
if(MSVC)
- try_add_compile_option(/W2)
- try_add_compile_option(/wd4146)
+ # Keep the following commands ordered lexicographically.
+ try_append_c_flags(/W3) # Production quality warning level.
+ try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
+ try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
+ try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
+ # Eliminate deprecation warnings for the older, less secure functions.
+ add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
- try_add_compile_option(-pedantic)
- try_add_compile_option(-Wall)
- try_add_compile_option(-Wcast-align)
- try_add_compile_option(-Wcast-align=strict)
- try_add_compile_option(-Wconditional-uninitialized)
- try_add_compile_option(-Wextra)
- try_add_compile_option(-Wnested-externs)
- try_add_compile_option(-Wno-long-long)
- try_add_compile_option(-Wno-overlength-strings)
- try_add_compile_option(-Wno-unused-function)
- try_add_compile_option(-Wreserved-identifier)
- try_add_compile_option(-Wshadow)
- try_add_compile_option(-Wstrict-prototypes)
- try_add_compile_option(-Wundef)
+ # Keep the following commands ordered lexicographically.
+ try_append_c_flags(-pedantic)
+ try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers.
+ try_append_c_flags(-Wcast-align) # GCC >= 2.95.
+ try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0.
+ try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only.
+ try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
+ try_append_c_flags(-Wnested-externs)
+ try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
+ try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
+ try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall.
+ try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only.
+ try_append_c_flags(-Wshadow)
+ try_append_c_flags(-Wstrict-prototypes)
+ try_append_c_flags(-Wundef)
endif()
-if(CMAKE_VERSION VERSION_GREATER 3.2)
- # Honor visibility properties for all target types.
- # See: https://cmake.org/cmake/help/latest/policy/CMP0063.html
- cmake_policy(SET CMP0063 NEW)
-endif()
set(CMAKE_C_VISIBILITY_PRESET hidden)
# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target.
@@ -230,13 +263,19 @@ message("\n")
message("secp256k1 configure summary")
message("===========================")
message("Build artifacts:")
-message(" shared library ...................... ${SECP256K1_BUILD_SHARED}")
-message(" static library ...................... ${SECP256K1_BUILD_STATIC}")
+if(BUILD_SHARED_LIBS)
+ set(library_type "Shared")
+else()
+ set(library_type "Static")
+endif()
+
+message(" library type ........................ ${library_type}")
message("Optional modules:")
message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
+message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
@@ -273,7 +312,7 @@ message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
get_directory_property(compile_options COMPILE_OPTIONS)
string(REPLACE ";" " " compile_options "${compile_options}")
message("Compile options ....................... " ${compile_options})
-if(DEFINED CMAKE_BUILD_TYPE)
+if(NOT is_multi_config)
message("Build type:")
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
@@ -281,7 +320,7 @@ if(DEFINED CMAKE_BUILD_TYPE)
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
else()
- message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
+ message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
message("RelWithDebInfo configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
diff --git a/src/secp256k1/CMakePresets.json b/src/secp256k1/CMakePresets.json
new file mode 100644
index 0000000000..b35cd80579
--- /dev/null
+++ b/src/secp256k1/CMakePresets.json
@@ -0,0 +1,19 @@
+{
+ "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0},
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "dev-mode",
+ "displayName": "Development mode (intended only for developers of the library)",
+ "cacheVariables": {
+ "SECP256K1_EXPERIMENTAL": "ON",
+ "SECP256K1_ENABLE_MODULE_RECOVERY": "ON",
+ "SECP256K1_BUILD_EXAMPLES": "ON"
+ },
+ "warnings": {
+ "dev": true,
+ "uninitialized": true
+ }
+ }
+ ]
+}
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index e3fdf4da27..ee14ac4509 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -1,5 +1,3 @@
-.PHONY: clean-precomp precomp
-
ACLOCAL_AMFLAGS = -I build-aux/m4
# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo
@@ -65,6 +63,7 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
+noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
@@ -190,11 +189,11 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
CLEANFILES = $(EXTRA_PROGRAMS)
precompute_ecmult_SOURCES = src/precompute_ecmult.c
-precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
precompute_ecmult_LDADD = $(COMMON_LIB)
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
-precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
+precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# See Automake manual, Section "Errors with distclean".
@@ -202,7 +201,7 @@ precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# otherwise make's decision whether to rebuild them (even in the first
# build by a normal user) depends on mtimes, and thus is very fragile.
# This means that rebuilds of the prebuilt files always need to be
-# forced by deleting them, e.g., by invoking `make clean-precomp`.
+# forced by deleting them.
src/precomputed_ecmult.c:
$(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT)
./precompute_ecmult$(EXEEXT)
@@ -217,11 +216,29 @@ precomp: $(PRECOMP)
# e.g., after `make maintainer-clean`).
BUILT_SOURCES = $(PRECOMP)
-maintainer-clean-local: clean-precomp
-
+.PHONY: clean-precomp
clean-precomp:
rm -f $(PRECOMP)
+maintainer-clean-local: clean-precomp
+
+### Pregenerated test vectors
+### (see the comments in the previous section for detailed rationale)
+TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
+
+src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h:
+ mkdir -p $(@D)
+ python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@
+testvectors: $(TESTVECTORS)
+
+BUILT_SOURCES += $(TESTVECTORS)
+
+.PHONY: clean-testvectors
+clean-testvectors:
+ rm -f $(TESTVECTORS)
+maintainer-clean-local: clean-testvectors
+
+### Additional files to distribute
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
EXTRA_DIST += examples/EXAMPLES_COPYING
@@ -231,6 +248,9 @@ EXTRA_DIST += sage/group_prover.sage
EXTRA_DIST += sage/prove_group_implementations.sage
EXTRA_DIST += sage/secp256k1_params.sage
EXTRA_DIST += sage/weierstrass_prover.sage
+EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING
+EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
+EXTRA_DIST += tools/tests_wycheproof_generate.py
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
@@ -247,3 +267,7 @@ endif
if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif
+
+if ENABLE_MODULE_ELLSWIFT
+include src/modules/ellswift/Makefile.am.include
+endif
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index 624f5e956e..11adef4f22 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -1,12 +1,31 @@
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
-AC_DEFUN([SECP_64BIT_ASM_CHECK],[
+AC_DEFUN([SECP_X86_64_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
- ]])],[has_64bit_asm=yes],[has_64bit_asm=no])
-AC_MSG_RESULT([$has_64bit_asm])
+ ]])], [has_x86_64_asm=yes], [has_x86_64_asm=no])
+AC_MSG_RESULT([$has_x86_64_asm])
+])
+
+AC_DEFUN([SECP_ARM32_ASM_CHECK], [
+ AC_MSG_CHECKING(for ARM32 assembly availability)
+ SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS"
+ CFLAGS="-x assembler"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[
+ .syntax unified
+ .eabi_attribute 24, 1
+ .eabi_attribute 25, 1
+ .text
+ .global main
+ main:
+ ldr r0, =0x002A
+ mov r7, #1
+ swi 0
+ ]])], [has_arm32_asm=yes], [has_arm32_asm=no])
+ AC_MSG_RESULT([$has_arm32_asm])
+ CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS"
])
AC_DEFUN([SECP_VALGRIND_CHECK],[
@@ -21,6 +40,7 @@ if test x"$has_valgrind" != x"yes"; then
# error "Valgrind does not support this platform."
#endif
]])], [has_valgrind=yes])
+ CPPFLAGS="$CPPFLAGS_TEMP"
fi
AC_MSG_RESULT($has_valgrind)
])
diff --git a/src/secp256k1/ci/cirrus.sh b/src/secp256k1/ci/cirrus.sh
index 8495c39203..8d82818611 100755
--- a/src/secp256k1/ci/cirrus.sh
+++ b/src/secp256k1/ci/cirrus.sh
@@ -36,8 +36,7 @@ case "$WRAPPER_CMD" in
*wine*)
# Make sure to shutdown wineserver whenever we exit.
trap "wineserver -k || true" EXIT INT HUP
- # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
- wineserver -p && wine hh.exe
+ wineserver -p
;;
esac
@@ -62,6 +61,7 @@ fi
--with-ecmult-window="$ECMULTWINDOW" \
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
+ --enable-module-ellswift="$ELLSWIFT" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
@@ -109,8 +109,8 @@ fi
# Rebuild precomputed files (if not cross-compiling).
if [ -z "$HOST" ]
then
- make clean-precomp
- make precomp
+ make clean-precomp clean-testvectors
+ make precomp testvectors
fi
# Check that no repo files have been modified by the build.
diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile
index a83a4e36db..54eafcab25 100644
--- a/src/secp256k1/ci/linux-debian.Dockerfile
+++ b/src/secp256k1/ci/linux-debian.Dockerfile
@@ -29,9 +29,10 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
git clone https://github.com/mstorsjo/msvc-wine && \
mkdir /opt/msvc && \
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
- msvc-wine/install.sh /opt/msvc
-
-# Initialize the wine environment. Wait until the wineserver process has
-# exited before closing the session, to avoid corrupting the wine prefix.
-RUN wine64 wineboot --init && \
+# Since commit 2146cbfaf037e21de56c7157ec40bb6372860f51, the
+# msvc-wine effectively initializes the wine prefix when running
+# the install.sh script.
+ msvc-wine/install.sh /opt/msvc && \
+# Wait until the wineserver process has exited before closing the session,
+# to avoid corrupting the wine prefix.
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done
diff --git a/src/secp256k1/cmake/CheckArm32Assembly.cmake b/src/secp256k1/cmake/CheckArm32Assembly.cmake
new file mode 100644
index 0000000000..15c44b24b0
--- /dev/null
+++ b/src/secp256k1/cmake/CheckArm32Assembly.cmake
@@ -0,0 +1,6 @@
+function(check_arm32_assembly)
+ try_compile(HAVE_ARM32_ASM
+ ${CMAKE_BINARY_DIR}/check_arm32_assembly
+ SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s
+ )
+endfunction()
diff --git a/src/secp256k1/cmake/CheckStringOptionValue.cmake b/src/secp256k1/cmake/CheckStringOptionValue.cmake
index bc4d7b5749..5a4d939b9e 100644
--- a/src/secp256k1/cmake/CheckStringOptionValue.cmake
+++ b/src/secp256k1/cmake/CheckStringOptionValue.cmake
@@ -1,11 +1,9 @@
function(check_string_option_value option)
get_property(expected_values CACHE ${option} PROPERTY STRINGS)
if(expected_values)
- foreach(value IN LISTS expected_values)
- if(value STREQUAL "${${option}}")
- return()
- endif()
- endforeach()
+ if(${option} IN_LIST expected_values)
+ return()
+ endif()
message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.")
endif()
message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.")
diff --git a/src/secp256k1/cmake/Check64bitAssembly.cmake b/src/secp256k1/cmake/CheckX86_64Assembly.cmake
index 3f65887765..ae82cd476e 100644
--- a/src/secp256k1/cmake/Check64bitAssembly.cmake
+++ b/src/secp256k1/cmake/CheckX86_64Assembly.cmake
@@ -1,6 +1,6 @@
include(CheckCSourceCompiles)
-function(check_64bit_assembly)
+function(check_x86_64_assembly)
check_c_source_compiles("
#include <stdint.h>
@@ -9,6 +9,6 @@ function(check_64bit_assembly)
uint64_t a = 11, tmp;
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
}
- " HAS_64BIT_ASM)
- set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE)
+ " HAVE_X86_64_ASM)
+ set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE)
endfunction()
diff --git a/src/secp256k1/cmake/FindValgrind.cmake b/src/secp256k1/cmake/FindValgrind.cmake
index f6c1f58649..3af5e691e4 100644
--- a/src/secp256k1/cmake/FindValgrind.cmake
+++ b/src/secp256k1/cmake/FindValgrind.cmake
@@ -1,4 +1,4 @@
-if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+if(CMAKE_HOST_APPLE)
find_program(BREW_COMMAND brew)
execute_process(
COMMAND ${BREW_COMMAND} --prefix valgrind
diff --git a/src/secp256k1/cmake/TryAddCompileOption.cmake b/src/secp256k1/cmake/TryAddCompileOption.cmake
deleted file mode 100644
index f53c252c2d..0000000000
--- a/src/secp256k1/cmake/TryAddCompileOption.cmake
+++ /dev/null
@@ -1,23 +0,0 @@
-include(CheckCCompilerFlag)
-
-function(try_add_compile_option option)
- string(MAKE_C_IDENTIFIER ${option} result)
- string(TOUPPER ${result} result)
- set(result "C_SUPPORTS${result}")
- set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
- if(NOT MSVC)
- set(CMAKE_REQUIRED_FLAGS "-Werror")
- endif()
- check_c_compiler_flag(${option} ${result})
- if(${result})
- get_property(compile_options
- DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- PROPERTY COMPILE_OPTIONS
- )
- list(APPEND compile_options "${option}")
- set_property(
- DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- PROPERTY COMPILE_OPTIONS "${compile_options}"
- )
- endif()
-endfunction()
diff --git a/src/secp256k1/cmake/TryAppendCFlags.cmake b/src/secp256k1/cmake/TryAppendCFlags.cmake
new file mode 100644
index 0000000000..1d81a9317a
--- /dev/null
+++ b/src/secp256k1/cmake/TryAppendCFlags.cmake
@@ -0,0 +1,24 @@
+include(CheckCCompilerFlag)
+
+function(secp256k1_check_c_flags_internal flags output)
+ string(MAKE_C_IDENTIFIER "${flags}" result)
+ string(TOUPPER "${result}" result)
+ set(result "C_SUPPORTS_${result}")
+ if(NOT MSVC)
+ set(CMAKE_REQUIRED_FLAGS "-Werror")
+ endif()
+
+ # This avoids running a linker.
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ check_c_compiler_flag("${flags}" ${result})
+
+ set(${output} ${${result}} PARENT_SCOPE)
+endfunction()
+
+# Append flags to the COMPILE_OPTIONS directory property if CC accepts them.
+macro(try_append_c_flags)
+ secp256k1_check_c_flags_internal("${ARGV}" result)
+ if(result)
+ add_compile_options(${ARGV})
+ endif()
+endmacro()
diff --git a/src/secp256k1/cmake/source_arm32.s b/src/secp256k1/cmake/source_arm32.s
new file mode 100644
index 0000000000..d3d9347057
--- /dev/null
+++ b/src/secp256k1/cmake/source_arm32.s
@@ -0,0 +1,9 @@
+.syntax unified
+.eabi_attribute 24, 1
+.eabi_attribute 25, 1
+.text
+.global main
+main:
+ ldr r0, =0x002A
+ mov r7, #1
+ swi 0
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index a46a0a7be3..82cf95132d 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -5,8 +5,8 @@ AC_PREREQ([2.60])
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
define(_PKG_VERSION_MINOR, 3)
-define(_PKG_VERSION_PATCH, 0)
-define(_PKG_VERSION_IS_RELEASE, true)
+define(_PKG_VERSION_PATCH, 3)
+define(_PKG_VERSION_IS_RELEASE, false)
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
@@ -14,7 +14,7 @@ define(_PKG_VERSION_IS_RELEASE, true)
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
define(_LIB_VERSION_CURRENT, 2)
-define(_LIB_VERSION_REVISION, 0)
+define(_LIB_VERSION_REVISION, 3)
define(_LIB_VERSION_AGE, 0)
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
@@ -29,6 +29,11 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
# Make the compilation flags quiet unless V=1 is used.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+if test "${CFLAGS+set}" = "set"; then
+ CFLAGS_overridden=yes
+else
+ CFLAGS_overridden=no
+fi
AC_PROG_CC
AM_PROG_AS
AM_PROG_AR
@@ -88,11 +93,14 @@ esac
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
# GCC and compatible (incl. clang)
if test "x$GCC" = "xyes"; then
- # Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
- # not error out if it gets unknown warning flags and the checks here will always succeed
- # no matter if clang knows the flag or not.
+ # Try to append -Werror to CFLAGS temporarily. Otherwise checks for some unsupported
+ # flags will succeed.
+ # Note that failure to append -Werror does not necessarily mean that -Werror is not
+ # supported. The compiler may already be warning about something unrelated, for example
+ # about some path issue. If that is the case, -Werror cannot be used because all
+ # of those warnings would be turned into errors.
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
- SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
+ SECP_TRY_APPEND_CFLAGS([-Werror], CFLAGS)
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
@@ -113,8 +121,12 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
# libtool makes the same assumption internally.
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
- SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
- SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
+ SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level.
+ SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
+ SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
+ SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
+ # Eliminate deprecation warnings for the older, less secure functions.
+ CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS"
# We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when
# importing variables from a statically linked secp256k1.
# (See the libtool manual, section "Windows DLLs" for background.)
@@ -178,6 +190,10 @@ AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
+AC_ARG_ENABLE(module_ellswift,
+ AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
+
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
@@ -190,8 +206,8 @@ AC_ARG_ENABLE(external_default_callbacks,
# * and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
-AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
-[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
+AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
+[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
@@ -241,6 +257,12 @@ fi
if test x"$enable_coverage" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
+ # If coverage is enabled, and the user has not overridden CFLAGS,
+ # override Autoconf's value "-g -O2" with "-g". Otherwise we'd end up
+ # with "-O0 --coverage -g -O2".
+ if test "$CFLAGS_overridden" = "no"; then
+ CFLAGS="-g"
+ fi
LDFLAGS="--coverage $LDFLAGS"
else
# Most likely the CFLAGS already contain -O2 because that is autoconf's default.
@@ -250,8 +272,8 @@ else
fi
if test x"$req_asm" = x"auto"; then
- SECP_64BIT_ASM_CHECK
- if test x"$has_64bit_asm" = x"yes"; then
+ SECP_X86_64_ASM_CHECK
+ if test x"$has_x86_64_asm" = x"yes"; then
set_asm=x86_64
fi
if test x"$set_asm" = x; then
@@ -261,12 +283,16 @@ else
set_asm=$req_asm
case $set_asm in
x86_64)
- SECP_64BIT_ASM_CHECK
- if test x"$has_64bit_asm" != x"yes"; then
+ SECP_X86_64_ASM_CHECK
+ if test x"$has_x86_64_asm" != x"yes"; then
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
- arm)
+ arm32)
+ SECP_ARM32_ASM_CHECK
+ if test x"$has_arm32_asm" != x"yes"; then
+ AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
+ fi
;;
no)
;;
@@ -283,7 +309,7 @@ case $set_asm in
x86_64)
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
;;
-arm)
+arm32)
enable_external_asm=yes
;;
no)
@@ -380,6 +406,10 @@ if test x"$enable_module_schnorrsig" = x"yes"; then
enable_module_extrakeys=yes
fi
+if test x"$enable_module_ellswift" = x"yes"; then
+ AC_DEFINE(ENABLE_MODULE_ELLSWIFT, 1, [Define this symbol to enable the ElligatorSwift module])
+fi
+
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
@@ -400,8 +430,8 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
AC_MSG_NOTICE([******])
else
- if test x"$set_asm" = x"arm"; then
- AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
+ if test x"$set_asm" = x"arm32"; then
+ AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
fi
fi
@@ -422,8 +452,9 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
+AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
-AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
+AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
@@ -443,6 +474,7 @@ echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
+echo " module ellswift = $enable_module_ellswift"
echo
echo " asm = $set_asm"
echo " ecmult window size = $set_ecmult_window"
diff --git a/src/secp256k1/doc/ellswift.md b/src/secp256k1/doc/ellswift.md
new file mode 100644
index 0000000000..7fbb7c1787
--- /dev/null
+++ b/src/secp256k1/doc/ellswift.md
@@ -0,0 +1,483 @@
+# ElligatorSwift for secp256k1 explained
+
+In this document we explain how the `ellswift` module implementation is related to the
+construction in the
+["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
+paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
+
+* [1. Introduction](#1-introduction)
+* [2. The decoding function](#2-the-decoding-function)
+ + [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
+* [3. The encoding function](#3-the-encoding-function)
+ + [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates)
+ + [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
+ + [3.3 Finding the inverse](#33-finding-the-inverse)
+ + [3.4 Dealing with special cases](#34-dealing-with-special-cases)
+ + [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
+* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
+ + [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
+
+## 1. Introduction
+
+The `ellswift` module effectively introduces a new 64-byte public key format, with the property
+that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally
+indistinguishable from uniform byte arrays. The module provides functions to convert public keys
+from and to this format, as well as convenience functions for key generation and ECDH that operate
+directly on ellswift-encoded keys.
+
+The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$
+and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on
+the curve.
+
+**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$
+are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid
+x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
+
+**Encoding** a given $x$ coordinate is conceptually done as follows:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements.
+ * With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
+ * Select a uniformly random $t \in L$ and return $(u, t).$
+
+This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full
+$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
+The algorithm finds a uniformly random $(u, t)$ among (almost all) those
+for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
+almost all x-coordinates on the curve (all but at most 39) is close to two times the field size
+(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field).
+
+## 2. The decoding function
+
+First some definitions:
+* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
+ * For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
+* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
+ public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
+ This implies that the order of $E$ is either odd, or a multiple of *4*.
+ If $a=0$, this condition is always fulfilled.
+ * For `secp256k1`, $a=0$ and $b=7.$
+* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
+* Let the function $h(x) = 3x^3 + 4a.$
+* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
+* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
+* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
+* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
+
+**Note**: In the paper:
+* $F_u$ corresponds to $F_{0,u}$ there.
+* $P_u(t)$ is called $P$ there.
+* All $S_u$ sets together correspond to $S$ there.
+* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
+
+Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
+hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
+out of the three right-hand side factors an even number must be non-squares.
+This implies that exactly *1* or exactly *3* out of
+$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
+at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
+to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
+
+**Define** the decoding function $F_u(t)$ as:
+* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
+* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
+
+$P_u(t) = (X(u, t), Y(u, t))$, where:
+
+$$
+\begin{array}{lcl}
+X(u, t) & = & \left\\{\begin{array}{ll}
+ \dfrac{g(u) - t^2}{2t} & a = 0 \\
+ \dfrac{g(u) + h(u)(Y_0(u) + X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0
+\end{array}\right. \\
+Y(u, t) & = & \left\\{\begin{array}{ll}
+ \dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\
+ Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0
+\end{array}\right.
+\end{array}
+$$
+
+$P_u(t)$ is defined:
+* For $a=0$, unless:
+ * $u = 0$ or $t = 0$ (division by zero)
+ * $g(u) = -t^2$ (would give $Y=0$).
+* For $a \neq 0$, unless:
+ * $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
+ * $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
+
+The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
+
+The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where:
+
+$$
+\begin{array}{lcl}
+ x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\
+ x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\
+ x_3 & = & u + 4Y^2 && \\
+ z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3}
+\end{array}
+$$
+
+### 2.1 Decoding for `secp256k1`
+
+Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
+
+**Define** $F_u(t)$ as:
+* Let $X = \dfrac{u^3 + b - t^2}{2t}.$
+* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
+* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
+
+To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
+$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
+
+**Define** $F_u(t)$ as:
+* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
+* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
+* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
+* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
+* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
+* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
+
+The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
+but the approach here is simple enough and gives fairly uniform output even in these cases.
+
+**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there.
+We wish to avoid the need for callers to deal with this special case.
+
+This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and
+in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate).
+
+## 3. The encoding function
+
+To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
+* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
+* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
+* For each of the found $t$ values, verify that $F_u(t) = x.$
+* Return the remaining $t$ values.
+
+The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
+
+$$
+P_u^{-1}(X, Y) = \left\\{\begin{array}{ll}
+Yu\sqrt{-3} - X & a = 0 \\
+\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\
+\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u)
+\end{array}\right.
+$$
+
+The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions,
+it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the
+$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected.
+
+Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$,
+the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid.
+This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of
+$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out.
+
+Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as
+$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square,
+and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined
+before those values are computed.
+
+It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would
+take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take
+precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$
+values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
+any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
+
+### 3.1 Switching to *v, w* coordinates
+
+Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
+$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
+* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
+* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
+* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
+
+$$
+\begin{array}{lcl}
+ x_1 & = & v \\
+ x_2 & = & -u - v \\
+ x_3 & = & u + w^2 \\
+ z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3}
+\end{array}
+$$
+
+We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
+expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
+* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
+* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
+* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
+
+### 3.2 Avoiding computing all inverses
+
+The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
+set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
+
+Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
+uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
+picking a uniformly random element from that, restarting whenever $\bot$ is picked:
+
+**Define** *ElligatorSwift(x)* as:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Compute the set $L = F_u^{-1}(x).$
+ * Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
+ * Select a uniformly random $t \in T.$
+ * If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
+
+Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
+random element in it, so we do not need to have all $\bot$ values at the end.
+As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
+we can associate every index in $T$ with exactly one of those formulas, making sure that:
+* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
+* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
+* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
+
+The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
+to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
+for an analysis of all the negligible cases.
+
+If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
+the loop can be simplified to only compute one of the inverses instead of all of them:
+
+**Define** *ElligatorSwift(x)* as:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Pick a uniformly random integer $c$ in $[0,8).$
+ * Let $t = G_{c,u}(x).$
+ * If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
+
+This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
+
+### 3.3 Finding the inverse
+
+To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula.
+Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression).
+Ignoring the negligible cases, we get:
+
+**Define** $G_{c,u}(x)$ as:
+* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
+ * If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
+ * If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
+ * Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}.$
+ * Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
+* Let $w = \sqrt{s}.$
+* Depending on $c:$
+ * If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
+ * If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
+
+Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
+50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
+with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$
+implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered
+and $\bot$ would have been returned already.
+
+**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4).
+The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to
+have the $G_{c,u}$ be deterministic, and capture all choices in $c.$
+
+Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$
+transformation. Furthermore, that transformation has no effect on $s$ in the first branch
+as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
+
+**Define** $G_{c,u}(x)$ as:
+* If $c \in \\{0, 1, 4, 5\\}:$
+ * If $g(-u-x)$ is square, return $\bot.$
+ * Let $s = -g(u)/(u^2 + ux + x^2 + a).$
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}.$
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
+ * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
+ * If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
+ * If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
+
+This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
+There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
+
+### 3.4 Dealing with special cases
+
+As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs.
+For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness
+we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that
+do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
+$t$ value for multiple $c$ inputs (thereby biasing that encoding):
+
+* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
+ * When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
+ Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
+ fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
+ This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
+ the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
+ encoder anyway as there will generally be more than 8.
+ * When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
+ as it can deal with $g(u)=0$.
+ This is again only possible on even-ordered curves.
+* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
+ * When $s=0$, a division by zero would occur.
+ * When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
+ It is equivalent to checking whether $r=0$.
+ This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
+ A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
+ it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
+* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
+ * For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
+ * For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $2w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
+
+**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
+* If $a=0$ and $u=0$, return $\bot.$
+* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
+* If $c \in \\{0, 1, 4, 5\\}:$
+ * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
+ * If $g(-u-x)$ is square, return $\bot.$
+ * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
+ * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
+ * If $s = 0$, return $\bot.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}$; return $\bot$ if not square.
+* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
+ * If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
+ * If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
+ * If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
+* If $a=0$ and $t=0$, return $\bot$ (even curves only).
+* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
+* Return $t.$
+
+Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
+for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
+* All cases where $P_u(t)$ is not defined:
+ * For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
+ * For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
+* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
+
+These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
+
+### 3.5 Encoding for `secp256k1`
+
+Specialized for odd-ordered $a=0$ curves:
+
+**Define** $G_{c,u}(x)$ as:
+* If $u=0$, return $\bot.$
+* If $c \in \\{0, 1, 4, 5\\}:$
+ * If $(-u-x)^3 + b$ is square, return $\bot$
+ * Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
+ * If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
+ * If $s = 0$, return $\bot.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}$; return $\bot$ if not square.
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
+ * If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
+ * If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
+ * If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
+
+This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
+
+And the x-only ElligatorSwift encoding algorithm is still:
+
+**Define** *ElligatorSwift(x)* as:
+* Loop:
+ * Pick a uniformly random field element $u.$
+ * Pick a uniformly random integer $c$ in $[0,8).$
+ * Let $t = G_{c,u}(x).$
+ * If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
+
+Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
+While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
+combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
+
+## 4. Encoding and decoding full *(x, y)* coordinates
+
+So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
+for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
+in $t$ as well.
+
+Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are
+mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$
+being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order
+of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead.
+
+Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode
+the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the
+four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$
+
+**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit.
+
+To encode the sign of $y$ in the sign of $Y:$
+
+**Define** *Decode(u, t)* for full $(x, y)$ as:
+* Let $(X, Y) = P_u(t).$
+* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
+* Let $y = \sqrt{g(x)}.$
+* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
+
+And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
+
+**Define** $G_{c,u}(x, y)$ as:
+* If $c \in \\{0, 1\\}:$
+ * If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
+ * If $g(-u-x)$ is square, return $\bot.$
+ * Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
+ * Let $v = x.$
+* Otherwise, when $c \in \\{2, 3\\}:$
+ * Let $s = x-u.$
+ * Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
+ * If $c = 3$ and $r = 0$, return $\bot.$
+ * Let $v = (r/s - u)/2.$
+* Let $w = \sqrt{s}$; return $\bot$ if not square.
+* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
+* Depending on $c:$
+ * If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
+ * If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
+
+Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
+This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
+
+In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation
+of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
+$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
+
+### 4.1 Full *(x, y)* coordinates for `secp256k1`
+
+For $a=0$ curves, there is another option. Note that for those,
+the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
+encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
+as decoder:
+
+**Define** *Decode(u, t)* as:
+* Let $u'=u$ if $u \neq 0$; $1$ otherwise.
+* Let $t'=t$ if $t \neq 0$; $1$ otherwise.
+* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
+* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
+* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
+* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
+* Let $y = \sqrt{g(x)}.$
+* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
+
+This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
+
+The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$
+
+This is implemented in `secp256k1_ellswift_elligatorswift_var`.
+
+Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points
+where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in
+[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift
+in the first place.
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
index b522f89657..ea6087c9ff 100644
--- a/src/secp256k1/doc/release-process.md
+++ b/src/secp256k1/doc/release-process.md
@@ -12,33 +12,69 @@ It is best if the maintainers are present during the release, so they can help e
This process also assumes that there will be no minor releases for old major releases.
+We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
+
+## Sanity Checks
+Perform these checks before creating a release:
+
+1. Ensure `make distcheck` doesn't fail.
+```shell
+./autogen.sh && ./configure --enable-dev-mode && make distcheck
+```
+2. Check installation with autotools:
+```shell
+dir=$(mktemp -d)
+./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -l $dir/include $dir/lib
+gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
+```
+3. Check installation with CMake:
+```shell
+dir=$(mktemp -d)
+build=$(mktemp -d)
+cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -l $dir/include $dir/lib*
+gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
+```
+
## Regular release
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
- * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`) and
- * updates `_PKG_VERSION_*`, `_LIB_VERSION_*`, and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`.
+ * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
+ * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
+ * removing the `[Unreleased]` section header, and
+ * including an entry for `### ABI Compatibility` if it doesn't exist that mentions the library soname of the release,
+ * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
+ * if this is not a patch release
+ * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
+ * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
2. After the PR is merged, tag the commit and push it:
```
RELEASE_COMMIT=<merge commit of step 1>
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
-3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that sets `_PKG_VERSION_IS_RELEASE` to `false` and `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs.
+3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
+ * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
+ * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
+ * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
+
+ If other maintainers are not present to approve the PR, it can be merged without ACKs.
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
## Maintenance release
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
-1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
+1. If there's no maintenance branch `$MAJOR.$MINOR`, create one:
```
- git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
+ git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1))
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
```
2. Open a pull request to the `$MAJOR.$MINOR` branch that
* includes the bugfixes,
- * finalizes the release notes,
- * bumps `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` (with commit message `"release: update PKG_ and LIB_VERSION for $MAJOR.$MINOR.$PATCH"`, for example).
+ * finalizes the release notes similar to a regular release,
+ * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
+ and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
+ (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
3. After the PRs are merged, update the release branch and tag the commit:
```
git checkout $MAJOR.$MINOR && git pull
diff --git a/src/secp256k1/examples/CMakeLists.txt b/src/secp256k1/examples/CMakeLists.txt
index 0884b645e0..e095b7f84f 100644
--- a/src/secp256k1/examples/CMakeLists.txt
+++ b/src/secp256k1/examples/CMakeLists.txt
@@ -2,33 +2,26 @@ add_library(example INTERFACE)
target_include_directories(example INTERFACE
${PROJECT_SOURCE_DIR}/include
)
-target_compile_options(example INTERFACE
- $<$<C_COMPILER_ID:MSVC>:/wd4005>
-)
target_link_libraries(example INTERFACE
+ secp256k1
$<$<PLATFORM_ID:Windows>:bcrypt>
)
-if(SECP256K1_BUILD_SHARED)
- target_link_libraries(example INTERFACE secp256k1)
-elseif(SECP256K1_BUILD_STATIC)
- target_link_libraries(example INTERFACE secp256k1_static)
- if(MSVC)
- target_link_options(example INTERFACE /IGNORE:4217)
- endif()
+if(NOT BUILD_SHARED_LIBS AND MSVC)
+ target_link_options(example INTERFACE /IGNORE:4217)
endif()
add_executable(ecdsa_example ecdsa.c)
target_link_libraries(ecdsa_example example)
-add_test(ecdsa_example ecdsa_example)
+add_test(NAME ecdsa_example COMMAND ecdsa_example)
if(SECP256K1_ENABLE_MODULE_ECDH)
add_executable(ecdh_example ecdh.c)
target_link_libraries(ecdh_example example)
- add_test(ecdh_example ecdh_example)
+ add_test(NAME ecdh_example COMMAND ecdh_example)
endif()
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
add_executable(schnorr_example schnorr.c)
target_link_libraries(schnorr_example example)
- add_test(schnorr_example schnorr_example)
+ add_test(NAME schnorr_example COMMAND schnorr_example)
endif()
diff --git a/src/secp256k1/examples/examples_util.h b/src/secp256k1/examples/examples_util.h
index a52b1fa115..8e3a8f00cf 100644
--- a/src/secp256k1/examples/examples_util.h
+++ b/src/secp256k1/examples/examples_util.h
@@ -17,7 +17,13 @@
*/
#if defined(_WIN32)
+/*
+ * The defined WIN32_NO_STATUS macro disables return code definitions in
+ * windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h.
+ */
+#define WIN32_NO_STATUS
#include <windows.h>
+#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <bcrypt.h>
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
@@ -77,7 +83,7 @@ static void print_hex(unsigned char* data, size_t size) {
#include <Windows.h>
#endif
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
-static SECP256K1_INLINE void secure_erase(void *ptr, size_t len) {
+static void secure_erase(void *ptr, size_t len) {
#if defined(_MSC_VER)
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 325f35eb04..a7a2be7a3a 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -122,18 +122,6 @@ typedef int (*secp256k1_nonce_function)(
# endif
# endif
-# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
-# if SECP256K1_GNUC_PREREQ(2,7)
-# define SECP256K1_INLINE __inline__
-# elif (defined(_MSC_VER))
-# define SECP256K1_INLINE __inline
-# else
-# define SECP256K1_INLINE
-# endif
-# else
-# define SECP256K1_INLINE inline
-# endif
-
/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
@@ -288,7 +276,7 @@ SECP256K1_API void secp256k1_selftest(void);
* Do not create a new context object for each operation, as construction and
* randomization can take non-negligible time.
*/
-SECP256K1_API secp256k1_context* secp256k1_context_create(
+SECP256K1_API secp256k1_context *secp256k1_context_create(
unsigned int flags
) SECP256K1_WARN_UNUSED_RESULT;
@@ -304,8 +292,8 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
* Returns: a newly created context object.
* Args: ctx: an existing context to copy (not secp256k1_context_static)
*/
-SECP256K1_API secp256k1_context* secp256k1_context_clone(
- const secp256k1_context* ctx
+SECP256K1_API secp256k1_context *secp256k1_context_clone(
+ const secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
@@ -323,7 +311,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
* (i.e., not secp256k1_context_static).
*/
SECP256K1_API void secp256k1_context_destroy(
- secp256k1_context* ctx
+ secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an illegal argument is passed to
@@ -347,8 +335,8 @@ SECP256K1_API void secp256k1_context_destroy(
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
* has been configured with --enable-external-default-callbacks. Then the
* following two symbols must be provided to link against:
- * - void secp256k1_default_illegal_callback_fn(const char* message, void* data);
- * - void secp256k1_default_error_callback_fn(const char* message, void* data);
+ * - void secp256k1_default_illegal_callback_fn(const char *message, void *data);
+ * - void secp256k1_default_error_callback_fn(const char *message, void *data);
* The library can call these default handlers even before a proper callback data
* pointer could have been set using secp256k1_context_set_illegal_callback or
* secp256k1_context_set_error_callback, e.g., when the creation of a context
@@ -364,9 +352,9 @@ SECP256K1_API void secp256k1_context_destroy(
* See also secp256k1_context_set_error_callback.
*/
SECP256K1_API void secp256k1_context_set_illegal_callback(
- secp256k1_context* ctx,
- void (*fun)(const char* message, void* data),
- const void* data
+ secp256k1_context *ctx,
+ void (*fun)(const char *message, void *data),
+ const void *data
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an internal consistency check
@@ -392,9 +380,9 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
* See also secp256k1_context_set_illegal_callback.
*/
SECP256K1_API void secp256k1_context_set_error_callback(
- secp256k1_context* ctx,
- void (*fun)(const char* message, void* data),
- const void* data
+ secp256k1_context *ctx,
+ void (*fun)(const char *message, void *data),
+ const void *data
) SECP256K1_ARG_NONNULL(1);
/** Create a secp256k1 scratch space object.
@@ -404,8 +392,8 @@ SECP256K1_API void secp256k1_context_set_error_callback(
* In: size: amount of memory to be available as scratch space. Some extra
* (<100 bytes) will be allocated for extra accounting.
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
- const secp256k1_context* ctx,
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create(
+ const secp256k1_context *ctx,
size_t size
) SECP256K1_ARG_NONNULL(1);
@@ -416,8 +404,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_sc
* scratch: space to destroy
*/
SECP256K1_API void secp256k1_scratch_space_destroy(
- const secp256k1_context* ctx,
- secp256k1_scratch_space* scratch
+ const secp256k1_context *ctx,
+ secp256k1_scratch_space *scratch
) SECP256K1_ARG_NONNULL(1);
/** Parse a variable-length public key into the pubkey object.
@@ -435,8 +423,8 @@ SECP256K1_API void secp256k1_scratch_space_destroy(
* byte 0x06 or 0x07) format public keys.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
- const secp256k1_context* ctx,
- secp256k1_pubkey* pubkey,
+ const secp256k1_context *ctx,
+ secp256k1_pubkey *pubkey,
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -457,10 +445,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
* compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
*/
SECP256K1_API int secp256k1_ec_pubkey_serialize(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *output,
size_t *outputlen,
- const secp256k1_pubkey* pubkey,
+ const secp256k1_pubkey *pubkey,
unsigned int flags
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
@@ -474,9 +462,9 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize(
* pubkey2: second public key to compare
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
- const secp256k1_context* ctx,
- const secp256k1_pubkey* pubkey1,
- const secp256k1_pubkey* pubkey2
+ const secp256k1_context *ctx,
+ const secp256k1_pubkey *pubkey1,
+ const secp256k1_pubkey *pubkey2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse an ECDSA signature in compact (64 bytes) format.
@@ -495,8 +483,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
* any message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
- const secp256k1_context* ctx,
- secp256k1_ecdsa_signature* sig,
+ const secp256k1_context *ctx,
+ secp256k1_ecdsa_signature *sig,
const unsigned char *input64
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -516,8 +504,8 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
* guaranteed to fail for every message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
- const secp256k1_context* ctx,
- secp256k1_ecdsa_signature* sig,
+ const secp256k1_context *ctx,
+ secp256k1_ecdsa_signature *sig,
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -534,10 +522,10 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
* In: sig: a pointer to an initialized signature object
*/
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *output,
size_t *outputlen,
- const secp256k1_ecdsa_signature* sig
+ const secp256k1_ecdsa_signature *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Serialize an ECDSA signature in compact (64 byte) format.
@@ -550,9 +538,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
*/
SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *output64,
- const secp256k1_ecdsa_signature* sig
+ const secp256k1_ecdsa_signature *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Verify an ECDSA signature.
@@ -581,7 +569,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
* For details, see the comments for that function.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *msghash32,
const secp256k1_pubkey *pubkey
@@ -629,7 +617,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
* secp256k1_ecdsa_signature_normalize must be called before verification.
*/
SECP256K1_API int secp256k1_ecdsa_signature_normalize(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sigout,
const secp256k1_ecdsa_signature *sigin
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
@@ -662,7 +650,7 @@ SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_defaul
* secp256k1_ecdsa_signature_normalize for more details.
*/
SECP256K1_API int secp256k1_ecdsa_sign(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *msghash32,
const unsigned char *seckey,
@@ -683,7 +671,7 @@ SECP256K1_API int secp256k1_ecdsa_sign(
* In: seckey: pointer to a 32-byte secret key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
@@ -696,7 +684,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
* In: seckey: pointer to a 32-byte secret key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -712,14 +700,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
* seckey will be set to some unspecified value.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
@@ -731,7 +719,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
* In/Out: pubkey: pointer to the public key to be negated.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
@@ -751,7 +739,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -759,7 +747,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
@@ -779,7 +767,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -798,7 +786,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -806,7 +794,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
@@ -824,7 +812,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -862,7 +850,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
* enhanced protection against side-channel leakage currently.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
- secp256k1_context* ctx,
+ secp256k1_context *ctx,
const unsigned char *seed32
) SECP256K1_ARG_NONNULL(1);
@@ -876,9 +864,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
* n: the number of public keys to add together (must be at least 1).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *out,
- const secp256k1_pubkey * const * ins,
+ const secp256k1_pubkey * const *ins,
size_t n
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -899,7 +887,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
* msglen: length of the message array
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *hash32,
const unsigned char *tag,
size_t taglen,
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
index 625061b282..837ae2abe5 100644
--- a/src/secp256k1/include/secp256k1_ecdh.h
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -48,7 +48,7 @@ SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_functio
* (can be NULL for secp256k1_ecdh_hash_function_sha256).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *output,
const secp256k1_pubkey *pubkey,
const unsigned char *seckey,
diff --git a/src/secp256k1/include/secp256k1_ellswift.h b/src/secp256k1/include/secp256k1_ellswift.h
new file mode 100644
index 0000000000..3851f93098
--- /dev/null
+++ b/src/secp256k1/include/secp256k1_ellswift.h
@@ -0,0 +1,198 @@
+#ifndef SECP256K1_ELLSWIFT_H
+#define SECP256K1_ELLSWIFT_H
+
+#include "secp256k1.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This module provides an implementation of ElligatorSwift as well as a
+ * version of x-only ECDH using it (including compatibility with BIP324).
+ *
+ * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
+ * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
+ * uniformly chosen public keys as 64-byte arrays which are indistinguishable
+ * from uniformly random arrays.
+ *
+ * Let f be the function from pairs of field elements to point X coordinates,
+ * defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
+ * f(u,t):
+ * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
+ * a square root of -3.
+ * - If u=0, set u=1 instead.
+ * - If t=0, set t=1 instead.
+ * - If u^3 + t^2 + 7 = 0, multiply t by 2.
+ * - Let X = (u^3 + 7 - t^2) / (2 * t)
+ * - Let Y = (X + t) / (C * u)
+ * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
+ * X coordinate on the curve (at least one of them is, for any u and t).
+ *
+ * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
+ * encodings of field elements u and t concatenated, where f(u,t) = x.
+ * The encoding algorithm is described in the paper, and effectively picks a
+ * uniformly random pair (u,t) among those which encode x.
+ *
+ * If the Y coordinate is relevant, it is given the same parity as t.
+ *
+ * Changes w.r.t. the the paper:
+ * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
+ * at infinity in the paper. Here they are remapped to finite points.
+ * - The paper uses an additional encoding bit for the parity of y. Here the
+ * parity of t is used (negating t does not affect the decoded x coordinate,
+ * so this is possible).
+ */
+
+/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X
+ * coordinate along with the encoded public keys to a uniform shared secret.
+ *
+ * Returns: 1 if a shared secret was successfully computed.
+ * 0 will cause secp256k1_ellswift_xdh to fail and return 0.
+ * Other return values are not allowed, and the behaviour of
+ * secp256k1_ellswift_xdh is undefined for other return values.
+ * Out: output: pointer to an array to be filled by the function
+ * In: x32: pointer to the 32-byte serialized X coordinate
+ * of the resulting shared point (will not be NULL)
+ * ell_a64: pointer to the 64-byte encoded public key of party A
+ * (will not be NULL)
+ * ell_b64: pointer to the 64-byte encoded public key of party B
+ * (will not be NULL)
+ * data: arbitrary data pointer that is passed through
+ */
+typedef int (*secp256k1_ellswift_xdh_hash_function)(
+ unsigned char *output,
+ const unsigned char *x32,
+ const unsigned char *ell_a64,
+ const unsigned char *ell_b64,
+ void *data
+);
+
+/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
+ * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte
+ * array pointed to by data. */
+SECP256K1_API_VAR const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix;
+
+/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with
+ * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the
+ * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent
+ * to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to
+ * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh").
+ * The data argument is ignored. */
+SECP256K1_API_VAR const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324;
+
+/** Construct a 64-byte ElligatorSwift encoding of a given pubkey.
+ *
+ * Returns: 1 always.
+ * Args: ctx: pointer to a context object
+ * Out: ell64: pointer to a 64-byte array to be filled
+ * In: pubkey: a pointer to a secp256k1_pubkey containing an
+ * initialized public key
+ * rnd32: pointer to 32 bytes of randomness
+ *
+ * It is recommended that rnd32 consists of 32 uniformly random bytes, not
+ * known to any adversary trying to detect whether public keys are being
+ * encoded, though 16 bytes of randomness (padded to an array of 32 bytes,
+ * e.g., with zeros) suffice to make the result indistinguishable from
+ * uniform. The randomness in rnd32 must not be a deterministic function of
+ * the pubkey (it can be derived from the private key, though).
+ *
+ * It is not guaranteed that the computed encoding is stable across versions
+ * of the library, even if all arguments to this function (including rnd32)
+ * are the same.
+ *
+ * This function runs in variable time.
+ */
+SECP256K1_API int secp256k1_ellswift_encode(
+ const secp256k1_context *ctx,
+ unsigned char *ell64,
+ const secp256k1_pubkey *pubkey,
+ const unsigned char *rnd32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
+
+/** Decode a 64-bytes ElligatorSwift encoded public key.
+ *
+ * Returns: always 1
+ * Args: ctx: pointer to a context object
+ * Out: pubkey: pointer to a secp256k1_pubkey that will be filled
+ * In: ell64: pointer to a 64-byte array to decode
+ *
+ * This function runs in variable time.
+ */
+SECP256K1_API int secp256k1_ellswift_decode(
+ const secp256k1_context *ctx,
+ secp256k1_pubkey *pubkey,
+ const unsigned char *ell64
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Compute an ElligatorSwift public key for a secret key.
+ *
+ * Returns: 1: secret was valid, public key was stored.
+ * 0: secret was invalid, try again.
+ * Args: ctx: pointer to a context object
+ * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
+ * public key
+ * In: seckey32: pointer to a 32-byte secret key
+ * auxrnd32: (optional) pointer to 32 bytes of randomness
+ *
+ * Constant time in seckey and auxrnd32, but not in the resulting public key.
+ *
+ * It is recommended that auxrnd32 contains 32 uniformly random bytes, though
+ * it is optional (and does result in encodings that are indistinguishable from
+ * uniform even without any auxrnd32). It differs from the (mandatory) rnd32
+ * argument to secp256k1_ellswift_encode in this regard.
+ *
+ * This function can be used instead of calling secp256k1_ec_pubkey_create
+ * followed by secp256k1_ellswift_encode. It is safer, as it uses the secret
+ * key as entropy for the encoding (supplemented with auxrnd32, if provided).
+ *
+ * Like secp256k1_ellswift_encode, this function does not guarantee that the
+ * computed encoding is stable across versions of the library, even if all
+ * arguments (including auxrnd32) are the same.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
+ const secp256k1_context *ctx,
+ unsigned char *ell64,
+ const unsigned char *seckey32,
+ const unsigned char *auxrnd32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
+/** Given a private key, and ElligatorSwift public keys sent in both directions,
+ * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH).
+ *
+ * Returns: 1: shared secret was succesfully computed
+ * 0: secret was invalid or hashfp returned 0
+ * Args: ctx: pointer to a context object.
+ * Out: output: pointer to an array to be filled by hashfp.
+ * In: ell_a64: pointer to the 64-byte encoded public key of party A
+ * (will not be NULL)
+ * ell_b64: pointer to the 64-byte encoded public key of party B
+ * (will not be NULL)
+ * seckey32: a pointer to our 32-byte secret key
+ * party: boolean indicating which party we are: zero if we are
+ * party A, non-zero if we are party B. seckey32 must be
+ * the private key corresponding to that party's ell_?64.
+ * This correspondence is not checked.
+ * hashfp: pointer to a hash function.
+ * data: arbitrary data pointer passed through to hashfp.
+ *
+ * Constant time in seckey32.
+ *
+ * This function is more efficient than decoding the public keys, and performing
+ * ECDH on them.
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
+ const secp256k1_context *ctx,
+ unsigned char *output,
+ const unsigned char *ell_a64,
+ const unsigned char *ell_b64,
+ const unsigned char *seckey32,
+ int party,
+ secp256k1_ellswift_xdh_hash_function hashfp,
+ void *data
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECP256K1_ELLSWIFT_H */
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
index 3591bc0012..673fca01f9 100644
--- a/src/secp256k1/include/secp256k1_extrakeys.h
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -45,8 +45,8 @@ typedef struct {
* In: input32: pointer to a serialized xonly_pubkey.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
- const secp256k1_context* ctx,
- secp256k1_xonly_pubkey* pubkey,
+ const secp256k1_context *ctx,
+ secp256k1_xonly_pubkey *pubkey,
const unsigned char *input32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -59,9 +59,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an initialized public key.
*/
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *output32,
- const secp256k1_xonly_pubkey* pubkey
+ const secp256k1_xonly_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compare two x-only public keys using lexicographic order
@@ -74,9 +74,9 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize(
* pubkey2: second public key to compare
*/
SECP256K1_API int secp256k1_xonly_pubkey_cmp(
- const secp256k1_context* ctx,
- const secp256k1_xonly_pubkey* pk1,
- const secp256k1_xonly_pubkey* pk2
+ const secp256k1_context *ctx,
+ const secp256k1_xonly_pubkey *pk1,
+ const secp256k1_xonly_pubkey *pk2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
@@ -91,7 +91,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp(
* In: pubkey: pointer to a public key that is converted.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_xonly_pubkey *xonly_pubkey,
int *pk_parity,
const secp256k1_pubkey *pubkey
@@ -118,7 +118,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke
* chance of being invalid is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *output_pubkey,
const secp256k1_xonly_pubkey *internal_pubkey,
const unsigned char *tweak32
@@ -148,7 +148,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
* tweak32: pointer to a 32-byte tweak.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
const unsigned char *tweaked_pubkey32,
int tweaked_pk_parity,
const secp256k1_xonly_pubkey *internal_pubkey,
@@ -164,7 +164,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
* In: seckey: pointer to a 32-byte secret key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_keypair *keypair,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -177,7 +177,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *seckey,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -185,13 +185,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
/** Get the public key from a keypair.
*
* Returns: 1 always.
- * Args: ctx: pointer to a context object.
- * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
- * the keypair public key. If not, it's set to an invalid value.
+ * Args: ctx: pointer to a context object.
+ * Out: pubkey: pointer to a pubkey object, set to the keypair public key.
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -203,15 +202,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
*
* Returns: 1 always.
* Args: ctx: pointer to a context object.
- * Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
- * to the keypair public key after converting it to an
- * xonly_pubkey. If not, it's set to an invalid value.
+ * Out: pubkey: pointer to an xonly_pubkey object, set to the keypair
+ * public key after converting it to an xonly_pubkey.
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_xonly_pubkey *pubkey,
int *pk_parity,
const secp256k1_keypair *keypair
@@ -237,7 +235,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_keypair *keypair,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
diff --git a/src/secp256k1/include/secp256k1_preallocated.h b/src/secp256k1/include/secp256k1_preallocated.h
index ffa96dd339..f37744777b 100644
--- a/src/secp256k1/include/secp256k1_preallocated.h
+++ b/src/secp256k1/include/secp256k1_preallocated.h
@@ -63,8 +63,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size(
* See also secp256k1_context_randomize (in secp256k1.h)
* and secp256k1_context_preallocated_destroy.
*/
-SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
- void* prealloc,
+SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create(
+ void *prealloc,
unsigned int flags
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
@@ -75,7 +75,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
* In: ctx: an existing context to copy.
*/
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
- const secp256k1_context* ctx
+ const secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Copy a secp256k1 context object into caller-provided memory.
@@ -97,9 +97,9 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above.
*/
-SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
- const secp256k1_context* ctx,
- void* prealloc
+SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone(
+ const secp256k1_context *ctx,
+ void *prealloc
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object that has been created in
@@ -124,7 +124,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
* (i.e., not secp256k1_context_static).
*/
SECP256K1_API void secp256k1_context_preallocated_destroy(
- secp256k1_context* ctx
+ secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1);
#ifdef __cplusplus
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
index 824c604025..b12ca4d972 100644
--- a/src/secp256k1/include/secp256k1_recovery.h
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -34,8 +34,8 @@ typedef struct {
* recid: the recovery id (0, 1, 2 or 3)
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
- const secp256k1_context* ctx,
- secp256k1_ecdsa_recoverable_signature* sig,
+ const secp256k1_context *ctx,
+ secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *input64,
int recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@@ -48,9 +48,9 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
* In: sigin: a pointer to a recoverable signature.
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
- const secp256k1_context* ctx,
- secp256k1_ecdsa_signature* sig,
- const secp256k1_ecdsa_recoverable_signature* sigin
+ const secp256k1_context *ctx,
+ secp256k1_ecdsa_signature *sig,
+ const secp256k1_ecdsa_recoverable_signature *sigin
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
@@ -62,10 +62,10 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
* In: sig: a pointer to an initialized signature object.
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *output64,
int *recid,
- const secp256k1_ecdsa_recoverable_signature* sig
+ const secp256k1_ecdsa_recoverable_signature *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Create a recoverable ECDSA signature.
@@ -82,7 +82,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
* (can be NULL for secp256k1_nonce_function_default).
*/
SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *msghash32,
const unsigned char *seckey,
@@ -100,7 +100,7 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
* msghash32: the 32-byte message hash assumed to be signed.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *msghash32
diff --git a/src/secp256k1/include/secp256k1_schnorrsig.h b/src/secp256k1/include/secp256k1_schnorrsig.h
index 4cd2d98256..1ee665fd19 100644
--- a/src/secp256k1/include/secp256k1_schnorrsig.h
+++ b/src/secp256k1/include/secp256k1_schnorrsig.h
@@ -82,7 +82,7 @@ SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_functi
typedef struct {
unsigned char magic[4];
secp256k1_nonce_function_hardened noncefp;
- void* ndata;
+ void *ndata;
} secp256k1_schnorrsig_extraparams;
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c }
@@ -117,7 +117,7 @@ typedef struct {
* argument and for guidance if randomness is expensive.
*/
SECP256K1_API int secp256k1_schnorrsig_sign32(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
@@ -127,7 +127,7 @@ SECP256K1_API int secp256k1_schnorrsig_sign32(
/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API int secp256k1_schnorrsig_sign(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
@@ -141,15 +141,23 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
* variable length messages and accepts a pointer to an extraparams object that
* allows customizing signing by passing additional arguments.
*
- * Creates the same signatures as schnorrsig_sign if msglen is 32 and the
- * extraparams.ndata is the same as aux_rand32.
+ * Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32
+ * and extraparams is initialized as follows:
+ * ```
+ * secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
+ * extraparams.ndata = (unsigned char*)aux_rand32;
+ * ```
*
+ * Returns 1 on success, 0 on failure.
+ * Args: ctx: pointer to a context object (not secp256k1_context_static).
+ * Out: sig64: pointer to a 64-byte array to store the serialized signature.
* In: msg: the message being signed. Can only be NULL if msglen is 0.
- * msglen: length of the message
- * extraparams: pointer to a extraparams object (can be NULL)
+ * msglen: length of the message.
+ * keypair: pointer to an initialized keypair.
+ * extraparams: pointer to an extraparams object (can be NULL).
*/
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *msg,
size_t msglen,
@@ -168,7 +176,7 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
- const secp256k1_context* ctx,
+ const secp256k1_context *ctx,
const unsigned char *sig64,
const unsigned char *msg,
size_t msglen,
diff --git a/src/secp256k1/src/CMakeLists.txt b/src/secp256k1/src/CMakeLists.txt
index 26272d0950..0bba19982a 100644
--- a/src/secp256k1/src/CMakeLists.txt
+++ b/src/secp256k1/src/CMakeLists.txt
@@ -1,151 +1,165 @@
# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
include(GNUInstallDirs)
-set(${PROJECT_NAME}_installables "")
-if(SECP256K1_ASM STREQUAL "arm")
- add_library(common OBJECT
- asm/field_10x26_arm.s
- )
- set(common_obj "$<TARGET_OBJECTS:common>")
-else()
- set(common_obj "")
-endif()
-
-add_library(precomputed OBJECT
+add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
precomputed_ecmult.c
precomputed_ecmult_gen.c
)
-set(internal_obj "$<TARGET_OBJECTS:precomputed>" "${common_obj}")
-add_library(secp256k1 SHARED EXCLUDE_FROM_ALL
- secp256k1.c
- ${internal_obj}
-)
-target_include_directories(secp256k1 INTERFACE
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-)
-target_compile_definitions(secp256k1 PRIVATE
- $<$<PLATFORM_ID:Windows>:DLL_EXPORT>
-)
-set_target_properties(secp256k1 PROPERTIES
- VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}"
- SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}"
-)
-if(SECP256K1_BUILD_SHARED)
- get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
- set_target_properties(precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
- set_target_properties(secp256k1 PROPERTIES EXCLUDE_FROM_ALL FALSE)
- list(APPEND ${PROJECT_NAME}_installables secp256k1)
-endif()
+# Add objects explicitly rather than linking to the object libs to keep them
+# from being exported.
+add_library(secp256k1 secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
-add_library(secp256k1_static STATIC EXCLUDE_FROM_ALL
- secp256k1.c
- ${internal_obj}
-)
-target_include_directories(secp256k1_static INTERFACE
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-)
-if(NOT MSVC)
- set_target_properties(secp256k1_static PROPERTIES
- OUTPUT_NAME secp256k1
+add_library(secp256k1_asm INTERFACE)
+if(SECP256K1_ASM STREQUAL "arm32")
+ add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL)
+ target_sources(secp256k1_asm_arm PUBLIC
+ asm/field_10x26_arm.s
)
+ target_sources(secp256k1 PRIVATE $<TARGET_OBJECTS:secp256k1_asm_arm>)
+ target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
endif()
-if(SECP256K1_BUILD_STATIC)
- set_target_properties(secp256k1_static PROPERTIES EXCLUDE_FROM_ALL FALSE)
- list(APPEND ${PROJECT_NAME}_installables secp256k1_static)
+
+# Define our export symbol only for Win32 and only for shared libs.
+# This matches libtool's usage of DLL_EXPORT
+if(WIN32)
+ set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL "DLL_EXPORT")
endif()
-add_library(binary_interface INTERFACE)
-target_compile_definitions(binary_interface INTERFACE
- $<$<C_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
+# Object libs don't know if they're being built for a shared or static lib.
+# Grab the PIC property from secp256k1 which knows.
+get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
+set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
+
+target_include_directories(secp256k1 INTERFACE
+ # Add the include path for parent projects so that they don't have to manually add it.
+ $<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
-add_library(link_library INTERFACE)
-if(SECP256K1_BUILD_SHARED)
- target_link_libraries(link_library INTERFACE secp256k1)
-elseif(SECP256K1_BUILD_STATIC)
- target_link_libraries(link_library INTERFACE secp256k1_static)
+# This emulates Libtool to make sure Libtool and CMake agree on the ABI version,
+# see below "Calculate the version variables" in build-aux/ltmain.sh.
+math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}")
+set_target_properties(secp256k1 PROPERTIES
+ SOVERSION ${${PROJECT_NAME}_soversion}
+)
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ set_target_properties(secp256k1 PROPERTIES
+ VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
+ )
+elseif(APPLE)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
+ math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1")
+ set_target_properties(secp256k1 PROPERTIES
+ MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version}
+ MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
+ )
+ unset(${PROJECT_NAME}_compatibility_version)
+ elseif(BUILD_SHARED_LIBS)
+ message(WARNING
+ "The 'compatibility version' and 'current version' values of the DYLIB "
+ "will diverge from the values set by the GNU Libtool. To ensure "
+ "compatibility, it is recommended to upgrade CMake to at least version 3.17."
+ )
+ endif()
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ set(${PROJECT_NAME}_windows "secp256k1")
+ if(MSVC)
+ set(${PROJECT_NAME}_windows "${PROJECT_NAME}")
+ endif()
+ set_target_properties(secp256k1 PROPERTIES
+ ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}"
+ RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}"
+ )
+ unset(${PROJECT_NAME}_windows)
endif()
+unset(${PROJECT_NAME}_soversion)
if(SECP256K1_BUILD_BENCHMARK)
add_executable(bench bench.c)
- target_link_libraries(bench binary_interface link_library)
- add_executable(bench_internal bench_internal.c ${internal_obj})
- target_link_libraries(bench_internal binary_interface)
- add_executable(bench_ecmult bench_ecmult.c ${internal_obj})
- target_link_libraries(bench_ecmult binary_interface)
+ target_link_libraries(bench secp256k1)
+ add_executable(bench_internal bench_internal.c)
+ target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm)
+ add_executable(bench_ecmult bench_ecmult.c)
+ target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm)
endif()
if(SECP256K1_BUILD_TESTS)
- add_executable(noverify_tests tests.c ${internal_obj})
- target_link_libraries(noverify_tests binary_interface)
- add_test(noverify_tests noverify_tests)
+ add_executable(noverify_tests tests.c)
+ target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
+ add_test(NAME noverify_tests COMMAND noverify_tests)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
- add_executable(tests tests.c ${internal_obj})
+ add_executable(tests tests.c)
target_compile_definitions(tests PRIVATE VERIFY)
- target_link_libraries(tests binary_interface)
- add_test(tests tests)
+ target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
+ add_test(NAME tests COMMAND tests)
endif()
endif()
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
- # Note: do not include $<TARGET_OBJECTS:precomputed> in exhaustive_tests (it uses runtime-generated tables).
- add_executable(exhaustive_tests tests_exhaustive.c ${common_obj})
+ # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables).
+ add_executable(exhaustive_tests tests_exhaustive.c)
+ target_link_libraries(exhaustive_tests secp256k1_asm)
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
- target_link_libraries(exhaustive_tests binary_interface)
- add_test(exhaustive_tests exhaustive_tests)
+ add_test(NAME exhaustive_tests COMMAND exhaustive_tests)
endif()
if(SECP256K1_BUILD_CTIME_TESTS)
add_executable(ctime_tests ctime_tests.c)
- target_link_libraries(ctime_tests binary_interface link_library)
+ target_link_libraries(ctime_tests secp256k1)
endif()
-install(TARGETS ${${PROJECT_NAME}_installables}
- EXPORT ${PROJECT_NAME}-targets
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-)
-set(${PROJECT_NAME}_headers
- "${PROJECT_SOURCE_DIR}/include/secp256k1.h"
- "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
-)
-if(SECP256K1_ENABLE_MODULE_ECDH)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
-endif()
-if(SECP256K1_ENABLE_MODULE_RECOVERY)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
-endif()
-if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
-endif()
-if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
-endif()
-install(FILES ${${PROJECT_NAME}_headers}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-)
+if(SECP256K1_INSTALL)
+ install(TARGETS secp256k1
+ EXPORT ${PROJECT_NAME}-targets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ set(${PROJECT_NAME}_headers
+ "${PROJECT_SOURCE_DIR}/include/secp256k1.h"
+ "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
+ )
+ if(SECP256K1_ENABLE_MODULE_ECDH)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_RECOVERY)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
+ endif()
+ if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
+ list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
+ endif()
+ install(FILES ${${PROJECT_NAME}_headers}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ )
-install(EXPORT ${PROJECT_NAME}-targets
- FILE ${PROJECT_NAME}-targets.cmake
- NAMESPACE ${PROJECT_NAME}::
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
-)
+ install(EXPORT ${PROJECT_NAME}-targets
+ FILE ${PROJECT_NAME}-targets.cmake
+ NAMESPACE ${PROJECT_NAME}::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ )
-include(CMakePackageConfigHelpers)
-configure_package_config_file(
- ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
- ${PROJECT_NAME}-config.cmake
- INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
- NO_SET_AND_CHECK_MACRO
-)
-write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
- COMPATIBILITY SameMajorVersion
-)
-install(
- FILES
- ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ include(CMakePackageConfigHelpers)
+ configure_package_config_file(
+ ${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
+ ${PROJECT_NAME}-config.cmake
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ NO_SET_AND_CHECK_MACRO
+ )
+ write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
+ COMPATIBILITY SameMinorVersion
+ )
+
+ install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
+endif()
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
index 5f68cefc46..42cbf879ef 100644
--- a/src/secp256k1/src/asm/field_10x26_arm.s
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -29,6 +29,7 @@ Note:
.align 2
.global secp256k1_fe_mul_inner
.type secp256k1_fe_mul_inner, %function
+ .hidden secp256k1_fe_mul_inner
@ Arguments:
@ r0 r Restrict: can overlap with a, not with b
@ r1 a
@@ -516,6 +517,7 @@ secp256k1_fe_mul_inner:
.align 2
.global secp256k1_fe_sqr_inner
.type secp256k1_fe_sqr_inner, %function
+ .hidden secp256k1_fe_sqr_inner
@ Arguments:
@ r0 r Can overlap with a
@ r1 a
diff --git a/src/secp256k1/src/bench.c b/src/secp256k1/src/bench.c
index 833f70718b..1127df67ae 100644
--- a/src/secp256k1/src/bench.c
+++ b/src/secp256k1/src/bench.c
@@ -38,6 +38,8 @@ static void help(int default_iters) {
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
printf(" ecdsa_sign : ECDSA siging algorithm\n");
printf(" ecdsa_verify : ECDSA verification algorithm\n");
+ printf(" ec : all EC public key algorithms (keygen)\n");
+ printf(" ec_keygen : EC public key generation\n");
#ifdef ENABLE_MODULE_RECOVERY
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
@@ -53,6 +55,14 @@ static void help(int default_iters) {
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n");
+ printf(" ellswift_encode : ElligatorSwift encoding\n");
+ printf(" ellswift_decode : ElligatorSwift decoding\n");
+ printf(" ellswift_keygen : ElligatorSwift key generation\n");
+ printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n");
+#endif
+
printf("\n");
}
@@ -64,11 +74,11 @@ typedef struct {
size_t siglen;
unsigned char pubkey[33];
size_t pubkeylen;
-} bench_verify_data;
+} bench_data;
static void bench_verify(void* arg, int iters) {
int i;
- bench_verify_data* data = (bench_verify_data*)arg;
+ bench_data* data = (bench_data*)arg;
for (i = 0; i < iters; i++) {
secp256k1_pubkey pubkey;
@@ -85,15 +95,9 @@ static void bench_verify(void* arg, int iters) {
}
}
-typedef struct {
- secp256k1_context* ctx;
- unsigned char msg[32];
- unsigned char key[32];
-} bench_sign_data;
-
static void bench_sign_setup(void* arg) {
int i;
- bench_sign_data *data = (bench_sign_data*)arg;
+ bench_data *data = (bench_data*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = i + 1;
@@ -105,7 +109,7 @@ static void bench_sign_setup(void* arg) {
static void bench_sign_run(void* arg, int iters) {
int i;
- bench_sign_data *data = (bench_sign_data*)arg;
+ bench_data *data = (bench_data*)arg;
unsigned char sig[74];
for (i = 0; i < iters; i++) {
@@ -121,6 +125,30 @@ static void bench_sign_run(void* arg, int iters) {
}
}
+static void bench_keygen_setup(void* arg) {
+ int i;
+ bench_data *data = (bench_data*)arg;
+
+ for (i = 0; i < 32; i++) {
+ data->key[i] = i + 65;
+ }
+}
+
+static void bench_keygen_run(void *arg, int iters) {
+ int i;
+ bench_data *data = (bench_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ unsigned char pub33[33];
+ size_t len = 33;
+ secp256k1_pubkey pubkey;
+ CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
+ memcpy(data->key, pub33 + 1, 32);
+ }
+}
+
+
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/bench_impl.h"
#endif
@@ -133,11 +161,15 @@ static void bench_sign_run(void* arg, int iters) {
# include "modules/schnorrsig/bench_impl.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/bench_impl.h"
+#endif
+
int main(int argc, char** argv) {
int i;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
- bench_verify_data data;
+ bench_data data;
int d = argc == 1;
int default_iters = 20000;
@@ -145,7 +177,9 @@ int main(int argc, char** argv) {
/* Check for invalid user arguments */
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
- "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"};
+ "ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
+ "keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
+ "ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
@@ -187,6 +221,16 @@ int main(int argc, char** argv) {
}
#endif
+#ifndef ENABLE_MODULE_ELLSWIFT
+ if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") ||
+ have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
+ have_flag(argc, argv, "ellswift_ecdh")) {
+ fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
+ fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n");
+ return 1;
+ }
+#endif
+
/* ECDSA benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
@@ -207,6 +251,7 @@ int main(int argc, char** argv) {
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
@@ -225,5 +270,10 @@ int main(int argc, char** argv) {
run_schnorrsig_bench(iters, argc, argv);
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ /* ElligatorSwift benchmarks */
+ run_ellswift_bench(iters, argc, argv);
+#endif
+
return 0;
}
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index bf9a932ff4..1564b1a176 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -15,7 +15,7 @@
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
# include <time.h>
#else
-# include "sys/time.h"
+# include <sys/time.h>
#endif
static int64_t gettime_i64(void) {
diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c
index 98fb798d82..8818aa81b5 100644
--- a/src/secp256k1/src/bench_ecmult.c
+++ b/src/secp256k1/src/bench_ecmult.c
@@ -113,7 +113,7 @@ static void bench_ecmult_const(void* arg, int iters) {
int i;
for (i = 0; i < iters; ++i) {
- secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], 256);
+ secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]);
}
}
@@ -138,12 +138,10 @@ static void bench_ecmult_1p_teardown(void* arg, int iters) {
static void bench_ecmult_0p_g(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
- secp256k1_scalar zero;
int i;
- secp256k1_scalar_set_int(&zero, 0);
for (i = 0; i < iters; ++i) {
- secp256k1_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]);
+ secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]);
}
}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index c248ab8ebc..f3686dd289 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -65,10 +65,10 @@ static void bench_setup(void* arg) {
secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
- secp256k1_fe_set_b32(&data->fe[0], init[0]);
- secp256k1_fe_set_b32(&data->fe[1], init[1]);
- secp256k1_fe_set_b32(&data->fe[2], init[2]);
- secp256k1_fe_set_b32(&data->fe[3], init[3]);
+ secp256k1_fe_set_b32_limit(&data->fe[0], init[0]);
+ secp256k1_fe_set_b32_limit(&data->fe[1], init[1]);
+ secp256k1_fe_set_b32_limit(&data->fe[2], init[2]);
+ secp256k1_fe_set_b32_limit(&data->fe[3], init[3]);
CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);
diff --git a/src/secp256k1/src/ctime_tests.c b/src/secp256k1/src/ctime_tests.c
index 713eb427d3..af7891a91c 100644
--- a/src/secp256k1/src/ctime_tests.c
+++ b/src/secp256k1/src/ctime_tests.c
@@ -30,6 +30,10 @@
#include "../include/secp256k1_schnorrsig.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+#include "../include/secp256k1_ellswift.h"
+#endif
+
static void run_tests(secp256k1_context *ctx, unsigned char *key);
int main(void) {
@@ -80,6 +84,10 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
#ifdef ENABLE_MODULE_EXTRAKEYS
secp256k1_keypair keypair;
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ unsigned char ellswift[64];
+ static const unsigned char prefix[64] = {'t', 'e', 's', 't'};
+#endif
for (i = 0; i < 32; i++) {
msg[i] = i + 1;
@@ -171,4 +179,31 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
+
+#ifdef ENABLE_MODULE_ELLSWIFT
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ for (i = 0; i < 2; i++) {
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ VALGRIND_MAKE_MEM_DEFINED(&ellswift, sizeof(ellswift));
+ ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+
+ VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
+ VALGRIND_MAKE_MEM_DEFINED(&ellswift, sizeof(ellswift));
+ ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix);
+ VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
+ CHECK(ret == 1);
+ }
+
+#endif
}
diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h
index 90b4b22b77..48e30851b5 100644
--- a/src/secp256k1/src/ecdsa_impl.h
+++ b/src/secp256k1/src/ecdsa_impl.h
@@ -239,7 +239,8 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
}
#else
secp256k1_scalar_get_b32(c, sigr);
- secp256k1_fe_set_b32(&xr, c);
+ /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
+ (void)secp256k1_fe_set_b32_limit(&xr, c);
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index e0506d3e2b..121966f8b5 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -17,10 +17,10 @@
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
secp256k1_fe x;
- return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
+ return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
secp256k1_fe x, y;
- if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
+ if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) {
return 0;
}
secp256k1_ge_set_xy(elem, &x, &y);
@@ -59,10 +59,8 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp25
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) {
secp256k1_gej pt;
- secp256k1_scalar one;
secp256k1_gej_set_ge(&pt, key);
- secp256k1_scalar_set_int(&one, 1);
- secp256k1_ecmult(&pt, &pt, &one, tweak);
+ secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak);
if (secp256k1_gej_is_infinity(&pt)) {
return 0;
@@ -80,15 +78,13 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp25
}
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) {
- secp256k1_scalar zero;
secp256k1_gej pt;
if (secp256k1_scalar_is_zero(tweak)) {
return 0;
}
- secp256k1_scalar_set_int(&zero, 0);
secp256k1_gej_set_ge(&pt, key);
- secp256k1_ecmult(&pt, &pt, tweak, &zero);
+ secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
secp256k1_ge_set_gej(key, &pt);
return 1;
}
diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h
index f891f3f306..080e04bc88 100644
--- a/src/secp256k1/src/ecmult_const.h
+++ b/src/secp256k1/src/ecmult_const.h
@@ -11,11 +11,28 @@
#include "group.h"
/**
- * Multiply: R = q*A (in constant-time)
- * Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
- * one because we internally sometimes add 2 to the number during the WNAF conversion.
- * A must not be infinity.
+ * Multiply: R = q*A (in constant-time for q)
*/
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
+
+/**
+ * Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point
+ * only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is
+ * returned.
+ *
+ * If known_on_curve is 0, a verification is performed that n/d is a valid X
+ * coordinate, and 0 is returned if not. Otherwise, 1 is returned.
+ *
+ * d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero.
+ *
+ * Constant time in the value of q, but not any other inputs.
+ */
+static int secp256k1_ecmult_const_xonly(
+ secp256k1_fe *r,
+ const secp256k1_fe *n,
+ const secp256k1_fe *d,
+ const secp256k1_scalar *q,
+ int known_on_curve
+);
#endif /* SECP256K1_ECMULT_CONST_H */
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 12dbcc6c5b..26b3e238d8 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -29,7 +29,7 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
int m = 0; \
/* Extract the sign-bit for a constant time absolute-value. */ \
- int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
+ int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
int abs_n = ((n) + mask) ^ mask; \
int idx_n = abs_n >> 1; \
secp256k1_fe neg_y; \
@@ -130,7 +130,7 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
return skew;
}
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge tmpa;
secp256k1_fe Z;
@@ -144,20 +144,17 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
int i;
- /* build wnaf representation for q. */
- int rsize = size;
- if (size > 128) {
- rsize = 128;
- /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
- secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
- skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
- skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
- } else
- {
- skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size);
- skew_lam = 0;
+ if (secp256k1_ge_is_infinity(a)) {
+ secp256k1_gej_set_infinity(r);
+ return;
}
+ /* build wnaf representation for q. */
+ /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
+ secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
+ skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
+ skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
+
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
@@ -170,28 +167,23 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_fe_normalize_weak(&pre_a[i].y);
}
- if (size > 128) {
- for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
- }
-
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
- i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
+ i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
- if (size > 128) {
- i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
- secp256k1_gej_add_ge(r, r, &tmpa);
- }
+ i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
+ VERIFY_CHECK(i != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
+ secp256k1_gej_add_ge(r, r, &tmpa);
/* remaining loop iterations */
- for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
+ for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) {
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
@@ -202,12 +194,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
- if (size > 128) {
- n = wnaf_lam[i];
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
- VERIFY_CHECK(n != 0);
- secp256k1_gej_add_ge(r, r, &tmpa);
- }
+ n = wnaf_lam[i];
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
+ VERIFY_CHECK(n != 0);
+ secp256k1_gej_add_ge(r, r, &tmpa);
}
{
@@ -218,14 +208,147 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
secp256k1_gej_cmov(r, &tmpj, skew_1);
- if (size > 128) {
- secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
- secp256k1_gej_add_ge(&tmpj, r, &tmpa);
- secp256k1_gej_cmov(r, &tmpj, skew_lam);
- }
+ secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
+ secp256k1_gej_add_ge(&tmpj, r, &tmpa);
+ secp256k1_gej_cmov(r, &tmpj, skew_lam);
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
}
+static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
+
+ /* This algorithm is a generalization of Peter Dettman's technique for
+ * avoiding the square root in a random-basepoint x-only multiplication
+ * on a Weierstrass curve:
+ * https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/
+ *
+ *
+ * === Background: the effective affine technique ===
+ *
+ * Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to
+ * x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as
+ * the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as
+ * the curve b=7 coefficient does not appear in those formulas (or at least does not appear in
+ * the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2
+ * in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf.
+ *
+ * This means any linear combination of secp256k1 points can be computed by applying phi_u
+ * (with non-zero u) on all input points (including the generator, if used), computing the
+ * linear combination on the isomorphic curve (using the same group laws), and then applying
+ * phi_u^{-1} to get back to secp256k1.
+ *
+ * Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply
+ * (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z
+ * coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic
+ * curve where the affine addition formula can be used instead.
+ * If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is
+ * (X3, Y3, Z3*Z).
+ *
+ * This is the effective affine technique: if we have a linear combination of group elements
+ * to compute, and all those group elements have the same Z coordinate, we can simply pretend
+ * that all those Z coordinates are 1, perform the computation that way, and then multiply the
+ * original Z coordinate back in.
+ *
+ * The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to
+ * other curves too, but there the isomorphic curves will have different 'a' coefficients,
+ * which typically does affect the group laws.
+ *
+ *
+ * === Avoiding the square root for x-only point multiplication ===
+ *
+ * In this function, we want to compute the X coordinate of q*(n/d, y), for
+ * y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention
+ * we pick whatever sqrt returns (which we assume to be a deterministic function).
+ *
+ * Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3).
+ * Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2.
+ *
+ * The input point (n/d, y) also has Jacobian coordinates:
+ *
+ * (n/d, y, 1)
+ * = (n/d * v^2, y * v^3, v)
+ * = (n/d * d*g, y * sqrt(d^3*g^3), v)
+ * = (n/d * d*g, sqrt(y^2 * d^3*g^3), v)
+ * = (n*g, sqrt(g/d^3 * d^3*g^3), v)
+ * = (n*g, sqrt(g^4), v)
+ * = (n*g, g^2, v)
+ *
+ * It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X
+ * coordinate n/d, and this holds even when the square root function doesn't have a
+ * determinstic sign. We choose the (n*g, g^2, v) version.
+ *
+ * Now switch to the effective affine curve using phi_v, where the input point has coordinates
+ * (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there.
+ *
+ * Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X
+ * coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve
+ * a square root, but as long as we only care about the resulting X coordinate, no square root
+ * is needed anywhere in this computation.
+ */
+
+ secp256k1_fe g, i;
+ secp256k1_ge p;
+ secp256k1_gej rj;
+
+ /* Compute g = (n^3 + B*d^3). */
+ secp256k1_fe_sqr(&g, n);
+ secp256k1_fe_mul(&g, &g, n);
+ if (d) {
+ secp256k1_fe b;
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d));
+#endif
+ secp256k1_fe_sqr(&b, d);
+ VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */
+ secp256k1_fe_mul_int(&b, SECP256K1_B);
+ secp256k1_fe_mul(&b, &b, d);
+ secp256k1_fe_add(&g, &b);
+ if (!known_on_curve) {
+ /* We need to determine whether (n/d)^3 + 7 is square.
+ *
+ * is_square((n/d)^3 + 7)
+ * <=> is_square(((n/d)^3 + 7) * d^4)
+ * <=> is_square((n^3 + 7*d^3) * d)
+ * <=> is_square(g * d)
+ */
+ secp256k1_fe c;
+ secp256k1_fe_mul(&c, &g, d);
+ if (!secp256k1_fe_is_square_var(&c)) return 0;
+ }
+ } else {
+ secp256k1_fe_add_int(&g, SECP256K1_B);
+ if (!known_on_curve) {
+ /* g at this point equals x^3 + 7. Test if it is square. */
+ if (!secp256k1_fe_is_square_var(&g)) return 0;
+ }
+ }
+
+ /* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has
+ * corresponding affine X coordinate n/d. */
+ secp256k1_fe_mul(&p.x, &g, n);
+ secp256k1_fe_sqr(&p.y, &g);
+ p.infinity = 0;
+
+ /* Perform x-only EC multiplication of P with q. */
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
+#endif
+ secp256k1_ecmult_const(&rj, &p, q);
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
+#endif
+
+ /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
+ * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
+ * (X / (Z^2*d*g)). */
+ secp256k1_fe_sqr(&i, &rj.z);
+ secp256k1_fe_mul(&i, &i, &g);
+ if (d) secp256k1_fe_mul(&i, &i, d);
+ secp256k1_fe_inv(&i, &i);
+ secp256k1_fe_mul(r, &rj.x, &i);
+
+ return 1;
+}
+
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
diff --git a/src/secp256k1/src/ecmult_gen_compute_table_impl.h b/src/secp256k1/src/ecmult_gen_compute_table_impl.h
index ff6a2992dc..7d672b9950 100644
--- a/src/secp256k1/src/ecmult_gen_compute_table_impl.h
+++ b/src/secp256k1/src/ecmult_gen_compute_table_impl.h
@@ -31,7 +31,7 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
secp256k1_fe nums_x;
secp256k1_ge nums_ge;
int r;
- r = secp256k1_fe_set_b32(&nums_x, nums_b32);
+ r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
(void)r;
VERIFY_CHECK(r);
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 4f5ea9f3c0..af412173e9 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -87,7 +87,6 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_fe s;
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
- int overflow;
unsigned char keydata[64];
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
@@ -106,11 +105,9 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
memcpy(keydata + 32, seed32, 32);
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
memset(keydata, 0, sizeof(keydata));
- /* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
- overflow = !secp256k1_fe_set_b32(&s, nonce32);
- overflow |= secp256k1_fe_is_zero(&s);
- secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
+ secp256k1_fe_set_b32_mod(&s, nonce32);
+ secp256k1_fe_cmov(&s, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&s));
/* Randomize the projection to defend against multiplier sidechannels.
Do this before our own call to secp256k1_ecmult_gen below. */
secp256k1_gej_rescale(&ctx->initial, &s);
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 3776fe73fc..f4624677d7 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -97,7 +97,7 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, sec
secp256k1_gej_set_ge(&ai, &pre_a[0]);
ai.z = a->z;
- /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a.
+ /* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a.
* Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
*/
zr[0] = d.z;
@@ -114,13 +114,16 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, sec
secp256k1_fe_mul(z, &ai.z, &d.z);
}
-#define SECP256K1_ECMULT_TABLE_VERIFY(n,w) \
- VERIFY_CHECK(((n) & 1) == 1); \
- VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
+SECP256K1_INLINE static void secp256k1_ecmult_table_verify(int n, int w) {
+ (void)n;
+ (void)w;
+ VERIFY_CHECK(((n) & 1) == 1);
+ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1));
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1));
+}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) {
- SECP256K1_ECMULT_TABLE_VERIFY(n,w)
+ secp256k1_ecmult_table_verify(n,w);
if (n > 0) {
*r = pre[(n-1)/2];
} else {
@@ -130,7 +133,7 @@ SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, cons
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) {
- SECP256K1_ECMULT_TABLE_VERIFY(n,w)
+ secp256k1_ecmult_table_verify(n,w);
if (n > 0) {
secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y);
} else {
@@ -140,7 +143,7 @@ SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) {
- SECP256K1_ECMULT_TABLE_VERIFY(n,w)
+ secp256k1_ecmult_table_verify(n,w);
if (n > 0) {
secp256k1_ge_from_storage(r, &pre[(n-1)/2]);
} else {
@@ -276,9 +279,6 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
*/
tmp = a[np];
if (no) {
-#ifdef VERIFY
- secp256k1_fe_normalize_var(&Z);
-#endif
secp256k1_gej_rescale(&tmp, &Z);
}
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
@@ -680,7 +680,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
}
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps));
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
- buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<<bucket_window) * sizeof(*buckets));
+ buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets));
if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
@@ -770,14 +770,12 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
* require a scratch space */
static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
size_t point_idx;
- secp256k1_scalar szero;
secp256k1_gej tmpj;
- secp256k1_scalar_set_int(&szero, 0);
secp256k1_gej_set_infinity(r);
secp256k1_gej_set_infinity(&tmpj);
/* r = inp_g_sc*G */
- secp256k1_ecmult(r, &tmpj, &szero, inp_g_sc);
+ secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc);
for (point_idx = 0; point_idx < n_points; point_idx++) {
secp256k1_ge point;
secp256k1_gej pointj;
@@ -825,9 +823,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback,
if (inp_g_sc == NULL && n == 0) {
return 1;
} else if (n == 0) {
- secp256k1_scalar szero;
- secp256k1_scalar_set_int(&szero, 0);
- secp256k1_ecmult(r, r, &szero, inp_g_sc);
+ secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc);
return 1;
}
if (scratch == NULL) {
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 64ceead4d2..e632f9e3e2 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -7,19 +7,36 @@
#ifndef SECP256K1_FIELD_H
#define SECP256K1_FIELD_H
-/** Field element module.
- *
- * Field elements can be represented in several ways, but code accessing
- * it (and implementations) need to take certain properties into account:
- * - Each field element can be normalized or not.
- * - Each field element has a magnitude, which represents how far away
- * its representation is away from normalization. Normalized elements
- * always have a magnitude of 0 or 1, but a magnitude of 1 doesn't
- * imply normality.
- */
-
#include "util.h"
+/* This file defines the generic interface for working with secp256k1_fe
+ * objects, which represent field elements (integers modulo 2^256 - 2^32 - 977).
+ *
+ * The actual definition of the secp256k1_fe type depends on the chosen field
+ * implementation; see the field_5x52.h and field_10x26.h files for details.
+ *
+ * All secp256k1_fe objects have implicit properties that determine what
+ * operations are permitted on it. These are purely a function of what
+ * secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at
+ * compile time, and do not depend on the chosen field implementation. Despite
+ * that, what these properties actually entail for the field representation
+ * values depends on the chosen field implementation. These properties are:
+ * - magnitude: an integer in [0,32]
+ * - normalized: 0 or 1; normalized=1 implies magnitude <= 1.
+ *
+ * In VERIFY mode, they are materialized explicitly as fields in the struct,
+ * allowing run-time verification of these properties. In that case, the field
+ * implementation also provides a secp256k1_fe_verify routine to verify that
+ * these fields match the run-time value and perform internal consistency
+ * checks. */
+#ifdef VERIFY
+# define SECP256K1_FE_VERIFY_FIELDS \
+ int magnitude; \
+ int normalized;
+#else
+# define SECP256K1_FE_VERIFY_FIELDS
+#endif
+
#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52.h"
#elif defined(SECP256K1_WIDEMUL_INT64)
@@ -28,117 +45,297 @@
#error "Please select wide multiplication implementation"
#endif
+#ifdef VERIFY
+/* Magnitude and normalized value for constants. */
+#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \
+ /* Magnitude is 0 for constant 0; 1 otherwise. */ \
+ , (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \
+ /* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \
+ , (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f)))))
+#else
+#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0)
+#endif
+
+/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p.
+ *
+ * It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0.
+ * It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p.
+ *
+ * SECP256K1_FE_CONST_INNER is provided by the implementation.
+ */
+#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) }
+
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
);
-/** Normalize a field element. This brings the field element to a canonical representation, reduces
- * its magnitude to 1, and reduces it modulo field size `p`.
+#ifndef VERIFY
+/* In non-VERIFY mode, we #define the fe operations to be identical to their
+ * internal field implementation, to avoid the potential overhead of a
+ * function call (even though presumably inlinable). */
+# define secp256k1_fe_normalize secp256k1_fe_impl_normalize
+# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak
+# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var
+# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero
+# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
+# define secp256k1_fe_set_int secp256k1_fe_impl_set_int
+# define secp256k1_fe_clear secp256k1_fe_impl_clear
+# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
+# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
+# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
+# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
+# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
+# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
+# define secp256k1_fe_negate secp256k1_fe_impl_negate
+# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
+# define secp256k1_fe_add secp256k1_fe_impl_add
+# define secp256k1_fe_mul secp256k1_fe_impl_mul
+# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
+# define secp256k1_fe_cmov secp256k1_fe_impl_cmov
+# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage
+# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage
+# define secp256k1_fe_inv secp256k1_fe_impl_inv
+# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var
+# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds
+# define secp256k1_fe_half secp256k1_fe_impl_half
+# define secp256k1_fe_add_int secp256k1_fe_impl_add_int
+# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var
+#endif /* !defined(VERIFY) */
+
+/** Normalize a field element.
+ *
+ * On input, r must be a valid field element.
+ * On output, r represents the same value but has normalized=1 and magnitude=1.
*/
static void secp256k1_fe_normalize(secp256k1_fe *r);
-/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
+/** Give a field element magnitude 1.
+ *
+ * On input, r must be a valid field element.
+ * On output, r represents the same value but has magnitude=1. Normalized is unchanged.
+ */
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
-/** Normalize a field element, without constant-time guarantee. */
+/** Normalize a field element, without constant-time guarantee.
+ *
+ * Identical in behavior to secp256k1_fe_normalize, but not constant time in r.
+ */
static void secp256k1_fe_normalize_var(secp256k1_fe *r);
-/** Verify whether a field element represents zero i.e. would normalize to a zero value. */
+/** Determine whether r represents field element 0.
+ *
+ * On input, r must be a valid field element.
+ * Returns whether r = 0 (mod p).
+ */
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r);
-/** Verify whether a field element represents zero i.e. would normalize to a zero value,
- * without constant-time guarantee. */
+/** Determine whether r represents field element 0, without constant-time guarantee.
+ *
+ * Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r.
+ */
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
-/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer.
- * Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise.
+/** Set a field element to an integer in range [0,0x7FFF].
+ *
+ * On input, r does not need to be initialized, a must be in [0,0x7FFF].
+ * On output, r represents value a, is normalized and has magnitude (a!=0).
*/
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
-/** Sets a field element equal to zero, initializing all fields. */
+/** Set a field element to 0.
+ *
+ * On input, a does not need to be initialized.
+ * On output, a represents 0, is normalized and has magnitude 0.
+ */
static void secp256k1_fe_clear(secp256k1_fe *a);
-/** Verify whether a field element is zero. Requires the input to be normalized. */
+/** Determine whether a represents field element 0.
+ *
+ * On input, a must be a valid normalized field element.
+ * Returns whether a = 0 (mod p).
+ *
+ * This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires
+ * normalized input (and is much faster).
+ */
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
-/** Check the "oddness" of a field element. Requires the input to be normalized. */
+/** Determine whether a (mod p) is odd.
+ *
+ * On input, a must be a valid normalized field element.
+ * Returns (int(a) mod p) & 1.
+ */
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
-/** Compare two field elements. Requires magnitude-1 inputs. */
+/** Determine whether two field elements are equal.
+ *
+ * On input, a and b must be valid field elements with magnitudes not exceeding
+ * 1 and 31, respectively.
+ * Returns a = b (mod p).
+ */
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Same as secp256k1_fe_equal, but may be variable time. */
+/** Determine whether two field elements are equal, without constant-time guarantee.
+ *
+ * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b.
+ */
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Compare two field elements. Requires both inputs to be normalized */
+/** Compare the values represented by 2 field elements, without constant-time guarantee.
+ *
+ * On input, a and b must be valid normalized field elements.
+ * Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers
+ * in range 0..p-1).
+ */
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
-/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */
-static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);
+/** Set a field element equal to a provided 32-byte big endian value, reducing it.
+ *
+ * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
+ * On output, r = a (mod p). It will have magnitude 1, and not be normalized.
+ */
+static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
+
+/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
+ *
+ * On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
+ * On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
+ * If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
+ */
+static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
-/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
+/** Convert a field element to 32-byte big endian byte array.
+ * On input, a must be a valid normalized field element, and r a pointer to a 32-byte array.
+ * On output, r = a (mod p).
+ */
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
-/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
- * as an argument. The magnitude of the output is one higher. */
+/** Negate a field element.
+ *
+ * On input, r does not need to be initialized. a must be a valid field element with
+ * magnitude not exceeding m. m must be an integer in [0,31].
+ * Performs {r = -a}.
+ * On output, r will not be normalized, and will have magnitude m+1.
+ */
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
-/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */
+/** Add a small integer to a field element.
+ *
+ * Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
+ * a must be in range [0,0x7FFF].
+ */
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
-/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
- * small integer. */
+/** Multiply a field element with a small integer.
+ *
+ * On input, r must be a valid field element. a must be an integer in [0,32].
+ * The magnitude of r times a must not exceed 32.
+ * Performs {r *= a}.
+ * On output, r's magnitude is multiplied by a, and r will not be normalized.
+ */
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
-/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
+/** Increment a field element by another.
+ *
+ * On input, r and a must be valid field elements, not necessarily normalized.
+ * The sum of their magnitudes must not exceed 32.
+ * Performs {r += a}.
+ * On output, r will not be normalized, and will have magnitude incremented by a's.
+ */
static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
-/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
- * The output magnitude is 1 (but not guaranteed to be normalized). */
+/** Multiply two field elements.
+ *
+ * On input, a and b must be valid field elements; r does not need to be initialized.
+ * r and a may point to the same object, but neither can be equal to b. The magnitudes
+ * of a and b must not exceed 8.
+ * Performs {r = a * b}
+ * On output, r will have magnitude 1, but won't be normalized.
+ */
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
-/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
- * The output magnitude is 1 (but not guaranteed to be normalized). */
+/** Square a field element.
+ *
+ * On input, a must be a valid field element; r does not need to be initialized. The magnitude
+ * of a must not exceed 8.
+ * Performs {r = a**2}
+ * On output, r will have magnitude 1, but won't be normalized.
+ */
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
-/** If a has a square root, it is computed in r and 1 is returned. If a does not
- * have a square root, the root of its negation is computed and 0 is returned.
- * The input's magnitude can be at most 8. The output magnitude is 1 (but not
- * guaranteed to be normalized). The result in r will always be a square
- * itself. */
-static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
+/** Compute a square root of a field element.
+ *
+ * On input, a must be a valid field element with magnitude<=8; r need not be initialized.
+ * Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value
+ * represented by r will be a square itself. Variables r and a must not point to the same object.
+ * On output, r will have magnitude 1 but will not be normalized.
+ */
+static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
-/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
- * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
+/** Compute the modular inverse of a field element.
+ *
+ * On input, a must be a valid field element; r need not be initialized.
+ * Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its
+ * inverse).
+ * On output, r will have magnitude (a.magnitude != 0) and be normalized.
+ */
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
-/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
+/** Compute the modular inverse of a field element, without constant-time guarantee.
+ *
+ * Behaves identically to secp256k1_fe_inv, but is not constant-time in a.
+ */
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
-/** Convert a field element to the storage type. */
+/** Convert a field element to secp256k1_fe_storage.
+ *
+ * On input, a must be a valid normalized field element.
+ * Performs {r = a}.
+ */
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
-/** Convert a field element back from the storage type. */
+/** Convert a field element back from secp256k1_fe_storage.
+ *
+ * On input, r need not be initialized.
+ * Performs {r = a}.
+ * On output, r will be normalized and will have magnitude 1.
+ */
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
-/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
+/** Conditionally move a field element in constant time.
+ *
+ * On input, both r and a must be valid field elements. Flag must be 0 or 1.
+ * Performs {r = flag ? a : r}.
+ *
+ * On output, r's magnitude will be the maximum of both input magnitudes.
+ * It will be normalized if and only if both inputs were normalized.
+ */
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
-/** Halves the value of a field element modulo the field prime. Constant-time.
- * For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'.
- * The output is not guaranteed to be normalized, regardless of the input. */
+/** Halve the value of a field element modulo the field prime in constant-time.
+ *
+ * On input, r must be a valid field element.
+ * On output, r will be normalized and have magnitude floor(m/2) + 1 where m is
+ * the magnitude of r on input.
+ */
static void secp256k1_fe_half(secp256k1_fe *r);
-/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its
- * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
+/** Sets r to a field element with magnitude m, normalized if (and only if) m==0.
+ * The value is chosen so that it is likely to trigger edge cases related to
+ * internal overflows. */
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
-/** Determine whether a is a square (modulo p). */
+/** Determine whether a is a square (modulo p).
+ *
+ * On input, a must be a valid field element.
+ */
static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
+/** Check invariants on a field element (no-op unless VERIFY is enabled). */
+static void secp256k1_fe_verify(const secp256k1_fe *a);
+
#endif /* SECP256K1_FIELD_H */
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 9eb65607f1..203c10167c 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -9,15 +9,28 @@
#include <stdint.h>
+/** This field implementation represents the value as 10 uint32_t limbs in base
+ * 2^26. */
typedef struct {
- /* X = sum(i=0..9, n[i]*2^(i*26)) mod p
- * where p = 2^256 - 0x1000003D1
- */
+ /* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p,
+ * where p is the field modulus, 2^256 - 2^32 - 977.
+ *
+ * The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly
+ * corresponds to how much excess is allowed. The value
+ * sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is
+ * normalized. */
uint32_t n[10];
-#ifdef VERIFY
- int magnitude;
- int normalized;
-#endif
+ /*
+ * Magnitude m requires:
+ * n[i] <= 2 * m * (2^26 - 1) for i=0..8
+ * n[9] <= 2 * m * (2^22 - 1)
+ *
+ * Normalized requires:
+ * n[i] <= (2^26 - 1) for i=0..8
+ * sum(i=0..9, n[i] << (i*26)) < p
+ * (together these imply n[9] <= 2^22 - 1)
+ */
+ SECP256K1_FE_VERIFY_FIELDS
} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
@@ -34,12 +47,6 @@ typedef struct {
(((uint32_t)d7) >> 10) \
}
-#ifdef VERIFY
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
-#else
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
-#endif
-
typedef struct {
uint32_t n[8];
} secp256k1_fe_storage;
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 46b72ce78d..c1b32b80a8 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -12,47 +12,32 @@
#include "field.h"
#include "modinv32_impl.h"
-/** See the comment at the top of field_5x52_impl.h for more details.
- *
- * Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first,
- * where limbs can contain >26 bits.
- * A magnitude M means:
- * - 2*M*(2^22-1) is the max (inclusive) of the most significant limb
- * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs
- */
-
#ifdef VERIFY
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
+static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
const uint32_t *d = a->n;
- int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
- r &= (d[0] <= 0x3FFFFFFUL * m);
- r &= (d[1] <= 0x3FFFFFFUL * m);
- r &= (d[2] <= 0x3FFFFFFUL * m);
- r &= (d[3] <= 0x3FFFFFFUL * m);
- r &= (d[4] <= 0x3FFFFFFUL * m);
- r &= (d[5] <= 0x3FFFFFFUL * m);
- r &= (d[6] <= 0x3FFFFFFUL * m);
- r &= (d[7] <= 0x3FFFFFFUL * m);
- r &= (d[8] <= 0x3FFFFFFUL * m);
- r &= (d[9] <= 0x03FFFFFUL * m);
- r &= (a->magnitude >= 0);
- r &= (a->magnitude <= 32);
+ int m = a->normalized ? 1 : 2 * a->magnitude;
+ VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m);
+ VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m);
if (a->normalized) {
- r &= (a->magnitude <= 1);
- if (r && (d[9] == 0x03FFFFFUL)) {
+ if (d[9] == 0x03FFFFFUL) {
uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2];
if (mid == 0x3FFFFFFUL) {
- r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
+ VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
}
}
}
- VERIFY_CHECK(r == 1);
}
#endif
-static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
- VERIFY_CHECK(m >= 0);
- VERIFY_CHECK(m <= 2048);
+static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
r->n[0] = 0x3FFFFFFUL * 2 * m;
r->n[1] = 0x3FFFFFFUL * 2 * m;
r->n[2] = 0x3FFFFFFUL * 2 * m;
@@ -63,14 +48,9 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
r->n[7] = 0x3FFFFFFUL * 2 * m;
r->n[8] = 0x3FFFFFFUL * 2 * m;
r->n[9] = 0x03FFFFFUL * 2 * m;
-#ifdef VERIFY
- r->magnitude = m;
- r->normalized = (m == 0);
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -117,15 +97,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -149,14 +123,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
-
-#ifdef VERIFY
- r->magnitude = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -204,15 +173,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@@ -241,7 +204,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
-static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
uint32_t z0, z1;
uint32_t x;
@@ -293,53 +256,29 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
- VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
-#ifdef VERIFY
- r->magnitude = (a != 0);
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
const uint32_t *t = a->n;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;
}
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
return a->n[0] & 1;
}
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
int i;
-#ifdef VERIFY
- a->magnitude = 0;
- a->normalized = 1;
-#endif
for (i=0; i<10; i++) {
a->n[i] = 0;
}
}
-static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- VERIFY_CHECK(b->normalized);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
-#endif
for (i = 9; i >= 0; i--) {
if (a->n[i] > b->n[i]) {
return 1;
@@ -351,8 +290,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
return 0;
}
-static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int ret;
+static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
@@ -363,26 +301,15 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
+}
- ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
-#ifdef VERIFY
- r->magnitude = 1;
- if (ret) {
- r->normalized = 1;
- secp256k1_fe_verify(r);
- } else {
- r->normalized = 0;
- }
-#endif
- return ret;
+static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
+ secp256k1_fe_impl_set_b32_mod(r, a);
+ return !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[0] = (a->n[9] >> 14) & 0xff;
r[1] = (a->n[9] >> 6) & 0xff;
r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
@@ -417,15 +344,15 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[31] = a->n[0] & 0xff;
}
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= m);
- secp256k1_fe_verify(a);
+SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+ /* For all legal values of m (0..31), the following properties hold: */
VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m);
-#endif
+
+ /* Due to the properties above, the left hand in the subtractions below is never less than
+ * the right hand. */
r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0];
r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1];
r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2];
@@ -436,14 +363,9 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k
r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7];
r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8];
r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
-#ifdef VERIFY
- r->magnitude = m + 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
@@ -454,17 +376,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
r->n[7] *= a;
r->n[8] *= a;
r->n[9] *= a;
-#ifdef VERIFY
- r->magnitude *= a;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
@@ -475,25 +389,10 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
r->n[7] += a->n[7];
r->n[8] += a->n[8];
r->n[9] += a->n[9];
-#ifdef VERIFY
- r->magnitude += a->magnitude;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
-#ifdef VERIFY
- secp256k1_fe_verify(r);
- VERIFY_CHECK(a >= 0);
- VERIFY_CHECK(a <= 0x7FFF);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
r->n[0] += a;
-#ifdef VERIFY
- r->magnitude += 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
#if defined(USE_EXTERNAL_ASM)
@@ -1115,40 +1014,19 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
}
#endif
-static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- VERIFY_CHECK(b->magnitude <= 8);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
- VERIFY_CHECK(r != b);
- VERIFY_CHECK(a != b);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_mul_inner(r->n, a->n, b->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_sqr_inner(r->n, a->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
@@ -1160,25 +1038,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
-#ifdef VERIFY
- if (flag) {
- r->magnitude = a->magnitude;
- r->normalized = a->normalized;
- }
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
+static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
uint32_t one = (uint32_t)1;
uint32_t mask = -(t0 & one) >> 6;
-#ifdef VERIFY
- secp256k1_fe_verify(r);
- VERIFY_CHECK(r->magnitude < 32);
-#endif
-
/* Bounds analysis (over the rationals).
*
* Let m = r->magnitude
@@ -1225,10 +1092,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
*
* Current bounds: t0..t8 <= C * (m/2 + 1/2)
* t9 <= D * (m/2 + 1/4)
- */
-
-#ifdef VERIFY
- /* Therefore the output magnitude (M) has to be set such that:
+ *
+ * Therefore the output magnitude (M) has to be set such that:
* t0..t8: C * M >= C * (m/2 + 1/2)
* t9: D * M >= D * (m/2 + 1/4)
*
@@ -1238,16 +1103,13 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
* and since we want the smallest such integer value for M:
* M == floor(m/2) + 1
*/
- r->magnitude = (r->magnitude >> 1) + 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
@@ -1259,10 +1121,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
}
-static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
+static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
r->n[0] = a->n[0] | a->n[1] << 26;
r->n[1] = a->n[1] >> 6 | a->n[2] << 20;
r->n[2] = a->n[2] >> 12 | a->n[3] << 14;
@@ -1273,7 +1132,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
}
-static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0x3FFFFFFUL;
r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);
r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);
@@ -1284,11 +1143,6 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL);
r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL);
r->n[9] = a->n[7] >> 10;
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) {
@@ -1319,12 +1173,6 @@ static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32
r->n[7] = (a6 >> 2 ) & M26;
r->n[8] = (a6 >> 28 | a7 << 2) & M26;
r->n[9] = (a7 >> 24 | a8 << 6);
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) {
@@ -1332,10 +1180,6 @@ static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp2
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4],
a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9];
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
-
r->v[0] = (a0 | a1 << 26) & M30;
r->v[1] = (a1 >> 4 | a2 << 22) & M30;
r->v[2] = (a2 >> 8 | a3 << 18) & M30;
@@ -1353,33 +1197,27 @@ static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = {
0x2DDACACFL
};
-static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv32_signed30 s;
- tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
-
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
-static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv32_signed30 s;
- tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
-
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
-static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv32_signed30 s;
int jac, ret;
@@ -1397,10 +1235,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
-#ifdef VERIFY
- secp256k1_fe dummy;
- VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
-#endif
ret = jac >= 0;
}
return ret;
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index 50ee3f9ec9..f20c246fdd 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -9,15 +9,28 @@
#include <stdint.h>
+/** This field implementation represents the value as 5 uint64_t limbs in base
+ * 2^52. */
typedef struct {
- /* X = sum(i=0..4, n[i]*2^(i*52)) mod p
- * where p = 2^256 - 0x1000003D1
- */
+ /* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p,
+ * where p is the field modulus, 2^256 - 2^32 - 977.
+ *
+ * The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly
+ * corresponds to how much excess is allowed. The value
+ * sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is
+ * normalized. */
uint64_t n[5];
-#ifdef VERIFY
- int magnitude;
- int normalized;
-#endif
+ /*
+ * Magnitude m requires:
+ * n[i] <= 2 * m * (2^52 - 1) for i=0..3
+ * n[4] <= 2 * m * (2^48 - 1)
+ *
+ * Normalized requires:
+ * n[i] <= (2^52 - 1) for i=0..3
+ * sum(i=0..4, n[i] << (i*52)) < p
+ * (together these imply n[4] <= 2^48 - 1)
+ */
+ SECP256K1_FE_VERIFY_FIELDS
} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
@@ -29,12 +42,6 @@ typedef struct {
((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \
}
-#ifdef VERIFY
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
-#else
-#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
-#endif
-
typedef struct {
uint64_t n[4];
} secp256k1_fe_storage;
diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h
index a2118044ab..04a9af2105 100644
--- a/src/secp256k1/src/field_5x52_asm_impl.h
+++ b/src/secp256k1/src/field_5x52_asm_impl.h
@@ -14,6 +14,8 @@
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
#define SECP256K1_FIELD_INNER5X52_IMPL_H
+#include "util.h"
+
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
/**
* Registers: rdx:rax = multiplication accumulator
@@ -278,7 +280,7 @@ __asm__ __volatile__(
"addq %%rsi,%%r8\n"
/* r[4] = c */
"movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3)
+: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
: "b"(b), "D"(r)
: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
);
@@ -493,7 +495,7 @@ __asm__ __volatile__(
"addq %%rsi,%%r8\n"
/* r[4] = c */
"movq %%r8,32(%%rdi)\n"
-: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3)
+: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
: "D"(r)
: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
);
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 4c4466eceb..0a4cc1a630 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -18,59 +18,33 @@
#include "field_5x52_int128_impl.h"
#endif
-/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
- * represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to
- * contain >52 bits each.
- *
- * Each field element has a 'magnitude' associated with it. Internally, a magnitude M means:
- * - 2*M*(2^48-1) is the max (inclusive) of the most significant limb
- * - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs
- *
- * Operations have different rules for propagating magnitude to their outputs. If an operation takes a
- * magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive).
- *
- * Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either
- * 0 or 1, and its value is already reduced modulo the order of the field.
- */
-
#ifdef VERIFY
-static void secp256k1_fe_verify(const secp256k1_fe *a) {
+static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
const uint64_t *d = a->n;
- int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
+ int m = a->normalized ? 1 : 2 * a->magnitude;
/* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
- r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m);
- r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m);
- r &= (a->magnitude >= 0);
- r &= (a->magnitude <= 2048);
+ VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m);
+ VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m);
if (a->normalized) {
- r &= (a->magnitude <= 1);
- if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
- r &= (d[0] < 0xFFFFEFFFFFC2FULL);
+ if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
+ VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL);
}
}
- VERIFY_CHECK(r == 1);
}
#endif
-static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
- VERIFY_CHECK(m >= 0);
- VERIFY_CHECK(m <= 2048);
+static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
-#ifdef VERIFY
- r->magnitude = m;
- r->normalized = (m == 0);
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -105,15 +79,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
t4 &= 0x0FFFFFFFFFFFFULL;
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -130,14 +98,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
VERIFY_CHECK(t4 >> 49 == 0);
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
-
-#ifdef VERIFY
- r->magnitude = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
+static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@@ -173,15 +136,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
}
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
@@ -204,7 +161,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
-static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
+static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
uint64_t t0, t1, t2, t3, t4;
uint64_t z0, z1;
uint64_t x;
@@ -245,53 +202,29 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
-SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
- VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
-#ifdef VERIFY
- r->magnitude = (a != 0);
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
+SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
const uint64_t *t = a->n;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
}
-SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
return a->n[0] & 1;
}
-SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
int i;
-#ifdef VERIFY
- a->magnitude = 0;
- a->normalized = 1;
-#endif
for (i=0; i<5; i++) {
a->n[i] = 0;
}
}
-static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- VERIFY_CHECK(b->normalized);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
-#endif
for (i = 4; i >= 0; i--) {
if (a->n[i] > b->n[i]) {
return 1;
@@ -303,8 +236,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
return 0;
}
-static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
- int ret;
+static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
r->n[0] = (uint64_t)a[31]
| ((uint64_t)a[30] << 8)
| ((uint64_t)a[29] << 16)
@@ -339,25 +271,15 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
| ((uint64_t)a[2] << 24)
| ((uint64_t)a[1] << 32)
| ((uint64_t)a[0] << 40);
- ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
-#ifdef VERIFY
- r->magnitude = 1;
- if (ret) {
- r->normalized = 1;
- secp256k1_fe_verify(r);
- } else {
- r->normalized = 0;
- }
-#endif
- return ret;
+}
+
+static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
+ secp256k1_fe_impl_set_b32_mod(r, a);
+ return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
}
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
-static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
- secp256k1_fe_verify(a);
-#endif
+static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[0] = (a->n[4] >> 40) & 0xFF;
r[1] = (a->n[4] >> 32) & 0xFF;
r[2] = (a->n[4] >> 24) & 0xFF;
@@ -392,127 +314,67 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[31] = a->n[0] & 0xFF;
}
-SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= m);
- secp256k1_fe_verify(a);
+SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+ /* For all legal values of m (0..31), the following properties hold: */
VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m);
-#endif
+
+ /* Due to the properties above, the left hand in the subtractions below is never less than
+ * the right hand. */
r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2];
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3];
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
-#ifdef VERIFY
- r->magnitude = m + 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
+SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
-#ifdef VERIFY
- r->magnitude *= a;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
-#ifdef VERIFY
- secp256k1_fe_verify(r);
- VERIFY_CHECK(a >= 0);
- VERIFY_CHECK(a <= 0x7FFF);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
r->n[0] += a;
-#ifdef VERIFY
- r->magnitude += 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
r->n[3] += a->n[3];
r->n[4] += a->n[4];
-#ifdef VERIFY
- r->magnitude += a->magnitude;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- VERIFY_CHECK(b->magnitude <= 8);
- secp256k1_fe_verify(a);
- secp256k1_fe_verify(b);
- VERIFY_CHECK(r != b);
- VERIFY_CHECK(a != b);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_mul_inner(r->n, a->n, b->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->magnitude <= 8);
- secp256k1_fe_verify(a);
-#endif
+SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_sqr_inner(r->n, a->n);
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint64_t)0);
+ mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
-#ifdef VERIFY
- if (flag) {
- r->magnitude = a->magnitude;
- r->normalized = a->normalized;
- }
-#endif
}
-static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
+static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
uint64_t one = (uint64_t)1;
uint64_t mask = -(t0 & one) >> 12;
-#ifdef VERIFY
- secp256k1_fe_verify(r);
- VERIFY_CHECK(r->magnitude < 32);
-#endif
-
/* Bounds analysis (over the rationals).
*
* Let m = r->magnitude
@@ -549,10 +411,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
*
* Current bounds: t0..t3 <= C * (m/2 + 1/2)
* t4 <= D * (m/2 + 1/4)
- */
-
-#ifdef VERIFY
- /* Therefore the output magnitude (M) has to be set such that:
+ *
+ * Therefore the output magnitude (M) has to be set such that:
* t0..t3: C * M >= C * (m/2 + 1/2)
* t4: D * M >= D * (m/2 + 1/4)
*
@@ -562,16 +422,13 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
* and since we want the smallest such integer value for M:
* M == floor(m/2) + 1
*/
- r->magnitude = (r->magnitude >> 1) + 1;
- r->normalized = 0;
- secp256k1_fe_verify(r);
-#endif
}
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
- mask0 = flag + ~((uint64_t)0);
+ mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
@@ -579,27 +436,19 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
}
-static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
+static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
r->n[0] = a->n[0] | a->n[1] << 52;
r->n[1] = a->n[1] >> 12 | a->n[2] << 40;
r->n[2] = a->n[2] >> 24 | a->n[3] << 28;
r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
}
-static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);
r->n[4] = a->n[3] >> 16;
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) {
@@ -620,22 +469,12 @@ static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64
r->n[2] = (a1 >> 42 | a2 << 20) & M52;
r->n[3] = (a2 >> 32 | a3 << 30) & M52;
r->n[4] = (a3 >> 22 | a4 << 40);
-
-#ifdef VERIFY
- r->magnitude = 1;
- r->normalized = 1;
- secp256k1_fe_verify(r);
-#endif
}
static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) {
const uint64_t M62 = UINT64_MAX >> 2;
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4];
-#ifdef VERIFY
- VERIFY_CHECK(a->normalized);
-#endif
-
r->v[0] = (a0 | a1 << 52) & M62;
r->v[1] = (a1 >> 10 | a2 << 42) & M62;
r->v[2] = (a2 >> 20 | a3 << 32) & M62;
@@ -648,37 +487,27 @@ static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = {
0x27C7F6E22DDACACFLL
};
-static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv64_signed62 s;
- tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
-
-#ifdef VERIFY
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
-#endif
}
-static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
- secp256k1_fe tmp;
+static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+ secp256k1_fe tmp = *x;
secp256k1_modinv64_signed62 s;
- tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
-
-#ifdef VERIFY
- VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
-#endif
}
-static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv64_signed62 s;
int jac, ret;
@@ -696,10 +525,6 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
-#ifdef VERIFY
- secp256k1_fe dummy;
- VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
-#endif
ret = jac >= 0;
}
return ret;
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 18567b95f3..b2a391dec9 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -10,6 +10,7 @@
#include <stdint.h>
#include "int128.h"
+#include "util.h"
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 0a03076bbc..f9769a4a39 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -7,6 +7,7 @@
#ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H
+#include "field.h"
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
@@ -19,6 +20,12 @@
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
+#ifdef VERIFY
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->magnitude <= 1);
+ VERIFY_CHECK(b->magnitude <= 31);
+#endif
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero(&na);
@@ -26,6 +33,12 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
+#ifdef VERIFY
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->magnitude <= 1);
+ VERIFY_CHECK(b->magnitude <= 31);
+#endif
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero_var(&na);
@@ -42,9 +55,13 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
* itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
*/
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
- int j;
+ int j, ret;
+#ifdef VERIFY
VERIFY_CHECK(r != a);
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->magnitude <= 8);
+#endif
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
@@ -128,7 +145,286 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
/* Check that a square root was actually calculated */
secp256k1_fe_sqr(&t1, r);
- return secp256k1_fe_equal(&t1, a);
+ ret = secp256k1_fe_equal(&t1, a);
+
+#ifdef VERIFY
+ if (!ret) {
+ secp256k1_fe_negate(&t1, &t1, 1);
+ secp256k1_fe_normalize_var(&t1);
+ VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a));
+ }
+#endif
+ return ret;
+}
+
+#ifndef VERIFY
+static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
+#else
+static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
+static void secp256k1_fe_verify(const secp256k1_fe *a) {
+ /* Magnitude between 0 and 32. */
+ VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32));
+ /* Normalized is 0 or 1. */
+ VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
+ /* If normalized, magnitude must be 0 or 1. */
+ if (a->normalized) VERIFY_CHECK(a->magnitude <= 1);
+ /* Invoke implementation-specific checks. */
+ secp256k1_fe_impl_verify(a);
+}
+
+static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_normalize(r);
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_normalize_weak(r);
+ r->magnitude = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_normalize_var(r);
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
+SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ return secp256k1_fe_impl_normalizes_to_zero(r);
+}
+
+static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
+SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ return secp256k1_fe_impl_normalizes_to_zero_var(r);
+}
+
+static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
+SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
+ VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+ secp256k1_fe_impl_set_int(r, a);
+ r->magnitude = (a != 0);
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
+SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
+ VERIFY_CHECK(0 <= a && a <= 0x7FFF);
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_add_int(r, a);
+ r->magnitude += 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_clear(secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
+ a->magnitude = 0;
+ a->normalized = 1;
+ secp256k1_fe_impl_clear(a);
+ secp256k1_fe_verify(a);
+}
+
+static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
+SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ return secp256k1_fe_impl_is_zero(a);
+}
+
+static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
+SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ return secp256k1_fe_impl_is_odd(a);
+}
+
+static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
+SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->normalized);
+ VERIFY_CHECK(b->normalized);
+ return secp256k1_fe_impl_cmp_var(a, b);
+}
+
+static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
+SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
+ secp256k1_fe_impl_set_b32_mod(r, a);
+ r->magnitude = 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
}
+static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
+SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
+ if (secp256k1_fe_impl_set_b32_limit(r, a)) {
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+ return 1;
+ } else {
+ /* Mark the output field element as invalid. */
+ r->magnitude = -1;
+ return 0;
+ }
+}
+
+static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ secp256k1_fe_impl_get_b32(r, a);
+}
+
+static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
+SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(m >= 0 && m <= 31);
+ VERIFY_CHECK(a->magnitude <= m);
+ secp256k1_fe_impl_negate(r, a, m);
+ r->magnitude = m + 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a);
+SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(a >= 0 && a <= 32);
+ VERIFY_CHECK(a*r->magnitude <= 32);
+ secp256k1_fe_impl_mul_int(r, a);
+ r->magnitude *= a;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(r);
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
+ secp256k1_fe_impl_add(r, a);
+ r->magnitude += a->magnitude;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
+SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(b);
+ VERIFY_CHECK(a->magnitude <= 8);
+ VERIFY_CHECK(b->magnitude <= 8);
+ VERIFY_CHECK(r != b);
+ VERIFY_CHECK(a != b);
+ secp256k1_fe_impl_mul(r, a, b);
+ r->magnitude = 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->magnitude <= 8);
+ secp256k1_fe_impl_sqr(r, a);
+ r->magnitude = 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
+SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
+ VERIFY_CHECK(flag == 0 || flag == 1);
+ secp256k1_fe_verify(a);
+ secp256k1_fe_verify(r);
+ secp256k1_fe_impl_cmov(r, a, flag);
+ if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
+ if (!a->normalized) r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
+SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
+ secp256k1_fe_verify(a);
+ VERIFY_CHECK(a->normalized);
+ secp256k1_fe_impl_to_storage(r, a);
+}
+
+static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
+SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
+ secp256k1_fe_impl_from_storage(r, a);
+ r->magnitude = 1;
+ r->normalized = 1;
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
+SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
+ int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
+ secp256k1_fe_verify(x);
+ secp256k1_fe_impl_inv(r, x);
+ r->magnitude = x->magnitude > 0;
+ r->normalized = 1;
+ VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
+SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
+ int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
+ secp256k1_fe_verify(x);
+ secp256k1_fe_impl_inv_var(r, x);
+ r->magnitude = x->magnitude > 0;
+ r->normalized = 1;
+ VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
+ secp256k1_fe_verify(r);
+}
+
+static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
+SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
+ int ret;
+ secp256k1_fe tmp = *x, sqrt;
+ secp256k1_fe_verify(x);
+ ret = secp256k1_fe_impl_is_square_var(x);
+ secp256k1_fe_normalize_weak(&tmp);
+ VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
+ return ret;
+}
+
+static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
+SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
+ VERIFY_CHECK(m >= 0);
+ VERIFY_CHECK(m <= 32);
+ secp256k1_fe_impl_get_bounds(r, m);
+ r->magnitude = m;
+ r->normalized = (m == 0);
+ secp256k1_fe_verify(r);
+}
+
+static void secp256k1_fe_impl_half(secp256k1_fe *r);
+SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
+ secp256k1_fe_verify(r);
+ VERIFY_CHECK(r->magnitude < 32);
+ secp256k1_fe_impl_half(r);
+ r->magnitude = (r->magnitude >> 1) + 1;
+ r->normalized = 0;
+ secp256k1_fe_verify(r);
+}
+
+#endif /* defined(VERIFY) */
+
#endif /* SECP256K1_FIELD_IMPL_H */
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index b79ba597db..877c3eaeed 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -51,6 +51,12 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
* for Y. Return value indicates whether the result is valid. */
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
+/** Determine whether x is a valid X coordinate on the curve. */
+static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
+
+/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
+static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
+
/** Check whether a group element is the point at infinity. */
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
@@ -164,4 +170,10 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
*/
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
+/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
+static void secp256k1_ge_verify(const secp256k1_ge *a);
+
+/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
+static void secp256k1_gej_verify(const secp256k1_gej *a);
+
#endif /* SECP256K1_GROUP_H */
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 82ce3f8d8b..dcd171f574 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -9,6 +9,7 @@
#include "field.h"
#include "group.h"
+#include "util.h"
/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\
@@ -72,37 +73,80 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
#endif
/* End of section generated by sage/gen_exhaustive_groups.sage. */
-static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, SECP256K1_B);
+static void secp256k1_ge_verify(const secp256k1_ge *a) {
+#ifdef VERIFY
+ secp256k1_fe_verify(&a->x);
+ secp256k1_fe_verify(&a->y);
+ VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
+#endif
+ (void)a;
+}
+
+static void secp256k1_gej_verify(const secp256k1_gej *a) {
+#ifdef VERIFY
+ secp256k1_fe_verify(&a->x);
+ secp256k1_fe_verify(&a->y);
+ secp256k1_fe_verify(&a->z);
+ VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
+#endif
+ (void)a;
+}
+/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
+ secp256k1_gej_verify(a);
+ secp256k1_fe_verify(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi);
secp256k1_fe_mul(&r->x, &a->x, &zi2);
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
+ secp256k1_ge_verify(r);
+}
+
+/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
+static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
+ secp256k1_fe zi2;
+ secp256k1_fe zi3;
+ secp256k1_ge_verify(a);
+ secp256k1_fe_verify(zi);
+ VERIFY_CHECK(!a->infinity);
+ secp256k1_fe_sqr(&zi2, zi);
+ secp256k1_fe_mul(&zi3, &zi2, zi);
+ secp256k1_fe_mul(&r->x, &a->x, &zi2);
+ secp256k1_fe_mul(&r->y, &a->y, &zi3);
+ r->infinity = a->infinity;
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
+ secp256k1_fe_verify(x);
+ secp256k1_fe_verify(y);
r->infinity = 0;
r->x = *x;
r->y = *y;
+ secp256k1_ge_verify(r);
}
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
+ secp256k1_ge_verify(a);
return a->infinity;
}
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
+ secp256k1_ge_verify(a);
*r = *a;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
+ secp256k1_gej_verify(a);
r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
@@ -112,14 +156,17 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_set_int(&a->z, 1);
r->x = a->x;
r->y = a->y;
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
- if (a->infinity) {
+ secp256k1_gej_verify(a);
+ if (secp256k1_gej_is_infinity(a)) {
secp256k1_ge_set_infinity(r);
return;
}
+ r->infinity = 0;
secp256k1_fe_inv_var(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_mul(&z3, &a->z, &z2);
@@ -127,6 +174,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
secp256k1_ge_set_xy(r, &a->x, &a->y);
+ secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
@@ -135,6 +183,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
size_t last_i = SIZE_MAX;
for (i = 0; i < len; i++) {
+ secp256k1_gej_verify(&a[i]);
if (a[i].infinity) {
secp256k1_ge_set_infinity(&r[i]);
} else {
@@ -168,6 +217,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
}
+ secp256k1_ge_verify(&r[i]);
}
}
@@ -176,21 +226,25 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
secp256k1_fe zs;
if (len > 0) {
+ /* Verify inputs a[len-1] and zr[len-1]. */
+ secp256k1_ge_verify(&a[i]);
+ secp256k1_fe_verify(&zr[i]);
/* Ensure all y values are in weak normal form for fast negation of points */
secp256k1_fe_normalize_weak(&a[i].y);
zs = zr[i];
/* Work our way backwards, using the z-ratios to scale the x/y values. */
while (i > 0) {
- secp256k1_gej tmpa;
+ /* Verify all inputs a[i] and zr[i]. */
+ secp256k1_fe_verify(&zr[i]);
+ secp256k1_ge_verify(&a[i]);
if (i != len - 1) {
secp256k1_fe_mul(&zs, &zs, &zr[i]);
}
i--;
- tmpa.x = a[i].x;
- tmpa.y = a[i].y;
- tmpa.infinity = 0;
- secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
+ secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs);
+ /* Verify the output a[i]. */
+ secp256k1_ge_verify(&a[i]);
}
}
}
@@ -200,12 +254,14 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z);
+ secp256k1_gej_verify(r);
}
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
r->infinity = 1;
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
+ secp256k1_ge_verify(r);
}
static void secp256k1_gej_clear(secp256k1_gej *r) {
@@ -223,31 +279,35 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
secp256k1_fe x2, x3;
+ int ret;
+ secp256k1_fe_verify(x);
r->x = *x;
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
secp256k1_fe_add_int(&x3, SECP256K1_B);
- if (!secp256k1_fe_sqrt(&r->y, &x3)) {
- return 0;
- }
+ ret = secp256k1_fe_sqrt(&r->y, &x3);
secp256k1_fe_normalize_var(&r->y);
if (secp256k1_fe_is_odd(&r->y) != odd) {
secp256k1_fe_negate(&r->y, &r->y, 1);
}
- return 1;
-
+ secp256k1_ge_verify(r);
+ return ret;
}
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
+ secp256k1_ge_verify(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_set_int(&r->z, 1);
+ secp256k1_gej_verify(r);
}
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej tmp;
+ secp256k1_gej_verify(b);
+ secp256k1_gej_verify(a);
secp256k1_gej_neg(&tmp, a);
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
return secp256k1_gej_is_infinity(&tmp);
@@ -255,6 +315,8 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b)
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r, r2;
+ secp256k1_fe_verify(x);
+ secp256k1_gej_verify(a);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
@@ -262,20 +324,24 @@ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a)
}
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
+ secp256k1_gej_verify(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
r->z = a->z;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
+ secp256k1_gej_verify(r);
}
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
+ secp256k1_gej_verify(a);
return a->infinity;
}
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
secp256k1_fe y2, x3;
+ secp256k1_ge_verify(a);
if (a->infinity) {
return 0;
}
@@ -291,6 +357,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
secp256k1_fe l, s, t;
+ secp256k1_gej_verify(a);
r->infinity = a->infinity;
/* Formula used:
@@ -317,6 +384,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
@@ -330,6 +398,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
* the infinity flag even though the point doubles to infinity, and the result
* point will be gibberish (z = 0 but infinity = 0).
*/
+ secp256k1_gej_verify(a);
if (a->infinity) {
secp256k1_gej_set_infinity(r);
if (rzr != NULL) {
@@ -344,12 +413,15 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
}
secp256k1_gej_double(r, a);
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
+ secp256k1_gej_verify(a);
+ secp256k1_gej_verify(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
*r = *b;
@@ -404,11 +476,14 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
/* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
+ secp256k1_gej_verify(a);
+ secp256k1_ge_verify(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
secp256k1_gej_set_ge(r, b);
@@ -461,12 +536,16 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
+ secp256k1_gej_verify(r);
+ if (rzr != NULL) secp256k1_fe_verify(rzr);
}
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
/* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
+ secp256k1_ge_verify(b);
+ secp256k1_fe_verify(bzinv);
if (a->infinity) {
secp256k1_fe bzinv2, bzinv3;
r->infinity = b->infinity;
@@ -525,6 +604,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
+ secp256k1_gej_verify(r);
}
@@ -533,6 +613,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
int degenerate;
+ secp256k1_gej_verify(a);
+ secp256k1_ge_verify(b);
VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
@@ -658,21 +740,28 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* We have degenerate = false, r->z = (y1 + y2) * Z.
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
+ secp256k1_gej_verify(r);
}
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
/* Operations: 4 mul, 1 sqr */
secp256k1_fe zz;
- VERIFY_CHECK(!secp256k1_fe_is_zero(s));
+ secp256k1_gej_verify(r);
+ secp256k1_fe_verify(s);
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
+#endif
secp256k1_fe_sqr(&zz, s);
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
secp256k1_fe_mul(&r->y, &r->y, &zz);
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
+ secp256k1_gej_verify(r);
}
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
secp256k1_fe x, y;
+ secp256k1_ge_verify(a);
VERIFY_CHECK(!a->infinity);
x = a->x;
secp256k1_fe_normalize(&x);
@@ -686,14 +775,18 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
secp256k1_fe_from_storage(&r->x, &a->x);
secp256k1_fe_from_storage(&r->y, &a->y);
r->infinity = 0;
+ secp256k1_ge_verify(r);
}
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
+ secp256k1_gej_verify(r);
+ secp256k1_gej_verify(a);
secp256k1_fe_cmov(&r->x, &a->x, flag);
secp256k1_fe_cmov(&r->y, &a->y, flag);
secp256k1_fe_cmov(&r->z, &a->z, flag);
r->infinity ^= (r->infinity ^ a->infinity) & flag;
+ secp256k1_gej_verify(r);
}
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
@@ -703,7 +796,9 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
*r = *a;
+ secp256k1_ge_verify(a);
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
+ secp256k1_ge_verify(r);
}
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
@@ -711,6 +806,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
secp256k1_gej out;
int i;
+ secp256k1_ge_verify(ge);
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
secp256k1_gej_set_infinity(&out);
for (i = 0; i < 32; ++i) {
@@ -727,4 +823,32 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
#endif
}
+static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
+ secp256k1_fe c;
+ secp256k1_fe_sqr(&c, x);
+ secp256k1_fe_mul(&c, &c, x);
+ secp256k1_fe_add_int(&c, SECP256K1_B);
+ return secp256k1_fe_is_square_var(&c);
+}
+
+static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
+ /* We want to determine whether (xn/xd) is on the curve.
+ *
+ * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
+ */
+ secp256k1_fe r, t;
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
+#endif
+ secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
+ secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
+ secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
+ secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
+ secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
+ VERIFY_CHECK(SECP256K1_B <= 31);
+ secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
+ secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
+ return secp256k1_fe_is_square_var(&r);
+}
+
#endif /* SECP256K1_GROUP_IMPL_H */
diff --git a/src/secp256k1/src/int128_native_impl.h b/src/secp256k1/src/int128_native_impl.h
index 996e542cf9..7f02e1590b 100644
--- a/src/secp256k1/src/int128_native_impl.h
+++ b/src/secp256k1/src/int128_native_impl.h
@@ -2,6 +2,7 @@
#define SECP256K1_INT128_NATIVE_IMPL_H
#include "int128.h"
+#include "util.h"
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
*r = (((uint128_t)hi) << 64) + lo;
diff --git a/src/secp256k1/src/int128_struct_impl.h b/src/secp256k1/src/int128_struct_impl.h
index 2eb337cb54..990982da84 100644
--- a/src/secp256k1/src/int128_struct_impl.h
+++ b/src/secp256k1/src/int128_struct_impl.h
@@ -2,6 +2,7 @@
#define SECP256K1_INT128_STRUCT_IMPL_H
#include "int128.h"
+#include "util.h"
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
# include <intrin.h>
@@ -193,7 +194,7 @@ static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r,
VERIFY_CHECK(n < 127);
VERIFY_CHECK(sign == 1 || sign == -1);
return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
- : r->hi == (uint64_t)((sign - 1) >> 1) && r->lo == (uint64_t)sign << n;
+ : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n;
}
#endif
diff --git a/src/secp256k1/src/modinv32_impl.h b/src/secp256k1/src/modinv32_impl.h
index 643750560e..0ea2699863 100644
--- a/src/secp256k1/src/modinv32_impl.h
+++ b/src/secp256k1/src/modinv32_impl.h
@@ -64,7 +64,7 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4],
r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8];
- int32_t cond_add, cond_negate;
+ volatile int32_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^30,2^30). */
@@ -186,7 +186,8 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* being inside [-2^31,2^31) means that casting to signed works correctly.
*/
uint32_t u = 1, v = 0, q = 0, r = 1;
- uint32_t c1, c2, f = f0, g = g0, x, y, z;
+ volatile uint32_t c1, c2;
+ uint32_t mask1, mask2, f = f0, g = g0, x, y, z;
int i;
for (i = 0; i < 30; ++i) {
@@ -195,23 +196,25 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 31;
- c2 = -(g & 1);
+ mask1 = c1;
+ c2 = g & 1;
+ mask2 = -c2;
/* Compute x,y,z, conditionally negated versions of f,u,v. */
- x = (f ^ c1) - c1;
- y = (u ^ c1) - c1;
- z = (v ^ c1) - c1;
+ x = (f ^ mask1) - mask1;
+ y = (u ^ mask1) - mask1;
+ z = (v ^ mask1) - mask1;
/* Conditionally add x,y,z to g,q,r. */
- g += x & c2;
- q += y & c2;
- r += z & c2;
- /* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
- c1 &= c2;
+ g += x & mask2;
+ q += y & mask2;
+ r += z & mask2;
+ /* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */
+ mask1 &= mask2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
- zeta = (zeta ^ c1) - 1;
+ zeta = (zeta ^ mask1) - 1;
/* Conditionally add g,q,r to f,u,v. */
- f += g & c1;
- u += q & c1;
- v += r & c1;
+ f += g & mask1;
+ u += q & mask1;
+ v += r & mask1;
/* Shifts */
g >>= 1;
u <<= 1;
@@ -232,7 +235,7 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
return zeta;
}
-/* inv256[i] = -(2*i+1)^-1 (mod 256) */
+/* secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */
static const uint8_t secp256k1_modinv32_inv256[128] = {
0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
diff --git a/src/secp256k1/src/modinv64_impl.h b/src/secp256k1/src/modinv64_impl.h
index e33727d385..c7cef872a4 100644
--- a/src/secp256k1/src/modinv64_impl.h
+++ b/src/secp256k1/src/modinv64_impl.h
@@ -88,7 +88,7 @@ static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *
static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4];
- int64_t cond_add, cond_negate;
+ volatile int64_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^62,2^62). */
@@ -175,7 +175,8 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
* being inside [-2^63,2^63) means that casting to signed works correctly.
*/
uint64_t u = 8, v = 0, q = 0, r = 8;
- uint64_t c1, c2, f = f0, g = g0, x, y, z;
+ volatile uint64_t c1, c2;
+ uint64_t mask1, mask2, f = f0, g = g0, x, y, z;
int i;
for (i = 3; i < 62; ++i) {
@@ -184,23 +185,25 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 63;
- c2 = -(g & 1);
+ mask1 = c1;
+ c2 = g & 1;
+ mask2 = -c2;
/* Compute x,y,z, conditionally negated versions of f,u,v. */
- x = (f ^ c1) - c1;
- y = (u ^ c1) - c1;
- z = (v ^ c1) - c1;
+ x = (f ^ mask1) - mask1;
+ y = (u ^ mask1) - mask1;
+ z = (v ^ mask1) - mask1;
/* Conditionally add x,y,z to g,q,r. */
- g += x & c2;
- q += y & c2;
- r += z & c2;
+ g += x & mask2;
+ q += y & mask2;
+ r += z & mask2;
/* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
- c1 &= c2;
+ mask1 &= mask2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
- zeta = (zeta ^ c1) - 1;
+ zeta = (zeta ^ mask1) - 1;
/* Conditionally add g,q,r to f,u,v. */
- f += g & c1;
- u += q & c1;
- v += r & c1;
+ f += g & mask1;
+ u += q & mask1;
+ v += r & mask1;
/* Shifts */
g >>= 1;
u <<= 1;
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
index 5408c9de70..82b082a9f0 100644
--- a/src/secp256k1/src/modules/ecdh/main_impl.h
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -50,7 +50,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
overflow |= secp256k1_scalar_is_zero(&s);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
- secp256k1_ecmult_const(&res, &pt, &s, 256);
+ secp256k1_ecmult_const(&res, &pt, &s);
secp256k1_ge_set_gej(&pt, &res);
/* Compute a hash of the point */
diff --git a/src/secp256k1/src/modules/ellswift/Makefile.am.include b/src/secp256k1/src/modules/ellswift/Makefile.am.include
new file mode 100644
index 0000000000..e7efea2981
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/Makefile.am.include
@@ -0,0 +1,4 @@
+include_HEADERS += include/secp256k1_ellswift.h
+noinst_HEADERS += src/modules/ellswift/bench_impl.h
+noinst_HEADERS += src/modules/ellswift/main_impl.h
+noinst_HEADERS += src/modules/ellswift/tests_impl.h
diff --git a/src/secp256k1/src/modules/ellswift/bench_impl.h b/src/secp256k1/src/modules/ellswift/bench_impl.h
new file mode 100644
index 0000000000..b16a3a3687
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/bench_impl.h
@@ -0,0 +1,106 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H
+#define SECP256K1_MODULE_ELLSWIFT_BENCH_H
+
+#include "../../../include/secp256k1_ellswift.h"
+
+typedef struct {
+ secp256k1_context *ctx;
+ secp256k1_pubkey point[256];
+ unsigned char rnd64[64];
+} bench_ellswift_data;
+
+static void bench_ellswift_setup(void *arg) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+ static const unsigned char init[64] = {
+ 0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68,
+ 0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e,
+ 0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79,
+ 0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21,
+ 0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f,
+ 0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30,
+ 0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85,
+ 0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc
+ };
+ memcpy(data->rnd64, init, 64);
+ for (i = 0; i < 256; ++i) {
+ int j;
+ CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64));
+ for (j = 0; j < 64; ++j) {
+ data->rnd64[j] += 1;
+ }
+ }
+ CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16));
+}
+
+static void bench_ellswift_encode(void *arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16));
+ }
+}
+
+static void bench_ellswift_create(void *arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ unsigned char buf[64];
+ CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32));
+ memcpy(data->rnd64, buf, 64);
+ }
+}
+
+static void bench_ellswift_decode(void *arg, int iters) {
+ int i;
+ secp256k1_pubkey out;
+ size_t len;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1);
+ len = 33;
+ CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED));
+ }
+}
+
+static void bench_ellswift_xdh(void *arg, int iters) {
+ int i;
+ bench_ellswift_data *data = (bench_ellswift_data*)arg;
+
+ for (i = 0; i < iters; i++) {
+ int party = i & 1;
+ CHECK(secp256k1_ellswift_xdh(data->ctx,
+ data->rnd64 + (i % 33),
+ data->rnd64,
+ data->rnd64,
+ data->rnd64 + ((i + 16) % 33),
+ party,
+ secp256k1_ellswift_xdh_hash_function_bip324,
+ NULL) == 1);
+ }
+}
+
+void run_ellswift_bench(int iters, int argc, char **argv) {
+ bench_ellswift_data data;
+ int d = argc == 1;
+
+ /* create a context with signing capabilities */
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters);
+ if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters);
+
+ secp256k1_context_destroy(data.ctx);
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/ellswift/main_impl.h b/src/secp256k1/src/modules/ellswift/main_impl.h
new file mode 100644
index 0000000000..00bb8a3da5
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/main_impl.h
@@ -0,0 +1,589 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H
+#define SECP256K1_MODULE_ELLSWIFT_MAIN_H
+
+#include "../../../include/secp256k1.h"
+#include "../../../include/secp256k1_ellswift.h"
+#include "../../eckey.h"
+#include "../../hash.h"
+
+/** c1 = (sqrt(-3)-1)/2 */
+static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40);
+/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */
+static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee);
+/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */
+static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef);
+/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */
+static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41);
+
+/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */
+static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) {
+ /* The implemented algorithm is the following (all operations in GF(p)):
+ *
+ * - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852.
+ * - If u = 0, set u = 1.
+ * - If t = 0, set t = 1.
+ * - If u^3+7+t^2 = 0, set t = 2*t.
+ * - Let X = (u^3+7-t^2)/(2*t).
+ * - Let Y = (X+t)/(c0*u).
+ * - If x3 = u+4*Y^2 is a valid x coordinate, return it.
+ * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
+ * - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate).
+ *
+ * Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get:
+ *
+ * - Let c0 = ...
+ * - If u = 0, set u = 1.
+ * - If t = 0, set t = 1.
+ * - Let s = t^2
+ * - Let g = u^3+7
+ * - If g+s = 0, set t = 2*t, s = 4*s
+ * - Let X = (g-s)/(2*t).
+ * - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u).
+ * - If x3 = u+4*Y^2 is a valid x coordinate, return it.
+ * - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
+ * - Return x1 = -(x2+u).
+ *
+ * Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This
+ * means X and Y do not need to be evaluated explicitly anymore.
+ *
+ * - ...
+ * - If g+s = 0, set s = 4*s.
+ * - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it.
+ * - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it.
+ * - Return x1 = -(x2+u).
+ *
+ * Simplifying x2 using 2 additional constants:
+ *
+ * - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
+ * - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
+ * - ...
+ * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
+ * - ...
+ *
+ * Writing x3 as a fraction:
+ *
+ * - ...
+ * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ...
+ * - ...
+
+ * Overall, we get:
+ *
+ * - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
+ * - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
+ * - If u = 0, set u = 1.
+ * - If t = 0, set s = 1, else set s = t^2.
+ * - Let g = u^3+7.
+ * - If g+s = 0, set s = 4*s.
+ * - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it.
+ * - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
+ * - Return x1 = -(x2+u).
+ */
+ secp256k1_fe u1, s, g, p, d, n, l;
+ u1 = *u;
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one;
+ secp256k1_fe_sqr(&s, t);
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one;
+ secp256k1_fe_sqr(&l, &u1); /* l = u^2 */
+ secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */
+ secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */
+ p = g; /* p = g */
+ secp256k1_fe_add(&p, &s); /* p = g+s */
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) {
+ secp256k1_fe_mul_int(&s, 4);
+ /* Recompute p = g+s */
+ p = g; /* p = g */
+ secp256k1_fe_add(&p, &s); /* p = g+s */
+ }
+ secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */
+ secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */
+ secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */
+ secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */
+ secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */
+ secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */
+ if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) {
+ /* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */
+ *xn = n;
+ *xd = d;
+ return;
+ }
+ *xd = p;
+ secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */
+ secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */
+ secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */
+ secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */
+ /* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed,
+ * which we already have computed above. This could be deduplicated. */
+ if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) {
+ /* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */
+ *xn = n;
+ return;
+ }
+ secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */
+ secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */
+ secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */
+#ifdef VERIFY
+ VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p));
+#endif
+ /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */
+}
+
+/** Decode ElligatorSwift encoding (u, t) to X coordinate. */
+static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) {
+ secp256k1_fe xn, xd;
+ secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t);
+ secp256k1_fe_inv_var(&xd, &xd);
+ secp256k1_fe_mul(x, &xn, &xd);
+}
+
+/** Decode ElligatorSwift encoding (u, t) to point P. */
+static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) {
+ secp256k1_fe x;
+ secp256k1_ellswift_xswiftec_var(&x, u, t);
+ secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t));
+}
+
+/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x.
+ *
+ * There may be up to 8 distinct t values such that (u, t) decodes back to x, but also
+ * fewer, or none at all. Each such partial inverse can be accessed individually using a
+ * distinct input argument c (in range 0-7), and some or all of these may return failure.
+ * The following guarantees exist:
+ * - Given (x, u), no two distinct c values give the same successful result t.
+ * - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var.
+ * - Given (x, u), all t values that map back to x can be reached by combining the
+ * successful results from this function over all c values, with the exception of:
+ * - this function cannot be called with u=0
+ * - no result with t=0 will be returned
+ * - no result for which u^3 + t^2 + 7 = 0 will be returned.
+ *
+ * The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then
+ * using the low and high bits to pick signs of square roots) is to match the paper's
+ * encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through
+ * c=7 are copies of those with an additional negation of sqrt(w).
+ */
+static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) {
+ /* The implemented algorithm is this (all arithmetic, except involving c, is mod p):
+ *
+ * - If (c & 2) = 0:
+ * - If (-x-u) is a valid X coordinate, fail.
+ * - Let s=-(u^3+7)/(u^2+u*x+x^2).
+ * - If s is not square, fail.
+ * - Let v=x.
+ * - If (c & 2) = 2:
+ * - Let s=x-u.
+ * - If s is not square, fail.
+ * - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist.
+ * - If (c & 1) = 1 and r = 0, fail.
+ * - If s=0, fail.
+ * - Let v=(r/s-u)/2.
+ * - Let w=sqrt(s).
+ * - If (c & 5) = 0: return -w*(c3*u + v).
+ * - If (c & 5) = 1: return w*(c4*u + v).
+ * - If (c & 5) = 4: return w*(c3*u + v).
+ * - If (c & 5) = 5: return -w*(c4*u + v).
+ */
+ secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q;
+ int ret;
+
+ secp256k1_fe_normalize_weak(&x);
+ secp256k1_fe_normalize_weak(&u);
+
+#ifdef VERIFY
+ VERIFY_CHECK(c >= 0 && c < 8);
+ VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x));
+#endif
+
+ if (!(c & 2)) {
+ /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or
+ * c=4) formula, or x2 (if c=1 or c=5) formula. */
+
+ /* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips
+ * back under the x3 formula instead (which has priority over x1 and x2, so the decoding
+ * would not match x). */
+ m = x; /* m = x */
+ secp256k1_fe_add(&m, &u); /* m = u+x */
+ secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */
+ /* Test if (-u-x) is a valid X coordinate. If so, fail. */
+ if (secp256k1_ge_x_on_curve_var(&m)) return 0;
+
+ /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */
+ secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */
+ secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */
+ secp256k1_fe_mul(&m, &u, &x); /* m = u*x */
+ secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */
+
+ /* Note that at this point, s = 0 is impossible. If it were the case:
+ * s = -(u^2 + u*x + x^2) = 0
+ * => u^2 + u*x + x^2 = 0
+ * => (u + 2*x) * (u^2 + u*x + x^2) = 0
+ * => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0
+ * => (x + u)^3 + x^3 = 0
+ * => x^3 = -(x + u)^3
+ * => x^3 + B = (-u - x)^3 + B
+ *
+ * However, we know x^3 + B is square (because x is on the curve) and
+ * that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m)
+ * test above would have failed). This is a contradiction, and thus the
+ * assumption s=0 is false. */
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s));
+#endif
+
+ /* If s is not square, fail. We have not fully computed s yet, but s is square iff
+ * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is
+ * nonzero). */
+ secp256k1_fe_sqr(&g, &u); /* g = u^2 */
+ secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
+ secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */
+ secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */
+ if (!secp256k1_fe_is_square_var(&m)) return 0;
+
+ /* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */
+ secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */
+ secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */
+
+ /* Let v = x. */
+ v = x;
+ } else {
+ /* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */
+
+ /* Let s = x-u. */
+ secp256k1_fe_negate(&m, &u, 1); /* m = -u */
+ s = m; /* s = -u */
+ secp256k1_fe_add(&s, &x); /* s = x-u */
+
+ /* If s is not square, fail. */
+ if (!secp256k1_fe_is_square_var(&s)) return 0;
+
+ /* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */
+ secp256k1_fe_sqr(&g, &u); /* g = u^2 */
+ secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */
+ secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */
+ secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
+ secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */
+ secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */
+ secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */
+ secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */
+ secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */
+ if (!secp256k1_fe_is_square_var(&q)) return 0;
+ ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */
+ VERIFY_CHECK(ret);
+
+ /* If (c & 1) = 1 and r = 0, fail. */
+ if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0;
+
+ /* If s = 0, fail. */
+ if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0;
+
+ /* Let v = (r/s-u)/2. */
+ secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */
+ secp256k1_fe_mul(&v, &v, &r); /* v = r/s */
+ secp256k1_fe_add(&v, &m); /* v = r/s-u */
+ secp256k1_fe_half(&v); /* v = (r/s-u)/2 */
+ }
+
+ /* Let w = sqrt(s). */
+ ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */
+ VERIFY_CHECK(ret);
+
+ /* Return logic. */
+ if ((c & 5) == 0 || (c & 5) == 5) {
+ secp256k1_fe_negate(&m, &m, 1); /* m = -w */
+ }
+ /* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */
+ secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3);
+ /* u = {c4 if c&1=1; c3 otherwise}*u */
+ secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */
+ secp256k1_fe_mul(t, &m, &u);
+ return 1;
+}
+
+/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt).
+ *
+ * hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
+ * Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
+ * 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
+static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
+ secp256k1_sha256 hash = *hasher;
+ unsigned char buf4[4];
+#ifdef VERIFY
+ size_t blocks = hash.bytes >> 6;
+#endif
+ buf4[0] = cnt;
+ buf4[1] = cnt >> 8;
+ buf4[2] = cnt >> 16;
+ buf4[3] = cnt >> 24;
+ secp256k1_sha256_write(&hash, buf4, 4);
+ secp256k1_sha256_finalize(&hash, out32);
+#ifdef VERIFY
+ /* Writing and finalizing together should trigger exactly one SHA256 compression. */
+ VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
+#endif
+}
+
+/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate.
+ *
+ * u32 is the 32-byte big endian encoding of u; t is the output field element t that still
+ * needs encoding.
+ *
+ * hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
+static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
+ /* Pool of 3-bit branch values. */
+ unsigned char branch_hash[32];
+ /* Number of 3-bit values in branch_hash left. */
+ int branches_left = 0;
+ /* Field elements u and branch values are extracted from RNG based on hasher for consecutive
+ * values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64
+ * cnt values that follow are used to generate field elements u. cnt==65 (and multiples
+ * thereof) are used to repopulate the pool and start over, if that were ever necessary.
+ * On average, 4 iterations are needed. */
+ uint32_t cnt = 0;
+ while (1) {
+ int branch;
+ secp256k1_fe u;
+ /* If the pool of branch values is empty, populate it. */
+ if (branches_left == 0) {
+ secp256k1_ellswift_prng(branch_hash, hasher, cnt++);
+ branches_left = 64;
+ }
+ /* Take a 3-bit branch value from the branch pool (top bit is discarded). */
+ --branches_left;
+ branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
+ /* Compute a new u value by hashing. */
+ secp256k1_ellswift_prng(u32, hasher, cnt++);
+ /* overflow is not a problem (we prefer uniform u32 over uniform u). */
+ secp256k1_fe_set_b32_mod(&u, u32);
+ /* Since u is the output of a hash, it should practically never be 0. We could apply the
+ * u=0 to u=1 correction here too to deal with that case still, but it's such a low
+ * probability event that we do not bother. */
+#ifdef VERIFY
+ VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u));
+#endif
+ /* Find a remainder t, and return it if found. */
+ if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break;
+ }
+}
+
+/** Find an ElligatorSwift encoding (u, t) for point P.
+ *
+ * This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p
+ * as input, and returns an encoding that matches the provided Y coordinate rather than a random
+ * one.
+ */
+static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
+ secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher);
+ secp256k1_fe_normalize_var(t);
+ if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
+ secp256k1_fe_negate(t, t, 1);
+ secp256k1_fe_normalize_var(t);
+ }
+}
+
+/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */
+static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) {
+ secp256k1_sha256_initialize(hash);
+ hash->s[0] = 0xd1a6524bul;
+ hash->s[1] = 0x028594b3ul;
+ hash->s[2] = 0x96e42f4eul;
+ hash->s[3] = 0x1037a177ul;
+ hash->s[4] = 0x1b8fcb8bul;
+ hash->s[5] = 0x56023885ul;
+ hash->s[6] = 0x2560ede1ul;
+ hash->s[7] = 0xd626b715ul;
+
+ hash->bytes = 64;
+}
+
+int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(ell64 != NULL);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(rnd32 != NULL);
+
+ if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
+ secp256k1_fe t;
+ unsigned char p64[64] = {0};
+ size_t ser_size;
+ int ser_ret;
+ secp256k1_sha256 hash;
+
+ /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using
+ * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
+ secp256k1_ellswift_sha256_init_encode(&hash);
+ ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1);
+ VERIFY_CHECK(ser_ret && ser_size == 33);
+ secp256k1_sha256_write(&hash, p64, sizeof(p64));
+ secp256k1_sha256_write(&hash, rnd32, 32);
+
+ /* Compute ElligatorSwift encoding and construct output. */
+ secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
+ secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
+ return 1;
+ }
+ /* Only reached in case the provided pubkey is invalid. */
+ memset(ell64, 0, 64);
+ return 0;
+}
+
+/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */
+static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) {
+ secp256k1_sha256_initialize(hash);
+ hash->s[0] = 0xd29e1bf5ul;
+ hash->s[1] = 0xf7025f42ul;
+ hash->s[2] = 0x9b024773ul;
+ hash->s[3] = 0x094cb7d5ul;
+ hash->s[4] = 0xe59ed789ul;
+ hash->s[5] = 0x03bc9786ul;
+ hash->s[6] = 0x68335b35ul;
+ hash->s[7] = 0x4e363b53ul;
+
+ hash->bytes = 64;
+}
+
+int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) {
+ secp256k1_ge p;
+ secp256k1_fe t;
+ secp256k1_sha256 hash;
+ secp256k1_scalar seckey_scalar;
+ int ret;
+ static const unsigned char zero32[32] = {0};
+
+ /* Sanity check inputs. */
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(ell64 != NULL);
+ memset(ell64, 0, 64);
+ ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
+ ARG_CHECK(seckey32 != NULL);
+
+ /* Compute (affine) public key */
+ ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32);
+ secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */
+ secp256k1_fe_normalize_var(&p.x);
+ secp256k1_fe_normalize_var(&p.y);
+
+ /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++),
+ * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */
+ secp256k1_ellswift_sha256_init_create(&hash);
+ secp256k1_sha256_write(&hash, seckey32, 32);
+ secp256k1_sha256_write(&hash, zero32, sizeof(zero32));
+ secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */
+ if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32);
+
+ /* Compute ElligatorSwift encoding and construct output. */
+ secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
+ secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
+
+ secp256k1_memczero(ell64, 64, !ret);
+ secp256k1_scalar_clear(&seckey_scalar);
+
+ return ret;
+}
+
+int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) {
+ secp256k1_fe u, t;
+ secp256k1_ge p;
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(pubkey != NULL);
+ ARG_CHECK(ell64 != NULL);
+
+ secp256k1_fe_set_b32_mod(&u, ell64);
+ secp256k1_fe_set_b32_mod(&t, ell64 + 32);
+ secp256k1_fe_normalize_var(&t);
+ secp256k1_ellswift_swiftec_var(&p, &u, &t);
+ secp256k1_pubkey_save(pubkey, &p);
+ return 1;
+}
+
+static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
+ secp256k1_sha256 sha;
+
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, data, 64);
+ secp256k1_sha256_write(&sha, ell_a64, 64);
+ secp256k1_sha256_write(&sha, ell_b64, 64);
+ secp256k1_sha256_write(&sha, x32, 32);
+ secp256k1_sha256_finalize(&sha, output);
+
+ return 1;
+}
+
+/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */
+static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) {
+ secp256k1_sha256_initialize(hash);
+ hash->s[0] = 0x8c12d730ul;
+ hash->s[1] = 0x827bd392ul;
+ hash->s[2] = 0x9e4fb2eeul;
+ hash->s[3] = 0x207b373eul;
+ hash->s[4] = 0x2292bd7aul;
+ hash->s[5] = 0xaa5441bcul;
+ hash->s[6] = 0x15c3779ful;
+ hash->s[7] = 0xcfb52549ul;
+
+ hash->bytes = 64;
+}
+
+static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
+ secp256k1_sha256 sha;
+
+ (void)data;
+
+ secp256k1_ellswift_sha256_init_bip324(&sha);
+ secp256k1_sha256_write(&sha, ell_a64, 64);
+ secp256k1_sha256_write(&sha, ell_b64, 64);
+ secp256k1_sha256_write(&sha, x32, 32);
+ secp256k1_sha256_finalize(&sha, output);
+
+ return 1;
+}
+
+const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix;
+const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324;
+
+int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) {
+ int ret = 0;
+ int overflow;
+ secp256k1_scalar s;
+ secp256k1_fe xn, xd, px, u, t;
+ unsigned char sx[32];
+ const unsigned char* theirs64;
+
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK(output != NULL);
+ ARG_CHECK(ell_a64 != NULL);
+ ARG_CHECK(ell_b64 != NULL);
+ ARG_CHECK(seckey32 != NULL);
+ ARG_CHECK(hashfp != NULL);
+
+ /* Load remote public key (as fraction). */
+ theirs64 = party ? ell_a64 : ell_b64;
+ secp256k1_fe_set_b32_mod(&u, theirs64);
+ secp256k1_fe_set_b32_mod(&t, theirs64 + 32);
+ secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t);
+
+ /* Load private key (using one if invalid). */
+ secp256k1_scalar_set_b32(&s, seckey32, &overflow);
+ overflow = secp256k1_scalar_is_zero(&s);
+ secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
+
+ /* Compute shared X coordinate. */
+ secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1);
+ secp256k1_fe_normalize(&px);
+ secp256k1_fe_get_b32(sx, &px);
+
+ /* Invoke hasher */
+ ret = hashfp(output, sx, ell_a64, ell_b64, data);
+
+ memset(sx, 0, 32);
+ secp256k1_fe_clear(&px);
+ secp256k1_scalar_clear(&s);
+
+ return !!ret & !overflow;
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/ellswift/tests_impl.h b/src/secp256k1/src/modules/ellswift/tests_impl.h
new file mode 100644
index 0000000000..86ca09862b
--- /dev/null
+++ b/src/secp256k1/src/modules/ellswift/tests_impl.h
@@ -0,0 +1,434 @@
+/***********************************************************************
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
+ ***********************************************************************/
+
+#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H
+#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
+
+#include "../../../include/secp256k1_ellswift.h"
+
+struct ellswift_xswiftec_inv_test {
+ int enc_bitmap;
+ secp256k1_fe u;
+ secp256k1_fe x;
+ secp256k1_fe encs[8];
+};
+
+struct ellswift_decode_test {
+ unsigned char enc[64];
+ secp256k1_fe x;
+ int odd_y;
+};
+
+struct ellswift_xdh_test {
+ unsigned char priv_ours[32];
+ unsigned char ellswift_ours[64];
+ unsigned char ellswift_theirs[64];
+ int initiating;
+ unsigned char shared_secret[32];
+};
+
+/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324
+ * test vectors. Created using an independent implementation, and tested decoding against paper
+ * authors' code. */
+static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = {
+ {0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}},
+ {0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}},
+ {0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}},
+ {0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}},
+ {0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}},
+ {0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}},
+ {0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}},
+ {0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}},
+ {0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}},
+ {0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+ {0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}},
+ {0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}},
+ {0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
+};
+
+/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324
+ * test vectors. Created using an independent implementation, and tested decoding against the paper
+ * authors' code. */
+static const struct ellswift_decode_test ellswift_decode_tests[] = {
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
+ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
+ {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
+ {{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
+ {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0},
+ {{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1},
+ {{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0},
+ {{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0},
+ {{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1},
+ {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
+ {{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
+ {{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0},
+ {{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0},
+ {{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0},
+ {{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0},
+ {{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1},
+ {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
+ {{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
+ {{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1},
+ {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
+ {{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
+ {{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0},
+ {{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0},
+ {{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0},
+ {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0},
+ {{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1},
+ {{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0},
+ {{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1},
+ {{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0},
+ {{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1},
+ {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
+ {{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
+ {{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1},
+ {{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0},
+ {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0},
+};
+
+/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating,
+ * taken from the BIP324 test vectors. Created using an independent implementation, and tested
+ * against the paper authors' decoding code. */
+static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = {
+ {{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}},
+ {{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}},
+ {{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}},
+ {{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}},
+ {{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}},
+ {{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}},
+ {{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}},
+};
+
+/** This is a hasher for ellswift_xdh which just returns the shared X coordinate.
+ *
+ * This is generally a bad idea as it means changes to the encoding of the
+ * exchanged public keys do not affect the shared secret. However, it's used here
+ * in tests to be able to verify the X coordinate through other means.
+ */
+static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
+ (void)ell_a64;
+ (void)ell_b64;
+ (void)data;
+ memcpy(output, x32, 32);
+ return 1;
+}
+
+void run_ellswift_tests(void) {
+ int i = 0;
+ /* Test vectors. */
+ for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) {
+ const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i];
+ int c;
+ for (c = 0; c < 8; ++c) {
+ secp256k1_fe t;
+ int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c);
+ CHECK(ret == ((testcase->enc_bitmap >> c) & 1));
+ if (ret) {
+ secp256k1_fe x2;
+ CHECK(check_fe_equal(&t, &testcase->encs[c]));
+ secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]);
+ CHECK(check_fe_equal(&testcase->x, &x2));
+ }
+ }
+ }
+ for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) {
+ const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i];
+ secp256k1_pubkey pubkey;
+ secp256k1_ge ge;
+ int ret;
+ ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc);
+ CHECK(ret);
+ ret = secp256k1_pubkey_load(CTX, &ge, &pubkey);
+ CHECK(ret);
+ CHECK(check_fe_equal(&testcase->x, &ge.x));
+ CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y);
+ }
+ for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) {
+ const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i];
+ unsigned char shared_secret[32];
+ int ret;
+ int party = !test->initiating;
+ const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours;
+ const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs;
+ ret = secp256k1_ellswift_xdh(CTX, shared_secret,
+ ell_a64, ell_b64,
+ test->priv_ours,
+ party,
+ secp256k1_ellswift_xdh_hash_function_bip324,
+ NULL);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0);
+ }
+ /* Verify that secp256k1_ellswift_encode + decode roundtrips. */
+ for (i = 0; i < 1000 * COUNT; i++) {
+ unsigned char rnd32[32];
+ unsigned char ell64[64];
+ secp256k1_ge g, g2;
+ secp256k1_pubkey pubkey, pubkey2;
+ /* Generate random public key and random randomizer. */
+ random_group_element_test(&g);
+ secp256k1_pubkey_save(&pubkey, &g);
+ secp256k1_testrand256(rnd32);
+ /* Convert the public key to ElligatorSwift and back. */
+ secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32);
+ secp256k1_ellswift_decode(CTX, &pubkey2, ell64);
+ secp256k1_pubkey_load(CTX, &g2, &pubkey2);
+ /* Compare with original. */
+ ge_equals_ge(&g, &g2);
+ }
+ /* Verify the behavior of secp256k1_ellswift_create */
+ for (i = 0; i < 400 * COUNT; i++) {
+ unsigned char auxrnd32[32], sec32[32];
+ secp256k1_scalar sec;
+ secp256k1_gej res;
+ secp256k1_ge dec;
+ secp256k1_pubkey pub;
+ unsigned char ell64[64];
+ int ret;
+ /* Generate random secret key and random randomizer. */
+ if (i & 1) secp256k1_testrand256_test(auxrnd32);
+ random_scalar_order_test(&sec);
+ secp256k1_scalar_get_b32(sec32, &sec);
+ /* Construct ElligatorSwift-encoded public keys for that key. */
+ ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL);
+ CHECK(ret);
+ /* Decode it, and compare with traditionally-computed public key. */
+ secp256k1_ellswift_decode(CTX, &pub, ell64);
+ secp256k1_pubkey_load(CTX, &dec, &pub);
+ secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
+ ge_equals_gej(&dec, &res);
+ }
+ /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */
+ for (i = 0; i < 800 * COUNT; i++) {
+ unsigned char ell64[64], sec32[32], share32[32];
+ secp256k1_scalar sec;
+ secp256k1_ge dec, res;
+ secp256k1_fe share_x;
+ secp256k1_gej decj, resj;
+ secp256k1_pubkey pub;
+ int ret;
+ /* Generate random secret key. */
+ random_scalar_order_test(&sec);
+ secp256k1_scalar_get_b32(sec32, &sec);
+ /* Generate random ElligatorSwift encoding for the remote key and decode it. */
+ secp256k1_testrand256_test(ell64);
+ secp256k1_testrand256_test(ell64 + 32);
+ secp256k1_ellswift_decode(CTX, &pub, ell64);
+ secp256k1_pubkey_load(CTX, &dec, &pub);
+ secp256k1_gej_set_ge(&decj, &dec);
+ /* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we
+ * pass ell64 as claimed (but incorrect) encoding for sec32 here; this works
+ * because the "hasher" function we use here ignores the ell64 arguments. */
+ ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL);
+ CHECK(ret);
+ (void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */
+ secp256k1_fe_verify(&share_x);
+ /* Compute seckey*pubkey directly. */
+ secp256k1_ecmult(&resj, &decj, &sec, NULL);
+ secp256k1_ge_set_gej(&res, &resj);
+ /* Compare. */
+ CHECK(check_fe_equal(&res.x, &share_x));
+ }
+ /* Verify the joint behavior of secp256k1_ellswift_xdh */
+ for (i = 0; i < 200 * COUNT; i++) {
+ unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32];
+ unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32];
+ secp256k1_scalar seca, secb;
+ unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64];
+ unsigned char share32a[32], share32b[32], share32_bad[32];
+ unsigned char prefix64[64];
+ secp256k1_ellswift_xdh_hash_function hash_function;
+ void* data;
+ int ret;
+
+ /* Pick hasher to use. */
+ if ((i % 3) == 0) {
+ hash_function = ellswift_xdh_hash_x32;
+ data = NULL;
+ } else if ((i % 3) == 1) {
+ hash_function = secp256k1_ellswift_xdh_hash_function_bip324;
+ data = NULL;
+ } else {
+ hash_function = secp256k1_ellswift_xdh_hash_function_prefix;
+ secp256k1_testrand256_test(prefix64);
+ secp256k1_testrand256_test(prefix64 + 32);
+ data = prefix64;
+ }
+
+ /* Generate random secret keys and random randomizers. */
+ secp256k1_testrand256_test(auxrnd32a);
+ secp256k1_testrand256_test(auxrnd32b);
+ random_scalar_order_test(&seca);
+ random_scalar_order_test(&secb);
+ secp256k1_scalar_get_b32(sec32a, &seca);
+ secp256k1_scalar_get_b32(sec32b, &secb);
+
+ /* Construct ElligatorSwift-encoded public keys for those keys. */
+ /* For A: */
+ ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a);
+ CHECK(ret);
+ /* For B: */
+ ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b);
+ CHECK(ret);
+
+ /* Compute the shared secret both ways and compare with each other. */
+ /* For A: */
+ ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data);
+ CHECK(ret);
+ /* For B: */
+ ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data);
+ CHECK(ret);
+ /* And compare: */
+ CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0);
+
+ /* Verify that the shared secret doesn't match if other side's public key is incorrect. */
+ /* For A (using a bad public key for B): */
+ memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad));
+ secp256k1_testrand_flip(ell64b_bad, sizeof(ell64b_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
+ CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */
+ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B (using a bad public key for A): */
+ memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad));
+ secp256k1_testrand_flip(ell64a_bad, sizeof(ell64a_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+
+ /* Verify that the shared secret doesn't match if the private key is incorrect. */
+ /* For A: */
+ memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad));
+ secp256k1_testrand_flip(sec32a_bad, sizeof(sec32a_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data);
+ CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B: */
+ memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad));
+ secp256k1_testrand_flip(sec32b_bad, sizeof(sec32b_bad));
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data);
+ CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+
+ if (hash_function != ellswift_xdh_hash_x32) {
+ /* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */
+ /* For A (changing B's public key): */
+ memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad));
+ secp256k1_testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad));
+ ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad);
+ CHECK(ret);
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B (changing A's public key): */
+ memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad));
+ secp256k1_testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad));
+ ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad);
+ CHECK(ret);
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+
+ /* Verify that swapping sides changes the shared secret. */
+ /* For A (claiming to be B): */
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
+ /* For B (claiming to be A): */
+ ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data);
+ CHECK(ret);
+ CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
+ }
+ }
+
+ /* Test hash initializers. */
+ {
+ secp256k1_sha256 sha, sha_optimized;
+ static const unsigned char encode_tag[25] = "secp256k1_ellswift_encode";
+ static const unsigned char create_tag[25] = "secp256k1_ellswift_create";
+ static const unsigned char bip324_tag[26] = "bip324_ellswift_xonly_ecdh";
+
+ /* Check that hash initialized by
+ * secp256k1_ellswift_sha256_init_encode has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag));
+ secp256k1_ellswift_sha256_init_encode(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+
+ /* Check that hash initialized by
+ * secp256k1_ellswift_sha256_init_create has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag));
+ secp256k1_ellswift_sha256_init_create(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+
+ /* Check that hash initialized by
+ * secp256k1_ellswift_sha256_init_bip324 has the expected
+ * state. */
+ secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag));
+ secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
+ test_sha256_eq(&sha, &sha_optimized);
+ }
+}
+
+#endif
diff --git a/src/secp256k1/src/modules/extrakeys/main_impl.h b/src/secp256k1/src/modules/extrakeys/main_impl.h
index e1003052f4..0c7e266777 100644
--- a/src/secp256k1/src/modules/extrakeys/main_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/main_impl.h
@@ -9,6 +9,7 @@
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_extrakeys.h"
+#include "../../util.h"
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
@@ -27,7 +28,7 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p
memset(pubkey, 0, sizeof(*pubkey));
ARG_CHECK(input32 != NULL);
- if (!secp256k1_fe_set_b32(&x, input32)) {
+ if (!secp256k1_fe_set_b32_limit(&x, input32)) {
return 0;
}
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
diff --git a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
index 5ecc90d50f..d3d817a131 100644
--- a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
+++ b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h
@@ -47,7 +47,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
/* Compare the xonly_pubkey bytes against the precomputed group. */
- secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]);
+ secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]);
CHECK(secp256k1_fe_equal_var(&fe, &group[i].x));
/* Check the parity against the precomputed group. */
diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h
index e7906eb62e..76a005e017 100644
--- a/src/secp256k1/src/modules/recovery/main_impl.h
+++ b/src/secp256k1/src/modules/recovery/main_impl.h
@@ -98,7 +98,7 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp2
}
secp256k1_scalar_get_b32(brx, sigr);
- r = secp256k1_fe_set_b32(&fx, brx);
+ r = secp256k1_fe_set_b32_limit(&fx, brx);
(void)r;
VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) {
diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h
index cd651591c4..4e7b45a045 100644
--- a/src/secp256k1/src/modules/schnorrsig/main_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h
@@ -232,7 +232,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
ARG_CHECK(msg != NULL || msglen == 0);
ARG_CHECK(pubkey != NULL);
- if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
+ if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) {
return 0;
}
diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
index 062005ee63..90337ff03e 100644
--- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h
+++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h
@@ -20,17 +20,6 @@ static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, s
CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0);
}
-/* Tests for the equality of two sha256 structs. This function only produces a
- * correct result if an integer multiple of 64 many bytes have been written
- * into the hash functions. */
-static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
- /* Is buffer fully consumed? */
- CHECK((sha1->bytes & 0x3F) == 0);
-
- CHECK(sha1->bytes == sha2->bytes);
- CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
-}
-
static void run_nonce_function_bip340_tests(void) {
unsigned char tag[13] = "BIP0340/nonce";
unsigned char aux_tag[11] = "BIP0340/aux";
@@ -215,28 +204,36 @@ static void test_schnorrsig_sha256_tagged(void) {
/* Helper function for schnorrsig_bip_vectors
* Signs the message and checks that it's the same as expected_sig. */
-static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
+static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg, size_t msglen, const unsigned char *expected_sig) {
unsigned char sig[64];
secp256k1_keypair keypair;
secp256k1_xonly_pubkey pk, pk_expected;
+ secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
+ extraparams.ndata = (unsigned char*)aux_rand;
+
CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
- CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg32, &keypair, aux_rand));
+ CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, msglen, &keypair, &extraparams));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
+ if (msglen == 32) {
+ memset(sig, 0, 64);
+ CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, aux_rand));
+ CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
+ }
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized));
CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
- CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
+ CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk));
}
/* Helper function for schnorrsig_bip_vectors
* Checks that both verify and verify_batch (TODO) return the same value as expected. */
-static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
+static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg, size_t msglen, const unsigned char *sig, int expected) {
secp256k1_xonly_pubkey pk;
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized));
- CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
+ CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg, msglen, &pk));
}
/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
@@ -256,7 +253,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -278,8 +275,8 @@ static void test_schnorrsig_bip_vectors(void) {
0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47,
0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 1 */
@@ -295,7 +292,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -317,8 +314,8 @@ static void test_schnorrsig_bip_vectors(void) {
0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C,
0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 2 */
@@ -334,7 +331,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9,
0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE,
0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC,
0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C,
@@ -356,8 +353,8 @@ static void test_schnorrsig_bip_vectors(void) {
0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E,
0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 3 */
@@ -373,7 +370,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A,
0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17
};
- unsigned char aux_rand[32] = {
+ const unsigned char aux_rand[32] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -395,8 +392,8 @@ static void test_schnorrsig_bip_vectors(void) {
0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27,
0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3
};
- test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 4 */
@@ -422,7 +419,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93,
0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
}
{
/* Test vector 5 */
@@ -460,7 +457,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E,
0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 7 */
@@ -486,7 +483,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35,
0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 8 */
@@ -512,7 +509,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C,
0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 9 */
@@ -538,7 +535,7 @@ static void test_schnorrsig_bip_vectors(void) {
0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC,
0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 10 */
@@ -564,7 +561,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9,
0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 11 */
@@ -590,7 +587,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 12 */
@@ -616,7 +613,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 13 */
@@ -642,7 +639,7 @@ static void test_schnorrsig_bip_vectors(void) {
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
};
- test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 0);
}
{
/* Test vector 14 */
@@ -656,6 +653,147 @@ static void test_schnorrsig_bip_vectors(void) {
/* No need to check the signature of the test vector as parsing the pubkey already fails */
CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
}
+ {
+ /* Test vector 15 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ /* const unsigned char msg[0] = {}; */
+ const unsigned char sig[64] = {
+ 0x71, 0x53, 0x5D, 0xB1, 0x65, 0xEC, 0xD9, 0xFB,
+ 0xBC, 0x04, 0x6E, 0x5F, 0xFA, 0xEA, 0x61, 0x18,
+ 0x6B, 0xB6, 0xAD, 0x43, 0x67, 0x32, 0xFC, 0xCC,
+ 0x25, 0x29, 0x1A, 0x55, 0x89, 0x54, 0x64, 0xCF,
+ 0x60, 0x69, 0xCE, 0x26, 0xBF, 0x03, 0x46, 0x62,
+ 0x28, 0xF1, 0x9A, 0x3A, 0x62, 0xDB, 0x8A, 0x64,
+ 0x9F, 0x2D, 0x56, 0x0F, 0xAC, 0x65, 0x28, 0x27,
+ 0xD1, 0xAF, 0x05, 0x74, 0xE4, 0x27, 0xAB, 0x63,
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, NULL, 0, sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, NULL, 0, sig, 1);
+ }
+ {
+ /* Test vector 16 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ const unsigned char msg[] = { 0x11 };
+ const unsigned char sig[64] = {
+ 0x08, 0xA2, 0x0A, 0x0A, 0xFE, 0xF6, 0x41, 0x24,
+ 0x64, 0x92, 0x32, 0xE0, 0x69, 0x3C, 0x58, 0x3A,
+ 0xB1, 0xB9, 0x93, 0x4A, 0xE6, 0x3B, 0x4C, 0x35,
+ 0x11, 0xF3, 0xAE, 0x11, 0x34, 0xC6, 0xA3, 0x03,
+ 0xEA, 0x31, 0x73, 0xBF, 0xEA, 0x66, 0x83, 0xBD,
+ 0x10, 0x1F, 0xA5, 0xAA, 0x5D, 0xBC, 0x19, 0x96,
+ 0xFE, 0x7C, 0xAC, 0xFC, 0x5A, 0x57, 0x7D, 0x33,
+ 0xEC, 0x14, 0x56, 0x4C, 0xEC, 0x2B, 0xAC, 0xBF,
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+ }
+ {
+ /* Test vector 17 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ const unsigned char msg[] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
+ 0x11,
+ };
+ const unsigned char sig[64] = {
+ 0x51, 0x30, 0xF3, 0x9A, 0x40, 0x59, 0xB4, 0x3B,
+ 0xC7, 0xCA, 0xC0, 0x9A, 0x19, 0xEC, 0xE5, 0x2B,
+ 0x5D, 0x86, 0x99, 0xD1, 0xA7, 0x1E, 0x3C, 0x52,
+ 0xDA, 0x9A, 0xFD, 0xB6, 0xB5, 0x0A, 0xC3, 0x70,
+ 0xC4, 0xA4, 0x82, 0xB7, 0x7B, 0xF9, 0x60, 0xF8,
+ 0x68, 0x15, 0x40, 0xE2, 0x5B, 0x67, 0x71, 0xEC,
+ 0xE1, 0xE5, 0xA3, 0x7F, 0xD8, 0x0E, 0x5A, 0x51,
+ 0x89, 0x7C, 0x55, 0x66, 0xA9, 0x7E, 0xA5, 0xA5,
+ };
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+ }
+ {
+ /* Test vector 18 */
+ const unsigned char sk[32] = {
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ 0x03, 0x40, 0x03, 0x40, 0x03, 0x40, 0x03, 0x40,
+ };
+ const unsigned char pk[32] = {
+ 0x77, 0x8C, 0xAA, 0x53, 0xB4, 0x39, 0x3A, 0xC4,
+ 0x67, 0x77, 0x4D, 0x09, 0x49, 0x7A, 0x87, 0x22,
+ 0x4B, 0xF9, 0xFA, 0xB6, 0xF6, 0xE6, 0x8B, 0x23,
+ 0x08, 0x64, 0x97, 0x32, 0x4D, 0x6F, 0xD1, 0x17,
+ };
+ const unsigned char aux_rand[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ const unsigned char sig[64] = {
+ 0x40, 0x3B, 0x12, 0xB0, 0xD8, 0x55, 0x5A, 0x34,
+ 0x41, 0x75, 0xEA, 0x7E, 0xC7, 0x46, 0x56, 0x63,
+ 0x03, 0x32, 0x1E, 0x5D, 0xBF, 0xA8, 0xBE, 0x6F,
+ 0x09, 0x16, 0x35, 0x16, 0x3E, 0xCA, 0x79, 0xA8,
+ 0x58, 0x5E, 0xD3, 0xE3, 0x17, 0x08, 0x07, 0xE7,
+ 0xC0, 0x3B, 0x72, 0x0F, 0xC5, 0x4C, 0x7B, 0x23,
+ 0x89, 0x7F, 0xCB, 0xA0, 0xE9, 0xD0, 0xB4, 0xA0,
+ 0x68, 0x94, 0xCF, 0xD2, 0x49, 0xF2, 0x23, 0x67,
+ };
+ unsigned char msg[100];
+ memset(msg, 0x99, sizeof(msg));
+ test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sizeof(msg), sig);
+ test_schnorrsig_bip_vectors_check_verify(pk, msg, sizeof(msg), sig, 1);
+ }
}
/* Nonce function that returns constant 0 */
diff --git a/src/secp256k1/src/precompute_ecmult.c b/src/secp256k1/src/precompute_ecmult.c
index 10aba5b97d..742142cf58 100644
--- a/src/secp256k1/src/precompute_ecmult.c
+++ b/src/secp256k1/src/precompute_ecmult.c
@@ -68,7 +68,6 @@ int main(void) {
fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
fprintf(fp, " */\n");
- fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult.h\"\n");
fprintf(fp, "#include \"precomputed_ecmult.h\"\n");
diff --git a/src/secp256k1/src/precompute_ecmult_gen.c b/src/secp256k1/src/precompute_ecmult_gen.c
index bfe212fdd2..ce648cb9b0 100644
--- a/src/secp256k1/src/precompute_ecmult_gen.c
+++ b/src/secp256k1/src/precompute_ecmult_gen.c
@@ -33,7 +33,6 @@ int main(int argc, char **argv) {
fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n");
fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n");
- fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult_gen.h\"\n");
fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n");
diff --git a/src/secp256k1/src/precomputed_ecmult.c b/src/secp256k1/src/precomputed_ecmult.c
index fbc634ef1b..cbd030ce50 100644
--- a/src/secp256k1/src/precomputed_ecmult.c
+++ b/src/secp256k1/src/precomputed_ecmult.c
@@ -2,7 +2,6 @@
/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and
* an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.
*/
-#include "../include/secp256k1.h"
#include "group.h"
#include "ecmult.h"
#include "precomputed_ecmult.h"
diff --git a/src/secp256k1/src/precomputed_ecmult.h b/src/secp256k1/src/precomputed_ecmult.h
index a4aa83e4ca..17df102967 100644
--- a/src/secp256k1/src/precomputed_ecmult.h
+++ b/src/secp256k1/src/precomputed_ecmult.h
@@ -11,6 +11,7 @@
extern "C" {
#endif
+#include "ecmult.h"
#include "group.h"
#if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 7
diff --git a/src/secp256k1/src/precomputed_ecmult_gen.c b/src/secp256k1/src/precomputed_ecmult_gen.c
index e9d62a1c1b..75ec59c27a 100644
--- a/src/secp256k1/src/precomputed_ecmult_gen.c
+++ b/src/secp256k1/src/precomputed_ecmult_gen.c
@@ -1,6 +1,5 @@
/* This file was automatically generated by precompute_ecmult_gen. */
/* See ecmult_gen_impl.h for details about the contents of this file. */
-#include "../include/secp256k1.h"
#include "group.h"
#include "ecmult_gen.h"
#include "precomputed_ecmult_gen.h"
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index 1b83575b3e..1d14740577 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -10,6 +10,7 @@
#include "checkmem.h"
#include "int128.h"
#include "modinv64_impl.h"
+#include "util.h"
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL)
@@ -110,8 +111,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
secp256k1_uint128 t;
+ volatile int vflag = flag;
VERIFY_CHECK(bit < 256);
- bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
+ bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
secp256k1_u128_from_u64(&t, r->d[0]);
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
@@ -131,10 +133,10 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
- r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56;
- r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56;
- r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56;
- r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56;
+ r->d[0] = secp256k1_read_be64(&b32[24]);
+ r->d[1] = secp256k1_read_be64(&b32[16]);
+ r->d[2] = secp256k1_read_be64(&b32[8]);
+ r->d[3] = secp256k1_read_be64(&b32[0]);
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
@@ -142,10 +144,10 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3];
- bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2];
- bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1];
- bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
+ secp256k1_write_be64(&bin[0], a->d[3]);
+ secp256k1_write_be64(&bin[8], a->d[2]);
+ secp256k1_write_be64(&bin[16], a->d[1]);
+ secp256k1_write_be64(&bin[24], a->d[0]);
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
@@ -188,7 +190,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
- uint64_t mask = !flag - 1;
+ volatile int vflag = flag;
+ uint64_t mask = -vflag;
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
secp256k1_uint128 t;
secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
@@ -380,7 +383,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
"movq %%r10, %q5\n"
/* extract m6 */
"movq %%r8, %q6\n"
- : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
+ : "=&g"(m0), "=&g"(m1), "=&g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
: "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
@@ -811,8 +814,9 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint64_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
- mask0 = flag + ~((uint64_t)0);
+ mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h
index c433adce75..80ef3ef248 100644
--- a/src/secp256k1/src/scalar_8x32_impl.h
+++ b/src/secp256k1/src/scalar_8x32_impl.h
@@ -9,6 +9,7 @@
#include "checkmem.h"
#include "modinv32_impl.h"
+#include "util.h"
/* Limbs of the secp256k1 order. */
#define SECP256K1_N_0 ((uint32_t)0xD0364141UL)
@@ -141,8 +142,9 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
uint64_t t;
+ volatile int vflag = flag;
VERIFY_CHECK(bit < 256);
- bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
+ bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F));
@@ -167,14 +169,14 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
int over;
- r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;
- r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;
- r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24;
- r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24;
- r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24;
- r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24;
- r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24;
- r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24;
+ r->d[0] = secp256k1_read_be32(&b32[28]);
+ r->d[1] = secp256k1_read_be32(&b32[24]);
+ r->d[2] = secp256k1_read_be32(&b32[20]);
+ r->d[3] = secp256k1_read_be32(&b32[16]);
+ r->d[4] = secp256k1_read_be32(&b32[12]);
+ r->d[5] = secp256k1_read_be32(&b32[8]);
+ r->d[6] = secp256k1_read_be32(&b32[4]);
+ r->d[7] = secp256k1_read_be32(&b32[0]);
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
if (overflow) {
*overflow = over;
@@ -182,14 +184,14 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
}
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
- bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7];
- bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6];
- bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5];
- bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4];
- bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3];
- bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2];
- bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1];
- bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
+ secp256k1_write_be32(&bin[0], a->d[7]);
+ secp256k1_write_be32(&bin[4], a->d[6]);
+ secp256k1_write_be32(&bin[8], a->d[5]);
+ secp256k1_write_be32(&bin[12], a->d[4]);
+ secp256k1_write_be32(&bin[16], a->d[3]);
+ secp256k1_write_be32(&bin[20], a->d[2]);
+ secp256k1_write_be32(&bin[24], a->d[1]);
+ secp256k1_write_be32(&bin[28], a->d[0]);
}
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
@@ -241,7 +243,8 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
/* If we are flag = 0, mask = 00...00 and this is a no-op;
* if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */
- uint32_t mask = !flag - 1;
+ volatile int vflag = flag;
+ uint32_t mask = -vflag;
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
r->d[0] = t & nonzero; t >>= 32;
@@ -632,8 +635,9 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h
index e780083339..428a5deb33 100644
--- a/src/secp256k1/src/scalar_low_impl.h
+++ b/src/secp256k1/src/scalar_low_impl.h
@@ -9,6 +9,7 @@
#include "checkmem.h"
#include "scalar.h"
+#include "util.h"
#include <string.h>
@@ -116,8 +117,9 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1;
+ volatile int vflag = flag;
SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r));
- mask0 = flag + ~((uint32_t)0);
+ mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
*r = (*r & mask0) | (*a & mask1);
}
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 7af333ca90..4c11e7f0b8 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -247,8 +247,8 @@ static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge,
} else {
/* Otherwise, fall back to 32-byte big endian for X and Y. */
secp256k1_fe x, y;
- secp256k1_fe_set_b32(&x, pubkey->data);
- secp256k1_fe_set_b32(&y, pubkey->data + 32);
+ ARG_CHECK(secp256k1_fe_set_b32_limit(&x, pubkey->data));
+ ARG_CHECK(secp256k1_fe_set_b32_limit(&y, pubkey->data + 32));
secp256k1_ge_set_xy(ge, &x, &y);
}
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
@@ -811,3 +811,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
#ifdef ENABLE_MODULE_SCHNORRSIG
# include "modules/schnorrsig/main_impl.h"
#endif
+
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/main_impl.h"
+#endif
diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h
index d109bb9f8b..721099d039 100644
--- a/src/secp256k1/src/testrand.h
+++ b/src/secp256k1/src/testrand.h
@@ -7,6 +7,8 @@
#ifndef SECP256K1_TESTRAND_H
#define SECP256K1_TESTRAND_H
+#include "util.h"
+
/* A non-cryptographic RNG used only for test infrastructure. */
/** Seed the pseudorandom number generator for testing. */
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index e9b9d7ded4..1b7481a53b 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -13,6 +13,7 @@
#include "testrand.h"
#include "hash.h"
+#include "util.h"
static uint64_t secp256k1_test_state[4];
static uint64_t secp256k1_test_rng_integer;
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 1c0d797349..8ada3f869b 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -10,7 +10,15 @@
#include <time.h>
+#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
+ #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in tests.")
+ #undef USE_EXTERNAL_DEFAULT_CALLBACKS
+#endif
+#if defined(VERIFY) && defined(COVERAGE)
+ #pragma message("Defining VERIFY for tests being built for coverage analysis support is meaningless.")
+#endif
#include "secp256k1.c"
+
#include "../include/secp256k1.h"
#include "../include/secp256k1_preallocated.h"
#include "testrand_impl.h"
@@ -85,7 +93,7 @@ static void random_field_element_test(secp256k1_fe *fe) {
do {
unsigned char b32[32];
secp256k1_testrand256_test(b32);
- if (secp256k1_fe_set_b32(fe, b32)) {
+ if (secp256k1_fe_set_b32_limit(fe, b32)) {
break;
}
} while(1);
@@ -689,6 +697,17 @@ static void run_sha256_counter_tests(void) {
}
}
+/* Tests for the equality of two sha256 structs. This function only produces a
+ * correct result if an integer multiple of 64 many bytes have been written
+ * into the hash functions. This function is used by some module tests. */
+static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
+ /* Is buffer fully consumed? */
+ CHECK((sha1->bytes & 0x3F) == 0);
+
+ CHECK(sha1->bytes == sha2->bytes);
+ CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
+}
+
static void run_hmac_sha256_tests(void) {
static const char *keys[6] = {
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
@@ -2221,7 +2240,7 @@ static void scalar_test(void) {
for (i = 0; i < 100; ++i) {
int low;
int shift = 1 + secp256k1_testrand_int(15);
- int expected = r.d[0] % (1 << shift);
+ int expected = r.d[0] % (1ULL << shift);
low = secp256k1_scalar_shr_int(&r, shift);
CHECK(expected == low);
}
@@ -2299,26 +2318,23 @@ static void scalar_test(void) {
{
/* Test multiplicative identity. */
- secp256k1_scalar r1, v1;
- secp256k1_scalar_set_int(&v1,1);
- secp256k1_scalar_mul(&r1, &s1, &v1);
+ secp256k1_scalar r1;
+ secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_one);
CHECK(secp256k1_scalar_eq(&r1, &s1));
}
{
/* Test additive identity. */
- secp256k1_scalar r1, v0;
- secp256k1_scalar_set_int(&v0,0);
- secp256k1_scalar_add(&r1, &s1, &v0);
+ secp256k1_scalar r1;
+ secp256k1_scalar_add(&r1, &s1, &secp256k1_scalar_zero);
CHECK(secp256k1_scalar_eq(&r1, &s1));
}
{
/* Test zero product property. */
- secp256k1_scalar r1, v0;
- secp256k1_scalar_set_int(&v0,0);
- secp256k1_scalar_mul(&r1, &s1, &v0);
- CHECK(secp256k1_scalar_eq(&r1, &v0));
+ secp256k1_scalar r1;
+ secp256k1_scalar_mul(&r1, &s1, &secp256k1_scalar_zero);
+ CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero));
}
}
@@ -2350,12 +2366,24 @@ static void run_scalar_tests(void) {
}
{
+ /* Check that the scalar constants secp256k1_scalar_zero and
+ secp256k1_scalar_one contain the expected values. */
+ secp256k1_scalar zero, one;
+
+ CHECK(secp256k1_scalar_is_zero(&secp256k1_scalar_zero));
+ secp256k1_scalar_set_int(&zero, 0);
+ CHECK(secp256k1_scalar_eq(&zero, &secp256k1_scalar_zero));
+
+ CHECK(secp256k1_scalar_is_one(&secp256k1_scalar_one));
+ secp256k1_scalar_set_int(&one, 1);
+ CHECK(secp256k1_scalar_eq(&one, &secp256k1_scalar_one));
+ }
+
+ {
/* (-1)+1 should be zero. */
- secp256k1_scalar s, o;
- secp256k1_scalar_set_int(&s, 1);
- CHECK(secp256k1_scalar_is_one(&s));
- secp256k1_scalar_negate(&o, &s);
- secp256k1_scalar_add(&o, &o, &s);
+ secp256k1_scalar o;
+ secp256k1_scalar_negate(&o, &secp256k1_scalar_one);
+ secp256k1_scalar_add(&o, &o, &secp256k1_scalar_one);
CHECK(secp256k1_scalar_is_zero(&o));
secp256k1_scalar_negate(&o, &o);
CHECK(secp256k1_scalar_is_zero(&o));
@@ -2380,7 +2408,6 @@ static void run_scalar_tests(void) {
secp256k1_scalar y;
secp256k1_scalar z;
secp256k1_scalar zz;
- secp256k1_scalar one;
secp256k1_scalar r1;
secp256k1_scalar r2;
secp256k1_scalar zzv;
@@ -2917,7 +2944,6 @@ static void run_scalar_tests(void) {
0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}
};
- secp256k1_scalar_set_int(&one, 1);
for (i = 0; i < 33; i++) {
secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
CHECK(!overflow);
@@ -2940,7 +2966,7 @@ static void run_scalar_tests(void) {
CHECK(secp256k1_scalar_eq(&x, &z));
secp256k1_scalar_mul(&zz, &zz, &y);
CHECK(!secp256k1_scalar_check_overflow(&zz));
- CHECK(secp256k1_scalar_eq(&one, &zz));
+ CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz));
}
}
}
@@ -2952,7 +2978,7 @@ static void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256(bin);
- if (secp256k1_fe_set_b32(x, bin)) {
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
return;
}
} while(1);
@@ -2962,7 +2988,7 @@ static void random_fe_test(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256_test(bin);
- if (secp256k1_fe_set_b32(x, bin)) {
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
return;
}
} while(1);
@@ -3016,7 +3042,7 @@ static void run_field_convert(void) {
unsigned char b322[32];
secp256k1_fe_storage fes2;
/* Check conversions to fe. */
- CHECK(secp256k1_fe_set_b32(&fe2, b32));
+ CHECK(secp256k1_fe_set_b32_limit(&fe2, b32));
CHECK(secp256k1_fe_equal_var(&fe, &fe2));
secp256k1_fe_from_storage(&fe2, &fes);
CHECK(secp256k1_fe_equal_var(&fe, &fe2));
@@ -3027,13 +3053,75 @@ static void run_field_convert(void) {
CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0);
}
+static void run_field_be32_overflow(void) {
+ {
+ static const unsigned char zero_overflow[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F,
+ };
+ static const unsigned char zero[32] = { 0x00 };
+ unsigned char out[32];
+ secp256k1_fe fe;
+ CHECK(secp256k1_fe_set_b32_limit(&fe, zero_overflow) == 0);
+ secp256k1_fe_set_b32_mod(&fe, zero_overflow);
+ CHECK(secp256k1_fe_normalizes_to_zero(&fe) == 1);
+ secp256k1_fe_normalize(&fe);
+ CHECK(secp256k1_fe_is_zero(&fe) == 1);
+ secp256k1_fe_get_b32(out, &fe);
+ CHECK(secp256k1_memcmp_var(out, zero, 32) == 0);
+ }
+ {
+ static const unsigned char one_overflow[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30,
+ };
+ static const unsigned char one[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ };
+ unsigned char out[32];
+ secp256k1_fe fe;
+ CHECK(secp256k1_fe_set_b32_limit(&fe, one_overflow) == 0);
+ secp256k1_fe_set_b32_mod(&fe, one_overflow);
+ secp256k1_fe_normalize(&fe);
+ CHECK(secp256k1_fe_cmp_var(&fe, &secp256k1_fe_one) == 0);
+ secp256k1_fe_get_b32(out, &fe);
+ CHECK(secp256k1_memcmp_var(out, one, 32) == 0);
+ }
+ {
+ static const unsigned char ff_overflow[32] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ };
+ static const unsigned char ff[32] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0xD0,
+ };
+ unsigned char out[32];
+ secp256k1_fe fe;
+ const secp256k1_fe fe_ff = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0x01, 0x000003d0);
+ CHECK(secp256k1_fe_set_b32_limit(&fe, ff_overflow) == 0);
+ secp256k1_fe_set_b32_mod(&fe, ff_overflow);
+ secp256k1_fe_normalize(&fe);
+ CHECK(secp256k1_fe_cmp_var(&fe, &fe_ff) == 0);
+ secp256k1_fe_get_b32(out, &fe);
+ CHECK(secp256k1_memcmp_var(out, ff, 32) == 0);
+ }
+}
+
/* Returns true if two field elements have the same representation. */
static int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
int ret = 1;
-#ifdef VERIFY
- ret &= (a->magnitude == b->magnitude);
- ret &= (a->normalized == b->normalized);
-#endif
/* Compare the struct member that holds the limbs. */
ret &= (secp256k1_memcmp_var(a->n, b->n, sizeof(a->n)) == 0);
return ret;
@@ -3121,16 +3209,22 @@ static void run_field_misc(void) {
q = x;
secp256k1_fe_cmov(&x, &z, 0);
#ifdef VERIFY
- CHECK(x.normalized && x.magnitude == 1);
+ CHECK(!x.normalized);
+ CHECK((x.magnitude == q.magnitude) || (x.magnitude == z.magnitude));
+ CHECK((x.magnitude >= q.magnitude) && (x.magnitude >= z.magnitude));
#endif
+ x = q;
secp256k1_fe_cmov(&x, &x, 1);
CHECK(!fe_identical(&x, &z));
CHECK(fe_identical(&x, &q));
secp256k1_fe_cmov(&q, &z, 1);
#ifdef VERIFY
- CHECK(!q.normalized && q.magnitude == z.magnitude);
+ CHECK(!q.normalized);
+ CHECK((q.magnitude == x.magnitude) || (q.magnitude == z.magnitude));
+ CHECK((q.magnitude >= x.magnitude) && (q.magnitude >= z.magnitude));
#endif
CHECK(fe_identical(&q, &z));
+ q = z;
secp256k1_fe_normalize_var(&x);
secp256k1_fe_normalize_var(&z);
CHECK(!secp256k1_fe_equal_var(&x, &z));
@@ -3144,7 +3238,7 @@ static void run_field_misc(void) {
secp256k1_fe_normalize_var(&q);
secp256k1_fe_cmov(&q, &z, (j&1));
#ifdef VERIFY
- CHECK((q.normalized != (j&1)) && q.magnitude == ((j&1) ? z.magnitude : 1));
+ CHECK(!q.normalized && q.magnitude == z.magnitude);
#endif
}
secp256k1_fe_normalize_var(&z);
@@ -3605,7 +3699,7 @@ static void run_inverse_tests(void)
b32[31] = i & 0xff;
b32[30] = (i >> 8) & 0xff;
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
- secp256k1_fe_set_b32(&x_fe, b32);
+ secp256k1_fe_set_b32_mod(&x_fe, b32);
for (var = 0; var <= 1; ++var) {
test_inverse_scalar(NULL, &x_scalar, var);
test_inverse_field(NULL, &x_fe, var);
@@ -3622,7 +3716,7 @@ static void run_inverse_tests(void)
for (i = 0; i < 64 * COUNT; ++i) {
(testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32);
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
- secp256k1_fe_set_b32(&x_fe, b32);
+ secp256k1_fe_set_b32_mod(&x_fe, b32);
for (var = 0; var <= 1; ++var) {
test_inverse_scalar(NULL, &x_scalar, var);
test_inverse_field(NULL, &x_fe, var);
@@ -3692,7 +3786,7 @@ static void test_ge(void) {
*/
secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
- secp256k1_fe zf;
+ secp256k1_fe zf, r;
secp256k1_fe zfi2, zfi3;
secp256k1_gej_set_infinity(&gej[0]);
@@ -3734,6 +3828,11 @@ static void test_ge(void) {
secp256k1_fe_sqr(&zfi2, &zfi3);
secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);
+ /* Generate random r */
+ do {
+ random_field_element_test(&r);
+ } while(secp256k1_fe_is_zero(&r));
+
for (i1 = 0; i1 < 1 + 4 * runs; i1++) {
int i2;
for (i2 = 0; i2 < 1 + 4 * runs; i2++) {
@@ -3846,6 +3945,29 @@ static void test_ge(void) {
free(ge_set_all);
}
+ /* Test that all elements have X coordinates on the curve. */
+ for (i = 1; i < 4 * runs + 1; i++) {
+ secp256k1_fe n;
+ CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x));
+ /* And the same holds after random rescaling. */
+ secp256k1_fe_mul(&n, &zf, &ge[i].x);
+ CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf));
+ }
+
+ /* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */
+ {
+ secp256k1_fe n;
+ secp256k1_ge q;
+ int ret_on_curve, ret_frac_on_curve, ret_set_xo;
+ secp256k1_fe_mul(&n, &zf, &r);
+ ret_on_curve = secp256k1_ge_x_on_curve_var(&r);
+ ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf);
+ ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0);
+ CHECK(ret_on_curve == ret_frac_on_curve);
+ CHECK(ret_on_curve == ret_set_xo);
+ if (ret_set_xo) CHECK(secp256k1_fe_equal_var(&r, &q.x));
+ }
+
/* Test batch gej -> ge conversion with many infinities. */
for (i = 0; i < 4 * runs + 1; i++) {
int odd;
@@ -4338,9 +4460,9 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) {
secp256k1_ecmult(&p2j, &pj, &n2, &zero);
secp256k1_ecmult(&ptj, &pj, target, &zero);
} else {
- secp256k1_ecmult_const(&p1j, &p, &n1, 256);
- secp256k1_ecmult_const(&p2j, &p, &n2, 256);
- secp256k1_ecmult_const(&ptj, &p, target, 256);
+ secp256k1_ecmult_const(&p1j, &p, &n1);
+ secp256k1_ecmult_const(&p2j, &p, &n2);
+ secp256k1_ecmult_const(&ptj, &p, target);
}
/* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */
@@ -4403,7 +4525,7 @@ static void ecmult_const_random_mult(void) {
0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
);
secp256k1_gej b;
- secp256k1_ecmult_const(&b, &a, &xn, 256);
+ secp256k1_ecmult_const(&b, &a, &xn);
CHECK(secp256k1_ge_is_valid_var(&a));
ge_equals_gej(&expected_b, &b);
@@ -4419,12 +4541,12 @@ static void ecmult_const_commutativity(void) {
random_scalar_order_test(&a);
random_scalar_order_test(&b);
- secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256);
- secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256);
+ secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
+ secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
- secp256k1_ecmult_const(&res1, &mid1, &b, 256);
- secp256k1_ecmult_const(&res2, &mid2, &a, 256);
+ secp256k1_ecmult_const(&res1, &mid1, &b);
+ secp256k1_ecmult_const(&res2, &mid2, &a);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
ge_equals_ge(&mid1, &mid2);
@@ -4440,18 +4562,80 @@ static void ecmult_const_mult_zero_one(void) {
secp256k1_scalar_negate(&negone, &one);
random_group_element_test(&point);
- secp256k1_ecmult_const(&res1, &point, &zero, 3);
+ secp256k1_ecmult_const(&res1, &point, &zero);
secp256k1_ge_set_gej(&res2, &res1);
CHECK(secp256k1_ge_is_infinity(&res2));
- secp256k1_ecmult_const(&res1, &point, &one, 2);
+ secp256k1_ecmult_const(&res1, &point, &one);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
- secp256k1_ecmult_const(&res1, &point, &negone, 256);
+ secp256k1_ecmult_const(&res1, &point, &negone);
secp256k1_gej_neg(&res1, &res1);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
}
+static void ecmult_const_mult_xonly(void) {
+ int i;
+
+ /* Test correspondence between secp256k1_ecmult_const and secp256k1_ecmult_const_xonly. */
+ for (i = 0; i < 2*COUNT; ++i) {
+ secp256k1_ge base;
+ secp256k1_gej basej, resj;
+ secp256k1_fe n, d, resx, v;
+ secp256k1_scalar q;
+ int res;
+ /* Random base point. */
+ random_group_element_test(&base);
+ /* Random scalar to multiply it with. */
+ random_scalar_order_test(&q);
+ /* If i is odd, n=d*base.x for random non-zero d */
+ if (i & 1) {
+ do {
+ random_field_element_test(&d);
+ } while (secp256k1_fe_normalizes_to_zero_var(&d));
+ secp256k1_fe_mul(&n, &base.x, &d);
+ } else {
+ n = base.x;
+ }
+ /* Perform x-only multiplication. */
+ res = secp256k1_ecmult_const_xonly(&resx, &n, (i & 1) ? &d : NULL, &q, i & 2);
+ CHECK(res);
+ /* Perform normal multiplication. */
+ secp256k1_gej_set_ge(&basej, &base);
+ secp256k1_ecmult(&resj, &basej, &q, NULL);
+ /* Check that resj's X coordinate corresponds with resx. */
+ secp256k1_fe_sqr(&v, &resj.z);
+ secp256k1_fe_mul(&v, &v, &resx);
+ CHECK(check_fe_equal(&v, &resj.x));
+ }
+
+ /* Test that secp256k1_ecmult_const_xonly correctly rejects X coordinates not on curve. */
+ for (i = 0; i < 2*COUNT; ++i) {
+ secp256k1_fe x, n, d, c, r;
+ int res;
+ secp256k1_scalar q;
+ random_scalar_order_test(&q);
+ /* Generate random X coordinate not on the curve. */
+ do {
+ random_field_element_test(&x);
+ secp256k1_fe_sqr(&c, &x);
+ secp256k1_fe_mul(&c, &c, &x);
+ secp256k1_fe_add_int(&c, SECP256K1_B);
+ } while (secp256k1_fe_is_square_var(&c));
+ /* If i is odd, n=d*x for random non-zero d. */
+ if (i & 1) {
+ do {
+ random_field_element_test(&d);
+ } while (secp256k1_fe_normalizes_to_zero_var(&d));
+ secp256k1_fe_mul(&n, &x, &d);
+ } else {
+ n = x;
+ }
+ res = secp256k1_ecmult_const_xonly(&r, &n, (i & 1) ? &d : NULL, &q, 0);
+ CHECK(res == 0);
+ }
+}
+
static void ecmult_const_chain_multiply(void) {
/* Check known result (randomly generated test problem from sage) */
const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST(
@@ -4472,7 +4656,7 @@ static void ecmult_const_chain_multiply(void) {
for (i = 0; i < 100; ++i) {
secp256k1_ge tmp;
secp256k1_ge_set_gej(&tmp, &point);
- secp256k1_ecmult_const(&point, &tmp, &scalar, 256);
+ secp256k1_ecmult_const(&point, &tmp, &scalar);
}
secp256k1_ge_set_gej(&res, &point);
ge_equals_gej(&res, &expected_point);
@@ -4483,6 +4667,7 @@ static void run_ecmult_const_tests(void) {
ecmult_const_random_mult();
ecmult_const_commutativity();
ecmult_const_chain_multiply();
+ ecmult_const_mult_xonly();
}
typedef struct {
@@ -4507,7 +4692,6 @@ static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, s
static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) {
int ncount;
- secp256k1_scalar szero;
secp256k1_scalar sc[32];
secp256k1_ge pt[32];
secp256k1_gej r;
@@ -4516,7 +4700,6 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
data.sc = sc;
data.pt = pt;
- secp256k1_scalar_set_int(&szero, 0);
/* No points to multiply */
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
@@ -4534,21 +4717,21 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
pt[1] = secp256k1_ge_const_g;
/* only G scalar */
- secp256k1_ecmult(&r2, &ptgj, &szero, &sc[0]);
+ secp256k1_ecmult(&r2, &ptgj, &secp256k1_scalar_zero, &sc[0]);
CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 1-point */
- secp256k1_ecmult(&r2, &ptgj, &sc[0], &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
+ secp256k1_ecmult(&r2, &ptgj, &sc[0], &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* Try to multiply 1 point, but callback returns false */
- CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
+ CHECK(!ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_false_callback, &data, 1));
/* 2-point */
secp256k1_ecmult(&r2, &ptgj, &sc[0], &sc[1]);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2));
CHECK(secp256k1_gej_eq_var(&r, &r2));
/* 2-point with G scalar */
@@ -4568,7 +4751,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
random_scalar_order(&sc[i]);
secp256k1_ge_set_infinity(&pt[i]);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4578,7 +4761,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
pt[i] = ptg;
secp256k1_scalar_set_int(&sc[i], 0);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4591,7 +4774,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
pt[2 * i + 1] = ptg;
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
random_scalar_order(&sc[0]);
@@ -4604,7 +4787,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4619,7 +4802,7 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_scalar_negate(&sc[i], &sc[i]);
}
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 32));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -4637,8 +4820,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL);
}
- secp256k1_ecmult(&r2, &r, &sc[0], &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_ecmult(&r2, &r, &sc[0], &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
@@ -4658,8 +4841,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
}
secp256k1_gej_set_ge(&p0j, &pt[0]);
- secp256k1_ecmult(&r2, &p0j, &rs, &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_ecmult(&r2, &p0j, &rs, &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20));
CHECK(secp256k1_gej_eq_var(&r, &r2));
}
@@ -4670,13 +4853,13 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
}
secp256k1_scalar_clear(&sc[0]);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 20));
secp256k1_scalar_clear(&sc[1]);
secp256k1_scalar_clear(&sc[2]);
secp256k1_scalar_clear(&sc[3]);
secp256k1_scalar_clear(&sc[4]);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 6));
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 5));
CHECK(secp256k1_gej_is_infinity(&r));
/* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */
@@ -4700,8 +4883,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_scalar_set_int(&t1, (t1i + 1) / 2);
secp256k1_scalar_cond_negate(&t1, t1i & 1);
- secp256k1_ecmult(&t0p, &ptgj, &t0, &szero);
- secp256k1_ecmult(&t1p, &ptgj, &t1, &szero);
+ secp256k1_ecmult(&t0p, &ptgj, &t0, &secp256k1_scalar_zero);
+ secp256k1_ecmult(&t1p, &ptgj, &t1, &secp256k1_scalar_zero);
for(s0i = 0; s0i < TOP; s0i++) {
for(s1i = 0; s1i < TOP; s1i++) {
@@ -4720,8 +4903,8 @@ static void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi
secp256k1_scalar_mul(&tmp2, &t1, &sc[1]);
secp256k1_scalar_add(&tmp1, &tmp1, &tmp2);
- secp256k1_ecmult(&expected, &ptgj, &tmp1, &szero);
- CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
+ secp256k1_ecmult(&expected, &ptgj, &tmp1, &secp256k1_scalar_zero);
+ CHECK(ecmult_multi(&CTX->error_callback, scratch, &actual, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 2));
CHECK(secp256k1_gej_eq_var(&actual, &expected));
}
}
@@ -4897,7 +5080,6 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) {
}
static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
- secp256k1_scalar szero;
secp256k1_scalar sc;
secp256k1_ge pt;
secp256k1_gej r;
@@ -4908,11 +5090,10 @@ static void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_mu
random_scalar_order(&sc);
data.sc = &sc;
data.pt = &pt;
- secp256k1_scalar_set_int(&szero, 0);
/* Try to multiply 1 point, but scratch space is empty.*/
scratch_empty = secp256k1_scratch_create(&CTX->error_callback, 0);
- CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
+ CHECK(!ecmult_multi(&CTX->error_callback, scratch_empty, &r, &secp256k1_scalar_zero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(&CTX->error_callback, scratch_empty);
}
@@ -5020,7 +5201,6 @@ static void test_ecmult_multi_batch_size_helper(void) {
static void test_ecmult_multi_batching(void) {
static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD;
secp256k1_scalar scG;
- secp256k1_scalar szero;
secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points);
secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points);
secp256k1_gej r;
@@ -5030,11 +5210,10 @@ static void test_ecmult_multi_batching(void) {
secp256k1_scratch *scratch;
secp256k1_gej_set_infinity(&r2);
- secp256k1_scalar_set_int(&szero, 0);
/* Get random scalars and group elements and compute result */
random_scalar_order(&scG);
- secp256k1_ecmult(&r2, &r2, &szero, &scG);
+ secp256k1_ecmult(&r2, &r2, &secp256k1_scalar_zero, &scG);
for(i = 0; i < n_points; i++) {
secp256k1_ge ptg;
secp256k1_gej ptgj;
@@ -5369,7 +5548,7 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar
secp256k1_ecmult(&rj3, &infj, &zero, x);
secp256k1_ecmult_multi_var(NULL, scratch, &rj4, x, NULL, NULL, 0);
secp256k1_ecmult_multi_var(NULL, scratch, &rj5, &zero, test_ecmult_accumulate_cb, (void*)x, 1);
- secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x, 256);
+ secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x);
secp256k1_ge_set_gej_var(&r, &rj1);
ge_equals_gej(&r, &rj2);
ge_equals_gej(&r, &rj3);
@@ -7306,6 +7485,44 @@ static void run_ecdsa_edge_cases(void) {
test_ecdsa_edge_cases();
}
+/** Wycheproof tests
+
+The tests check for known attacks (range checks in (r,s), arithmetic errors, malleability).
+*/
+static void test_ecdsa_wycheproof(void) {
+ #include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h"
+
+ int t;
+ for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) {
+ secp256k1_ecdsa_signature signature;
+ secp256k1_sha256 hasher;
+ secp256k1_pubkey pubkey;
+ const unsigned char *msg, *sig, *pk;
+ unsigned char out[32] = {0};
+ int actual_verify = 0;
+
+ memset(&pubkey, 0, sizeof(pubkey));
+ pk = &wycheproof_ecdsa_public_keys[testvectors[t].pk_offset];
+ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pk, 65) == 1);
+
+ secp256k1_sha256_initialize(&hasher);
+ msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset];
+ secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len);
+ secp256k1_sha256_finalize(&hasher, out);
+
+ sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset];
+ if (secp256k1_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) {
+ actual_verify = secp256k1_ecdsa_verify(CTX, (const secp256k1_ecdsa_signature *)&signature, out, &pubkey);
+ }
+ CHECK(testvectors[t].expected_verify == actual_verify);
+ }
+}
+
+/* Tests cases from Wycheproof test suite. */
+static void run_ecdsa_wycheproof(void) {
+ test_ecdsa_wycheproof();
+}
+
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/tests_impl.h"
#endif
@@ -7322,6 +7539,10 @@ static void run_ecdsa_edge_cases(void) {
# include "modules/schnorrsig/tests_impl.h"
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+# include "modules/ellswift/tests_impl.h"
+#endif
+
static void run_secp256k1_memczero_test(void) {
unsigned char buf1[6] = {1, 2, 3, 4, 5, 6};
unsigned char buf2[sizeof(buf1)];
@@ -7338,16 +7559,31 @@ static void run_secp256k1_memczero_test(void) {
}
static void run_secp256k1_byteorder_tests(void) {
- const uint32_t x = 0xFF03AB45;
- const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
- unsigned char buf[4];
- uint32_t x_;
+ {
+ const uint32_t x = 0xFF03AB45;
+ const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
+ unsigned char buf[4];
+ uint32_t x_;
+
+ secp256k1_write_be32(buf, x);
+ CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
- secp256k1_write_be32(buf, x);
- CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
+ x_ = secp256k1_read_be32(buf);
+ CHECK(x == x_);
+ }
+
+ {
+ const uint64_t x = 0xCAFE0123BEEF4567;
+ const unsigned char x_be[8] = {0xCA, 0xFE, 0x01, 0x23, 0xBE, 0xEF, 0x45, 0x67};
+ unsigned char buf[8];
+ uint64_t x_;
- x_ = secp256k1_read_be32(buf);
- CHECK(x == x_);
+ secp256k1_write_be64(buf, x);
+ CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
+
+ x_ = secp256k1_read_be64(buf);
+ CHECK(x == x_);
+ }
}
static void int_cmov_test(void) {
@@ -7386,23 +7622,23 @@ static void fe_cmov_test(void) {
secp256k1_fe a = zero;
secp256k1_fe_cmov(&r, &a, 0);
- CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &max));
r = zero; a = max;
secp256k1_fe_cmov(&r, &a, 1);
- CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &max));
a = zero;
secp256k1_fe_cmov(&r, &a, 1);
- CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &zero));
a = one;
secp256k1_fe_cmov(&r, &a, 1);
- CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &one));
r = one; a = zero;
secp256k1_fe_cmov(&r, &a, 0);
- CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0);
+ CHECK(fe_identical(&r, &one));
}
static void fe_storage_cmov_test(void) {
@@ -7592,6 +7828,7 @@ int main(int argc, char **argv) {
run_field_half();
run_field_misc();
run_field_convert();
+ run_field_be32_overflow();
run_fe_mul();
run_sqr();
run_sqrt();
@@ -7638,6 +7875,7 @@ int main(int argc, char **argv) {
run_ecdsa_sign_verify();
run_ecdsa_end_to_end();
run_ecdsa_edge_cases();
+ run_ecdsa_wycheproof();
#ifdef ENABLE_MODULE_RECOVERY
/* ECDSA pubkey recovery tests */
@@ -7652,6 +7890,10 @@ int main(int argc, char **argv) {
run_schnorrsig_tests();
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ run_ellswift_tests();
+#endif
+
/* util tests */
run_secp256k1_memczero_test();
run_secp256k1_byteorder_tests();
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index 86b9334cae..d35acdd58e 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -13,13 +13,19 @@
#define EXHAUSTIVE_TEST_ORDER 13
#endif
+#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
+ #pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.")
+ #undef USE_EXTERNAL_DEFAULT_CALLBACKS
+#endif
#include "secp256k1.c"
+
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "group.h"
#include "testrand_impl.h"
#include "ecmult_compute_table_impl.h"
#include "ecmult_gen_compute_table_impl.h"
+#include "util.h"
static int count = 2;
@@ -54,11 +60,24 @@ static void random_fe(secp256k1_fe *x) {
unsigned char bin[32];
do {
secp256k1_testrand256(bin);
- if (secp256k1_fe_set_b32(x, bin)) {
+ if (secp256k1_fe_set_b32_limit(x, bin)) {
return;
}
} while(1);
}
+
+static void random_fe_non_zero(secp256k1_fe *nz) {
+ int tries = 10;
+ while (--tries >= 0) {
+ random_fe(nz);
+ secp256k1_fe_normalize(nz);
+ if (!secp256k1_fe_is_zero(nz)) {
+ break;
+ }
+ }
+ /* Infinitesimal probability of spurious failure here */
+ CHECK(tries >= 0);
+}
/** END stolen from tests.c */
static uint32_t num_cores = 1;
@@ -174,10 +193,37 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng);
ge_equals_gej(&group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
- if (i > 0) {
- secp256k1_ecmult_const(&tmp, &group[i], &ng, 256);
- ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp);
- }
+ }
+ }
+ }
+
+ for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) {
+ for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
+ int ret;
+ secp256k1_gej tmp;
+ secp256k1_fe xn, xd, tmpf;
+ secp256k1_scalar ng;
+
+ if (skip_section(&iter)) continue;
+
+ secp256k1_scalar_set_int(&ng, j);
+
+ /* Test secp256k1_ecmult_const. */
+ secp256k1_ecmult_const(&tmp, &group[i], &ng);
+ ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp);
+
+ if (i != 0 && j != 0) {
+ /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */
+ ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0);
+ CHECK(ret);
+ CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
+
+ /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */
+ random_fe_non_zero(&xd);
+ secp256k1_fe_mul(&xn, &xd, &group[i].x);
+ ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0);
+ CHECK(ret);
+ CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
}
}
}
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index e75c5ad552..e2ee8a8f19 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -7,6 +7,8 @@
#ifndef SECP256K1_UTIL_H
#define SECP256K1_UTIL_H
+#include "../include/secp256k1.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
@@ -17,6 +19,38 @@
#define DEBUG_CONFIG_MSG(x) "DEBUG_CONFIG: " x
#define DEBUG_CONFIG_DEF(x) DEBUG_CONFIG_MSG(#x "=" STR(x))
+/* Debug helper for printing arrays of unsigned char. */
+#define PRINT_BUF(buf, len) do { \
+ printf("%s[%lu] = ", #buf, (unsigned long)len); \
+ print_buf_plain(buf, len); \
+} while(0)
+
+static void print_buf_plain(const unsigned char *buf, size_t len) {
+ size_t i;
+ printf("{");
+ for (i = 0; i < len; i++) {
+ if (i % 8 == 0) {
+ printf("\n ");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X,", buf[i]);
+ }
+ printf("\n}\n");
+}
+
+# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if SECP256K1_GNUC_PREREQ(2,7)
+# define SECP256K1_INLINE __inline__
+# elif (defined(_MSC_VER))
+# define SECP256K1_INLINE __inline
+# else
+# define SECP256K1_INLINE
+# endif
+# else
+# define SECP256K1_INLINE inline
+# endif
+
typedef struct {
void (*fn)(const char *text, void* data);
const void* data;
@@ -319,4 +353,28 @@ SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x)
p[0] = x >> 24;
}
+/* Read a uint64_t in big endian */
+SECP256K1_INLINE static uint64_t secp256k1_read_be64(const unsigned char* p) {
+ return (uint64_t)p[0] << 56 |
+ (uint64_t)p[1] << 48 |
+ (uint64_t)p[2] << 40 |
+ (uint64_t)p[3] << 32 |
+ (uint64_t)p[4] << 24 |
+ (uint64_t)p[5] << 16 |
+ (uint64_t)p[6] << 8 |
+ (uint64_t)p[7];
+}
+
+/* Write a uint64_t in big endian */
+SECP256K1_INLINE static void secp256k1_write_be64(unsigned char* p, uint64_t x) {
+ p[7] = x;
+ p[6] = x >> 8;
+ p[5] = x >> 16;
+ p[4] = x >> 24;
+ p[3] = x >> 32;
+ p[2] = x >> 40;
+ p[1] = x >> 48;
+ p[0] = x >> 56;
+}
+
#endif /* SECP256K1_UTIL_H */
diff --git a/src/secp256k1/src/wycheproof/WYCHEPROOF_COPYING b/src/secp256k1/src/wycheproof/WYCHEPROOF_COPYING
new file mode 100644
index 0000000000..cddf9d9182
--- /dev/null
+++ b/src/secp256k1/src/wycheproof/WYCHEPROOF_COPYING
@@ -0,0 +1,212 @@
+* The file `ecdsa_secp256k1_sha256_bitcoin_test.json` in this directory
+ comes from Google's project Wycheproof with git commit
+ `b063b4aedae951c69df014cd25fa6d69ae9e8cb9`, see
+ https://github.com/google/wycheproof/blob/b063b4aedae951c69df014cd25fa6d69ae9e8cb9/testvectors_v1/ecdsa_secp256k1_sha256_bitcoin_test.json
+
+* The file `ecdsa_secp256k1_sha256_bitcoin_test.h` is generated from
+ `ecdsa_secp256k1_sha256_bitcoin_test.json` using the script
+ `tests_wycheproof_generate.py`.
+
+-------------------------------------------------------------------------------
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h b/src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
new file mode 100644
index 0000000000..736737fd61
--- /dev/null
+++ b/src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
@@ -0,0 +1,1564 @@
+/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */
+#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS (463)
+
+typedef struct {
+ size_t pk_offset;
+ size_t msg_offset;
+ size_t msg_len;
+ size_t sig_offset;
+ size_t sig_len;
+ int expected_verify;
+} wycheproof_ecdsa_testvector;
+
+static const unsigned char wycheproof_ecdsa_messages[] = { 0x31,0x32,0x33,0x34,0x30,0x30,
+ 0x32,0x35,0x35,0x38,0x35,
+ 0x34,0x32,0x36,0x34,0x37,0x39,0x37,0x32,0x34,
+ 0x37,0x31,0x33,0x38,0x36,0x38,0x34,0x38,0x39,0x31,
+ 0x31,0x30,0x33,0x35,0x39,0x33,0x33,0x31,0x36,0x36,0x38,
+ 0x33,0x39,0x34,0x39,0x34,0x30,0x31,0x32,0x31,0x35,
+ 0x31,0x33,0x34,0x34,0x32,0x39,0x33,0x30,0x37,0x39,
+ 0x33,0x37,0x30,0x36,0x32,0x31,0x31,0x37,0x31,0x32,
+ 0x33,0x34,0x33,0x36,0x38,0x38,0x37,0x31,0x32,
+ 0x31,0x33,0x35,0x31,0x35,0x33,0x30,0x33,0x37,0x30,
+ 0x36,0x35,0x35,0x33,0x32,0x30,0x33,0x31,0x32,0x36,
+ 0x31,0x35,0x36,0x34,0x33,0x34,0x36,0x36,0x30,0x33,
+ 0x34,0x34,0x32,0x39,0x35,0x33,0x39,0x31,0x31,0x37,
+ 0x31,0x30,0x39,0x35,0x33,0x32,0x36,0x31,0x33,0x35,0x31,
+ 0x35,0x39,0x38,0x37,0x33,0x35,0x30,0x30,0x34,0x31,
+ 0x33,0x34,0x36,0x33,0x30,0x30,0x36,0x38,0x37,0x38,
+ 0x39,0x38,0x31,0x37,0x33,0x32,0x30,0x32,0x38,0x37,
+ 0x33,0x32,0x32,0x32,0x30,0x34,0x31,0x30,0x34,0x36,
+ 0x36,0x36,0x36,0x36,0x33,0x30,0x37,0x31,0x30,0x34,
+ 0x31,0x30,0x33,0x35,0x39,0x35,0x31,0x38,0x39,0x38,
+ 0x31,0x38,0x34,0x36,0x35,0x39,0x37,0x31,0x39,0x35,
+ 0x33,0x31,0x33,0x36,0x30,0x34,0x36,0x31,0x38,0x39,
+ 0x32,0x36,0x36,0x33,0x37,0x38,0x34,0x32,0x35,0x34,
+ 0x31,0x36,0x35,0x32,0x31,0x30,0x30,0x35,0x32,0x34,
+ 0x35,0x37,0x34,0x38,0x30,0x38,0x31,0x36,0x39,0x36,
+ 0x36,0x33,0x34,0x33,0x39,0x31,0x33,0x34,0x36,0x38,
+ 0x31,0x35,0x34,0x31,0x31,0x30,0x33,0x35,0x39,0x38,
+ 0x31,0x30,0x34,0x37,0x38,0x35,0x38,0x30,0x31,0x32,0x38,
+ 0x31,0x30,0x35,0x33,0x36,0x32,0x38,0x35,0x35,0x36,0x38,
+ 0x39,0x35,0x33,0x39,0x30,0x34,0x31,0x30,0x35,
+ 0x39,0x37,0x38,0x38,0x34,0x38,0x30,0x33,0x39,
+ 0x33,0x36,0x31,0x30,0x36,0x37,0x32,0x34,0x34,0x32,
+ 0x31,0x30,0x35,0x34,0x32,0x34,0x30,0x37,0x30,0x35,
+ 0x35,0x31,0x37,0x34,0x34,0x34,0x38,0x31,0x39,0x37,
+ 0x31,0x39,0x36,0x37,0x35,0x36,0x31,0x32,0x35,0x31,
+ 0x33,0x34,0x34,0x37,0x32,0x35,0x33,0x33,0x34,0x33,
+ 0x33,0x36,0x38,0x32,0x36,0x34,0x33,0x31,0x38,
+ 0x33,0x32,0x36,0x31,0x31,0x39,0x38,0x36,0x30,0x38,
+ 0x39,0x36,0x37,0x38,0x37,0x38,0x31,0x30,0x39,0x34,
+ 0x34,0x39,0x35,0x38,0x38,0x32,0x33,0x38,0x32,0x33,
+ 0x38,0x32,0x34,0x36,0x33,0x37,0x38,0x33,0x37,
+ 0x31,0x31,0x30,0x32,0x30,0x38,0x33,0x33,0x37,0x37,0x36,
+ 0x31,0x33,0x33,0x38,0x37,0x31,0x36,0x34,0x38,
+ 0x33,0x32,0x32,0x31,0x34,0x34,0x31,0x36,0x32,
+ 0x31,0x30,0x36,0x38,0x36,0x36,0x35,0x35,0x35,0x34,0x36,
+ 0x36,0x32,0x31,0x35,0x35,0x32,0x34,0x36,
+ 0x37,0x30,0x33,0x30,0x38,0x31,0x38,0x37,0x37,0x34,
+ 0x35,0x39,0x32,0x34,0x35,0x32,0x33,0x37,0x34,0x34,
+ 0x31,0x34,0x39,0x35,0x35,0x38,0x36,0x36,0x32,0x31,
+ 0x34,0x30,0x30,0x35,0x33,0x31,0x34,0x34,0x30,0x36,
+ 0x33,0x30,0x39,0x36,0x34,0x35,0x37,0x35,0x31,0x32,
+ 0x32,0x37,0x38,0x34,0x30,0x32,0x35,0x36,0x32,0x30,
+ 0x32,0x36,0x31,0x38,0x37,0x38,0x37,0x34,0x31,0x38,
+ 0x31,0x36,0x34,0x32,0x36,0x32,0x35,0x32,0x36,0x32,
+ 0x36,0x38,0x32,0x34,0x31,0x38,0x39,0x34,0x33,0x36,
+ 0x34,0x38,0x34,0x32,0x34,0x35,0x34,0x32,0x35,
+ 0x4d,0x73,0x67,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x4d,0x65,0x73,0x73,0x61,0x67,0x65};
+
+static const unsigned char wycheproof_ecdsa_public_keys[] = { 0x04,0xb8,0x38,0xff,0x44,0xe5,0xbc,0x17,0x7b,0xf2,0x11,0x89,0xd0,0x76,0x60,0x82,0xfc,0x9d,0x84,0x32,0x26,0x88,0x7f,0xc9,0x76,0x03,0x71,0x10,0x0b,0x7e,0xe2,0x0a,0x6f,0xf0,0xc9,0xd7,0x5b,0xfb,0xa7,0xb3,0x1a,0x6b,0xca,0x19,0x74,0x49,0x6e,0xeb,0x56,0xde,0x35,0x70,0x71,0x95,0x5d,0x83,0xc4,0xb1,0xba,0xda,0xa0,0xb2,0x18,0x32,0xe9,
+ 0x04,0x07,0x31,0x0f,0x90,0xa9,0xea,0xe1,0x49,0xa0,0x84,0x02,0xf5,0x41,0x94,0xa0,0xf7,0xb4,0xac,0x42,0x7b,0xf8,0xd9,0xbd,0x6c,0x76,0x81,0x07,0x1d,0xc4,0x7d,0xc3,0x62,0x26,0xa6,0xd3,0x7a,0xc4,0x6d,0x61,0xfd,0x60,0x0c,0x0b,0xf1,0xbf,0xf8,0x76,0x89,0xed,0x11,0x7d,0xda,0x6b,0x0e,0x59,0x31,0x8a,0xe0,0x10,0xa1,0x97,0xa2,0x6c,0xa0,
+ 0x04,0xbc,0x97,0xe7,0x58,0x5e,0xec,0xad,0x48,0xe1,0x66,0x83,0xbc,0x40,0x91,0x70,0x8e,0x1a,0x93,0x0c,0x68,0x3f,0xc4,0x70,0x01,0xd4,0xb3,0x83,0x59,0x4f,0x2c,0x4e,0x22,0x70,0x59,0x89,0xcf,0x69,0xda,0xea,0xdd,0x4e,0x4e,0x4b,0x81,0x51,0xed,0x88,0x8d,0xfe,0xc2,0x0f,0xb0,0x17,0x28,0xd8,0x9d,0x56,0xb3,0xf3,0x8f,0x2a,0xe9,0xc8,0xc5,
+ 0x04,0x44,0xad,0x33,0x9a,0xfb,0xc2,0x1e,0x9a,0xbf,0x7b,0x60,0x2a,0x5c,0xa5,0x35,0xea,0x37,0x81,0x35,0xb6,0xd1,0x0d,0x81,0x31,0x0b,0xdd,0x82,0x93,0xd1,0xdf,0x32,0x52,0xb6,0x3f,0xf7,0xd0,0x77,0x47,0x70,0xf8,0xfe,0x1d,0x17,0x22,0xfa,0x83,0xac,0xd0,0x2f,0x43,0x4e,0x4f,0xc1,0x10,0xa0,0xcc,0x8f,0x6d,0xdd,0xd3,0x7d,0x56,0xc4,0x63,
+ 0x04,0x12,0x60,0xc2,0x12,0x2c,0x9e,0x24,0x4e,0x1a,0xf5,0x15,0x1b,0xed,0xe0,0xc3,0xae,0x23,0xb5,0x4d,0x7c,0x59,0x68,0x81,0xd3,0xee,0xba,0xd2,0x1f,0x37,0xdd,0x87,0x8c,0x5c,0x9a,0x0c,0x1a,0x9a,0xde,0x76,0x73,0x7a,0x88,0x11,0xbd,0x6a,0x7f,0x92,0x87,0xc9,0x78,0xee,0x39,0x6a,0xa8,0x9c,0x11,0xe4,0x72,0x29,0xd2,0xcc,0xb5,0x52,0xf0,
+ 0x04,0x18,0x77,0x04,0x5b,0xe2,0x5d,0x34,0xa1,0xd0,0x60,0x0f,0x9d,0x5c,0x00,0xd0,0x64,0x5a,0x2a,0x54,0x37,0x9b,0x6c,0xee,0xfa,0xd2,0xe6,0xbf,0x5c,0x2a,0x33,0x52,0xce,0x82,0x1a,0x53,0x2c,0xc1,0x75,0x1e,0xe1,0xd3,0x6d,0x41,0xc3,0xd6,0xab,0x4e,0x9b,0x14,0x3e,0x44,0xec,0x46,0xd7,0x34,0x78,0xea,0x6a,0x79,0xa5,0xc0,0xe5,0x41,0x59,
+ 0x04,0x45,0x54,0x39,0xfc,0xc3,0xd2,0xde,0xec,0xed,0xde,0xae,0xce,0x60,0xe7,0xbd,0x17,0x30,0x4f,0x36,0xeb,0xb6,0x02,0xad,0xf5,0xa2,0x2e,0x0b,0x8f,0x1d,0xb4,0x6a,0x50,0xae,0xc3,0x8f,0xb2,0xba,0xf2,0x21,0xe9,0xa8,0xd1,0x88,0x7c,0x7b,0xf6,0x22,0x2d,0xd1,0x83,0x46,0x34,0xe7,0x72,0x63,0x31,0x5a,0xf6,0xd2,0x36,0x09,0xd0,0x4f,0x77,
+ 0x04,0x2e,0x1f,0x46,0x6b,0x02,0x4c,0x0c,0x3a,0xce,0x24,0x37,0xde,0x09,0x12,0x7f,0xed,0x04,0xb7,0x06,0xf9,0x4b,0x19,0xa2,0x1b,0xb1,0xc2,0xac,0xf3,0x5c,0xec,0xe7,0x18,0x04,0x49,0xae,0x35,0x23,0xd7,0x25,0x34,0xe9,0x64,0x97,0x2c,0xfd,0x3b,0x38,0xaf,0x0b,0xdd,0xd9,0x61,0x9e,0x5a,0xf2,0x23,0xe4,0xd1,0xa4,0x0f,0x34,0xcf,0x9f,0x1d,
+ 0x04,0x8e,0x7a,0xbd,0xbb,0xd1,0x8d,0xe7,0x45,0x23,0x74,0xc1,0x87,0x9a,0x1c,0x3b,0x01,0xd1,0x32,0x61,0xe7,0xd4,0x57,0x1c,0x3b,0x47,0xa1,0xc7,0x6c,0x55,0xa2,0x33,0x73,0x26,0xed,0x89,0x7c,0xd5,0x17,0xa4,0xf5,0x34,0x9d,0xb8,0x09,0x78,0x0f,0x6d,0x2f,0x2b,0x9f,0x62,0x99,0xd8,0xb5,0xa8,0x90,0x77,0xf1,0x11,0x9a,0x71,0x8f,0xd7,0xb3,
+ 0x04,0x7b,0x33,0x3d,0x43,0x40,0xd3,0xd7,0x18,0xdd,0x3e,0x6a,0xff,0x7d,0xe7,0xbb,0xf8,0xb7,0x2b,0xfd,0x61,0x6c,0x84,0x20,0x05,0x60,0x52,0x84,0x23,0x76,0xb9,0xaf,0x19,0x42,0x11,0x7c,0x5a,0xfe,0xac,0x75,0x5d,0x6f,0x37,0x6f,0xc6,0x32,0x9a,0x7d,0x76,0x05,0x1b,0x87,0x12,0x3a,0x4a,0x5d,0x0b,0xc4,0xa5,0x39,0x38,0x0f,0x03,0xde,0x7b,
+ 0x04,0xd3,0x0c,0xa4,0xa0,0xdd,0xb6,0x61,0x6c,0x85,0x1d,0x30,0xce,0xd6,0x82,0xc4,0x0f,0x83,0xc6,0x27,0x58,0xa1,0xf2,0x75,0x99,0x88,0xd6,0x76,0x3a,0x88,0xf1,0xc0,0xe5,0x03,0xa8,0x0d,0x54,0x15,0x65,0x0d,0x41,0x23,0x97,0x84,0xe8,0xe2,0xfb,0x12,0x35,0xe9,0xfe,0x99,0x1d,0x11,0x2e,0xbb,0x81,0x18,0x6c,0xbf,0x0d,0xa2,0xde,0x3a,0xff,
+ 0x04,0x48,0x96,0x9b,0x39,0x99,0x12,0x97,0xb3,0x32,0xa6,0x52,0xd3,0xee,0x6e,0x01,0xe9,0x09,0xb3,0x99,0x04,0xe7,0x1f,0xa2,0x35,0x4a,0x78,0x30,0xc7,0x75,0x0b,0xaf,0x24,0xb4,0x01,0x2d,0x1b,0x83,0x0d,0x19,0x9c,0xcb,0x1f,0xc9,0x72,0xb3,0x2b,0xfd,0xed,0x55,0xf0,0x9c,0xd6,0x2d,0x25,0x7e,0x5e,0x84,0x4e,0x27,0xe5,0x7a,0x15,0x94,0xec,
+ 0x04,0x02,0xef,0x4d,0x6d,0x6c,0xfd,0x5a,0x94,0xf1,0xd7,0x78,0x42,0x26,0xe3,0xe2,0xa6,0xc0,0xa4,0x36,0xc5,0x58,0x39,0x61,0x9f,0x38,0xfb,0x44,0x72,0xb5,0xf9,0xee,0x77,0x7e,0xb4,0xac,0xd4,0xee,0xbd,0xa5,0xcd,0x72,0x87,0x5f,0xfd,0x2a,0x2f,0x26,0x22,0x9c,0x2d,0xc6,0xb4,0x65,0x00,0x91,0x9a,0x43,0x2c,0x86,0x73,0x9f,0x3a,0xe8,0x66,
+ 0x04,0x46,0x4f,0x4f,0xf7,0x15,0x72,0x9c,0xae,0x50,0x72,0xca,0x3b,0xd8,0x01,0xd3,0x19,0x5b,0x67,0xae,0xc6,0x5e,0x9b,0x01,0xaa,0xd2,0x0a,0x29,0x43,0xdc,0xbc,0xb5,0x84,0xb1,0xaf,0xd2,0x9d,0x31,0xa3,0x9a,0x11,0xd5,0x70,0xaa,0x15,0x97,0x43,0x9b,0x3b,0x2d,0x19,0x71,0xbf,0x2f,0x1a,0xbf,0x15,0x43,0x2d,0x02,0x07,0xb1,0x0d,0x1d,0x08,
+ 0x04,0x15,0x7f,0x8f,0xdd,0xf3,0x73,0xeb,0x5f,0x49,0xcf,0xcf,0x10,0xd8,0xb8,0x53,0xcf,0x91,0xcb,0xcd,0x7d,0x66,0x5c,0x35,0x22,0xba,0x7d,0xd7,0x38,0xdd,0xb7,0x9a,0x4c,0xde,0xad,0xf1,0xa5,0xc4,0x48,0xea,0x3c,0x9f,0x41,0x91,0xa8,0x99,0x9a,0xbf,0xcc,0x75,0x7a,0xc6,0xd6,0x45,0x67,0xef,0x07,0x2c,0x47,0xfe,0xc6,0x13,0x44,0x3b,0x8f,
+ 0x04,0x09,0x34,0xa5,0x37,0x46,0x6c,0x07,0x43,0x0e,0x2c,0x48,0xfe,0xb9,0x90,0xbb,0x19,0xfb,0x78,0xce,0xcc,0x9c,0xee,0x42,0x4e,0xa4,0xd1,0x30,0x29,0x1a,0xa2,0x37,0xf0,0xd4,0xf9,0x2d,0x23,0xb4,0x62,0x80,0x4b,0x5b,0x68,0xc5,0x25,0x58,0xc0,0x1c,0x99,0x96,0xdb,0xf7,0x27,0xfc,0xca,0xbb,0xee,0xdb,0x96,0x21,0xa4,0x00,0x53,0x5a,0xfa,
+ 0x04,0xd6,0xef,0x20,0xbe,0x66,0xc8,0x93,0xf7,0x41,0xa9,0xbf,0x90,0xd9,0xb7,0x46,0x75,0xd1,0xc2,0xa3,0x12,0x96,0x39,0x7a,0xcb,0x3e,0xf1,0x74,0xfd,0x0b,0x30,0x0c,0x65,0x4a,0x0c,0x95,0x47,0x8c,0xa0,0x03,0x99,0x16,0x2d,0x7f,0x0f,0x2d,0xc8,0x9e,0xfd,0xc2,0xb2,0x8a,0x30,0xfb,0xab,0xe2,0x85,0x85,0x72,0x95,0xa4,0xb0,0xc4,0xe2,0x65,
+ 0x04,0xb7,0x29,0x1d,0x14,0x04,0xe0,0xc0,0xc0,0x7d,0xab,0x93,0x72,0x18,0x9f,0x4b,0xd5,0x8d,0x2c,0xea,0xa8,0xd1,0x5e,0xde,0x54,0x4d,0x95,0x14,0x54,0x5b,0xa9,0xee,0x06,0x29,0xc9,0xa6,0x3d,0x5e,0x30,0x87,0x69,0xcc,0x30,0xec,0x27,0x6a,0x41,0x0e,0x64,0x64,0xa2,0x7e,0xea,0xfd,0x9e,0x59,0x9d,0xb1,0x0f,0x05,0x3a,0x4f,0xe4,0xa8,0x29,
+ 0x04,0x6e,0x28,0x30,0x33,0x05,0xd6,0x42,0xcc,0xb9,0x23,0xb7,0x22,0xea,0x86,0xb2,0xa0,0xbc,0x8e,0x37,0x35,0xec,0xb2,0x6e,0x84,0x9b,0x19,0xc9,0xf7,0x6b,0x2f,0xdb,0xb8,0x18,0x6e,0x80,0xd6,0x4d,0x8c,0xab,0x16,0x4f,0x52,0x38,0xf5,0x31,0x84,0x61,0xbf,0x89,0xd4,0xd9,0x6e,0xe6,0x54,0x4c,0x81,0x6c,0x75,0x66,0x94,0x77,0x74,0xe0,0xf6,
+ 0x04,0x37,0x5b,0xda,0x93,0xf6,0xaf,0x92,0xfb,0x5f,0x8f,0x4b,0x1b,0x5f,0x05,0x34,0xe3,0xba,0xfa,0xb3,0x4c,0xb7,0xad,0x9f,0xb9,0xd0,0xb7,0x22,0xe4,0xa5,0xc3,0x02,0xa9,0xa0,0x0b,0x9f,0x38,0x7a,0x5a,0x39,0x60,0x97,0xaa,0x21,0x62,0xfc,0x5b,0xbc,0xf4,0xa5,0x26,0x33,0x72,0xf6,0x81,0xc9,0x4d,0xa5,0x1e,0x97,0x99,0x12,0x09,0x90,0xfd,
+ 0x04,0xd7,0x5b,0x68,0x21,0x6b,0xab,0xe0,0x3a,0xe2,0x57,0xe9,0x4b,0x4e,0x3b,0xf1,0xc5,0x2f,0x44,0xe3,0xdf,0x26,0x6d,0x15,0x24,0xff,0x8c,0x5e,0xa6,0x9d,0xa7,0x31,0x97,0xda,0x4b,0xff,0x9e,0xd1,0xc5,0x3f,0x44,0x91,0x7a,0x67,0xd7,0xb9,0x78,0x59,0x8e,0x89,0xdf,0x35,0x9e,0x3d,0x59,0x13,0xea,0xea,0x24,0xf3,0xae,0x25,0x9a,0xbc,0x44,
+ 0x04,0x78,0xbc,0xda,0x14,0x0a,0xed,0x23,0xd4,0x30,0xcb,0x23,0xc3,0xdc,0x0d,0x01,0xf4,0x23,0xdb,0x13,0x4e,0xe9,0x4a,0x3a,0x8c,0xb4,0x83,0xf2,0xde,0xac,0x2a,0xc6,0x53,0x11,0x81,0x14,0xf6,0xf3,0x30,0x45,0xd4,0xe9,0xed,0x91,0x07,0x08,0x50,0x07,0xbf,0xbd,0xdf,0x8f,0x58,0xfe,0x7a,0x1a,0x24,0x45,0xd6,0x6a,0x99,0x00,0x45,0x47,0x6e,
+ 0x04,0xbb,0x79,0xf6,0x18,0x57,0xf7,0x43,0xbf,0xa1,0xb6,0xe7,0x11,0x1c,0xe4,0x09,0x43,0x77,0x25,0x69,0x69,0xe4,0xe1,0x51,0x59,0x12,0x3d,0x95,0x48,0xac,0xc3,0xbe,0x6c,0x1f,0x9d,0x9f,0x88,0x60,0xdc,0xff,0xd3,0xeb,0x36,0xdd,0x6c,0x31,0xff,0x2e,0x72,0x26,0xc2,0x00,0x9c,0x4c,0x94,0xd8,0xd7,0xd2,0xb5,0x68,0x6b,0xf7,0xab,0xd6,0x77,
+ 0x04,0x93,0x59,0x18,0x27,0xd9,0xe6,0x71,0x3b,0x4e,0x9f,0xae,0xa6,0x2c,0x72,0xb2,0x8d,0xfe,0xfa,0x68,0xe0,0xc0,0x51,0x60,0xb5,0xd6,0xaa,0xe8,0x8f,0xd2,0xe3,0x6c,0x36,0x07,0x3f,0x55,0x45,0xad,0x5a,0xf4,0x10,0xaf,0x26,0xaf,0xff,0x68,0x65,0x4c,0xf7,0x2d,0x45,0xe4,0x93,0x48,0x93,0x11,0x20,0x32,0x47,0x34,0x7a,0x89,0x0f,0x45,0x18,
+ 0x04,0x31,0xed,0x30,0x81,0xae,0xfe,0x00,0x1e,0xb6,0x40,0x20,0x69,0xee,0x2c,0xcc,0x18,0x62,0x93,0x7b,0x85,0x99,0x51,0x44,0xdb,0xa9,0x50,0x39,0x43,0x58,0x7b,0xf0,0xda,0xda,0x01,0xb8,0xcc,0x4d,0xf3,0x4f,0x5a,0xb3,0xb1,0xa3,0x59,0x61,0x52,0x08,0x94,0x6e,0x5e,0xe3,0x5f,0x98,0xee,0x77,0x5b,0x8c,0xce,0xcd,0x86,0xcc,0xc1,0x65,0x0f,
+ 0x04,0x7d,0xff,0x66,0xfa,0x98,0x50,0x9f,0xf3,0xe2,0xe5,0x10,0x45,0xf4,0x39,0x05,0x23,0xdc,0xcd,0xa4,0x3a,0x3b,0xc2,0x88,0x5e,0x58,0xc2,0x48,0x09,0x09,0x90,0xee,0xa8,0x54,0xc7,0x6c,0x2b,0x9a,0xde,0xb6,0xbb,0x57,0x18,0x23,0xe0,0x7f,0xd7,0xc6,0x5c,0x86,0x39,0xcf,0x9d,0x90,0x52,0x60,0x06,0x4c,0x8e,0x76,0x75,0xce,0x6d,0x98,0xb4,
+ 0x04,0x42,0x80,0x50,0x9a,0xab,0x64,0xed,0xfc,0x0b,0x4a,0x29,0x67,0xe4,0xcb,0xce,0x84,0x9c,0xb5,0x44,0xe4,0xa7,0x73,0x13,0xc8,0xe6,0xec,0xe5,0x79,0xfb,0xd7,0x42,0x0a,0x2e,0x89,0xfe,0x5c,0xc1,0x92,0x7d,0x55,0x4e,0x6a,0x3b,0xb1,0x40,0x33,0xea,0x7c,0x92,0x2c,0xd7,0x5c,0xba,0x2c,0x74,0x15,0xfd,0xab,0x52,0xf2,0x0b,0x18,0x60,0xf1,
+ 0x04,0x4f,0x8d,0xf1,0x45,0x19,0x4e,0x3c,0x4f,0xc3,0xee,0xa2,0x6d,0x43,0xce,0x75,0xb4,0x02,0xd6,0xb1,0x74,0x72,0xdd,0xcb,0xb2,0x54,0xb8,0xa7,0x9b,0x0b,0xf3,0xd9,0xcb,0x2a,0xa2,0x0d,0x82,0x84,0x4c,0xb2,0x66,0x34,0x4e,0x71,0xca,0x78,0xf2,0xad,0x27,0xa7,0x5a,0x09,0xe5,0xbc,0x0f,0xa5,0x7e,0x4e,0xfd,0x9d,0x46,0x5a,0x08,0x88,0xdb,
+ 0x04,0x95,0x98,0xa5,0x7d,0xd6,0x7e,0xc3,0xe1,0x6b,0x58,0x7a,0x33,0x8a,0xa3,0xa1,0x0a,0x3a,0x39,0x13,0xb4,0x1a,0x3a,0xf3,0x2e,0x3e,0xd3,0xff,0x01,0x35,0x8c,0x6b,0x14,0x12,0x28,0x19,0xed,0xf8,0x07,0x4b,0xbc,0x52,0x1f,0x7d,0x4c,0xdc,0xe8,0x2f,0xef,0x7a,0x51,0x67,0x06,0xaf,0xfb,0xa1,0xd9,0x3d,0x9d,0xea,0x9c,0xca,0xe1,0xa2,0x07,
+ 0x04,0x91,0x71,0xfe,0xc3,0xca,0x20,0x80,0x6b,0xc0,0x84,0xf1,0x2f,0x07,0x60,0x91,0x1b,0x60,0x99,0x0b,0xd8,0x0e,0x5b,0x2a,0x71,0xca,0x03,0xa0,0x48,0xb2,0x0f,0x83,0x7e,0x63,0x4f,0xd1,0x78,0x63,0x76,0x1b,0x29,0x58,0xd2,0xbe,0x4e,0x14,0x9f,0x8d,0x3d,0x7a,0xbb,0xdc,0x18,0xbe,0x03,0xf4,0x51,0xab,0x6c,0x17,0xfa,0x0a,0x1f,0x83,0x30,
+ 0x04,0x77,0x7c,0x89,0x30,0xb6,0xe1,0xd2,0x71,0x10,0x0f,0xe6,0x8c,0xe9,0x3f,0x16,0x3f,0xa3,0x76,0x12,0xc5,0xff,0xf6,0x7f,0x4a,0x62,0xfc,0x3b,0xaf,0xaf,0x3d,0x17,0xa9,0xed,0x73,0xd8,0x6f,0x60,0xa5,0x1b,0x5e,0xd9,0x13,0x53,0xa3,0xb0,0x54,0xed,0xc0,0xaa,0x92,0xc9,0xeb,0xcb,0xd0,0xb7,0x5d,0x18,0x8f,0xdc,0x88,0x27,0x91,0xd6,0x8d,
+ 0x04,0xea,0xbc,0x24,0x8f,0x62,0x6e,0x0a,0x63,0xe1,0xeb,0x81,0xc4,0x3d,0x46,0x1a,0x39,0xa1,0xdb,0xa8,0x81,0xeb,0x6e,0xe2,0x15,0x2b,0x07,0xc3,0x2d,0x71,0xbc,0xf4,0x70,0x06,0x03,0xca,0xa8,0xb9,0xd3,0x3d,0xb1,0x3a,0xf4,0x4c,0x6e,0xfb,0xec,0x8a,0x19,0x8e,0xd6,0x12,0x4a,0xc9,0xeb,0x17,0xea,0xaf,0xd2,0x82,0x4a,0x54,0x5e,0xc0,0x00,
+ 0x04,0x9f,0x7a,0x13,0xad,0xa1,0x58,0xa5,0x5f,0x9d,0xdf,0x1a,0x45,0xf0,0x44,0xf0,0x73,0xd9,0xb8,0x00,0x30,0xef,0xdc,0xfc,0x9f,0x9f,0x58,0x41,0x8f,0xbc,0xea,0xf0,0x01,0xf8,0xad,0xa0,0x17,0x50,0x90,0xf8,0x0d,0x47,0x22,0x7d,0x67,0x13,0xb6,0x74,0x0f,0x9a,0x00,0x91,0xd8,0x8a,0x83,0x7d,0x0a,0x1c,0xd7,0x7b,0x58,0xa8,0xf2,0x8d,0x73,
+ 0x04,0x11,0xc4,0xf3,0xe4,0x61,0xcd,0x01,0x9b,0x5c,0x06,0xea,0x0c,0xea,0x4c,0x40,0x90,0xc3,0xcc,0x3e,0x3c,0x5d,0x9f,0x3c,0x6d,0x65,0xb4,0x36,0x82,0x6d,0xa9,0xb4,0xdb,0xbb,0xeb,0x7a,0x77,0xe4,0xcb,0xfd,0xa2,0x07,0x09,0x7c,0x43,0x42,0x37,0x05,0xf7,0x2c,0x80,0x47,0x6d,0xa3,0xda,0xc4,0x0a,0x48,0x3b,0x0a,0xb0,0xf2,0xea,0xd1,0xcb,
+ 0x04,0xe2,0xe1,0x86,0x82,0xd5,0x31,0x23,0xaa,0x01,0xa6,0xc5,0xd0,0x0b,0x0c,0x62,0x3d,0x67,0x1b,0x46,0x2e,0xa8,0x0b,0xdd,0xd6,0x52,0x27,0xfd,0x51,0x05,0x98,0x8a,0xa4,0x16,0x19,0x07,0xb3,0xfd,0x25,0x04,0x4a,0x94,0x9e,0xa4,0x1c,0x8e,0x2e,0xa8,0x45,0x9d,0xc6,0xf1,0x65,0x48,0x56,0xb8,0xb6,0x1b,0x31,0x54,0x3b,0xb1,0xb4,0x5b,0xdb,
+ 0x04,0x90,0xf8,0xd4,0xca,0x73,0xde,0x08,0xa6,0x56,0x4a,0xaf,0x00,0x52,0x47,0xb6,0xf0,0xff,0xe9,0x78,0x50,0x4d,0xce,0x52,0x60,0x5f,0x46,0xb7,0xc3,0xe5,0x61,0x97,0xda,0xfa,0xdb,0xe5,0x28,0xeb,0x70,0xd9,0xee,0x7e,0xa0,0xe7,0x07,0x02,0xdb,0x54,0xf7,0x21,0x51,0x4c,0x7b,0x86,0x04,0xac,0x2c,0xb2,0x14,0xf1,0xde,0xcb,0x7e,0x38,0x3d,
+ 0x04,0x82,0x4c,0x19,0x5c,0x73,0xcf,0xfd,0xf0,0x38,0xd1,0x01,0xbc,0xe1,0x68,0x7b,0x5c,0x3b,0x61,0x46,0xf3,0x95,0xc8,0x85,0x97,0x6f,0x77,0x53,0xb2,0x37,0x6b,0x94,0x8e,0x3c,0xde,0xfa,0x6f,0xc3,0x47,0xd1,0x3e,0x4d,0xcb,0xc6,0x3a,0x0b,0x03,0xa1,0x65,0x18,0x0c,0xd2,0xbe,0x14,0x31,0xa0,0xcf,0x74,0xce,0x1e,0xa2,0x50,0x82,0xd2,0xbc,
+ 0x04,0x27,0x88,0xa5,0x2f,0x07,0x8e,0xb3,0xf2,0x02,0xc4,0xfa,0x73,0xe0,0xd3,0x38,0x6f,0xaf,0x3d,0xf6,0xbe,0x85,0x60,0x03,0x63,0x6f,0x59,0x99,0x22,0xd4,0xf5,0x26,0x8f,0x30,0xb4,0xf2,0x07,0xc9,0x19,0xbb,0xdf,0x5e,0x67,0xa8,0xbe,0x42,0x65,0xa8,0x17,0x47,0x54,0xb3,0xab,0xa8,0xf1,0x6e,0x57,0x5b,0x77,0xff,0x4d,0x5a,0x7e,0xb6,0x4f,
+ 0x04,0xd5,0x33,0xb7,0x89,0xa4,0xaf,0x89,0x0f,0xa7,0xa8,0x2a,0x1f,0xae,0x58,0xc4,0x04,0xf9,0xa6,0x2a,0x50,0xb4,0x9a,0xda,0xfa,0xb3,0x49,0xc5,0x13,0xb4,0x15,0x08,0x74,0x01,0xb4,0x17,0x1b,0x80,0x3e,0x76,0xb3,0x4a,0x98,0x61,0xe1,0x0f,0x7b,0xc2,0x89,0xa0,0x66,0xfd,0x01,0xbd,0x29,0xf8,0x4c,0x98,0x7a,0x10,0xa5,0xfb,0x18,0xc2,0xd4,
+ 0x04,0x3a,0x31,0x50,0x79,0x8c,0x8a,0xf6,0x9d,0x1e,0x6e,0x98,0x1f,0x3a,0x45,0x40,0x2b,0xa1,0xd7,0x32,0xf4,0xbe,0x83,0x30,0xc5,0x16,0x4f,0x49,0xe1,0x0e,0xc5,0x55,0xb4,0x22,0x1b,0xd8,0x42,0xbc,0x5e,0x4d,0x97,0xef,0xf3,0x71,0x65,0xf6,0x0e,0x39,0x98,0xa4,0x24,0xd7,0x2a,0x45,0x0c,0xf9,0x5e,0xa4,0x77,0xc7,0x82,0x87,0xd0,0x34,0x3a,
+ 0x04,0x3b,0x37,0xdf,0x5f,0xb3,0x47,0xc6,0x9a,0x0f,0x17,0xd8,0x5c,0x0c,0x7c,0xa8,0x37,0x36,0x88,0x3a,0x82,0x5e,0x13,0x14,0x3d,0x0f,0xcf,0xc8,0x10,0x1e,0x85,0x1e,0x80,0x0d,0xe3,0xc0,0x90,0xb6,0xca,0x21,0xba,0x54,0x35,0x17,0x33,0x0c,0x04,0xb1,0x2f,0x94,0x8c,0x6b,0xad,0xf1,0x4a,0x63,0xab,0xff,0xdf,0x4e,0xf8,0xc7,0x53,0x70,0x26,
+ 0x04,0xfe,0xb5,0x16,0x3b,0x0e,0xce,0x30,0xff,0x3e,0x03,0xc7,0xd5,0x5c,0x43,0x80,0xfa,0x2f,0xa8,0x1e,0xe2,0xc0,0x35,0x49,0x42,0xff,0x6f,0x08,0xc9,0x9d,0x0c,0xd8,0x2c,0xe8,0x7d,0xe0,0x5e,0xe1,0xbd,0xa0,0x89,0xd3,0xe4,0xe2,0x48,0xfa,0x0f,0x72,0x11,0x02,0xac,0xff,0xfd,0xf5,0x0e,0x65,0x4b,0xe2,0x81,0x43,0x39,0x99,0xdf,0x89,0x7e,
+ 0x04,0x23,0x8c,0xed,0x00,0x1c,0xf2,0x2b,0x88,0x53,0xe0,0x2e,0xdc,0x89,0xcb,0xec,0xa5,0x05,0x0b,0xa7,0xe0,0x42,0xa7,0xa7,0x7f,0x93,0x82,0xcd,0x41,0x49,0x22,0x89,0x76,0x40,0x68,0x3d,0x30,0x94,0x64,0x38,0x40,0xf2,0x95,0x89,0x0a,0xa4,0xc1,0x8a,0xa3,0x9b,0x41,0xd7,0x7d,0xd0,0xfb,0x3b,0xb2,0x70,0x0e,0x4f,0x9e,0xc2,0x84,0xff,0xc2,
+ 0x04,0x96,0x1c,0xf6,0x48,0x17,0xc0,0x6c,0x0e,0x51,0xb3,0xc2,0x73,0x6c,0x92,0x2f,0xde,0x18,0xbd,0x8c,0x49,0x06,0xfc,0xd7,0xf5,0xef,0x66,0xc4,0x67,0x85,0x08,0xf3,0x5e,0xd2,0xc5,0xd1,0x81,0x68,0xcf,0xbe,0x70,0xf2,0xf1,0x23,0xbd,0x74,0x19,0x23,0x2b,0xb9,0x2d,0xd6,0x91,0x13,0xe2,0x94,0x10,0x61,0x88,0x94,0x81,0xc5,0xa0,0x27,0xbf,
+ 0x04,0x13,0x68,0x1e,0xae,0x16,0x8c,0xd4,0xea,0x7c,0xf2,0xe2,0xa4,0x5d,0x05,0x27,0x42,0xd1,0x0a,0x9f,0x64,0xe7,0x96,0x86,0x7d,0xbd,0xcb,0x82,0x9f,0xe0,0xb1,0x02,0x88,0x16,0x52,0x87,0x60,0xd1,0x77,0x37,0x6c,0x09,0xdf,0x79,0xde,0x39,0x55,0x7c,0x32,0x9c,0xc1,0x75,0x35,0x17,0xac,0xff,0xe8,0xfa,0x2e,0xc2,0x98,0x02,0x6b,0x83,0x84,
+ 0x04,0x5a,0xa7,0xab,0xfd,0xb6,0xb4,0x08,0x6d,0x54,0x33,0x25,0xe5,0xd7,0x9c,0x6e,0x95,0xce,0x42,0xf8,0x66,0xd2,0xbb,0x84,0x90,0x96,0x33,0xa0,0x4b,0xb1,0xaa,0x31,0xc2,0x91,0xc8,0x00,0x88,0x79,0x49,0x05,0xe1,0xda,0x33,0x33,0x6d,0x87,0x4e,0x2f,0x91,0xcc,0xf4,0x5c,0xc5,0x91,0x85,0xbe,0xde,0x5d,0xd6,0xf3,0xf7,0xac,0xaa,0xe1,0x8b,
+ 0x04,0x00,0x27,0x77,0x91,0xb3,0x05,0xa4,0x5b,0x2b,0x39,0x59,0x0b,0x2f,0x05,0xd3,0x39,0x2a,0x6c,0x81,0x82,0xce,0xf4,0xeb,0x54,0x01,0x20,0xe0,0xf5,0xc2,0x06,0xc3,0xe4,0x64,0x10,0x82,0x33,0xfb,0x0b,0x8c,0x3a,0xc8,0x92,0xd7,0x9e,0xf8,0xe0,0xfb,0xf9,0x2e,0xd1,0x33,0xad,0xdb,0x45,0x54,0x27,0x01,0x32,0x58,0x4d,0xc5,0x2e,0xef,0x41,
+ 0x04,0x6e,0xfa,0x09,0x2b,0x68,0xde,0x94,0x60,0xf0,0xbc,0xc9,0x19,0x00,0x5a,0x5f,0x6e,0x80,0xe1,0x9d,0xe9,0x89,0x68,0xbe,0x3c,0xd2,0xc7,0x70,0xa9,0x94,0x9b,0xfb,0x1a,0xc7,0x5e,0x6e,0x50,0x87,0xd6,0x55,0x0d,0x5f,0x9b,0xeb,0x1e,0x79,0xe5,0x02,0x93,0x07,0xbc,0x25,0x52,0x35,0xe2,0xd5,0xdc,0x99,0x24,0x1a,0xc3,0xab,0x88,0x6c,0x49,
+ 0x04,0x72,0xd4,0xa1,0x9c,0x4f,0x9d,0x2c,0xf5,0x84,0x8e,0xa4,0x04,0x45,0xb7,0x0d,0x46,0x96,0xb5,0xf0,0x2d,0x63,0x2c,0x0c,0x65,0x4c,0xc7,0xd7,0xee,0xb0,0xc6,0xd0,0x58,0xe8,0xc4,0xcd,0x99,0x43,0xe4,0x59,0x17,0x4c,0x7a,0xc0,0x1f,0xa7,0x42,0x19,0x8e,0x47,0xe6,0xc1,0x9a,0x6b,0xdb,0x0c,0x4f,0x6c,0x23,0x78,0x31,0xc1,0xb3,0xf9,0x42,
+ 0x04,0x2a,0x8e,0xa2,0xf5,0x0d,0xcc,0xed,0x0c,0x21,0x75,0x75,0xbd,0xfa,0x7c,0xd4,0x7d,0x1c,0x6f,0x10,0x00,0x41,0xec,0x0e,0x35,0x51,0x27,0x94,0xc1,0xbe,0x7e,0x74,0x02,0x58,0xf8,0xc1,0x71,0x22,0xed,0x30,0x3f,0xda,0x71,0x43,0xeb,0x58,0xbe,0xde,0x70,0x29,0x5b,0x65,0x32,0x66,0x01,0x3b,0x0b,0x0e,0xbd,0x3f,0x05,0x31,0x37,0xf6,0xec,
+ 0x04,0x88,0xde,0x68,0x9c,0xe9,0xaf,0x1e,0x94,0xbe,0x6a,0x20,0x89,0xc8,0xa8,0xb1,0x25,0x3f,0xfd,0xbb,0x6c,0x8e,0x9c,0x86,0x24,0x9b,0xa2,0x20,0x00,0x1a,0x4a,0xd3,0xb8,0x0c,0x49,0x98,0xe5,0x48,0x42,0xf4,0x13,0xb9,0xed,0xb1,0x82,0x5a,0xcb,0xb6,0x33,0x5e,0x81,0xe4,0xd1,0x84,0xb2,0xb0,0x1c,0x8b,0xeb,0xdc,0x85,0xd1,0xf2,0x89,0x46,
+ 0x04,0xfe,0xa2,0xd3,0x1f,0x70,0xf9,0x0d,0x5f,0xb3,0xe0,0x0e,0x18,0x6a,0xc4,0x2a,0xb3,0xc1,0x61,0x5c,0xee,0x71,0x4e,0x0b,0x4e,0x11,0x31,0xb3,0xd4,0xd8,0x22,0x5b,0xf7,0xb0,0x37,0xa1,0x8d,0xf2,0xac,0x15,0x34,0x3f,0x30,0xf7,0x40,0x67,0xdd,0xf2,0x9e,0x81,0x7d,0x5f,0x77,0xf8,0xdc,0xe0,0x57,0x14,0xda,0x59,0xc0,0x94,0xf0,0xcd,0xa9,
+ 0x04,0x72,0x58,0x91,0x1e,0x3d,0x42,0x33,0x49,0x16,0x64,0x79,0xdb,0xe0,0xb8,0x34,0x1a,0xf7,0xfb,0xd0,0x3d,0x0a,0x7e,0x10,0xed,0xcc,0xb3,0x6b,0x6c,0xee,0xa5,0xa3,0xdb,0x17,0xac,0x2b,0x89,0x92,0x79,0x11,0x28,0xfa,0x3b,0x96,0xdc,0x2f,0xbd,0x4c,0xa3,0xbf,0xa7,0x82,0xef,0x28,0x32,0xfc,0x66,0x56,0x94,0x3d,0xb1,0x8e,0x73,0x46,0xb0,
+ 0x04,0x4f,0x28,0x46,0x1d,0xea,0x64,0x47,0x4d,0x6b,0xb3,0x4d,0x14,0x99,0xc9,0x7d,0x37,0xb9,0xe9,0x56,0x33,0xdf,0x1c,0xee,0xea,0xac,0xd4,0x50,0x16,0xc9,0x8b,0x39,0x14,0xc8,0x81,0x88,0x10,0xb8,0xcc,0x06,0xdd,0xb4,0x0e,0x8a,0x12,0x61,0xc5,0x28,0xfa,0xa5,0x89,0x45,0x5d,0x5a,0x6d,0xf9,0x3b,0x77,0xbc,0x5e,0x0e,0x49,0x3c,0x74,0x70,
+ 0x04,0x74,0xf2,0xa8,0x14,0xfb,0x5d,0x8e,0xca,0x91,0xa6,0x9b,0x5e,0x60,0x71,0x27,0x32,0xb3,0x93,0x7d,0xe3,0x28,0x29,0xbe,0x97,0x4e,0xd7,0xb6,0x8c,0x5c,0x2f,0x5d,0x66,0xef,0xf0,0xf0,0x7c,0x56,0xf9,0x87,0xa6,0x57,0xf4,0x21,0x96,0x20,0x5f,0x58,0x8c,0x0f,0x1d,0x96,0xfd,0x8a,0x63,0xa5,0xf2,0x38,0xb4,0x8f,0x47,0x87,0x88,0xfe,0x3b,
+ 0x04,0x19,0x5b,0x51,0xa7,0xcc,0x4a,0x21,0xb8,0x27,0x4a,0x70,0xa9,0x0d,0xe7,0x79,0x81,0x4c,0x3c,0x8c,0xa3,0x58,0x32,0x82,0x08,0xc0,0x9a,0x29,0xf3,0x36,0xb8,0x2d,0x6a,0xb2,0x41,0x6b,0x7c,0x92,0xff,0xfd,0xc2,0x9c,0x3b,0x12,0x82,0xdd,0x2a,0x77,0xa4,0xd0,0x4d,0xf7,0xf7,0x45,0x20,0x47,0x39,0x3d,0x84,0x99,0x89,0xc5,0xce,0xe9,0xad,
+ 0x04,0x62,0x2f,0xc7,0x47,0x32,0x03,0x4b,0xec,0x2d,0xdf,0x3b,0xc1,0x6d,0x34,0xb3,0xd1,0xf7,0xa3,0x27,0xdd,0x2a,0x8c,0x19,0xba,0xb4,0xbb,0x4f,0xe3,0xa2,0x4b,0x58,0xaa,0x73,0x6b,0x2f,0x2f,0xae,0x76,0xf4,0xdf,0xae,0xcc,0x90,0x96,0x33,0x3b,0x01,0x32,0x8d,0x51,0xeb,0x3f,0xda,0x9c,0x92,0x27,0xe9,0x0d,0x0b,0x44,0x99,0x83,0xc4,0xf0,
+ 0x04,0x1f,0x7f,0x85,0xca,0xf2,0xd7,0x55,0x0e,0x7a,0xf9,0xb6,0x50,0x23,0xeb,0xb4,0xdc,0xe3,0x45,0x03,0x11,0x69,0x23,0x09,0xdb,0x26,0x99,0x69,0xb8,0x34,0xb6,0x11,0xc7,0x08,0x27,0xf4,0x5b,0x78,0x02,0x0e,0xcb,0xba,0xf4,0x84,0xfd,0xd5,0xbf,0xaa,0xe6,0x87,0x0f,0x11,0x84,0xc2,0x15,0x81,0xba,0xf6,0xef,0x82,0xbd,0x7b,0x53,0x0f,0x93,
+ 0x04,0x49,0xc1,0x97,0xdc,0x80,0xad,0x1d,0xa4,0x7a,0x43,0x42,0xb9,0x38,0x93,0xe8,0xe1,0xfb,0x0b,0xb9,0x4f,0xc3,0x3a,0x83,0xe7,0x83,0xc0,0x0b,0x24,0xc7,0x81,0x37,0x7a,0xef,0xc2,0x0d,0xa9,0x2b,0xac,0x76,0x29,0x51,0xf7,0x24,0x74,0xbe,0xcc,0x73,0x4d,0x4c,0xc2,0x2b,0xa8,0x1b,0x89,0x5e,0x28,0x2f,0xda,0xc4,0xdf,0x7a,0xf0,0xf3,0x7d,
+ 0x04,0xd8,0xcb,0x68,0x51,0x7b,0x61,0x6a,0x56,0x40,0x0a,0xa3,0x86,0x86,0x35,0xe5,0x4b,0x6f,0x69,0x95,0x98,0xa2,0xf6,0x16,0x77,0x57,0x65,0x49,0x80,0xba,0xf6,0xac,0xbe,0x7e,0xc8,0xcf,0x44,0x9c,0x84,0x9a,0xa0,0x34,0x61,0xa3,0x0e,0xfa,0xda,0x41,0x45,0x3c,0x57,0xc6,0xe6,0xfb,0xc9,0x3b,0xbc,0x6f,0xa4,0x9a,0xda,0x6d,0xc0,0x55,0x5c,
+ 0x04,0x03,0x07,0x13,0xfb,0x63,0xf2,0xaa,0x6f,0xe2,0xca,0xdf,0x1b,0x20,0xef,0xc2,0x59,0xc7,0x74,0x45,0xda,0xfa,0x87,0xda,0xc3,0x98,0xb8,0x40,0x65,0xca,0x34,0x7d,0xf3,0xb2,0x27,0x81,0x8d,0xe1,0xa3,0x9b,0x58,0x9c,0xb0,0x71,0xd8,0x3e,0x53,0x17,0xcc,0xcd,0xc2,0x33,0x8e,0x51,0xe3,0x12,0xfe,0x31,0xd8,0xdc,0x34,0xa4,0x80,0x17,0x50,
+ 0x04,0xba,0xbb,0x36,0x77,0xb0,0x95,0x58,0x02,0xd8,0xe9,0x29,0xa4,0x13,0x55,0x64,0x0e,0xaf,0x1e,0xa1,0x35,0x3f,0x8a,0x77,0x13,0x31,0xc4,0x94,0x6e,0x34,0x80,0xaf,0xa7,0x25,0x2f,0x19,0x6c,0x87,0xed,0x3d,0x2a,0x59,0xd3,0xb1,0xb5,0x59,0x13,0x7f,0xed,0x00,0x13,0xfe,0xce,0xfc,0x19,0xfb,0x5a,0x92,0x68,0x2b,0x9b,0xca,0x51,0xb9,0x50,
+ 0x04,0x1a,0xab,0x20,0x18,0x79,0x34,0x71,0x11,0x1a,0x8a,0x0e,0x9b,0x14,0x3f,0xde,0x02,0xfc,0x95,0x92,0x07,0x96,0xd3,0xa6,0x3d,0xe3,0x29,0xb4,0x24,0x39,0x6f,0xba,0x60,0xbb,0xe4,0x13,0x07,0x05,0x17,0x47,0x92,0x44,0x1b,0x31,0x8d,0x3a,0xa3,0x1d,0xfe,0x85,0x77,0x82,0x1e,0x9b,0x44,0x6e,0xc5,0x73,0xd2,0x72,0xe0,0x36,0xc4,0xeb,0xe9,
+ 0x04,0x8c,0xb0,0xb9,0x09,0x49,0x9c,0x83,0xea,0x80,0x6c,0xd8,0x85,0xb1,0xdd,0x46,0x7a,0x01,0x19,0xf0,0x6a,0x88,0xa0,0x27,0x6e,0xb0,0xcf,0xda,0x27,0x45,0x35,0xa8,0xff,0x47,0xb5,0x42,0x88,0x33,0xbc,0x3f,0x2c,0x8b,0xf9,0xd9,0x04,0x11,0x58,0xcf,0x33,0x71,0x8a,0x69,0x96,0x1c,0xd0,0x17,0x29,0xbc,0x00,0x11,0xd1,0xe5,0x86,0xab,0x75,
+ 0x04,0x8f,0x03,0xcf,0x1a,0x42,0x27,0x2b,0xb1,0x53,0x27,0x23,0x09,0x3f,0x72,0xe6,0xfe,0xea,0xc8,0x5e,0x17,0x00,0xe9,0xfb,0xe9,0xa6,0xa2,0xdd,0x64,0x2d,0x74,0xbf,0x5d,0x3b,0x89,0xa7,0x18,0x9d,0xad,0x8c,0xf7,0x5f,0xc2,0x2f,0x6f,0x15,0x8a,0xa2,0x7f,0x9c,0x2c,0xa0,0x0d,0xac,0xa7,0x85,0xbe,0x33,0x58,0xf2,0xbd,0xa3,0x86,0x2c,0xa0,
+ 0x04,0x44,0xde,0x3b,0x9c,0x7a,0x57,0xa8,0xc9,0xe8,0x20,0x95,0x27,0x53,0x42,0x1e,0x7d,0x98,0x7b,0xb3,0xd7,0x9f,0x71,0xf0,0x13,0x80,0x5c,0x89,0x7e,0x01,0x8f,0x8a,0xce,0xa2,0x46,0x07,0x58,0xc8,0xf9,0x8d,0x3f,0xdc,0xe1,0x21,0xa9,0x43,0x65,0x9e,0x37,0x2c,0x32,0x6f,0xff,0x2e,0x5f,0xc2,0xae,0x7f,0xa3,0xf7,0x9d,0xaa,0xe1,0x3c,0x12,
+ 0x04,0x6f,0xb8,0xb2,0xb4,0x8e,0x33,0x03,0x12,0x68,0xad,0x6a,0x51,0x74,0x84,0xdc,0x88,0x39,0xea,0x90,0xf6,0x66,0x9e,0xa0,0xc7,0xac,0x32,0x33,0xe2,0xac,0x31,0x39,0x4a,0x0a,0xc8,0xbb,0xe7,0xf7,0x3c,0x2f,0xf4,0xdf,0x99,0x78,0x72,0x7a,0xc1,0xdf,0xc2,0xfd,0x58,0x64,0x7d,0x20,0xf3,0x1f,0x99,0x10,0x53,0x16,0xb6,0x46,0x71,0xf2,0x04,
+ 0x04,0xbe,0xa7,0x11,0x22,0xa0,0x48,0x69,0x3e,0x90,0x5f,0xf6,0x02,0xb3,0xcf,0x9d,0xd1,0x8a,0xf6,0x9b,0x9f,0xc9,0xd8,0x43,0x1d,0x2b,0x1d,0xd2,0x6b,0x94,0x2c,0x95,0xe6,0xf4,0x3c,0x7b,0x8b,0x95,0xeb,0x62,0x08,0x2c,0x12,0xdb,0x9d,0xbd,0xa7,0xfe,0x38,0xe4,0x5c,0xbe,0x4a,0x48,0x86,0x90,0x7f,0xb8,0x1b,0xdb,0x0c,0x5e,0xa9,0x24,0x6c,
+ 0x04,0xda,0x91,0x8c,0x73,0x1b,0xa0,0x6a,0x20,0xcb,0x94,0xef,0x33,0xb7,0x78,0xe9,0x81,0xa4,0x04,0xa3,0x05,0xf1,0x94,0x1f,0xe3,0x36,0x66,0xb4,0x5b,0x03,0x35,0x31,0x56,0xe2,0xbb,0x26,0x94,0xf5,0x75,0xb4,0x51,0x83,0xbe,0x78,0xe5,0xc9,0xb5,0x21,0x0b,0xf3,0xbf,0x48,0x8f,0xd4,0xc8,0x29,0x45,0x16,0xd8,0x95,0x72,0xca,0x4f,0x53,0x91,
+ 0x04,0x30,0x07,0xe9,0x2c,0x39,0x37,0xda,0xde,0x79,0x64,0xdf,0xa3,0x5b,0x0e,0xff,0x03,0x1f,0x7e,0xb0,0x2a,0xed,0x0a,0x03,0x14,0x41,0x11,0x06,0xcd,0xeb,0x70,0xfe,0x3d,0x5a,0x75,0x46,0xfc,0x05,0x52,0x99,0x7b,0x20,0xe3,0xd6,0xf4,0x13,0xe7,0x5e,0x2c,0xb6,0x6e,0x11,0x63,0x22,0x69,0x71,0x14,0xb7,0x9b,0xac,0x73,0x4b,0xfc,0x4d,0xc5,
+ 0x04,0x60,0xe7,0x34,0xef,0x56,0x24,0xd3,0xcb,0xf0,0xdd,0xd3,0x75,0x01,0x1b,0xd6,0x63,0xd6,0xd6,0xae,0xbc,0x64,0x4e,0xb5,0x99,0xfd,0xf9,0x8d,0xbd,0xcd,0x18,0xce,0x9b,0xd2,0xd9,0x0b,0x3a,0xc3,0x1f,0x13,0x9a,0xf8,0x32,0xcc,0xcf,0x6c,0xcb,0xbb,0x2c,0x6e,0xa1,0x1f,0xa9,0x73,0x70,0xdc,0x99,0x06,0xda,0x47,0x4d,0x7d,0x8a,0x75,0x67,
+ 0x04,0x85,0xa9,0x00,0xe9,0x78,0x58,0xf6,0x93,0xc0,0xb7,0xdf,0xa2,0x61,0xe3,0x80,0xda,0xd6,0xea,0x04,0x6d,0x1f,0x65,0xdd,0xee,0xed,0xd5,0xf7,0xd8,0xaf,0x0b,0xa3,0x37,0x69,0x74,0x4d,0x15,0xad,0xd4,0xf6,0xc0,0xbc,0x3b,0x0d,0xa2,0xae,0xc9,0x3b,0x34,0xcb,0x8c,0x65,0xf9,0x34,0x0d,0xdf,0x74,0xe7,0xb0,0x00,0x9e,0xee,0xcc,0xce,0x3c,
+ 0x04,0x38,0x06,0x6f,0x75,0xd8,0x8e,0xfc,0x4c,0x93,0xde,0x36,0xf4,0x9e,0x03,0x7b,0x23,0x4c,0xc1,0x8b,0x1d,0xe5,0x60,0x87,0x50,0xa6,0x2c,0xab,0x03,0x45,0x40,0x10,0x46,0xa3,0xe8,0x4b,0xed,0x8c,0xfc,0xb8,0x19,0xef,0x4d,0x55,0x04,0x44,0xf2,0xce,0x4b,0x65,0x17,0x66,0xb6,0x9e,0x2e,0x29,0x01,0xf8,0x88,0x36,0xff,0x90,0x03,0x4f,0xed,
+ 0x04,0x98,0xf6,0x81,0x77,0xdc,0x95,0xc1,0xb4,0xcb,0xfa,0x52,0x45,0x48,0x8c,0xa5,0x23,0xa7,0xd5,0x62,0x94,0x70,0xd0,0x35,0xd6,0x21,0xa4,0x43,0xc7,0x2f,0x39,0xaa,0xbf,0xa3,0x3d,0x29,0x54,0x6f,0xa1,0xc6,0x48,0xf2,0xc7,0xd5,0xcc,0xf7,0x0c,0xf1,0xce,0x4a,0xb7,0x9b,0x5d,0xb1,0xac,0x05,0x9d,0xbe,0xcd,0x06,0x8d,0xbd,0xff,0x1b,0x89,
+ 0x04,0x5c,0x2b,0xbf,0xa2,0x3c,0x9b,0x9a,0xd0,0x7f,0x03,0x8a,0xa8,0x9b,0x49,0x30,0xbf,0x26,0x7d,0x94,0x01,0xe4,0x25,0x5d,0xe9,0xe8,0xda,0x0a,0x50,0x78,0xec,0x82,0x77,0xe3,0xe8,0x82,0xa3,0x1d,0x5e,0x6a,0x37,0x9e,0x07,0x93,0x98,0x3c,0xcd,0xed,0x39,0xb9,0x5c,0x43,0x53,0xab,0x2f,0xf0,0x1e,0xa5,0x36,0x9b,0xa4,0x7b,0x0c,0x31,0x91,
+ 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0x35,0x47,0x80,0x82,0x98,0x44,0x8e,0xdb,0x5e,0x70,0x1a,0xde,0x84,0xcd,0x5f,0xb1,0xac,0x95,0x67,0xba,0x5e,0x8f,0xb6,0x8a,0x6b,0x93,0x3e,0xc4,0xb5,0xcc,0x84,0xcc,
+ 0x04,0x2e,0xa7,0x13,0x34,0x32,0x33,0x9c,0x69,0xd2,0x7f,0x9b,0x26,0x72,0x81,0xbd,0x2d,0xdd,0x5f,0x19,0xd6,0x33,0x8d,0x40,0x0a,0x05,0xcd,0x36,0x47,0xb1,0x57,0xa3,0x85,0xca,0xb8,0x7f,0x7d,0x67,0xbb,0x71,0x24,0xa1,0x8f,0xe5,0x21,0x7b,0x32,0xa0,0x4e,0x53,0x6a,0x98,0x45,0xa1,0x70,0x49,0x75,0x94,0x6c,0xc1,0x3a,0x4a,0x33,0x77,0x63,
+ 0x04,0x8a,0xa2,0xc6,0x4f,0xa9,0xc6,0x43,0x75,0x63,0xab,0xfb,0xcb,0xd0,0x0b,0x20,0x48,0xd4,0x8c,0x18,0xc1,0x52,0xa2,0xa6,0xf4,0x90,0x36,0xde,0x76,0x47,0xeb,0xe8,0x2e,0x1c,0xe6,0x43,0x87,0x99,0x5c,0x68,0xa0,0x60,0xfa,0x3b,0xc0,0x39,0x9b,0x05,0xcc,0x06,0xee,0xc7,0xd5,0x98,0xf7,0x50,0x41,0xa4,0x91,0x7e,0x69,0x2b,0x7f,0x51,0xff,
+ 0x04,0x39,0x14,0x27,0xff,0x7e,0xe7,0x80,0x13,0xc1,0x4a,0xec,0x7d,0x96,0xa8,0xa0,0x62,0x20,0x92,0x98,0xa7,0x83,0x83,0x5e,0x94,0xfd,0x65,0x49,0xd5,0x02,0xff,0xf7,0x1f,0xdd,0x66,0x24,0xec,0x34,0x3a,0xd9,0xfc,0xf4,0xd9,0x87,0x21,0x81,0xe5,0x9f,0x84,0x2f,0x9b,0xa4,0xcc,0xca,0xe0,0x9a,0x6c,0x09,0x72,0xfb,0x6a,0xc6,0xb4,0xc6,0xbd,
+ 0x04,0xe7,0x62,0xb8,0xa2,0x19,0xb4,0xf1,0x80,0x21,0x9c,0xc7,0xa9,0x05,0x92,0x45,0xe4,0x96,0x1b,0xd1,0x91,0xc0,0x38,0x99,0x78,0x9c,0x7a,0x34,0xb8,0x9e,0x8c,0x13,0x8e,0xc1,0x53,0x3e,0xf0,0x41,0x9b,0xb7,0x37,0x6e,0x0b,0xfd,0xe9,0x31,0x9d,0x10,0xa0,0x69,0x68,0x79,0x1d,0x9e,0xa0,0xee,0xd9,0xc1,0xce,0x63,0x45,0xae,0xd9,0x75,0x9e,
+ 0x04,0x9a,0xed,0xb0,0xd2,0x81,0xdb,0x16,0x4e,0x13,0x00,0x00,0xc5,0x69,0x7f,0xae,0x0f,0x30,0x5e,0xf8,0x48,0xbe,0x6f,0xff,0xb4,0x3a,0xc5,0x93,0xfb,0xb9,0x50,0xe9,0x52,0xfa,0x6f,0x63,0x33,0x59,0xbd,0xcd,0x82,0xb5,0x6b,0x0b,0x9f,0x96,0x5b,0x03,0x77,0x89,0xd4,0x6b,0x9a,0x81,0x41,0xb7,0x91,0xb2,0xae,0xfa,0x71,0x3f,0x96,0xc1,0x75,
+ 0x04,0x8a,0xd4,0x45,0xdb,0x62,0x81,0x62,0x60,0xe4,0xe6,0x87,0xfd,0x18,0x84,0xe4,0x8b,0x9f,0xc0,0x63,0x6d,0x03,0x15,0x47,0xd6,0x33,0x15,0xe7,0x92,0xe1,0x9b,0xfa,0xee,0x1d,0xe6,0x4f,0x99,0xd5,0xf1,0xcd,0x8b,0x6e,0xc9,0xcb,0x0f,0x78,0x7a,0x65,0x4a,0xe8,0x69,0x93,0xba,0x3d,0xb1,0x00,0x8e,0xf4,0x3c,0xff,0x06,0x84,0xcb,0x22,0xbd,
+ 0x04,0x1f,0x57,0x99,0xc9,0x5b,0xe8,0x90,0x63,0xb2,0x4f,0x26,0xe4,0x0c,0xb9,0x28,0xc1,0xa8,0x68,0xa7,0x6f,0xb0,0x09,0x46,0x07,0xe8,0x04,0x3d,0xb4,0x09,0xc9,0x1c,0x32,0xe7,0x57,0x24,0xe8,0x13,0xa4,0x19,0x1e,0x3a,0x83,0x90,0x07,0xf0,0x8e,0x2e,0x89,0x73,0x88,0xb0,0x6d,0x4a,0x00,0xde,0x6d,0xe6,0x0e,0x53,0x6d,0x91,0xfa,0xb5,0x66,
+ 0x04,0xa3,0x33,0x1a,0x4e,0x1b,0x42,0x23,0xec,0x2c,0x02,0x7e,0xdd,0x48,0x2c,0x92,0x8a,0x14,0xed,0x35,0x8d,0x93,0xf1,0xd4,0x21,0x7d,0x39,0xab,0xf6,0x9f,0xcb,0x5c,0xcc,0x28,0xd6,0x84,0xd2,0xaa,0xab,0xcd,0x63,0x83,0x77,0x5c,0xaa,0x62,0x39,0xde,0x26,0xd4,0xc6,0x93,0x7b,0xb6,0x03,0xec,0xb4,0x19,0x60,0x82,0xf4,0xcf,0xfd,0x50,0x9d,
+ 0x04,0x3f,0x39,0x52,0x19,0x97,0x74,0xc7,0xcf,0x39,0xb3,0x8b,0x66,0xcb,0x10,0x42,0xa6,0x26,0x0d,0x86,0x80,0x80,0x38,0x45,0xe4,0xd4,0x33,0xad,0xba,0x3b,0xb2,0x48,0x18,0x5e,0xa4,0x95,0xb6,0x8c,0xbc,0x7e,0xd4,0x17,0x3e,0xe6,0x3c,0x90,0x42,0xdc,0x50,0x26,0x25,0xc7,0xeb,0x7e,0x21,0xfb,0x02,0xca,0x9a,0x91,0x14,0xe0,0xa3,0xa1,0x8d,
+ 0x04,0xcd,0xfb,0x8c,0x0f,0x42,0x2e,0x14,0x4e,0x13,0x7c,0x24,0x12,0xc8,0x6c,0x17,0x1f,0x5f,0xe3,0xfa,0x3f,0x5b,0xbb,0x54,0x4e,0x90,0x76,0x28,0x8f,0x3c,0xed,0x78,0x6e,0x05,0x4f,0xd0,0x72,0x1b,0x77,0xc1,0x1c,0x79,0xbe,0xac,0xb3,0xc9,0x42,0x11,0xb0,0xa1,0x9b,0xda,0x08,0x65,0x2e,0xfe,0xaf,0x92,0x51,0x3a,0x3b,0x0a,0x16,0x36,0x98,
+ 0x04,0x73,0x59,0x8a,0x6a,0x1c,0x68,0x27,0x8f,0xa6,0xbf,0xd0,0xce,0x40,0x64,0xe6,0x82,0x35,0xbc,0x1c,0x0f,0x6b,0x20,0xa9,0x28,0x10,0x8b,0xe3,0x36,0x73,0x0f,0x87,0xe3,0xcb,0xae,0x61,0x25,0x19,0xb5,0x03,0x2e,0xcc,0x85,0xae,0xd8,0x11,0x27,0x1a,0x95,0xfe,0x79,0x39,0xd5,0xd3,0x46,0x01,0x40,0xba,0x31,0x8f,0x4d,0x14,0xab,0xa3,0x1d,
+ 0x04,0x58,0xde,0xbd,0x9a,0x7e,0xe2,0xc9,0xd5,0x91,0x32,0x47,0x8a,0x54,0x40,0xae,0x4d,0x5d,0x7e,0xd4,0x37,0x30,0x83,0x69,0xf9,0x2e,0xa8,0x6c,0x82,0x18,0x3f,0x10,0xa1,0x67,0x73,0xe7,0x6f,0x5e,0xdb,0xf4,0xda,0x0e,0x4f,0x1b,0xdf,0xfa,0xc0,0xf5,0x72,0x57,0xe1,0xdf,0xa4,0x65,0x84,0x29,0x31,0x30,0x9a,0x24,0x24,0x5f,0xda,0x6a,0x5d,
+ 0x04,0x8b,0x90,0x4d,0xe4,0x79,0x67,0x34,0x0c,0x5f,0x8c,0x35,0x72,0xa7,0x20,0x92,0x4e,0xf7,0x57,0x86,0x37,0xfe,0xab,0x19,0x49,0xac,0xb2,0x41,0xa5,0xa6,0xac,0x3f,0x5b,0x95,0x09,0x04,0x49,0x6f,0x98,0x24,0xb1,0xd6,0x3f,0x33,0x13,0xba,0xe2,0x1b,0x89,0xfa,0xe8,0x9a,0xfd,0xfc,0x81,0x1b,0x5e,0xce,0x03,0xfd,0x5a,0xa3,0x01,0x86,0x4f,
+ 0x04,0xf4,0x89,0x2b,0x6d,0x52,0x5c,0x77,0x1e,0x03,0x5f,0x2a,0x25,0x27,0x08,0xf3,0x78,0x4e,0x48,0x23,0x86,0x04,0xb4,0xf9,0x4d,0xc5,0x6e,0xaa,0x1e,0x54,0x6d,0x94,0x1a,0x34,0x6b,0x1a,0xa0,0xbc,0xe6,0x8b,0x1c,0x50,0xe5,0xb5,0x2f,0x50,0x9f,0xb5,0x52,0x2e,0x5c,0x25,0xe0,0x28,0xbc,0x8f,0x86,0x34,0x02,0xed,0xb7,0xbc,0xad,0x8b,0x1b,
+ 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4,0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48,0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10,0xd4,0xb8,
+ 0x04,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0xb7,0xc5,0x25,0x88,0xd9,0x5c,0x3b,0x9a,0xa2,0x5b,0x04,0x03,0xf1,0xee,0xf7,0x57,0x02,0xe8,0x4b,0xb7,0x59,0x7a,0xab,0xe6,0x63,0xb8,0x2f,0x6f,0x04,0xef,0x27,0x77,
+ 0x04,0x78,0x2c,0x8e,0xd1,0x7e,0x3b,0x2a,0x78,0x3b,0x54,0x64,0xf3,0x3b,0x09,0x65,0x2a,0x71,0xc6,0x78,0xe0,0x5e,0xc5,0x1e,0x84,0xe2,0xbc,0xfc,0x66,0x3a,0x3d,0xe9,0x63,0xaf,0x9a,0xcb,0x42,0x80,0xb8,0xc7,0xf7,0xc4,0x2f,0x4e,0xf9,0xab,0xa6,0x24,0x5e,0xc1,0xec,0x17,0x12,0xfd,0x38,0xa0,0xfa,0x96,0x41,0x8d,0x8c,0xd6,0xaa,0x61,0x52,
+ 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0x00,0x00,0x00,0x01,0x06,0x04,0x92,0xd5,0xa5,0x67,0x3e,0x0f,0x25,0xd8,0xd5,0x0f,0xb7,0xe5,0x8c,0x49,0xd8,0x6d,0x46,0xd4,0x21,0x69,0x55,0xe0,0xaa,0x3d,0x40,0xe1,
+ 0x04,0x6e,0x82,0x35,0x55,0x45,0x29,0x14,0x09,0x91,0x82,0xc6,0xb2,0xc1,0xd6,0xf0,0xb5,0xd2,0x8d,0x50,0xcc,0xd0,0x05,0xaf,0x2c,0xe1,0xbb,0xa5,0x41,0xaa,0x40,0xca,0xff,0xff,0xff,0xff,0xfe,0xf9,0xfb,0x6d,0x2a,0x5a,0x98,0xc1,0xf0,0xda,0x27,0x2a,0xf0,0x48,0x1a,0x73,0xb6,0x27,0x92,0xb9,0x2b,0xde,0x96,0xaa,0x1e,0x55,0xc2,0xbb,0x4e,
+ 0x04,0x00,0x00,0x00,0x01,0x3f,0xd2,0x22,0x48,0xd6,0x4d,0x95,0xf7,0x3c,0x29,0xb4,0x8a,0xb4,0x86,0x31,0x85,0x0b,0xe5,0x03,0xfd,0x00,0xf8,0x46,0x8b,0x5f,0x0f,0x70,0xe0,0xf6,0xee,0x7a,0xa4,0x3b,0xc2,0xc6,0xfd,0x25,0xb1,0xd8,0x26,0x92,0x41,0xcb,0xdd,0x9d,0xbb,0x0d,0xac,0x96,0xdc,0x96,0x23,0x1f,0x43,0x07,0x05,0xf8,0x38,0x71,0x7d,
+ 0x04,0x25,0xaf,0xd6,0x89,0xac,0xab,0xae,0xd6,0x7c,0x1f,0x29,0x6d,0xe5,0x94,0x06,0xf8,0xc5,0x50,0xf5,0x71,0x46,0xa0,0xb4,0xec,0x2c,0x97,0x87,0x6d,0xff,0xff,0xff,0xff,0xfa,0x46,0xa7,0x6e,0x52,0x03,0x22,0xdf,0xbc,0x49,0x1e,0xc4,0xf0,0xcc,0x19,0x74,0x20,0xfc,0x4e,0xa5,0x88,0x3d,0x8f,0x6d,0xd5,0x3c,0x35,0x4b,0xc4,0xf6,0x7c,0x35,
+ 0x04,0xd1,0x2e,0x6c,0x66,0xb6,0x77,0x34,0xc3,0xc8,0x4d,0x26,0x01,0xcf,0x5d,0x35,0xdc,0x09,0x7e,0x27,0x63,0x7f,0x0a,0xca,0x4a,0x4f,0xdb,0x74,0xb6,0xaa,0xdd,0x3b,0xb9,0x3f,0x5b,0xdf,0xf8,0x8b,0xd5,0x73,0x6d,0xf8,0x98,0xe6,0x99,0x00,0x6e,0xd7,0x50,0xf1,0x1c,0xf0,0x7c,0x58,0x66,0xcd,0x7a,0xd7,0x0c,0x71,0x21,0xff,0xff,0xff,0xff,
+ 0x04,0x6d,0x4a,0x7f,0x60,0xd4,0x77,0x4a,0x4f,0x0a,0xa8,0xbb,0xde,0xdb,0x95,0x3c,0x7e,0xea,0x79,0x09,0x40,0x7e,0x31,0x64,0x75,0x56,0x64,0xbc,0x28,0x00,0x00,0x00,0x00,0xe6,0x59,0xd3,0x4e,0x4d,0xf3,0x8d,0x9e,0x8c,0x9e,0xaa,0xdf,0xba,0x36,0x61,0x2c,0x76,0x91,0x95,0xbe,0x86,0xc7,0x7a,0xac,0x3f,0x36,0xe7,0x8b,0x53,0x86,0x80,0xfb};
+
+static const unsigned char wycheproof_ecdsa_signatures[] = { 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x00,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7d,0xb3,0x7c,0x21,0xf4,0xaf,0xd3,0x20,0x3a,0xe8,0xdc,0x4a,0xe7,0x79,0x4b,0x0f,0x87,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x81,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x82,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x85,0x01,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x84,0x7f,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x84,0x80,0x00,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x84,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x85,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0xff,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x47,0x00,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,
+ 0x30,0x4a,0x49,0x81,0x77,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x25,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef,
+ 0x30,0x4d,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x22,0x29,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x28,0xaa,0x00,0xbb,0x00,0xcd,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x81,
+ 0x30,0x4b,0xaa,0x02,0xaa,0xbb,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x80,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x80,0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x05,0x00,
+ 0x2e,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x2f,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x31,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x32,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0xff,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x00,
+ 0x30,0x49,0x30,0x01,0x02,0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,
+ 0x30,0x44,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x82,0x10,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,0x00,0x00,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x06,0x08,0x11,0x22,0x00,0x00,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0xfe,0x02,0xbe,0xef,
+ 0x30,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x02,0xbe,0xef,
+ 0x30,0x47,0x30,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x30,0x00,
+ 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x01,0x00,
+ 0x30,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xbf,0x7f,0x00,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x02,0x05,0x00,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0xa0,0x00,
+ 0x30,0x47,0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,
+ 0x30,0x67,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x64,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xca,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x13,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x08,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x46,0x02,0x81,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x82,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4a,0x02,0x85,0x01,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4e,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x84,0x7f,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x84,0x80,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x84,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4a,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x80,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x23,0x02,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x24,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,
+ 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x23,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x23,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4a,0x22,0x26,0x49,0x81,0x77,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x22,0x25,0x25,0x00,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x22,0x23,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x04,0xde,0xad,0xbe,0xef,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x24,0x02,0x81,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4b,0x22,0x27,0xaa,0x02,0xaa,0xbb,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x22,0x80,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x22,0x80,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x24,0x05,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x00,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x01,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x03,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x04,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0xff,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x24,0x02,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x22,0x25,0x02,0x01,0x00,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x02,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0xe5,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x20,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x82,0x10,0x48,0x02,0x82,0x10,0x22,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x46,0x02,0x22,0xff,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x25,0x09,0x01,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x25,0x02,0x01,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xbb,
+ 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa4,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf7,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x43,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x01,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0x01,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4e,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x89,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x7f,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0x80,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x84,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x85,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x88,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x80,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x47,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x22,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x05,0x00,
+ 0x30,0x4a,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x25,0x49,0x81,0x77,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x25,0x00,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x22,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x04,0xde,0xad,0xbe,0xef,
+ 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x81,
+ 0x30,0x4b,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x26,0xaa,0x02,0xaa,0xbb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x80,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,
+ 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x05,0x00,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x00,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x01,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x03,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x04,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0xff,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x25,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x00,
+ 0x30,0x49,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x22,0x24,0x02,0x01,0x6f,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6d,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0x3a,
+ 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,
+ 0x30,0x44,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x1f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x82,0x10,0x48,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x82,0x10,0x21,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x30,0x46,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x09,0x01,0x80,
+ 0x30,0x26,0x02,0x21,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x01,0x00,
+ 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x83,0xb9,0x0d,0xea,0xbc,0xa4,0xb0,0x5c,0x45,0x74,0xe4,0x9b,0x58,0x99,0xb9,0x64,0xa6,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x20,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x86,0x43,0xb0,0x30,0xef,0x46,0x1f,0x1b,0xcd,0xf5,0x3f,0xde,0x3e,0xf9,0x4c,0xe2,0x24,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x46,0x02,0x22,0x01,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x84,0x3f,0xad,0x3b,0xf4,0x85,0x3e,0x07,0xf7,0xc9,0x87,0x70,0xc9,0x9b,0xff,0xc4,0x64,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0xff,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7b,0x01,0xa0,0xf2,0x2a,0x0a,0x98,0x43,0xf6,0x4a,0xed,0xc3,0x34,0x36,0x7c,0xdc,0x9b,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x20,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x79,0xbc,0x4f,0xcf,0x10,0xb9,0xe0,0xe4,0x32,0x0a,0xc0,0x21,0xc1,0x06,0xb3,0x1d,0xdc,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0xfe,0x7e,0xc1,0x08,0x63,0x31,0x05,0x65,0xa9,0x08,0x45,0x7f,0xa0,0xf1,0xb8,0x7a,0x7c,0x46,0xf2,0x15,0x43,0x5b,0x4f,0xa3,0xba,0x8b,0x1b,0x64,0xa7,0x66,0x46,0x9b,0x5a,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x01,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0x3e,0xf7,0x9c,0xce,0xfa,0x9a,0x56,0xf7,0xba,0x80,0x5f,0x0e,0x47,0x85,0x84,0xfe,0x5f,0x0d,0xd5,0xf5,0x67,0xbc,0x09,0xb5,0x12,0x3c,0xcb,0xc9,0x83,0x23,0x65,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x7f,0xc1,0xe1,0x97,0xd8,0xae,0xbe,0x20,0x3c,0x96,0xc8,0x72,0x32,0x27,0x21,0x72,0xfb,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x82,0x4c,0x83,0xde,0x0b,0x50,0x2c,0xdf,0xc5,0x17,0x23,0xb5,0x18,0x86,0xb4,0xf0,0x79,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x46,0x02,0x22,0x01,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9a,0x3b,0xb6,0x0f,0xa1,0xa1,0x48,0x15,0xbb,0xc0,0xa9,0x54,0xa0,0x75,0x8d,0x2c,0x72,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x44,0x02,0x20,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x7e,0xf8,0xcd,0x45,0x0e,0x00,0x8a,0x7f,0xff,0x29,0x09,0xec,0x5a,0xa9,0x14,0xce,0x46,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0xfe,0x90,0x0e,0x75,0xad,0x23,0x3f,0xcc,0x90,0x85,0x09,0xdb,0xff,0x59,0x22,0x64,0x80,0x3e,0x1e,0x68,0x27,0x51,0x41,0xdf,0xc3,0x69,0x37,0x8d,0xcd,0xd8,0xde,0x8d,0x05,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0x01,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x45,0x02,0x21,0xff,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x4d,0x02,0x29,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,0x02,0x20,0x6f,0xf1,0x8a,0x52,0xdc,0xc0,0x33,0x6f,0x7a,0xf6,0x24,0x00,0xa6,0xdd,0x9b,0x81,0x07,0x32,0xba,0xf1,0xff,0x75,0x80,0x00,0xd6,0xf6,0x13,0xa5,0x56,0xeb,0x31,0xba,
+ 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x00,
+ 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0x00,0x02,0x01,0xff,
+ 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x26,0x02,0x01,0x00,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x00,
+ 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0xff,
+ 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x26,0x02,0x01,0x01,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x00,
+ 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0xff,0x02,0x01,0xff,
+ 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x26,0x02,0x01,0xff,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x01,0xff,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x01,0xff,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x01,0xff,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x01,0xff,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x01,0xff,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x40,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x42,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,
+ 0x30,0x46,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x30,
+ 0x30,0x08,0x02,0x01,0x00,0x09,0x03,0x80,0xfe,0x01,
+ 0x30,0x06,0x02,0x01,0x00,0x09,0x01,0x42,
+ 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0x00,0x01,0x01,0x00,
+ 0x30,0x05,0x02,0x01,0x00,0x05,0x00,
+ 0x30,0x05,0x02,0x01,0x00,0x0c,0x00,
+ 0x30,0x06,0x02,0x01,0x00,0x0c,0x01,0x30,
+ 0x30,0x05,0x02,0x01,0x00,0x30,0x00,
+ 0x30,0x08,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00,
+ 0x30,0x08,0x02,0x01,0x01,0x09,0x03,0x80,0xfe,0x01,
+ 0x30,0x06,0x02,0x01,0x01,0x09,0x01,0x42,
+ 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0x01,0x01,0x01,0x00,
+ 0x30,0x05,0x02,0x01,0x01,0x05,0x00,
+ 0x30,0x05,0x02,0x01,0x01,0x0c,0x00,
+ 0x30,0x06,0x02,0x01,0x01,0x0c,0x01,0x30,
+ 0x30,0x05,0x02,0x01,0x01,0x30,0x00,
+ 0x30,0x08,0x02,0x01,0x01,0x30,0x03,0x02,0x01,0x00,
+ 0x30,0x08,0x02,0x01,0xff,0x09,0x03,0x80,0xfe,0x01,
+ 0x30,0x06,0x02,0x01,0xff,0x09,0x01,0x42,
+ 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0xff,0x01,0x01,0x00,
+ 0x30,0x05,0x02,0x01,0xff,0x05,0x00,
+ 0x30,0x05,0x02,0x01,0xff,0x0c,0x00,
+ 0x30,0x06,0x02,0x01,0xff,0x0c,0x01,0x30,
+ 0x30,0x05,0x02,0x01,0xff,0x30,0x00,
+ 0x30,0x08,0x02,0x01,0xff,0x30,0x03,0x02,0x01,0x00,
+ 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x03,0x80,0xfe,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x09,0x01,0x42,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x01,0x01,0x00,
+ 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x05,0x00,
+ 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x0c,0x01,0x30,
+ 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x00,
+ 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x41,0x30,0x03,0x02,0x01,0x00,
+ 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x03,0x80,0xfe,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x09,0x01,0x42,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x01,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x01,0x01,0x00,
+ 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x05,0x00,
+ 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x00,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x0c,0x01,0x30,
+ 0x30,0x25,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x00,
+ 0x30,0x28,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2f,0x30,0x03,0x02,0x01,0x00,
+ 0x30,0x0a,0x09,0x03,0x80,0xfe,0x01,0x09,0x03,0x80,0xfe,0x01,
+ 0x30,0x06,0x09,0x01,0x42,0x09,0x01,0x42,
+ 0x30,0x06,0x01,0x01,0x01,0x01,0x01,0x01,
+ 0x30,0x06,0x01,0x01,0x00,0x01,0x01,0x00,
+ 0x30,0x04,0x05,0x00,0x05,0x00,
+ 0x30,0x04,0x0c,0x00,0x0c,0x00,
+ 0x30,0x06,0x0c,0x01,0x30,0x0c,0x01,0x30,
+ 0x30,0x04,0x30,0x00,0x30,0x00,
+ 0x30,0x0a,0x30,0x03,0x02,0x01,0x00,0x30,0x03,0x02,0x01,0x00,
+ 0x30,0x08,0x09,0x03,0x80,0xfe,0x01,0x02,0x01,0x00,
+ 0x30,0x06,0x09,0x01,0x42,0x02,0x01,0x00,
+ 0x30,0x06,0x01,0x01,0x01,0x02,0x01,0x00,
+ 0x30,0x06,0x01,0x01,0x00,0x02,0x01,0x00,
+ 0x30,0x05,0x05,0x00,0x02,0x01,0x00,
+ 0x30,0x05,0x0c,0x00,0x02,0x01,0x00,
+ 0x30,0x06,0x0c,0x01,0x30,0x02,0x01,0x00,
+ 0x30,0x05,0x30,0x00,0x02,0x01,0x00,
+ 0x30,0x08,0x30,0x03,0x02,0x01,0x00,0x02,0x01,0x00,
+ 0x30,0x45,0x02,0x21,0x00,0xdd,0x1b,0x7d,0x09,0xa7,0xbd,0x82,0x18,0x96,0x10,0x34,0xa3,0x9a,0x87,0xfe,0xcf,0x53,0x14,0xf0,0x0c,0x4d,0x25,0xeb,0x58,0xa0,0x7a,0xc8,0x5e,0x85,0xea,0xb5,0x16,0x02,0x20,0x35,0x13,0x8c,0x40,0x1e,0xf8,0xd3,0x49,0x3d,0x65,0xc9,0x00,0x2f,0xe6,0x2b,0x43,0xae,0xe5,0x68,0x73,0x1b,0x74,0x45,0x48,0x35,0x89,0x96,0xd9,0xcc,0x42,0x7e,0x06,
+ 0x30,0x45,0x02,0x21,0x00,0x95,0xc2,0x92,0x67,0xd9,0x72,0xa0,0x43,0xd9,0x55,0x22,0x45,0x46,0x22,0x2b,0xba,0x34,0x3f,0xc1,0xd4,0xdb,0x0f,0xec,0x26,0x2a,0x33,0xac,0x61,0x30,0x56,0x96,0xae,0x02,0x20,0x6e,0xdf,0xe9,0x67,0x13,0xae,0xd5,0x6f,0x8a,0x28,0xa6,0x65,0x3f,0x57,0xe0,0xb8,0x29,0x71,0x2e,0x5e,0xdd,0xc6,0x7f,0x34,0x68,0x2b,0x24,0xf0,0x67,0x6b,0x26,0x40,
+ 0x30,0x44,0x02,0x20,0x28,0xf9,0x4a,0x89,0x4e,0x92,0x02,0x46,0x99,0xe3,0x45,0xfe,0x66,0x97,0x1e,0x3e,0xdc,0xd0,0x50,0x02,0x33,0x86,0x13,0x5a,0xb3,0x93,0x9d,0x55,0x08,0x98,0xfb,0x25,0x02,0x20,0x32,0x96,0x3e,0x5b,0xd4,0x1f,0xa5,0x91,0x1e,0xd8,0xf3,0x7d,0xeb,0x86,0xda,0xe0,0xa7,0x62,0xbb,0x61,0x21,0xc8,0x94,0x61,0x50,0x83,0xc5,0xd9,0x5e,0xa0,0x1d,0xb3,
+ 0x30,0x45,0x02,0x21,0x00,0xbe,0x26,0xb1,0x8f,0x95,0x49,0xf8,0x9f,0x41,0x1a,0x9b,0x52,0x53,0x6b,0x15,0xaa,0x27,0x0b,0x84,0x54,0x8d,0x0e,0x85,0x9a,0x19,0x52,0xa2,0x7a,0xf1,0xa7,0x7a,0xc6,0x02,0x20,0x70,0xc1,0xd4,0xfa,0x9c,0xd0,0x3c,0xc8,0xea,0xa8,0xd5,0x06,0xed,0xb9,0x7e,0xed,0x7b,0x83,0x58,0xb4,0x53,0xc8,0x8a,0xef,0xbb,0x88,0x0a,0x3f,0x0e,0x8d,0x47,0x2f,
+ 0x30,0x45,0x02,0x21,0x00,0xb1,0xa4,0xb1,0x47,0x8e,0x65,0xcc,0x3e,0xaf,0xdf,0x22,0x5d,0x12,0x98,0xb4,0x3f,0x2d,0xa1,0x9e,0x4b,0xcf,0xf7,0xea,0xcc,0x0a,0x2e,0x98,0xcd,0x4b,0x74,0xb1,0x14,0x02,0x20,0x17,0x9a,0xa3,0x1e,0x30,0x4c,0xc1,0x42,0xcf,0x50,0x73,0x17,0x17,0x51,0xb2,0x8f,0x3f,0x5e,0x0f,0xa8,0x8c,0x99,0x4e,0x7c,0x55,0xf1,0xbc,0x07,0xb8,0xd5,0x6c,0x16,
+ 0x30,0x44,0x02,0x20,0x32,0x53,0x32,0x02,0x12,0x61,0xf1,0xbd,0x18,0xf2,0x71,0x2a,0xa1,0xe2,0x25,0x2d,0xa2,0x37,0x96,0xda,0x8a,0x4b,0x1f,0xf6,0xea,0x18,0xca,0xfe,0xc7,0xe1,0x71,0xf2,0x02,0x20,0x40,0xb4,0xf5,0xe2,0x87,0xee,0x61,0xfc,0x3c,0x80,0x41,0x86,0x98,0x23,0x60,0x89,0x1e,0xaa,0x35,0xc7,0x5f,0x05,0xa4,0x3e,0xcd,0x48,0xb3,0x5d,0x98,0x4a,0x66,0x48,
+ 0x30,0x45,0x02,0x21,0x00,0xa2,0x3a,0xd1,0x8d,0x8f,0xc6,0x6d,0x81,0xaf,0x09,0x03,0x89,0x0c,0xbd,0x45,0x3a,0x55,0x4c,0xb0,0x4c,0xdc,0x1a,0x8c,0xa7,0xf7,0xf7,0x8e,0x53,0x67,0xed,0x88,0xa0,0x02,0x20,0x23,0xe3,0xeb,0x2c,0xe1,0xc0,0x4e,0xa7,0x48,0xc3,0x89,0xbd,0x97,0x37,0x4a,0xa9,0x41,0x3b,0x92,0x68,0x85,0x1c,0x04,0xdc,0xd9,0xf8,0x8e,0x78,0x81,0x3f,0xee,0x56,
+ 0x30,0x44,0x02,0x20,0x2b,0xde,0xa4,0x1c,0xda,0x63,0xa2,0xd1,0x4b,0xf4,0x73,0x53,0xbd,0x20,0x88,0x0a,0x69,0x09,0x01,0xde,0x7c,0xd6,0xe3,0xcc,0x6d,0x8e,0xd5,0xba,0x0c,0xdb,0x10,0x91,0x02,0x20,0x3c,0xea,0x66,0xbc,0xcf,0xc9,0xf9,0xbf,0x8c,0x7c,0xa4,0xe1,0xc1,0x45,0x7c,0xc9,0x14,0x5e,0x13,0xe9,0x36,0xd9,0x0b,0x3d,0x9c,0x77,0x86,0xb8,0xb2,0x6c,0xf4,0xc7,
+ 0x30,0x45,0x02,0x21,0x00,0xd7,0xcd,0x76,0xec,0x01,0xc1,0xb1,0x07,0x9e,0xba,0x9e,0x2a,0xa2,0xa3,0x97,0x24,0x3c,0x47,0x58,0xc9,0x8a,0x1b,0xa0,0xb7,0x40,0x4a,0x34,0x0b,0x9b,0x00,0xce,0xd6,0x02,0x20,0x35,0x75,0x00,0x1e,0x19,0xd9,0x22,0xe6,0xde,0x8b,0x3d,0x6c,0x84,0xea,0x43,0xb5,0xc3,0x33,0x81,0x06,0xcf,0x29,0x99,0x01,0x34,0xe7,0x66,0x9a,0x82,0x6f,0x78,0xe6,
+ 0x30,0x45,0x02,0x21,0x00,0xa8,0x72,0xc7,0x44,0xd9,0x36,0xdb,0x21,0xa1,0x0c,0x36,0x1d,0xd5,0xc9,0x06,0x33,0x55,0xf8,0x49,0x02,0x21,0x96,0x52,0xf6,0xfc,0x56,0xdc,0x95,0xa7,0x13,0x9d,0x96,0x02,0x20,0x40,0x0d,0xf7,0x57,0x5d,0x97,0x56,0x21,0x0e,0x9c,0xcc,0x77,0x16,0x2c,0x6b,0x59,0x3c,0x77,0x46,0xcf,0xb4,0x8a,0xc2,0x63,0xc4,0x27,0x50,0xb4,0x21,0xef,0x4b,0xb9,
+ 0x30,0x45,0x02,0x21,0x00,0x9f,0xa9,0xaf,0xe0,0x77,0x52,0xda,0x10,0xb3,0x6d,0x3a,0xfc,0xd0,0xfe,0x44,0xbf,0xc4,0x02,0x44,0xd7,0x52,0x03,0x59,0x9c,0xf8,0xf5,0x04,0x7f,0xa3,0x45,0x38,0x54,0x02,0x20,0x50,0xe0,0xa7,0xc0,0x13,0xbf,0xbf,0x51,0x81,0x97,0x36,0x97,0x2d,0x44,0xb4,0xb5,0x6b,0xc2,0xa2,0xb2,0xc1,0x80,0xdf,0x6e,0xc6,0x72,0xdf,0x17,0x14,0x10,0xd7,0x7a,
+ 0x30,0x45,0x02,0x21,0x00,0x88,0x56,0x40,0x38,0x4d,0x0d,0x91,0x0e,0xfb,0x17,0x7b,0x46,0xbe,0x6c,0x3d,0xc5,0xca,0xc8,0x1f,0x0b,0x88,0xc3,0x19,0x0b,0xb6,0xb5,0xf9,0x9c,0x26,0x41,0xf2,0x05,0x02,0x20,0x73,0x8e,0xd9,0xbf,0xf1,0x16,0x30,0x6d,0x9c,0xaa,0x0f,0x8f,0xc6,0x08,0xbe,0x24,0x3e,0x0b,0x56,0x77,0x79,0xd8,0xda,0xb0,0x3e,0x8e,0x19,0xd5,0x53,0xf1,0xdc,0x8e,
+ 0x30,0x44,0x02,0x20,0x2d,0x05,0x1f,0x91,0xc5,0xa9,0xd4,0x40,0xc5,0x67,0x69,0x85,0x71,0x04,0x83,0xbc,0x4f,0x1a,0x6c,0x61,0x1b,0x10,0xc9,0x5a,0x2f,0xf0,0x36,0x3d,0x90,0xc2,0xa4,0x58,0x02,0x20,0x6d,0xdf,0x94,0xe6,0xfb,0xa5,0xbe,0x58,0x68,0x33,0xd0,0xc5,0x3c,0xf2,0x16,0xad,0x39,0x48,0xf3,0x79,0x53,0xc2,0x6c,0x1c,0xf4,0x96,0x8e,0x9a,0x9e,0x82,0x43,0xdc,
+ 0x30,0x45,0x02,0x21,0x00,0xf3,0xac,0x25,0x23,0x96,0x74,0x82,0xf5,0x3d,0x50,0x85,0x22,0x71,0x2d,0x58,0x3f,0x43,0x79,0xcd,0x82,0x41,0x01,0xff,0x63,0x5e,0xa0,0x93,0x51,0x17,0xba,0xa5,0x4f,0x02,0x20,0x27,0xf1,0x08,0x12,0x22,0x73,0x97,0xe0,0x2c,0xea,0x96,0xfb,0x0e,0x68,0x07,0x61,0x63,0x6d,0xab,0x2b,0x08,0x0d,0x1f,0xc5,0xd1,0x16,0x85,0xcb,0xe8,0x50,0x0c,0xfe,
+ 0x30,0x45,0x02,0x21,0x00,0x96,0x44,0x7c,0xf6,0x8c,0x3a,0xb7,0x26,0x6e,0xd7,0x44,0x7d,0xe3,0xac,0x52,0xfe,0xd7,0xcc,0x08,0xcb,0xdf,0xea,0x39,0x1c,0x18,0xa9,0xb8,0xab,0x37,0x0b,0xc9,0x13,0x02,0x20,0x0f,0x5e,0x78,0x74,0xd3,0xac,0x0e,0x91,0x8f,0x01,0xc8,0x85,0xa1,0x63,0x91,0x77,0xc9,0x23,0xf8,0x66,0x0d,0x1c,0xeb,0xa1,0xca,0x1f,0x30,0x1b,0xc6,0x75,0xcd,0xbc,
+ 0x30,0x44,0x02,0x20,0x53,0x0a,0x08,0x32,0xb6,0x91,0xda,0x0b,0x56,0x19,0xa0,0xb1,0x1d,0xe6,0x87,0x7f,0x3c,0x09,0x71,0xba,0xaa,0x68,0xed,0x12,0x27,0x58,0xc2,0x9c,0xaa,0xf4,0x6b,0x72,0x02,0x20,0x6c,0x89,0xe4,0x4f,0x5e,0xb3,0x30,0x60,0xea,0x4b,0x46,0x31,0x8c,0x39,0x13,0x8e,0xae,0xde,0xc7,0x2d,0xe4,0x2b,0xa5,0x76,0x57,0x9a,0x6a,0x46,0x90,0xe3,0x39,0xf3,
+ 0x30,0x45,0x02,0x21,0x00,0x9c,0x54,0xc2,0x55,0x00,0xbd,0xe0,0xb9,0x2d,0x72,0xd6,0xec,0x48,0x3d,0xc2,0x48,0x2f,0x36,0x54,0x29,0x4c,0xa7,0x4d,0xe7,0x96,0xb6,0x81,0x25,0x5e,0xd5,0x8a,0x77,0x02,0x20,0x67,0x74,0x53,0xc6,0xb5,0x6f,0x52,0x76,0x31,0xc9,0xf6,0x7b,0x3f,0x3e,0xb6,0x21,0xfd,0x88,0x58,0x2b,0x4a,0xff,0x15,0x6d,0x2f,0x15,0x67,0xd6,0x21,0x1a,0x2a,0x33,
+ 0x30,0x45,0x02,0x21,0x00,0xe7,0x90,0x9d,0x41,0x43,0x9e,0x2f,0x6a,0xf2,0x91,0x36,0xc7,0x34,0x8c,0xa2,0x64,0x1a,0x2b,0x07,0x0d,0x5b,0x64,0xf9,0x1e,0xa9,0xda,0x70,0x70,0xc7,0xa2,0x61,0x8b,0x02,0x20,0x42,0xd7,0x82,0xf1,0x32,0xfa,0x1d,0x36,0xc2,0xc8,0x8b,0xa2,0x7c,0x3d,0x67,0x8d,0x80,0x18,0x4a,0x5d,0x1e,0xcc,0xac,0x75,0x01,0xf0,0xb4,0x7e,0x3d,0x20,0x50,0x08,
+ 0x30,0x44,0x02,0x20,0x59,0x24,0x87,0x32,0x09,0x59,0x31,0x35,0xa4,0xc3,0xda,0x7b,0xb3,0x81,0x22,0x7f,0x8a,0x4b,0x6a,0xa9,0xf3,0x4f,0xe5,0xbb,0x7f,0x8f,0xbc,0x13,0x1a,0x03,0x9f,0xfe,0x02,0x20,0x1f,0x1b,0xb1,0x1b,0x44,0x1c,0x8f,0xea,0xa4,0x0f,0x44,0x21,0x3d,0x9a,0x40,0x5e,0xd7,0x92,0xd5,0x9f,0xb4,0x9d,0x5b,0xcd,0xd9,0xa4,0x28,0x5a,0xe5,0x69,0x30,0x22,
+ 0x30,0x45,0x02,0x21,0x00,0xee,0xb6,0x92,0xc9,0xb2,0x62,0x96,0x9b,0x23,0x1c,0x38,0xb5,0xa7,0xf6,0x06,0x49,0xe0,0xc8,0x75,0xcd,0x64,0xdf,0x88,0xf3,0x3a,0xa5,0x71,0xfa,0x3d,0x29,0xab,0x0e,0x02,0x20,0x21,0x8b,0x3a,0x1e,0xb0,0x63,0x79,0xc2,0xc1,0x8c,0xf5,0x1b,0x06,0x43,0x07,0x86,0xd1,0xc6,0x4c,0xd2,0xd2,0x4c,0x9b,0x23,0x2b,0x23,0xe5,0xba,0xc7,0x98,0x9a,0xcd,
+ 0x30,0x45,0x02,0x21,0x00,0xa4,0x00,0x34,0x17,0x7f,0x36,0x09,0x1c,0x2b,0x65,0x36,0x84,0xa0,0xe3,0xeb,0x5d,0x4b,0xff,0x18,0xe4,0xd0,0x9f,0x66,0x4c,0x28,0x00,0xe7,0xca,0xfd,0xa1,0xda,0xf8,0x02,0x20,0x3a,0x3e,0xc2,0x98,0x53,0x70,0x4e,0x52,0x03,0x1c,0x58,0x92,0x7a,0x80,0x0a,0x96,0x83,0x53,0xad,0xc3,0xd9,0x73,0xbe,0xba,0x91,0x72,0xcb,0xbe,0xab,0x4d,0xd1,0x49,
+ 0x30,0x45,0x02,0x21,0x00,0xb5,0xd7,0x95,0xcc,0x75,0xce,0xa5,0xc4,0x34,0xfa,0x41,0x85,0x18,0x0c,0xd6,0xbd,0x21,0x22,0x3f,0x3d,0x5a,0x86,0xda,0x66,0x70,0xd7,0x1d,0x95,0x68,0x0d,0xad,0xbf,0x02,0x20,0x54,0xe4,0xd8,0x81,0x0a,0x00,0x1e,0xcb,0xb9,0xf7,0xca,0x1c,0x2e,0xbf,0xdb,0x9d,0x00,0x9e,0x90,0x31,0xa4,0x31,0xac,0xa3,0xc2,0x0a,0xb4,0xe0,0xd1,0x37,0x4e,0xc1,
+ 0x30,0x44,0x02,0x20,0x07,0xdc,0x24,0x78,0xd4,0x3c,0x12,0x32,0xa4,0x59,0x56,0x08,0xc6,0x44,0x26,0xc3,0x55,0x10,0x05,0x1a,0x63,0x1a,0xe6,0xa5,0xa6,0xeb,0x11,0x61,0xe5,0x7e,0x42,0xe1,0x02,0x20,0x4a,0x59,0xea,0x0f,0xdb,0x72,0xd1,0x21,0x65,0xce,0xa3,0xbf,0x1c,0xa8,0x6b,0xa9,0x75,0x17,0xbd,0x18,0x8d,0xb3,0xdb,0xd2,0x1a,0x5a,0x15,0x78,0x50,0x02,0x19,0x84,
+ 0x30,0x45,0x02,0x21,0x00,0xdd,0xd2,0x0c,0x4a,0x05,0x59,0x6c,0xa8,0x68,0xb5,0x58,0x83,0x9f,0xce,0x9f,0x65,0x11,0xdd,0xd8,0x3d,0x1c,0xcb,0x53,0xf8,0x2e,0x52,0x69,0xd5,0x59,0xa0,0x15,0x52,0x02,0x20,0x5b,0x91,0x73,0x47,0x29,0xd9,0x30,0x93,0xff,0x22,0x12,0x3c,0x4a,0x25,0x81,0x9d,0x7f,0xeb,0x66,0xa2,0x50,0x66,0x3f,0xc7,0x80,0xcb,0x66,0xfc,0x7b,0x6e,0x6d,0x17,
+ 0x30,0x45,0x02,0x21,0x00,0x9c,0xde,0x6e,0x0e,0xde,0x0a,0x00,0x3f,0x02,0xfd,0xa0,0xa0,0x1b,0x59,0xfa,0xcf,0xe5,0xde,0xc0,0x63,0x31,0x8f,0x27,0x9c,0xe2,0xde,0x7a,0x9b,0x10,0x62,0xf7,0xb7,0x02,0x20,0x28,0x86,0xa5,0xb8,0xc6,0x79,0xbd,0xf8,0x22,0x4c,0x66,0xf9,0x08,0xfd,0x62,0x05,0x49,0x2c,0xb7,0x0b,0x00,0x68,0xd4,0x6a,0xe4,0xf3,0x3a,0x41,0x49,0xb1,0x2a,0x52,
+ 0x30,0x45,0x02,0x21,0x00,0xc5,0x77,0x10,0x16,0xd0,0xdd,0x63,0x57,0x14,0x3c,0x89,0xf6,0x84,0xcd,0x74,0x04,0x23,0x50,0x25,0x54,0xc0,0xc5,0x9a,0xa8,0xc9,0x95,0x84,0xf1,0xff,0x38,0xf6,0x09,0x02,0x20,0x54,0xb4,0x05,0xf4,0x47,0x75,0x46,0x68,0x6e,0x46,0x4c,0x54,0x63,0xb4,0xfd,0x41,0x90,0x57,0x2e,0x58,0xd0,0xf7,0xe7,0x35,0x7f,0x6e,0x61,0x94,0x7d,0x20,0x71,0x5c,
+ 0x30,0x45,0x02,0x21,0x00,0xa2,0x4e,0xbc,0x0e,0xc2,0x24,0xbd,0x67,0xae,0x39,0x7c,0xbe,0x6f,0xa3,0x7b,0x31,0x25,0xad,0xbd,0x34,0x89,0x1a,0xbe,0x2d,0x7c,0x73,0x56,0x92,0x19,0x16,0xdf,0xe6,0x02,0x20,0x34,0xf6,0xeb,0x63,0x74,0x73,0x1b,0xbb,0xaf,0xc4,0x92,0x4f,0xb8,0xb0,0xbd,0xcd,0xda,0x49,0x45,0x6d,0x72,0x4c,0xda,0xe6,0x17,0x8d,0x87,0x01,0x4c,0xb5,0x3d,0x8c,
+ 0x30,0x44,0x02,0x20,0x25,0x57,0xd6,0x4a,0x7a,0xee,0x2e,0x09,0x31,0xc0,0x12,0xe4,0xfe,0xa1,0xcd,0x3a,0x2c,0x33,0x4e,0xda,0xe6,0x8c,0xde,0xb7,0x15,0x8c,0xaf,0x21,0xb6,0x8e,0x5a,0x24,0x02,0x20,0x7f,0x06,0xcd,0xbb,0x6a,0x90,0x02,0x3a,0x97,0x38,0x82,0xed,0x97,0xb0,0x80,0xfe,0x6b,0x05,0xaf,0x3e,0xc9,0x3d,0xb6,0xf1,0xa4,0x39,0x9a,0x69,0xed,0xf7,0x67,0x0d,
+ 0x30,0x45,0x02,0x21,0x00,0xc4,0xf2,0xec,0xcb,0xb6,0xa2,0x43,0x50,0xc8,0x46,0x64,0x50,0xb9,0xd6,0x1b,0x20,0x7e,0xe3,0x59,0xe0,0x37,0xb3,0xdc,0xed,0xb4,0x2a,0x3f,0x2e,0x6d,0xd6,0xae,0xb5,0x02,0x20,0x32,0x63,0xc6,0xb5,0x9a,0x2f,0x55,0xcd,0xd1,0xc6,0xe1,0x48,0x94,0xd5,0xe5,0x96,0x3b,0x28,0xbc,0x3e,0x24,0x69,0xac,0x9b,0xa1,0x19,0x79,0x91,0xca,0x7f,0xf9,0xc7,
+ 0x30,0x45,0x02,0x21,0x00,0xef,0xf0,0x47,0x81,0xc9,0xcb,0xcd,0x16,0x2d,0x0a,0x25,0xa6,0xe2,0xeb,0xcc,0xa4,0x35,0x06,0xc5,0x23,0x38,0x5c,0xb5,0x15,0xd4,0x9e,0xa3,0x8a,0x1b,0x12,0xfc,0xad,0x02,0x20,0x15,0xac,0xd7,0x31,0x94,0xc9,0x1a,0x95,0x47,0x85,0x34,0xf2,0x30,0x15,0xb6,0x72,0xeb,0xed,0x21,0x3e,0x45,0x42,0x4d,0xd2,0xc8,0xe2,0x6a,0xc8,0xb3,0xeb,0x34,0xa5,
+ 0x30,0x45,0x02,0x21,0x00,0xf5,0x8b,0x4e,0x31,0x10,0xa6,0x4b,0xf1,0xb5,0xdb,0x97,0x63,0x9e,0xe0,0xe5,0xa9,0xc8,0xdf,0xa4,0x9d,0xc5,0x9b,0x67,0x98,0x91,0xf5,0x20,0xfd,0xf0,0x58,0x4c,0x87,0x02,0x20,0x2c,0xd8,0xfe,0x51,0x88,0x8a,0xee,0x9d,0xb3,0xe0,0x75,0x44,0x0f,0xd4,0xdb,0x73,0xb5,0xc7,0x32,0xfb,0x87,0xb5,0x10,0xe9,0x70,0x93,0xd6,0x64,0x15,0xf6,0x2a,0xf7,
+ 0x30,0x45,0x02,0x21,0x00,0xf8,0xab,0xec,0xaa,0x4f,0x0c,0x50,0x2d,0xe4,0xbf,0x59,0x03,0xd4,0x84,0x17,0xf7,0x86,0xbf,0x92,0xe8,0xad,0x72,0xfe,0xc0,0xbd,0x7f,0xcb,0x78,0x00,0xc0,0xbb,0xe3,0x02,0x20,0x4c,0x7f,0x9e,0x23,0x10,0x76,0xa3,0x0b,0x7a,0xe3,0x6b,0x0c,0xeb,0xe6,0x9c,0xce,0xf1,0xcd,0x19,0x4f,0x7c,0xce,0x93,0xa5,0x58,0x8f,0xd6,0x81,0x4f,0x43,0x7c,0x0e,
+ 0x30,0x44,0x02,0x20,0x5d,0x5b,0x38,0xbd,0x37,0xad,0x49,0x8b,0x22,0x27,0xa6,0x33,0x26,0x8a,0x8c,0xca,0x87,0x9a,0x5c,0x7c,0x94,0xa4,0xe4,0x16,0xbd,0x0a,0x61,0x4d,0x09,0xe6,0x06,0xd2,0x02,0x20,0x12,0xb8,0xd6,0x64,0xea,0x99,0x91,0x06,0x2e,0xcb,0xb8,0x34,0xe5,0x84,0x00,0xe2,0x5c,0x46,0x00,0x7a,0xf8,0x4f,0x60,0x07,0xd7,0xf1,0x68,0x54,0x43,0x26,0x9a,0xfe,
+ 0x30,0x44,0x02,0x20,0x0c,0x1c,0xd9,0xfe,0x40,0x34,0xf0,0x86,0xa2,0xb5,0x2d,0x65,0xb9,0xd3,0x83,0x4d,0x72,0xae,0xbe,0x7f,0x33,0xdf,0xe8,0xf9,0x76,0xda,0x82,0x64,0x81,0x77,0xd8,0xe3,0x02,0x20,0x13,0x10,0x57,0x82,0xe3,0xd0,0xcf,0xe8,0x5c,0x27,0x78,0xde,0xc1,0xa8,0x48,0xb2,0x7a,0xc0,0xae,0x07,0x1a,0xa6,0xda,0x34,0x1a,0x95,0x53,0xa9,0x46,0xb4,0x1e,0x59,
+ 0x30,0x45,0x02,0x21,0x00,0xae,0x79,0x35,0xfb,0x96,0xff,0x24,0x6b,0x7b,0x5d,0x56,0x62,0x87,0x0d,0x1b,0xa5,0x87,0xb0,0x3d,0x6e,0x13,0x60,0xba,0xf4,0x79,0x88,0xb5,0xc0,0x2c,0xcc,0x1a,0x5b,0x02,0x20,0x5f,0x00,0xc3,0x23,0x27,0x20,0x83,0x78,0x2d,0x4a,0x59,0xf2,0xdf,0xd6,0x5e,0x49,0xde,0x06,0x93,0x62,0x70,0x16,0x90,0x0e,0xf7,0xe6,0x14,0x28,0x05,0x66,0x64,0xb3,
+ 0x30,0x44,0x02,0x20,0x00,0xa1,0x34,0xb5,0xc6,0xcc,0xbc,0xef,0xd4,0xc8,0x82,0xb9,0x45,0xba,0xeb,0x49,0x33,0x44,0x41,0x72,0x79,0x5f,0xa6,0x79,0x6a,0xae,0x14,0x90,0x67,0x54,0x70,0x98,0x02,0x20,0x56,0x6e,0x46,0x10,0x5d,0x24,0xd8,0x90,0x15,0x1e,0x3e,0xea,0x3e,0xbf,0x88,0xf5,0xb9,0x2b,0x3f,0x5e,0xc9,0x3a,0x21,0x77,0x65,0xa6,0xdc,0xbd,0x94,0xf2,0xc5,0x5b,
+ 0x30,0x44,0x02,0x20,0x2e,0x47,0x21,0x36,0x3a,0xd3,0x99,0x2c,0x13,0x9e,0x5a,0x1c,0x26,0x39,0x5d,0x2c,0x2d,0x77,0x78,0x24,0xaa,0x24,0xfd,0xe0,0x75,0xe0,0xd7,0x38,0x11,0x71,0x30,0x9d,0x02,0x20,0x74,0x0f,0x7c,0x49,0x44,0x18,0xe1,0x30,0x0d,0xd4,0x51,0x2f,0x78,0x2a,0x58,0x80,0x0b,0xff,0x6a,0x7a,0xbd,0xfd,0xd2,0x0f,0xbb,0xd4,0xf0,0x55,0x15,0xca,0x1a,0x4f,
+ 0x30,0x44,0x02,0x20,0x68,0x52,0xe9,0xd3,0xcd,0x9f,0xe3,0x73,0xc2,0xd5,0x04,0x87,0x79,0x67,0xd3,0x65,0xab,0x14,0x56,0x70,0x7b,0x68,0x17,0xa0,0x42,0x86,0x46,0x94,0xe1,0x96,0x0c,0xcf,0x02,0x20,0x06,0x4b,0x27,0xea,0x14,0x2b,0x30,0x88,0x7b,0x84,0xc8,0x6a,0xdc,0xcb,0x2f,0xa3,0x9a,0x69,0x11,0xad,0x21,0xfc,0x7e,0x81,0x9f,0x59,0x3b,0xe5,0x2b,0xc4,0xf3,0xbd,
+ 0x30,0x44,0x02,0x20,0x18,0x8a,0x8c,0x56,0x48,0xdc,0x79,0xea,0xce,0x15,0x8c,0xf8,0x86,0xc6,0x2b,0x54,0x68,0xf0,0x5f,0xd9,0x5f,0x03,0xa7,0x63,0x5c,0x5b,0x4c,0x31,0xf0,0x9a,0xf4,0xc5,0x02,0x20,0x36,0x36,0x1a,0x0b,0x57,0x1a,0x00,0xc6,0xcd,0x5e,0x68,0x6c,0xcb,0xfc,0xfa,0x70,0x3c,0x4f,0x97,0xe4,0x89,0x38,0x34,0x6d,0x0c,0x10,0x3f,0xdc,0x76,0xdc,0x58,0x67,
+ 0x30,0x45,0x02,0x21,0x00,0xa7,0x4f,0x1f,0xb9,0xa8,0x26,0x3f,0x62,0xfc,0x44,0x16,0xa5,0xb7,0xd5,0x84,0xf4,0x20,0x6f,0x39,0x96,0xbb,0x91,0xf6,0xfc,0x8e,0x73,0xb9,0xe9,0x2b,0xad,0x0e,0x13,0x02,0x20,0x68,0x15,0x03,0x2e,0x8c,0x7d,0x76,0xc3,0xab,0x06,0xa8,0x6f,0x33,0x24,0x9c,0xe9,0x94,0x01,0x48,0xcb,0x36,0xd1,0xf4,0x17,0xc2,0xe9,0x92,0xe8,0x01,0xaf,0xa3,0xfa,
+ 0x30,0x44,0x02,0x20,0x07,0x24,0x48,0x65,0xb7,0x2f,0xf3,0x7e,0x62,0xe3,0x14,0x6f,0x0d,0xc1,0x46,0x82,0xba,0xdd,0x71,0x97,0x79,0x91,0x35,0xf0,0xb0,0x0a,0xde,0x76,0x71,0x74,0x2b,0xfe,0x02,0x20,0x0d,0x80,0xc2,0x23,0x8e,0xdb,0x4e,0x4a,0x7a,0x86,0xa8,0xc5,0x7c,0xa9,0xaf,0x17,0x11,0xf4,0x06,0xf7,0xf5,0xda,0x02,0x99,0xaa,0x04,0xe2,0x93,0x2d,0x96,0x07,0x54,
+ 0x30,0x45,0x02,0x21,0x00,0xda,0x7f,0xdd,0x05,0xb5,0xba,0xda,0xbd,0x61,0x9d,0x80,0x5c,0x4e,0xe7,0xd9,0xa8,0x4f,0x84,0xdd,0xd5,0xcf,0x9c,0x5b,0xf4,0xd4,0x33,0x81,0x40,0xd6,0x89,0xef,0x08,0x02,0x20,0x28,0xf1,0xcf,0x4f,0xa1,0xc3,0xc5,0x86,0x2c,0xfa,0x14,0x9c,0x00,0x13,0xcf,0x5f,0xe6,0xcf,0x50,0x76,0xca,0xe0,0x00,0x51,0x10,0x63,0xe7,0xde,0x25,0xbb,0x38,0xe5,
+ 0x30,0x45,0x02,0x21,0x00,0xd3,0x02,0x7c,0x65,0x6f,0x6d,0x4f,0xdf,0xd8,0xed,0xe2,0x20,0x93,0xe3,0xc3,0x03,0xb0,0x13,0x3c,0x34,0x0d,0x61,0x5e,0x77,0x56,0xf6,0x25,0x3a,0xea,0x92,0x72,0x38,0x02,0x20,0x09,0xae,0xf0,0x60,0xc8,0xe4,0xce,0xf9,0x72,0x97,0x40,0x11,0x55,0x8d,0xf1,0x44,0xfe,0xd2,0x5c,0xa6,0x9a,0xe8,0xd0,0xb2,0xea,0xf1,0xa8,0xfe,0xef,0xbe,0xc4,0x17,
+ 0x30,0x44,0x02,0x20,0x0b,0xf6,0xc0,0x18,0x8d,0xc9,0x57,0x1c,0xd0,0xe2,0x1e,0xec,0xac,0x5f,0xbb,0x19,0xd2,0x43,0x49,0x88,0xe9,0xcc,0x10,0x24,0x45,0x93,0xef,0x3a,0x98,0x09,0x9f,0x69,0x02,0x20,0x48,0x64,0xa5,0x62,0x66,0x1f,0x92,0x21,0xec,0x88,0xe3,0xdd,0x0b,0xc2,0xf6,0xe2,0x7a,0xc1,0x28,0xc3,0x0c,0xc1,0xa8,0x0f,0x79,0xec,0x67,0x0a,0x22,0xb0,0x42,0xee,
+ 0x30,0x45,0x02,0x21,0x00,0xae,0x45,0x96,0x40,0xd5,0xd1,0x17,0x9b,0xe4,0x7a,0x47,0xfa,0x53,0x8e,0x16,0xd9,0x4d,0xde,0xa5,0x58,0x5e,0x7a,0x24,0x48,0x04,0xa5,0x17,0x42,0xc6,0x86,0x44,0x3a,0x02,0x20,0x6c,0x8e,0x30,0xe5,0x30,0xa6,0x34,0xfa,0xe8,0x0b,0x3c,0xeb,0x06,0x29,0x78,0xb3,0x9e,0xdb,0xe1,0x97,0x77,0xe0,0xa2,0x45,0x53,0xb6,0x88,0x86,0x18,0x1f,0xd8,0x97,
+ 0x30,0x44,0x02,0x20,0x1c,0xf3,0x51,0x7b,0xa3,0xbf,0x2a,0xb8,0xb9,0xea,0xd4,0xeb,0xb6,0xe8,0x66,0xcb,0x88,0xa1,0xde,0xac,0xb6,0xa7,0x85,0xd3,0xb6,0x3b,0x48,0x3c,0xa0,0x2a,0xc4,0x95,0x02,0x20,0x24,0x9a,0x79,0x8b,0x73,0x60,0x6f,0x55,0xf5,0xf1,0xc7,0x0d,0xe6,0x7c,0xb1,0xa0,0xcf,0xf9,0x5d,0x7d,0xc5,0x0b,0x3a,0x61,0x7d,0xf8,0x61,0xba,0xd3,0xc6,0xb1,0xc9,
+ 0x30,0x45,0x02,0x21,0x00,0xe6,0x9b,0x52,0x38,0x26,0x5e,0xa3,0x5d,0x77,0xe4,0xdd,0x17,0x22,0x88,0xd8,0xce,0xa1,0x98,0x10,0xa1,0x02,0x92,0x61,0x7d,0x59,0x76,0x51,0x9d,0xc5,0x75,0x7c,0xb8,0x02,0x20,0x4b,0x03,0xc5,0xbc,0x47,0xe8,0x26,0xbd,0xb2,0x73,0x28,0xab,0xd3,0x8d,0x30,0x56,0xd7,0x74,0x76,0xb2,0x13,0x0f,0x3d,0xf6,0xec,0x48,0x91,0xaf,0x08,0xba,0x1e,0x29,
+ 0x30,0x44,0x02,0x20,0x5f,0x9d,0x7d,0x7c,0x87,0x0d,0x08,0x5f,0xc1,0xd4,0x9f,0xff,0x69,0xe4,0xa2,0x75,0x81,0x28,0x00,0xd2,0xcf,0x89,0x73,0xe7,0x32,0x58,0x66,0xcb,0x40,0xfa,0x2b,0x6f,0x02,0x20,0x6d,0x1f,0x54,0x91,0xd9,0xf7,0x17,0xa5,0x97,0xa1,0x5f,0xd5,0x40,0x40,0x64,0x86,0xd7,0x6a,0x44,0x69,0x7b,0x3f,0x0d,0x9d,0x6d,0xce,0xf6,0x66,0x9f,0x8a,0x0a,0x56,
+ 0x30,0x44,0x02,0x20,0x0a,0x7d,0x5b,0x19,0x59,0xf7,0x1d,0xf9,0xf8,0x17,0x14,0x6e,0xe4,0x9b,0xd5,0xc8,0x9b,0x43,0x1e,0x79,0x93,0xe2,0xfd,0xec,0xab,0x68,0x58,0x95,0x7d,0xa6,0x85,0xae,0x02,0x20,0x0f,0x8a,0xad,0x2d,0x25,0x46,0x90,0xbd,0xc1,0x3f,0x34,0xa4,0xfe,0xc4,0x4a,0x02,0xfd,0x74,0x5a,0x42,0x2d,0xf0,0x5c,0xcb,0xb5,0x46,0x35,0xa8,0xb8,0x6b,0x96,0x09,
+ 0x30,0x44,0x02,0x20,0x79,0xe8,0x8b,0xf5,0x76,0xb7,0x4b,0xc0,0x7c,0xa1,0x42,0x39,0x5f,0xda,0x28,0xf0,0x3d,0x3d,0x5e,0x64,0x0b,0x0b,0x4f,0xf0,0x75,0x2c,0x6d,0x94,0xcd,0x55,0x34,0x08,0x02,0x20,0x32,0xce,0xa0,0x5b,0xd2,0xd7,0x06,0xc8,0xf6,0x03,0x6a,0x50,0x7e,0x2a,0xb7,0x76,0x60,0x04,0xf0,0x90,0x4e,0x2e,0x5c,0x58,0x62,0x74,0x9c,0x00,0x73,0x24,0x5d,0x6a,
+ 0x30,0x45,0x02,0x21,0x00,0x9d,0x54,0xe0,0x37,0xa0,0x02,0x12,0xb3,0x77,0xbc,0x88,0x74,0x79,0x8b,0x8d,0xa0,0x80,0x56,0x4b,0xbd,0xf7,0xe0,0x75,0x91,0xb8,0x61,0x28,0x58,0x09,0xd0,0x14,0x88,0x02,0x20,0x18,0xb4,0xe5,0x57,0x66,0x7a,0x82,0xbd,0x95,0x96,0x5f,0x07,0x06,0xf8,0x1a,0x29,0x24,0x3f,0xbd,0xd8,0x69,0x68,0xa7,0xeb,0xeb,0x43,0x06,0x9d,0xb3,0xb1,0x8c,0x7f,
+ 0x30,0x44,0x02,0x20,0x26,0x64,0xf1,0xff,0xa9,0x82,0xfe,0xdb,0xcc,0x7c,0xab,0x1b,0x8b,0xc6,0xe2,0xcb,0x42,0x02,0x18,0xd2,0xa6,0x07,0x7a,0xd0,0x8e,0x59,0x1b,0xa9,0xfe,0xab,0x33,0xbd,0x02,0x20,0x49,0xf5,0xc7,0xcb,0x51,0x5e,0x83,0x87,0x2a,0x3d,0x41,0xb4,0xcd,0xb8,0x5f,0x24,0x2a,0xd9,0xd6,0x1a,0x5b,0xfc,0x01,0xde,0xbf,0xbb,0x52,0xc6,0xc8,0x4b,0xa7,0x28,
+ 0x30,0x44,0x02,0x20,0x58,0x27,0x51,0x83,0x44,0x84,0x4f,0xd6,0xa7,0xde,0x73,0xcb,0xb0,0xa6,0xbe,0xfd,0xea,0x7b,0x13,0xd2,0xde,0xe4,0x47,0x53,0x17,0xf0,0xf1,0x8f,0xfc,0x81,0x52,0x4b,0x02,0x20,0x4f,0x5c,0xcb,0x4e,0x0b,0x48,0x8b,0x5a,0x5d,0x76,0x0a,0xac,0xdd,0xb2,0xd7,0x91,0x97,0x0f,0xe4,0x3d,0xa6,0x1e,0xb3,0x0e,0x2e,0x90,0x20,0x8a,0x81,0x7e,0x46,0xdb,
+ 0x30,0x45,0x02,0x21,0x00,0x97,0xab,0x19,0xbd,0x13,0x9c,0xac,0x31,0x93,0x25,0x86,0x92,0x18,0xb1,0xbc,0xe1,0x11,0x87,0x5d,0x63,0xfb,0x12,0x09,0x8a,0x04,0xb0,0xcd,0x59,0xb6,0xfd,0xd3,0xa3,0x02,0x20,0x43,0x1d,0x9c,0xea,0x3a,0x24,0x38,0x47,0x30,0x3c,0xeb,0xda,0x56,0x47,0x64,0x31,0xd0,0x34,0x33,0x9f,0x31,0xd7,0x85,0xee,0x88,0x52,0xdb,0x4f,0x04,0x0d,0x49,0x21,
+ 0x30,0x44,0x02,0x20,0x52,0xc6,0x83,0x14,0x4e,0x44,0x11,0x9a,0xe2,0x01,0x37,0x49,0xd4,0x96,0x4e,0xf6,0x75,0x09,0x27,0x8f,0x6d,0x38,0xba,0x86,0x9a,0xdc,0xfa,0x69,0x97,0x0e,0x12,0x3d,0x02,0x20,0x34,0x79,0x91,0x01,0x67,0x40,0x8f,0x45,0xbd,0xa4,0x20,0xa6,0x26,0xec,0x9c,0x4e,0xc7,0x11,0xc1,0x27,0x4b,0xe0,0x92,0x19,0x8b,0x41,0x87,0xc0,0x18,0xb5,0x62,0xca,
+ 0x30,0x16,0x02,0x11,0x01,0x45,0x51,0x23,0x19,0x50,0xb7,0x5f,0xc4,0x40,0x2d,0xa1,0x72,0x2f,0xc9,0xba,0xeb,0x02,0x01,0x03,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xfc,0x2c,0x02,0x01,0x03,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x3f,0x02,0x01,0x03,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x9a,0x75,0x82,0x88,0x60,0x89,0xc6,0x2f,0xb8,0x40,0xcf,0x3b,0x83,0x06,0x1c,0xd1,0xcf,0xf3,0xae,0x43,0x41,0x80,0x8b,0xb5,0xbd,0xee,0x61,0x91,0x17,0x41,0x77,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x24,0x23,0x8e,0x70,0xb4,0x31,0xb1,0xa6,0x4e,0xfd,0xf9,0x03,0x26,0x69,0x93,0x9d,0x4b,0x77,0xf2,0x49,0x50,0x3f,0xc6,0x90,0x5f,0xeb,0x75,0x40,0xde,0xa3,0xe6,0xd2,
+ 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x02,
+ 0x30,0x06,0x02,0x01,0x01,0x02,0x01,0x03,
+ 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x01,
+ 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x02,
+ 0x30,0x06,0x02,0x01,0x02,0x02,0x01,0x03,
+ 0x30,0x26,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x41,0x43,0x02,0x01,0x03,
+ 0x30,0x08,0x02,0x01,0x02,0x02,0x03,0xed,0x29,0x79,
+ 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0xe9,0xd3,0xa7,0x4e,0x9d,0x3a,0x74,0x9f,0x8a,0xb3,0x73,0x2a,0x0a,0x89,0x60,0x4a,0x09,0xbc,0xe5,0xb2,0x91,0x6d,0xa4,
+ 0x30,0x2b,0x02,0x07,0x2d,0x9b,0x4d,0x34,0x79,0x52,0xcc,0x02,0x20,0x03,0x43,0xae,0xfc,0x2f,0x25,0xd9,0x8b,0x88,0x2e,0x86,0xeb,0x9e,0x30,0xd5,0x5a,0x6e,0xb5,0x08,0xb5,0x16,0x51,0x0b,0x34,0x02,0x4a,0xe4,0xb6,0x36,0x23,0x30,0xb3,
+ 0x30,0x31,0x02,0x0d,0x10,0x33,0xe6,0x7e,0x37,0xb3,0x2b,0x44,0x55,0x80,0xbf,0x4e,0xfc,0x02,0x20,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x90,0x6f,0x8f,0xe1,0xca,0xb5,0xee,0xfd,0xb2,0x14,0x06,0x1d,0xce,0x3b,0x22,0x78,0x9f,0x1d,0x6f,
+ 0x30,0x26,0x02,0x02,0x01,0x01,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57,
+ 0x30,0x31,0x02,0x0d,0x06,0x25,0x22,0xbb,0xd3,0xec,0xbe,0x7c,0x39,0xe9,0x3e,0x7c,0x26,0x02,0x20,0x78,0x32,0x66,0xe9,0x0f,0x43,0xda,0xfe,0x5c,0xd9,0xb3,0xb0,0xbe,0x86,0xde,0x22,0xf9,0xde,0x83,0x67,0x7d,0x0f,0x50,0x71,0x3a,0x46,0x8e,0xc7,0x2f,0xcf,0x5d,0x57,
+ 0x30,0x45,0x02,0x21,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xba,0xae,0xdc,0xe6,0xaf,0x48,0xa0,0x3b,0xbf,0xd2,0x5e,0x8c,0xd0,0x36,0x40,0xc1,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,
+ 0x30,0x16,0x02,0x09,0x00,0x9c,0x44,0xfe,0xbf,0x31,0xc3,0x59,0x4d,0x02,0x09,0x00,0x83,0x9e,0xd2,0x82,0x47,0xc2,0xb0,0x6b,
+ 0x30,0x1e,0x02,0x0d,0x09,0xdf,0x8b,0x68,0x24,0x30,0xbe,0xef,0x6f,0x5f,0xd7,0xc7,0xcf,0x02,0x0d,0x0f,0xd0,0xa6,0x2e,0x13,0x77,0x8f,0x42,0x22,0xa0,0xd6,0x1c,0x8a,
+ 0x30,0x26,0x02,0x11,0x00,0x8a,0x59,0x8e,0x56,0x3a,0x89,0xf5,0x26,0xc3,0x2e,0xbe,0xc8,0xde,0x26,0x36,0x7a,0x02,0x11,0x00,0x84,0xf6,0x33,0xe2,0x04,0x26,0x30,0xe9,0x9d,0xd0,0xf1,0xe1,0x6f,0x7a,0x04,0xbf,
+ 0x30,0x2e,0x02,0x15,0x00,0xaa,0x6e,0xeb,0x58,0x23,0xf7,0xfa,0x31,0xb4,0x66,0xbb,0x47,0x37,0x97,0xf0,0xd0,0x31,0x4c,0x0b,0xdf,0x02,0x15,0x00,0xe2,0x97,0x7c,0x47,0x9e,0x6d,0x25,0x70,0x3c,0xeb,0xbc,0x6b,0xd5,0x61,0x93,0x8c,0xc9,0xd1,0xbf,0xb9,
+ 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x01,
+ 0x30,0x25,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x01,0x00,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x41,0x9d,0x98,0x1c,0x51,0x5a,0xf8,0xcc,0x82,0x54,0x5a,0xac,0x0c,0x85,0xe9,0xe3,0x08,0xfb,0xb2,0xea,0xb6,0xac,0xd7,0xed,0x49,0x7e,0x0b,0x41,0x45,0xa1,0x8f,0xd9,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x1b,0x21,0x71,0x7a,0xd7,0x1d,0x23,0xbb,0xac,0x60,0xa9,0xad,0x0b,0xaf,0x75,0xb0,0x63,0xc9,0xfd,0xf5,0x2a,0x00,0xeb,0xf9,0x9d,0x02,0x21,0x72,0x91,0x09,0x93,0xc9,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x2f,0x58,0x8f,0x66,0x01,0x8f,0x3d,0xd1,0x4d,0xb3,0xe2,0x8e,0x77,0x99,0x64,0x87,0xe3,0x24,0x86,0xb5,0x21,0xed,0x8e,0x5a,0x20,0xf0,0x65,0x91,0x95,0x17,0x77,0xe9,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x09,0x1a,0x08,0x87,0x0f,0xf4,0xda,0xf9,0x12,0x3b,0x30,0xc2,0x0e,0x8c,0x4f,0xc8,0x50,0x57,0x58,0xdc,0xf4,0x07,0x4f,0xca,0xff,0x21,0x70,0xc9,0xbf,0xcf,0x74,0xf4,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7c,0x37,0x0d,0xc0,0xce,0x8c,0x59,0xa8,0xb2,0x73,0xcb,0xa4,0x4a,0x7c,0x11,0x91,0xfc,0x31,0x86,0xdc,0x03,0xca,0xb9,0x6b,0x05,0x67,0x31,0x2d,0xf0,0xd0,0xb2,0x50,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x70,0xb5,0x9a,0x7d,0x1e,0xe7,0x7a,0x2f,0x9e,0x04,0x91,0xc2,0xa7,0xcf,0xcd,0x0e,0xd0,0x4d,0xf4,0xa3,0x51,0x92,0xf6,0x13,0x2d,0xcc,0x66,0x8c,0x79,0xa6,0x16,0x0e,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x27,0x36,0xd7,0x6e,0x41,0x22,0x46,0xe0,0x97,0x14,0x8e,0x2b,0xf6,0x29,0x15,0x61,0x4e,0xb7,0xc4,0x28,0x91,0x3a,0x58,0xeb,0x5e,0x9c,0xd4,0x67,0x4a,0x94,0x23,0xde,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4a,0x1e,0x12,0x83,0x1f,0xbe,0x93,0x62,0x7b,0x02,0xd6,0xe7,0xf2,0x4b,0xcc,0xdd,0x6e,0xf4,0xb2,0xd0,0xf4,0x67,0x39,0xea,0xf3,0xb1,0xea,0xf0,0xca,0x11,0x77,0x70,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x06,0xc7,0x78,0xd4,0xdf,0xff,0x7d,0xee,0x06,0xed,0x88,0xbc,0x4e,0x0e,0xd3,0x4f,0xc5,0x53,0xaa,0xd6,0x7c,0xaf,0x79,0x6f,0x2a,0x1c,0x64,0x87,0xc1,0xb2,0xe8,0x77,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x4d,0xe4,0x59,0xef,0x91,0x59,0xaf,0xa0,0x57,0xfe,0xb3,0xec,0x40,0xfe,0xf0,0x1c,0x45,0xb8,0x09,0xf4,0xab,0x29,0x6e,0xa4,0x8c,0x20,0x6d,0x42,0x49,0xa2,0xb4,0x51,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x74,0x5d,0x29,0x49,0x78,0x00,0x73,0x02,0x03,0x35,0x02,0xe1,0xac,0xc4,0x8b,0x63,0xae,0x65,0x00,0xbe,0x43,0xad,0xbe,0xa1,0xb2,0x58,0xd6,0xb4,0x23,0xdb,0xb4,0x16,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x7b,0x2a,0x78,0x5e,0x38,0x96,0xf5,0x9b,0x2d,0x69,0xda,0x57,0x64,0x8e,0x80,0xad,0x3c,0x13,0x3a,0x75,0x0a,0x28,0x47,0xfd,0x20,0x98,0xcc,0xd9,0x02,0x04,0x2b,0x6c,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x71,0xae,0x94,0xa7,0x2c,0xa8,0x96,0x87,0x5e,0x7a,0xa4,0xa4,0xc3,0xd2,0x9a,0xfd,0xb4,0xb3,0x5b,0x69,0x96,0x27,0x3e,0x63,0xc4,0x7a,0xc5,0x19,0x25,0x6c,0x5e,0xb1,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x0f,0xa5,0x27,0xfa,0x73,0x43,0xc0,0xbc,0x9e,0xc3,0x5a,0x62,0x78,0xbf,0xbf,0xf4,0xd8,0x33,0x01,0xb1,0x54,0xfc,0x4b,0xd1,0x4a,0xee,0x7e,0xb9,0x34,0x45,0xb5,0xf9,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc1,0x02,0x20,0x65,0x39,0xc0,0xad,0xad,0xd0,0x52,0x5f,0xf4,0x26,0x22,0x16,0x4c,0xe9,0x31,0x43,0x48,0xbd,0x08,0x63,0xb4,0xc8,0x0e,0x93,0x6b,0x23,0xca,0x04,0x14,0x26,0x46,0x71,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa0,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x57,0x6e,0x73,0x57,0xa4,0x50,0x1d,0xdf,0xe9,0x2f,0x46,0x68,0x1b,0x20,0xa1,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xb8,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x1c,0x94,0x0f,0x31,0x3f,0x92,0x64,0x7b,0xe2,0x57,0xec,0xcd,0x7e,0xd0,0x8b,0x0b,0xae,0xf3,0xf0,0x47,0x8f,0x25,0x87,0x1b,0x53,0x63,0x53,0x02,0xc5,0xf6,0x31,0x4a,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x15,0xd9,0x4a,0x85,0x07,0x7b,0x49,0x3f,0x91,0xcb,0x71,0x01,0xec,0x63,0xe1,0xb0,0x1b,0xe5,0x8b,0x59,0x4e,0x85,0x5f,0x45,0x05,0x0a,0x8c,0x14,0x06,0x2d,0x68,0x9b,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x1d,0x27,0xa7,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9d,0x9e,0xf3,0xb9,0xfb,0x58,0x38,0x54,0x18,0xd9,0xc9,0x82,0x10,0x50,0x77,0xd1,0xb7,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2d,0x85,0x89,0x6b,0x3e,0xb9,0xdb,0xb5,0xa5,0x2f,0x42,0xf9,0xc9,0x26,0x1e,0xd3,0xfc,0x46,0x64,0x4e,0xc6,0x5f,0x06,0xad,0xe3,0xfd,0x78,0xf2,0x57,0xe4,0x34,0x32,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x5b,0x0b,0x12,0xd6,0x7d,0x73,0xb7,0x6b,0x4a,0x5e,0x85,0xf3,0x92,0x4c,0x3d,0xa7,0xf8,0x8c,0xc8,0x9d,0x8c,0xbe,0x0d,0x5b,0xc7,0xfa,0xf1,0xe4,0xaf,0xc8,0x68,0x64,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x69,0x4c,0x14,0x62,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x09,0xe6,0x0e,0x68,0xb9,0x0d,0x0b,0x5e,0x6c,0x5d,0xdd,0xd0,0xcb,0x69,0x4d,0x87,0x99,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3d,0x7f,0x48,0x7c,0x07,0xbf,0xc5,0xf3,0x08,0x46,0x93,0x8a,0x3d,0xce,0xf6,0x96,0x44,0x47,0x07,0xcf,0x96,0x77,0x25,0x4a,0x92,0xb0,0x6c,0x63,0xab,0x86,0x7d,0x22,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6c,0x76,0x48,0xfc,0x0f,0xbf,0x8a,0x06,0xad,0xb8,0xb8,0x39,0xf9,0x7b,0x4f,0xf7,0xa8,0x00,0xf1,0x1b,0x1e,0x37,0xc5,0x93,0xb2,0x61,0x39,0x45,0x99,0x79,0x2b,0xa4,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x1c,0x9c,0x5d,0x79,0x0d,0xc0,0x9c,0xdd,0x3d,0xfa,0xbb,0x62,0xcd,0xf4,0x53,0xe6,0x97,0x47,0xa7,0xe3,0xd7,0xaa,0x1a,0x71,0x41,0x89,0xef,0x53,0x17,0x1a,0x99,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x29,0x79,0x8c,0x5c,0x45,0xbd,0xf5,0x8b,0x4a,0x7b,0x2f,0xdc,0x2c,0x46,0xab,0x4a,0xf1,0x21,0x8c,0x7e,0xeb,0x9f,0x0f,0x27,0xa8,0x8f,0x12,0x67,0x67,0x4d,0xe3,0xb0,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x0b,0x70,0xf2,0x2c,0xa2,0xbb,0x3c,0xef,0xad,0xca,0x1a,0x57,0x11,0xfa,0x3a,0x59,0xf4,0x69,0x53,0x85,0xeb,0x5a,0xed,0xf3,0x49,0x5d,0x0b,0x6d,0x00,0xf8,0xfd,0x85,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x16,0xe1,0xe4,0x59,0x45,0x76,0x79,0xdf,0x5b,0x94,0x34,0xae,0x23,0xf4,0x74,0xb3,0xe8,0xd2,0xa7,0x0b,0xd6,0xb5,0xdb,0xe6,0x92,0xba,0x16,0xda,0x01,0xf1,0xfb,0x0a,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x22,0x52,0xd6,0x85,0xe8,0x31,0xb6,0xcf,0x09,0x5e,0x4f,0x05,0x35,0xee,0xaf,0x0d,0xdd,0x3b,0xfa,0x91,0xc2,0x10,0xc9,0xd9,0xdc,0x17,0x22,0x47,0x02,0xea,0xf8,0x8f,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x75,0x13,0x5a,0xbd,0x7c,0x42,0x5b,0x60,0x37,0x1a,0x47,0x7f,0x09,0xce,0x0f,0x27,0x4f,0x64,0xa8,0xc6,0xb0,0x61,0xa0,0x7b,0x5d,0x63,0xe9,0x3c,0x65,0x04,0x6c,0x53,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3e,0x88,0x83,0x77,0xac,0x6c,0x71,0xac,0x9d,0xec,0x3f,0xdb,0x9b,0x56,0xc9,0xfe,0xaf,0x0c,0xfa,0xca,0x9f,0x82,0x7f,0xc5,0xeb,0x65,0xfc,0x3e,0xac,0x81,0x12,0x10,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x30,0xbb,0xb7,0x94,0xdb,0x58,0x83,0x63,0xb4,0x06,0x79,0xf6,0xc1,0x82,0xa5,0x0d,0x3c,0xe9,0x67,0x9a,0xcd,0xd3,0xff,0xbe,0x36,0xd7,0x81,0x3d,0xac,0xbd,0xc8,0x18,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2c,0x37,0xfd,0x99,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc7,0xce,0xe7,0x45,0x11,0x0c,0xb4,0x5a,0xb5,0x58,0xed,0x7c,0x90,0xc1,0x5a,0x2f,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x7f,0xd9,0x95,0x62,0x2c,0x4f,0xb7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5d,0x88,0x3f,0xfa,0xb5,0xb3,0x26,0x52,0xcc,0xdc,0xaa,0x29,0x0f,0xcc,0xb9,0x7d,
+ 0x30,0x43,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x1f,0x4c,0xd5,0x3b,0xa7,0x60,0x8f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x9e,0x5c,0xf1,0x43,0xe2,0x53,0x96,0x26,0x19,0x0a,0x3a,0xb0,0x9c,0xce,0x47,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x56,0x22,0xc4,0xfb,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x92,0x8a,0x8f,0x1c,0x7a,0xc7,0xbe,0xc1,0x80,0x8b,0x9f,0x61,0xc0,0x1e,0xc3,0x27,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x44,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x04,0x10,0x41,0x03,0xb8,0x78,0x53,0xfd,0x3b,0x7d,0x3f,0x8e,0x17,0x51,0x25,0xb4,0x38,0x2f,0x25,0xed,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x27,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x39,0xce,0x73,0x9c,0xe7,0x05,0x56,0x02,0x98,0xd1,0xf2,0xf0,0x8d,0xc4,0x19,0xac,0x27,0x3a,0x5b,0x54,0xd9,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x48,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x31,0xc8,0x3a,0xe8,0x2e,0xbe,0x08,0x98,0x77,0x6b,0x4c,0x69,0xd1,0x1f,0x88,0xde,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x64,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x06,0xdd,0x3a,0x19,0xb8,0xd5,0xfb,0x87,0x52,0x35,0x96,0x3c,0x59,0x3b,0xd2,0xd3,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x15,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x2a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0x3e,0x3a,0x49,0xa2,0x3a,0x6d,0x8a,0xbe,0x95,0x46,0x1f,0x84,0x45,0x67,0x6b,0x17,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,
+ 0x30,0x44,0x02,0x20,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x02,0x20,0x18,0x5d,0xdb,0xca,0x6d,0xac,0x41,0xb1,0xda,0x03,0x3c,0xfb,0x60,0xc1,0x52,0x86,0x9e,0x74,0xb3,0xcd,0x66,0xe9,0xff,0xdf,0x1b,0x6b,0xc0,0x9e,0xd6,0x5e,0xe4,0x0c,
+ 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9,
+ 0x30,0x44,0x02,0x20,0x32,0xb0,0xd1,0x0d,0x8d,0x0e,0x04,0xbc,0x8d,0x4d,0x06,0x4d,0x27,0x06,0x99,0xe8,0x7c,0xff,0xc9,0xb4,0x9c,0x5c,0x20,0x73,0x0e,0x1c,0x26,0xf6,0x10,0x5d,0xdc,0xda,0x02,0x20,0x29,0xed,0x3d,0x67,0xb3,0xd5,0x05,0xbe,0x95,0x58,0x0d,0x77,0xd5,0xb7,0x92,0xb4,0x36,0x88,0x11,0x79,0xb2,0xb6,0xb2,0xe0,0x4c,0x5f,0xe5,0x92,0xd3,0x8d,0x82,0xd9,
+ 0x30,0x44,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,0x02,0x20,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x32,0xf2,0x22,0xf8,0xfa,0xef,0xdb,0x53,0x3f,0x26,0x5d,0x46,0x1c,0x29,0xa4,0x73,0x73,
+ 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,
+ 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5,
+ 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7,
+ 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7,
+ 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5,
+ 0x30,0x45,0x02,0x21,0x00,0xc6,0x04,0x7f,0x94,0x41,0xed,0x7d,0x6d,0x30,0x45,0x40,0x6e,0x95,0xc0,0x7c,0xd8,0x5c,0x77,0x8e,0x4b,0x8c,0xef,0x3c,0xa7,0xab,0xac,0x09,0xb9,0x5c,0x70,0x9e,0xe5,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b,
+ 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,0xe8,0xe4,0xf4,0x4c,0xe5,0x18,0x35,0x69,0x3f,0xf0,0xca,0x2e,0xf0,0x12,0x15,0xc0,
+ 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5,
+ 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7,
+ 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x65,0xe4,0x45,0xf1,0xf5,0xdf,0xb6,0xa6,0x7e,0x4c,0xba,0x8c,0x38,0x53,0x48,0xe6,0xe7,
+ 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x48,0xc7,0x9f,0xac,0xd4,0x32,0x14,0xc0,0x11,0x12,0x3c,0x1b,0x03,0xa9,0x34,0x12,0xa5,
+ 0x30,0x44,0x02,0x20,0x79,0xbe,0x66,0x7e,0xf9,0xdc,0xbb,0xac,0x55,0xa0,0x62,0x95,0xce,0x87,0x0b,0x07,0x02,0x9b,0xfc,0xdb,0x2d,0xce,0x28,0xd9,0x59,0xf2,0x81,0x5b,0x16,0xf8,0x17,0x98,0x02,0x20,0x0e,0xb1,0x0e,0x5a,0xb9,0x5f,0x2f,0x27,0x53,0x48,0xd8,0x2a,0xd2,0xe4,0xd7,0x94,0x9c,0x81,0x93,0x80,0x0d,0x8c,0x9c,0x75,0xdf,0x58,0xe3,0x43,0xf0,0xeb,0xba,0x7b,
+ 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52,
+ 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52,
+ 0x30,0x45,0x02,0x21,0x00,0xbb,0x5a,0x52,0xf4,0x2f,0x9c,0x92,0x61,0xed,0x43,0x61,0xf5,0x94,0x22,0xa1,0xe3,0x00,0x36,0xe7,0xc3,0x2b,0x27,0x0c,0x88,0x07,0xa4,0x19,0xfe,0xca,0x60,0x50,0x23,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52,
+ 0x30,0x44,0x02,0x20,0x44,0xa5,0xad,0x0b,0xd0,0x63,0x6d,0x9e,0x12,0xbc,0x9e,0x0a,0x6b,0xdd,0x5e,0x1b,0xba,0x77,0xf5,0x23,0x84,0x21,0x93,0xb3,0xb8,0x2e,0x44,0x8e,0x05,0xd5,0xf1,0x1e,0x02,0x20,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x63,0xcf,0xd6,0x6a,0x19,0x0a,0x60,0x08,0x89,0x1e,0x0d,0x81,0xd4,0x9a,0x09,0x52,
+ 0x30,0x45,0x02,0x21,0x00,0xf8,0x0a,0xe4,0xf9,0x6c,0xdb,0xc9,0xd8,0x53,0xf8,0x3d,0x47,0xaa,0xe2,0x25,0xbf,0x40,0x7d,0x51,0xc5,0x6b,0x77,0x76,0xcd,0x67,0xd0,0xdc,0x19,0x5d,0x99,0xa9,0xdc,0x02,0x20,0x4c,0xfc,0x1d,0x94,0x1e,0x08,0xcb,0x9a,0xce,0xad,0xde,0x0f,0x4c,0xce,0xad,0x76,0xb3,0x0d,0x33,0x2f,0xc4,0x42,0x11,0x5d,0x50,0xe6,0x73,0xe2,0x86,0x86,0xb7,0x0b,
+ 0x30,0x44,0x02,0x20,0x10,0x9c,0xd8,0xae,0x03,0x74,0x35,0x89,0x84,0xa8,0x24,0x9c,0x0a,0x84,0x36,0x28,0xf2,0x83,0x5f,0xfa,0xd1,0xdf,0x1a,0x9a,0x69,0xaa,0x2f,0xe7,0x23,0x55,0x54,0x5c,0x02,0x20,0x53,0x90,0xff,0x25,0x0a,0xc4,0x27,0x4e,0x1c,0xb2,0x5c,0xd6,0xca,0x64,0x91,0xf6,0xb9,0x12,0x81,0xe3,0x2f,0x5b,0x26,0x4d,0x87,0x97,0x7a,0xed,0x4a,0x94,0xe7,0x7b,
+ 0x30,0x45,0x02,0x21,0x00,0xd0,0x35,0xee,0x1f,0x17,0xfd,0xb0,0xb2,0x68,0x1b,0x16,0x3e,0x33,0xc3,0x59,0x93,0x26,0x59,0x99,0x0a,0xf7,0x7d,0xca,0x63,0x20,0x12,0xb3,0x0b,0x27,0xa0,0x57,0xb3,0x02,0x20,0x19,0x39,0xd9,0xf3,0xb2,0x85,0x8b,0xc1,0x3e,0x34,0x74,0xcb,0x50,0xe6,0xa8,0x2b,0xe4,0x4f,0xaa,0x71,0x94,0x0f,0x87,0x6c,0x1c,0xba,0x4c,0x3e,0x98,0x92,0x02,0xb6,
+ 0x30,0x44,0x02,0x20,0x4f,0x05,0x3f,0x56,0x3a,0xd3,0x4b,0x74,0xfd,0x8c,0x99,0x34,0xce,0x59,0xe7,0x9c,0x2e,0xb8,0xe6,0xec,0xa0,0xfe,0xf5,0xb3,0x23,0xca,0x67,0xd5,0xac,0x7e,0xd2,0x38,0x02,0x20,0x4d,0x4b,0x05,0xda,0xa0,0x71,0x9e,0x77,0x3d,0x86,0x17,0xdc,0xe5,0x63,0x1c,0x5f,0xd6,0xf5,0x9c,0x9b,0xdc,0x74,0x8e,0x4b,0x55,0xc9,0x70,0x04,0x0a,0xf0,0x1b,0xe5,
+ 0x30,0x44,0x02,0x20,0x6d,0x6a,0x4f,0x55,0x6c,0xcc,0xe1,0x54,0xe7,0xfb,0x9f,0x19,0xe7,0x6c,0x3d,0xec,0xa1,0x3d,0x59,0xcc,0x2a,0xeb,0x4e,0xca,0xd9,0x68,0xaa,0xb2,0xde,0xd4,0x59,0x65,0x02,0x20,0x53,0xb9,0xfa,0x74,0x80,0x3e,0xde,0x0f,0xc4,0x44,0x1b,0xf6,0x83,0xd5,0x6c,0x56,0x4d,0x3e,0x27,0x4e,0x09,0xcc,0xf4,0x73,0x90,0xba,0xdd,0x14,0x71,0xc0,0x5f,0xb7,
+ 0x30,0x44,0x02,0x21,0x00,0xaa,0xd5,0x03,0xde,0x9b,0x9f,0xd6,0x6b,0x94,0x8e,0x9a,0xcf,0x59,0x6f,0x0a,0x0e,0x65,0xe7,0x00,0xb2,0x8b,0x26,0xec,0x56,0xe6,0xe4,0x5e,0x84,0x64,0x89,0xb3,0xc4,0x02,0x1f,0x0d,0xdc,0x3a,0x2f,0x89,0xab,0xb8,0x17,0xbb,0x85,0xc0,0x62,0xce,0x02,0xf8,0x23,0xc6,0x3f,0xc2,0x6b,0x26,0x9e,0x0b,0xc9,0xb8,0x4d,0x81,0xa5,0xaa,0x12,0x3d,
+ 0x30,0x45,0x02,0x21,0x00,0x91,0x82,0xce,0xbd,0x3b,0xb8,0xab,0x57,0x2e,0x16,0x71,0x74,0x39,0x72,0x09,0xef,0x4b,0x1d,0x43,0x9a,0xf3,0xb2,0x00,0xcd,0xf0,0x03,0x62,0x00,0x89,0xe4,0x32,0x25,0x02,0x20,0x54,0x47,0x7c,0x98,0x2e,0xa0,0x19,0xd2,0xe1,0x00,0x04,0x97,0xfc,0x25,0xfc,0xee,0x1b,0xcc,0xae,0x55,0xf2,0xac,0x27,0x53,0x0a,0xe5,0x3b,0x29,0xc4,0xb3,0x56,0xa4,
+ 0x30,0x44,0x02,0x20,0x38,0x54,0xa3,0x99,0x8a,0xeb,0xdf,0x2d,0xbc,0x28,0xad,0xac,0x41,0x81,0x46,0x2c,0xca,0xc7,0x87,0x39,0x07,0xab,0x7f,0x21,0x2c,0x42,0xdb,0x0e,0x69,0xb5,0x6e,0xd8,0x02,0x20,0x3e,0xd3,0xf6,0xb8,0xa3,0x88,0xd0,0x2f,0x3e,0x4d,0xf9,0xf2,0xae,0x9c,0x1b,0xd2,0xc3,0x91,0x6a,0x68,0x64,0x60,0xdf,0xfc,0xd4,0x29,0x09,0xcd,0x7f,0x82,0x05,0x8e,
+ 0x30,0x45,0x02,0x21,0x00,0xe9,0x4d,0xbd,0xc3,0x87,0x95,0xfe,0x5c,0x90,0x4d,0x8f,0x16,0xd9,0x69,0xd3,0xb5,0x87,0xf0,0xa2,0x5d,0x2d,0xe9,0x0b,0x6d,0x8c,0x5c,0x53,0xff,0x88,0x7e,0x36,0x07,0x02,0x20,0x7a,0x94,0x73,0x69,0xc1,0x64,0x97,0x25,0x21,0xbb,0x8a,0xf4,0x06,0x81,0x3b,0x2d,0x9f,0x94,0xd2,0xae,0xaa,0x53,0xd4,0xc2,0x15,0xaa,0xa0,0xa2,0x57,0x8a,0x2c,0x5d,
+ 0x30,0x44,0x02,0x20,0x49,0xfc,0x10,0x2a,0x08,0xca,0x47,0xb6,0x0e,0x08,0x58,0xcd,0x02,0x84,0xd2,0x2c,0xdd,0xd7,0x23,0x3f,0x94,0xaa,0xff,0xbb,0x2d,0xb1,0xdd,0x2c,0xf0,0x84,0x25,0xe1,0x02,0x20,0x5b,0x16,0xfc,0xa5,0xa1,0x2c,0xdb,0x39,0x70,0x16,0x97,0xad,0x8e,0x39,0xff,0xd6,0xbd,0xec,0x00,0x24,0x29,0x8a,0xfa,0xa2,0x32,0x6a,0xea,0x09,0x20,0x0b,0x14,0xd6,
+ 0x30,0x44,0x02,0x20,0x41,0xef,0xa7,0xd3,0xf0,0x5a,0x00,0x10,0x67,0x5f,0xcb,0x91,0x8a,0x45,0xc6,0x93,0xda,0x4b,0x34,0x8d,0xf2,0x1a,0x59,0xd6,0xf9,0xcd,0x73,0xe0,0xd8,0x31,0xd6,0x7a,0x02,0x20,0x44,0x54,0xad,0xa6,0x93,0xe5,0xe2,0x6b,0x7b,0xd6,0x93,0x23,0x6d,0x34,0x0f,0x80,0x54,0x5c,0x83,0x45,0x77,0xb6,0xf7,0x3d,0x37,0x8c,0x7b,0xcc,0x53,0x42,0x44,0xda,
+ 0x30,0x45,0x02,0x21,0x00,0xb6,0x15,0x69,0x8c,0x35,0x8b,0x35,0x92,0x0d,0xd8,0x83,0xec,0xa6,0x25,0xa6,0xc5,0xf7,0x56,0x39,0x70,0xcd,0xfc,0x37,0x8f,0x8f,0xe0,0xce,0xe1,0x70,0x92,0x14,0x4c,0x02,0x20,0x25,0xf4,0x7b,0x32,0x6b,0x5b,0xe1,0xfb,0x61,0x0b,0x88,0x51,0x53,0xea,0x84,0xd4,0x1e,0xb4,0x71,0x6b,0xe6,0x6a,0x99,0x4e,0x87,0x79,0x98,0x9d,0xf1,0xc8,0x63,0xd4,
+ 0x30,0x45,0x02,0x21,0x00,0x87,0xcf,0x8c,0x0e,0xb8,0x2d,0x44,0xf6,0x9c,0x60,0xa2,0xff,0x54,0x57,0xd3,0xaa,0xa3,0x22,0xe7,0xec,0x61,0xae,0x5a,0xec,0xfd,0x67,0x8a,0xe1,0xc1,0x93,0x2b,0x0e,0x02,0x20,0x3a,0xdd,0x3b,0x11,0x58,0x15,0x04,0x7d,0x6e,0xb3,0x40,0xa3,0xe0,0x08,0x98,0x9e,0xaa,0x0f,0x87,0x08,0xd1,0x79,0x48,0x14,0x72,0x90,0x94,0xd0,0x8d,0x24,0x60,0xd3,
+ 0x30,0x44,0x02,0x20,0x62,0xf4,0x8e,0xf7,0x1a,0xce,0x27,0xbf,0x5a,0x01,0x83,0x4d,0xe1,0xf7,0xe3,0xf9,0x48,0xb9,0xdc,0xe1,0xca,0x1e,0x91,0x1d,0x5e,0x13,0xd3,0xb1,0x04,0x47,0x1d,0x82,0x02,0x20,0x5e,0xa8,0xf3,0x3f,0x0c,0x77,0x89,0x72,0xc4,0x58,0x20,0x80,0xde,0xda,0x9b,0x34,0x18,0x57,0xdd,0x64,0x51,0x4f,0x08,0x49,0xa0,0x5f,0x69,0x64,0xc2,0xe3,0x40,0x22,
+ 0x30,0x45,0x02,0x21,0x00,0xf6,0xb0,0xe2,0xf6,0xfe,0x02,0x0c,0xf7,0xc0,0xc2,0x01,0x37,0x43,0x43,0x44,0xed,0x7a,0xdd,0x6c,0x4b,0xe5,0x18,0x61,0xe2,0xd1,0x4c,0xbd,0xa4,0x72,0xa6,0xff,0xb4,0x02,0x20,0x64,0x16,0xc8,0xdd,0x3e,0x5c,0x52,0x82,0xb3,0x06,0xe8,0xdc,0x8f,0xf3,0x4a,0xb6,0x4c,0xc9,0x95,0x49,0x23,0x2d,0x67,0x8d,0x71,0x44,0x02,0xeb,0x6c,0xa7,0xaa,0x0f,
+ 0x30,0x45,0x02,0x21,0x00,0xdb,0x09,0xd8,0x46,0x0f,0x05,0xef,0xf2,0x3b,0xc7,0xe4,0x36,0xb6,0x7d,0xa5,0x63,0xfa,0x4b,0x4e,0xdb,0x58,0xac,0x24,0xce,0x20,0x1f,0xa8,0xa3,0x58,0x12,0x50,0x57,0x02,0x20,0x46,0xda,0x11,0x67,0x54,0x60,0x29,0x40,0xc8,0x99,0x9c,0x8d,0x66,0x5f,0x78,0x6c,0x50,0xf5,0x77,0x2c,0x0a,0x3c,0xdb,0xda,0x07,0x5e,0x77,0xea,0xbc,0x64,0xdf,0x16,
+ 0x30,0x44,0x02,0x20,0x59,0x2c,0x41,0xe1,0x65,0x17,0xf1,0x2f,0xca,0xbd,0x98,0x26,0x76,0x74,0xf9,0x74,0xb5,0x88,0xe9,0xf3,0x5d,0x35,0x40,0x6c,0x1a,0x7b,0xb2,0xed,0x1d,0x19,0xb7,0xb8,0x02,0x20,0x3e,0x65,0xa0,0x6b,0xd9,0xf8,0x3c,0xaa,0xeb,0x7b,0x00,0xf2,0x36,0x8d,0x7e,0x0d,0xec,0xe6,0xb1,0x22,0x21,0x26,0x9a,0x9b,0x5b,0x76,0x51,0x98,0xf8,0x40,0xa3,0xa1,
+ 0x30,0x45,0x02,0x21,0x00,0xbe,0x0d,0x70,0x88,0x7d,0x5e,0x40,0x82,0x1a,0x61,0xb6,0x80,0x47,0xde,0x4e,0xa0,0x3d,0xeb,0xfd,0xf5,0x1c,0xdf,0x4d,0x4b,0x19,0x55,0x58,0xb9,0x59,0xa0,0x32,0xb2,0x02,0x20,0x7d,0x99,0x4b,0x2d,0x8f,0x1d,0xbb,0xeb,0x13,0x53,0x4e,0xb3,0xf6,0xe5,0xdc,0xcd,0x85,0xf5,0xc4,0x13,0x3c,0x27,0xd9,0xe6,0x42,0x71,0xb1,0x82,0x6c,0xe1,0xf6,0x7d,
+ 0x30,0x45,0x02,0x21,0x00,0xfa,0xe9,0x2d,0xfc,0xb2,0xee,0x39,0x2d,0x27,0x0a,0xf3,0xa5,0x73,0x9f,0xaa,0x26,0xd4,0xf9,0x7b,0xfd,0x39,0xed,0x3c,0xbe,0xe4,0xd2,0x9e,0x26,0xaf,0x3b,0x20,0x6a,0x02,0x20,0x6c,0x9b,0xa3,0x7f,0x9f,0xaa,0x6a,0x1f,0xd3,0xf6,0x5f,0x23,0xb4,0xe8,0x53,0xd4,0x69,0x2a,0x72,0x74,0x24,0x0a,0x12,0xdb,0x7b,0xa3,0x88,0x48,0x30,0x63,0x0d,0x16,
+ 0x30,0x44,0x02,0x20,0x17,0x6a,0x25,0x57,0x56,0x6f,0xfa,0x51,0x8b,0x11,0x22,0x66,0x94,0xeb,0x98,0x02,0xed,0x20,0x98,0xbf,0xe2,0x78,0xe5,0x57,0x0f,0xe1,0xd5,0xd7,0xaf,0x18,0xa9,0x43,0x02,0x20,0x12,0x91,0xdf,0x6a,0x0e,0xd5,0xfc,0x0d,0x15,0x09,0x8e,0x70,0xbc,0xf1,0x3a,0x00,0x92,0x84,0xdf,0xd0,0x68,0x9d,0x3b,0xb4,0xbe,0x6c,0xee,0xb9,0xbe,0x14,0x87,0xc4,
+ 0x30,0x44,0x02,0x20,0x60,0xbe,0x20,0xc3,0xdb,0xc1,0x62,0xdd,0x34,0xd2,0x67,0x80,0x62,0x1c,0x10,0x4b,0xbe,0x5d,0xac,0xe6,0x30,0x17,0x1b,0x2d,0xae,0xf0,0xd8,0x26,0x40,0x9e,0xe5,0xc2,0x02,0x20,0x42,0x7f,0x7e,0x4d,0x88,0x9d,0x54,0x91,0x70,0xbd,0xa6,0xa9,0x40,0x9f,0xb1,0xcb,0x8b,0x0e,0x76,0x3d,0x13,0xee,0xa7,0xbd,0x97,0xf6,0x4c,0xf4,0x1d,0xc6,0xe4,0x97,
+ 0x30,0x45,0x02,0x21,0x00,0xed,0xf0,0x3c,0xf6,0x3f,0x65,0x88,0x83,0x28,0x9a,0x1a,0x59,0x3d,0x10,0x07,0x89,0x5b,0x9f,0x23,0x6d,0x27,0xc9,0xc1,0xf1,0x31,0x30,0x89,0xaa,0xed,0x6b,0x16,0xae,0x02,0x20,0x1a,0x4d,0xd6,0xfc,0x08,0x14,0xdc,0x52,0x3d,0x1f,0xef,0xa8,0x1c,0x64,0xfb,0xf5,0xe6,0x18,0xe6,0x51,0xe7,0x09,0x6f,0xcc,0xad,0xbb,0x94,0xcd,0x48,0xe5,0xe0,0xcd};
+
+static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {
+ /* tcId: 1. Signature malleability */
+ {0, 0, 6, 0, 72, 0 },
+ /* tcId: 2. valid */
+ {0, 0, 6, 72, 71, 1 },
+ /* tcId: 3. length of sequence [r, s] uses long form encoding */
+ {0, 0, 6, 143, 72, 0 },
+ /* tcId: 4. length of sequence [r, s] contains a leading 0 */
+ {0, 0, 6, 215, 73, 0 },
+ /* tcId: 5. length of sequence [r, s] uses 70 instead of 69 */
+ {0, 0, 6, 288, 71, 0 },
+ /* tcId: 6. length of sequence [r, s] uses 68 instead of 69 */
+ {0, 0, 6, 359, 71, 0 },
+ /* tcId: 7. uint32 overflow in length of sequence [r, s] */
+ {0, 0, 6, 430, 76, 0 },
+ /* tcId: 8. uint64 overflow in length of sequence [r, s] */
+ {0, 0, 6, 506, 80, 0 },
+ /* tcId: 9. length of sequence [r, s] = 2**31 - 1 */
+ {0, 0, 6, 586, 75, 0 },
+ /* tcId: 10. length of sequence [r, s] = 2**31 */
+ {0, 0, 6, 661, 75, 0 },
+ /* tcId: 11. length of sequence [r, s] = 2**32 - 1 */
+ {0, 0, 6, 736, 75, 0 },
+ /* tcId: 12. length of sequence [r, s] = 2**40 - 1 */
+ {0, 0, 6, 811, 76, 0 },
+ /* tcId: 13. length of sequence [r, s] = 2**64 - 1 */
+ {0, 0, 6, 887, 79, 0 },
+ /* tcId: 14. incorrect length of sequence [r, s] */
+ {0, 0, 6, 966, 71, 0 },
+ /* tcId: 15. replaced sequence [r, s] by an indefinite length tag without termination */
+ {0, 0, 6, 1037, 71, 0 },
+ /* tcId: 16. removing sequence [r, s] */
+ {0, 0, 6, 1108, 0, 0 },
+ /* tcId: 17. lonely sequence tag */
+ {0, 0, 6, 1108, 1, 0 },
+ /* tcId: 18. appending 0's to sequence [r, s] */
+ {0, 0, 6, 1109, 73, 0 },
+ /* tcId: 19. prepending 0's to sequence [r, s] */
+ {0, 0, 6, 1182, 73, 0 },
+ /* tcId: 20. appending unused 0's to sequence [r, s] */
+ {0, 0, 6, 1255, 73, 0 },
+ /* tcId: 21. appending null value to sequence [r, s] */
+ {0, 0, 6, 1328, 73, 0 },
+ /* tcId: 22. prepending garbage to sequence [r, s] */
+ {0, 0, 6, 1401, 76, 0 },
+ /* tcId: 23. prepending garbage to sequence [r, s] */
+ {0, 0, 6, 1477, 75, 0 },
+ /* tcId: 24. appending garbage to sequence [r, s] */
+ {0, 0, 6, 1552, 79, 0 },
+ /* tcId: 25. including undefined tags */
+ {0, 0, 6, 1631, 79, 0 },
+ /* tcId: 26. including undefined tags */
+ {0, 0, 6, 1710, 79, 0 },
+ /* tcId: 27. including undefined tags */
+ {0, 0, 6, 1789, 79, 0 },
+ /* tcId: 28. truncated length of sequence [r, s] */
+ {0, 0, 6, 1868, 2, 0 },
+ /* tcId: 29. including undefined tags to sequence [r, s] */
+ {0, 0, 6, 1870, 77, 0 },
+ /* tcId: 30. using composition with indefinite length for sequence [r, s] */
+ {0, 0, 6, 1947, 75, 0 },
+ /* tcId: 31. using composition with wrong tag for sequence [r, s] */
+ {0, 0, 6, 2022, 75, 0 },
+ /* tcId: 32. Replacing sequence [r, s] with NULL */
+ {0, 0, 6, 2097, 2, 0 },
+ /* tcId: 33. changing tag value of sequence [r, s] */
+ {0, 0, 6, 2099, 71, 0 },
+ /* tcId: 34. changing tag value of sequence [r, s] */
+ {0, 0, 6, 2170, 71, 0 },
+ /* tcId: 35. changing tag value of sequence [r, s] */
+ {0, 0, 6, 2241, 71, 0 },
+ /* tcId: 36. changing tag value of sequence [r, s] */
+ {0, 0, 6, 2312, 71, 0 },
+ /* tcId: 37. changing tag value of sequence [r, s] */
+ {0, 0, 6, 2383, 71, 0 },
+ /* tcId: 38. dropping value of sequence [r, s] */
+ {0, 0, 6, 2454, 2, 0 },
+ /* tcId: 39. using composition for sequence [r, s] */
+ {0, 0, 6, 2456, 75, 0 },
+ /* tcId: 40. truncated sequence [r, s] */
+ {0, 0, 6, 2531, 70, 0 },
+ /* tcId: 41. truncated sequence [r, s] */
+ {0, 0, 6, 2601, 70, 0 },
+ /* tcId: 42. sequence [r, s] of size 4166 to check for overflows */
+ {0, 0, 6, 2671, 4170, 0 },
+ /* tcId: 43. indefinite length */
+ {0, 0, 6, 6841, 73, 0 },
+ /* tcId: 44. indefinite length with truncated delimiter */
+ {0, 0, 6, 6914, 72, 0 },
+ /* tcId: 45. indefinite length with additional element */
+ {0, 0, 6, 6986, 75, 0 },
+ /* tcId: 46. indefinite length with truncated element */
+ {0, 0, 6, 7061, 77, 0 },
+ /* tcId: 47. indefinite length with garbage */
+ {0, 0, 6, 7138, 77, 0 },
+ /* tcId: 48. indefinite length with nonempty EOC */
+ {0, 0, 6, 7215, 75, 0 },
+ /* tcId: 49. prepend empty sequence */
+ {0, 0, 6, 7290, 73, 0 },
+ /* tcId: 50. append empty sequence */
+ {0, 0, 6, 7363, 73, 0 },
+ /* tcId: 51. append zero */
+ {0, 0, 6, 7436, 74, 0 },
+ /* tcId: 52. append garbage with high tag number */
+ {0, 0, 6, 7510, 74, 0 },
+ /* tcId: 53. append null with explicit tag */
+ {0, 0, 6, 7584, 75, 0 },
+ /* tcId: 54. append null with implicit tag */
+ {0, 0, 6, 7659, 73, 0 },
+ /* tcId: 55. sequence of sequence */
+ {0, 0, 6, 7732, 73, 0 },
+ /* tcId: 56. truncated sequence: removed last 1 elements */
+ {0, 0, 6, 7805, 37, 0 },
+ /* tcId: 57. repeating element in sequence */
+ {0, 0, 6, 7842, 105, 0 },
+ /* tcId: 58. flipped bit 0 in r */
+ {0, 0, 6, 7947, 69, 0 },
+ /* tcId: 59. flipped bit 32 in r */
+ {0, 0, 6, 8016, 69, 0 },
+ /* tcId: 60. flipped bit 48 in r */
+ {0, 0, 6, 8085, 69, 0 },
+ /* tcId: 61. flipped bit 64 in r */
+ {0, 0, 6, 8154, 69, 0 },
+ /* tcId: 62. length of r uses long form encoding */
+ {0, 0, 6, 8223, 72, 0 },
+ /* tcId: 63. length of r contains a leading 0 */
+ {0, 0, 6, 8295, 73, 0 },
+ /* tcId: 64. length of r uses 34 instead of 33 */
+ {0, 0, 6, 8368, 71, 0 },
+ /* tcId: 65. length of r uses 32 instead of 33 */
+ {0, 0, 6, 8439, 71, 0 },
+ /* tcId: 66. uint32 overflow in length of r */
+ {0, 0, 6, 8510, 76, 0 },
+ /* tcId: 67. uint64 overflow in length of r */
+ {0, 0, 6, 8586, 80, 0 },
+ /* tcId: 68. length of r = 2**31 - 1 */
+ {0, 0, 6, 8666, 75, 0 },
+ /* tcId: 69. length of r = 2**31 */
+ {0, 0, 6, 8741, 75, 0 },
+ /* tcId: 70. length of r = 2**32 - 1 */
+ {0, 0, 6, 8816, 75, 0 },
+ /* tcId: 71. length of r = 2**40 - 1 */
+ {0, 0, 6, 8891, 76, 0 },
+ /* tcId: 72. length of r = 2**64 - 1 */
+ {0, 0, 6, 8967, 79, 0 },
+ /* tcId: 73. incorrect length of r */
+ {0, 0, 6, 9046, 71, 0 },
+ /* tcId: 74. replaced r by an indefinite length tag without termination */
+ {0, 0, 6, 9117, 71, 0 },
+ /* tcId: 75. removing r */
+ {0, 0, 6, 9188, 36, 0 },
+ /* tcId: 76. lonely integer tag */
+ {0, 0, 6, 9224, 37, 0 },
+ /* tcId: 77. lonely integer tag */
+ {0, 0, 6, 9261, 38, 0 },
+ /* tcId: 78. appending 0's to r */
+ {0, 0, 6, 9299, 73, 0 },
+ /* tcId: 79. prepending 0's to r */
+ {0, 0, 6, 9372, 73, 0 },
+ /* tcId: 80. appending unused 0's to r */
+ {0, 0, 6, 9445, 73, 0 },
+ /* tcId: 81. appending null value to r */
+ {0, 0, 6, 9518, 73, 0 },
+ /* tcId: 82. prepending garbage to r */
+ {0, 0, 6, 9591, 76, 0 },
+ /* tcId: 83. prepending garbage to r */
+ {0, 0, 6, 9667, 75, 0 },
+ /* tcId: 84. appending garbage to r */
+ {0, 0, 6, 9742, 79, 0 },
+ /* tcId: 85. truncated length of r */
+ {0, 0, 6, 9821, 38, 0 },
+ /* tcId: 86. including undefined tags to r */
+ {0, 0, 6, 9859, 77, 0 },
+ /* tcId: 87. using composition with indefinite length for r */
+ {0, 0, 6, 9936, 75, 0 },
+ /* tcId: 88. using composition with wrong tag for r */
+ {0, 0, 6, 10011, 75, 0 },
+ /* tcId: 89. Replacing r with NULL */
+ {0, 0, 6, 10086, 38, 0 },
+ /* tcId: 90. changing tag value of r */
+ {0, 0, 6, 10124, 71, 0 },
+ /* tcId: 91. changing tag value of r */
+ {0, 0, 6, 10195, 71, 0 },
+ /* tcId: 92. changing tag value of r */
+ {0, 0, 6, 10266, 71, 0 },
+ /* tcId: 93. changing tag value of r */
+ {0, 0, 6, 10337, 71, 0 },
+ /* tcId: 94. changing tag value of r */
+ {0, 0, 6, 10408, 71, 0 },
+ /* tcId: 95. dropping value of r */
+ {0, 0, 6, 10479, 38, 0 },
+ /* tcId: 96. using composition for r */
+ {0, 0, 6, 10517, 75, 0 },
+ /* tcId: 97. modifying first byte of r */
+ {0, 0, 6, 10592, 71, 0 },
+ /* tcId: 98. modifying last byte of r */
+ {0, 0, 6, 10663, 71, 0 },
+ /* tcId: 99. truncated r */
+ {0, 0, 6, 10734, 70, 0 },
+ /* tcId: 100. truncated r */
+ {0, 0, 6, 10804, 70, 0 },
+ /* tcId: 101. r of size 4130 to check for overflows */
+ {0, 0, 6, 10874, 4172, 0 },
+ /* tcId: 102. leading ff in r */
+ {0, 0, 6, 15046, 72, 0 },
+ /* tcId: 103. replaced r by infinity */
+ {0, 0, 6, 15118, 39, 0 },
+ /* tcId: 104. replacing r with zero */
+ {0, 0, 6, 15157, 39, 0 },
+ /* tcId: 105. flipped bit 0 in s */
+ {0, 0, 6, 15196, 69, 0 },
+ /* tcId: 106. flipped bit 32 in s */
+ {0, 0, 6, 15265, 69, 0 },
+ /* tcId: 107. flipped bit 48 in s */
+ {0, 0, 6, 15334, 69, 0 },
+ /* tcId: 108. flipped bit 64 in s */
+ {0, 0, 6, 15403, 69, 0 },
+ /* tcId: 109. length of s uses long form encoding */
+ {0, 0, 6, 15472, 72, 0 },
+ /* tcId: 110. length of s contains a leading 0 */
+ {0, 0, 6, 15544, 73, 0 },
+ /* tcId: 111. length of s uses 33 instead of 32 */
+ {0, 0, 6, 15617, 71, 0 },
+ /* tcId: 112. length of s uses 31 instead of 32 */
+ {0, 0, 6, 15688, 71, 0 },
+ /* tcId: 113. uint32 overflow in length of s */
+ {0, 0, 6, 15759, 76, 0 },
+ /* tcId: 114. uint64 overflow in length of s */
+ {0, 0, 6, 15835, 80, 0 },
+ /* tcId: 115. length of s = 2**31 - 1 */
+ {0, 0, 6, 15915, 75, 0 },
+ /* tcId: 116. length of s = 2**31 */
+ {0, 0, 6, 15990, 75, 0 },
+ /* tcId: 117. length of s = 2**32 - 1 */
+ {0, 0, 6, 16065, 75, 0 },
+ /* tcId: 118. length of s = 2**40 - 1 */
+ {0, 0, 6, 16140, 76, 0 },
+ /* tcId: 119. length of s = 2**64 - 1 */
+ {0, 0, 6, 16216, 79, 0 },
+ /* tcId: 120. incorrect length of s */
+ {0, 0, 6, 16295, 71, 0 },
+ /* tcId: 121. replaced s by an indefinite length tag without termination */
+ {0, 0, 6, 16366, 71, 0 },
+ /* tcId: 122. appending 0's to s */
+ {0, 0, 6, 16437, 73, 0 },
+ /* tcId: 123. prepending 0's to s */
+ {0, 0, 6, 16510, 73, 0 },
+ /* tcId: 124. appending null value to s */
+ {0, 0, 6, 16583, 73, 0 },
+ /* tcId: 125. prepending garbage to s */
+ {0, 0, 6, 16656, 76, 0 },
+ /* tcId: 126. prepending garbage to s */
+ {0, 0, 6, 16732, 75, 0 },
+ /* tcId: 127. appending garbage to s */
+ {0, 0, 6, 16807, 79, 0 },
+ /* tcId: 128. truncated length of s */
+ {0, 0, 6, 16886, 39, 0 },
+ /* tcId: 129. including undefined tags to s */
+ {0, 0, 6, 16925, 77, 0 },
+ /* tcId: 130. using composition with indefinite length for s */
+ {0, 0, 6, 17002, 75, 0 },
+ /* tcId: 131. using composition with wrong tag for s */
+ {0, 0, 6, 17077, 75, 0 },
+ /* tcId: 132. Replacing s with NULL */
+ {0, 0, 6, 17152, 39, 0 },
+ /* tcId: 133. changing tag value of s */
+ {0, 0, 6, 17191, 71, 0 },
+ /* tcId: 134. changing tag value of s */
+ {0, 0, 6, 17262, 71, 0 },
+ /* tcId: 135. changing tag value of s */
+ {0, 0, 6, 17333, 71, 0 },
+ /* tcId: 136. changing tag value of s */
+ {0, 0, 6, 17404, 71, 0 },
+ /* tcId: 137. changing tag value of s */
+ {0, 0, 6, 17475, 71, 0 },
+ /* tcId: 138. dropping value of s */
+ {0, 0, 6, 17546, 39, 0 },
+ /* tcId: 139. using composition for s */
+ {0, 0, 6, 17585, 75, 0 },
+ /* tcId: 140. modifying first byte of s */
+ {0, 0, 6, 17660, 71, 0 },
+ /* tcId: 141. modifying last byte of s */
+ {0, 0, 6, 17731, 71, 0 },
+ /* tcId: 142. truncated s */
+ {0, 0, 6, 17802, 70, 0 },
+ /* tcId: 143. truncated s */
+ {0, 0, 6, 17872, 70, 0 },
+ /* tcId: 144. s of size 4129 to check for overflows */
+ {0, 0, 6, 17942, 4172, 0 },
+ /* tcId: 145. leading ff in s */
+ {0, 0, 6, 22114, 72, 0 },
+ /* tcId: 146. replaced s by infinity */
+ {0, 0, 6, 22186, 40, 0 },
+ /* tcId: 147. replacing s with zero */
+ {0, 0, 6, 22226, 40, 0 },
+ /* tcId: 148. replaced r by r + n */
+ {0, 0, 6, 22266, 71, 0 },
+ /* tcId: 149. replaced r by r - n */
+ {0, 0, 6, 22337, 70, 0 },
+ /* tcId: 150. replaced r by r + 256 * n */
+ {0, 0, 6, 22407, 72, 0 },
+ /* tcId: 151. replaced r by -r */
+ {0, 0, 6, 22479, 71, 0 },
+ /* tcId: 152. replaced r by n - r */
+ {0, 0, 6, 22550, 70, 0 },
+ /* tcId: 153. replaced r by -n - r */
+ {0, 0, 6, 22620, 71, 0 },
+ /* tcId: 154. replaced r by r + 2**256 */
+ {0, 0, 6, 22691, 71, 0 },
+ /* tcId: 155. replaced r by r + 2**320 */
+ {0, 0, 6, 22762, 79, 0 },
+ /* tcId: 156. replaced s by s + n */
+ {0, 0, 6, 22841, 71, 0 },
+ /* tcId: 157. replaced s by s - n */
+ {0, 0, 6, 22912, 71, 0 },
+ /* tcId: 158. replaced s by s + 256 * n */
+ {0, 0, 6, 22983, 72, 0 },
+ /* tcId: 159. replaced s by -s */
+ {0, 0, 6, 23055, 70, 0 },
+ /* tcId: 160. replaced s by -n - s */
+ {0, 0, 6, 23125, 71, 0 },
+ /* tcId: 161. replaced s by s + 2**256 */
+ {0, 0, 6, 23196, 71, 0 },
+ /* tcId: 162. replaced s by s - 2**256 */
+ {0, 0, 6, 23267, 71, 0 },
+ /* tcId: 163. replaced s by s + 2**320 */
+ {0, 0, 6, 23338, 79, 0 },
+ /* tcId: 164. Signature with special case values r=0 and s=0 */
+ {0, 0, 6, 23417, 8, 0 },
+ /* tcId: 165. Signature with special case values r=0 and s=1 */
+ {0, 0, 6, 23425, 8, 0 },
+ /* tcId: 166. Signature with special case values r=0 and s=-1 */
+ {0, 0, 6, 23433, 8, 0 },
+ /* tcId: 167. Signature with special case values r=0 and s=n */
+ {0, 0, 6, 23441, 40, 0 },
+ /* tcId: 168. Signature with special case values r=0 and s=n - 1 */
+ {0, 0, 6, 23481, 40, 0 },
+ /* tcId: 169. Signature with special case values r=0 and s=n + 1 */
+ {0, 0, 6, 23521, 40, 0 },
+ /* tcId: 170. Signature with special case values r=0 and s=p */
+ {0, 0, 6, 23561, 40, 0 },
+ /* tcId: 171. Signature with special case values r=0 and s=p + 1 */
+ {0, 0, 6, 23601, 40, 0 },
+ /* tcId: 172. Signature with special case values r=1 and s=0 */
+ {0, 0, 6, 23641, 8, 0 },
+ /* tcId: 173. Signature with special case values r=1 and s=1 */
+ {0, 0, 6, 23649, 8, 0 },
+ /* tcId: 174. Signature with special case values r=1 and s=-1 */
+ {0, 0, 6, 23657, 8, 0 },
+ /* tcId: 175. Signature with special case values r=1 and s=n */
+ {0, 0, 6, 23665, 40, 0 },
+ /* tcId: 176. Signature with special case values r=1 and s=n - 1 */
+ {0, 0, 6, 23705, 40, 0 },
+ /* tcId: 177. Signature with special case values r=1 and s=n + 1 */
+ {0, 0, 6, 23745, 40, 0 },
+ /* tcId: 178. Signature with special case values r=1 and s=p */
+ {0, 0, 6, 23785, 40, 0 },
+ /* tcId: 179. Signature with special case values r=1 and s=p + 1 */
+ {0, 0, 6, 23825, 40, 0 },
+ /* tcId: 180. Signature with special case values r=-1 and s=0 */
+ {0, 0, 6, 23865, 8, 0 },
+ /* tcId: 181. Signature with special case values r=-1 and s=1 */
+ {0, 0, 6, 23873, 8, 0 },
+ /* tcId: 182. Signature with special case values r=-1 and s=-1 */
+ {0, 0, 6, 23881, 8, 0 },
+ /* tcId: 183. Signature with special case values r=-1 and s=n */
+ {0, 0, 6, 23889, 40, 0 },
+ /* tcId: 184. Signature with special case values r=-1 and s=n - 1 */
+ {0, 0, 6, 23929, 40, 0 },
+ /* tcId: 185. Signature with special case values r=-1 and s=n + 1 */
+ {0, 0, 6, 23969, 40, 0 },
+ /* tcId: 186. Signature with special case values r=-1 and s=p */
+ {0, 0, 6, 24009, 40, 0 },
+ /* tcId: 187. Signature with special case values r=-1 and s=p + 1 */
+ {0, 0, 6, 24049, 40, 0 },
+ /* tcId: 188. Signature with special case values r=n and s=0 */
+ {0, 0, 6, 24089, 40, 0 },
+ /* tcId: 189. Signature with special case values r=n and s=1 */
+ {0, 0, 6, 24129, 40, 0 },
+ /* tcId: 190. Signature with special case values r=n and s=-1 */
+ {0, 0, 6, 24169, 40, 0 },
+ /* tcId: 191. Signature with special case values r=n and s=n */
+ {0, 0, 6, 24209, 72, 0 },
+ /* tcId: 192. Signature with special case values r=n and s=n - 1 */
+ {0, 0, 6, 24281, 72, 0 },
+ /* tcId: 193. Signature with special case values r=n and s=n + 1 */
+ {0, 0, 6, 24353, 72, 0 },
+ /* tcId: 194. Signature with special case values r=n and s=p */
+ {0, 0, 6, 24425, 72, 0 },
+ /* tcId: 195. Signature with special case values r=n and s=p + 1 */
+ {0, 0, 6, 24497, 72, 0 },
+ /* tcId: 196. Signature with special case values r=n - 1 and s=0 */
+ {0, 0, 6, 24569, 40, 0 },
+ /* tcId: 197. Signature with special case values r=n - 1 and s=1 */
+ {0, 0, 6, 24609, 40, 0 },
+ /* tcId: 198. Signature with special case values r=n - 1 and s=-1 */
+ {0, 0, 6, 24649, 40, 0 },
+ /* tcId: 199. Signature with special case values r=n - 1 and s=n */
+ {0, 0, 6, 24689, 72, 0 },
+ /* tcId: 200. Signature with special case values r=n - 1 and s=n - 1 */
+ {0, 0, 6, 24761, 72, 0 },
+ /* tcId: 201. Signature with special case values r=n - 1 and s=n + 1 */
+ {0, 0, 6, 24833, 72, 0 },
+ /* tcId: 202. Signature with special case values r=n - 1 and s=p */
+ {0, 0, 6, 24905, 72, 0 },
+ /* tcId: 203. Signature with special case values r=n - 1 and s=p + 1 */
+ {0, 0, 6, 24977, 72, 0 },
+ /* tcId: 204. Signature with special case values r=n + 1 and s=0 */
+ {0, 0, 6, 25049, 40, 0 },
+ /* tcId: 205. Signature with special case values r=n + 1 and s=1 */
+ {0, 0, 6, 25089, 40, 0 },
+ /* tcId: 206. Signature with special case values r=n + 1 and s=-1 */
+ {0, 0, 6, 25129, 40, 0 },
+ /* tcId: 207. Signature with special case values r=n + 1 and s=n */
+ {0, 0, 6, 25169, 72, 0 },
+ /* tcId: 208. Signature with special case values r=n + 1 and s=n - 1 */
+ {0, 0, 6, 25241, 72, 0 },
+ /* tcId: 209. Signature with special case values r=n + 1 and s=n + 1 */
+ {0, 0, 6, 25313, 72, 0 },
+ /* tcId: 210. Signature with special case values r=n + 1 and s=p */
+ {0, 0, 6, 25385, 72, 0 },
+ /* tcId: 211. Signature with special case values r=n + 1 and s=p + 1 */
+ {0, 0, 6, 25457, 72, 0 },
+ /* tcId: 212. Signature with special case values r=p and s=0 */
+ {0, 0, 6, 25529, 40, 0 },
+ /* tcId: 213. Signature with special case values r=p and s=1 */
+ {0, 0, 6, 25569, 40, 0 },
+ /* tcId: 214. Signature with special case values r=p and s=-1 */
+ {0, 0, 6, 25609, 40, 0 },
+ /* tcId: 215. Signature with special case values r=p and s=n */
+ {0, 0, 6, 25649, 72, 0 },
+ /* tcId: 216. Signature with special case values r=p and s=n - 1 */
+ {0, 0, 6, 25721, 72, 0 },
+ /* tcId: 217. Signature with special case values r=p and s=n + 1 */
+ {0, 0, 6, 25793, 72, 0 },
+ /* tcId: 218. Signature with special case values r=p and s=p */
+ {0, 0, 6, 25865, 72, 0 },
+ /* tcId: 219. Signature with special case values r=p and s=p + 1 */
+ {0, 0, 6, 25937, 72, 0 },
+ /* tcId: 220. Signature with special case values r=p + 1 and s=0 */
+ {0, 0, 6, 26009, 40, 0 },
+ /* tcId: 221. Signature with special case values r=p + 1 and s=1 */
+ {0, 0, 6, 26049, 40, 0 },
+ /* tcId: 222. Signature with special case values r=p + 1 and s=-1 */
+ {0, 0, 6, 26089, 40, 0 },
+ /* tcId: 223. Signature with special case values r=p + 1 and s=n */
+ {0, 0, 6, 26129, 72, 0 },
+ /* tcId: 224. Signature with special case values r=p + 1 and s=n - 1 */
+ {0, 0, 6, 26201, 72, 0 },
+ /* tcId: 225. Signature with special case values r=p + 1 and s=n + 1 */
+ {0, 0, 6, 26273, 72, 0 },
+ /* tcId: 226. Signature with special case values r=p + 1 and s=p */
+ {0, 0, 6, 26345, 72, 0 },
+ /* tcId: 227. Signature with special case values r=p + 1 and s=p + 1 */
+ {0, 0, 6, 26417, 72, 0 },
+ /* tcId: 228. Signature encoding contains incorrect types: r=0, s=0.25 */
+ {0, 0, 6, 26489, 10, 0 },
+ /* tcId: 229. Signature encoding contains incorrect types: r=0, s=nan */
+ {0, 0, 6, 26499, 8, 0 },
+ /* tcId: 230. Signature encoding contains incorrect types: r=0, s=True */
+ {0, 0, 6, 26507, 8, 0 },
+ /* tcId: 231. Signature encoding contains incorrect types: r=0, s=False */
+ {0, 0, 6, 26515, 8, 0 },
+ /* tcId: 232. Signature encoding contains incorrect types: r=0, s=Null */
+ {0, 0, 6, 26523, 7, 0 },
+ /* tcId: 233. Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string */
+ {0, 0, 6, 26530, 7, 0 },
+ /* tcId: 234. Signature encoding contains incorrect types: r=0, s="0" */
+ {0, 0, 6, 26537, 8, 0 },
+ /* tcId: 235. Signature encoding contains incorrect types: r=0, s=empty list */
+ {0, 0, 6, 26545, 7, 0 },
+ /* tcId: 236. Signature encoding contains incorrect types: r=0, s=list containing 0 */
+ {0, 0, 6, 26552, 10, 0 },
+ /* tcId: 237. Signature encoding contains incorrect types: r=1, s=0.25 */
+ {0, 0, 6, 26562, 10, 0 },
+ /* tcId: 238. Signature encoding contains incorrect types: r=1, s=nan */
+ {0, 0, 6, 26572, 8, 0 },
+ /* tcId: 239. Signature encoding contains incorrect types: r=1, s=True */
+ {0, 0, 6, 26580, 8, 0 },
+ /* tcId: 240. Signature encoding contains incorrect types: r=1, s=False */
+ {0, 0, 6, 26588, 8, 0 },
+ /* tcId: 241. Signature encoding contains incorrect types: r=1, s=Null */
+ {0, 0, 6, 26596, 7, 0 },
+ /* tcId: 242. Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string */
+ {0, 0, 6, 26603, 7, 0 },
+ /* tcId: 243. Signature encoding contains incorrect types: r=1, s="0" */
+ {0, 0, 6, 26610, 8, 0 },
+ /* tcId: 244. Signature encoding contains incorrect types: r=1, s=empty list */
+ {0, 0, 6, 26618, 7, 0 },
+ /* tcId: 245. Signature encoding contains incorrect types: r=1, s=list containing 0 */
+ {0, 0, 6, 26625, 10, 0 },
+ /* tcId: 246. Signature encoding contains incorrect types: r=-1, s=0.25 */
+ {0, 0, 6, 26635, 10, 0 },
+ /* tcId: 247. Signature encoding contains incorrect types: r=-1, s=nan */
+ {0, 0, 6, 26645, 8, 0 },
+ /* tcId: 248. Signature encoding contains incorrect types: r=-1, s=True */
+ {0, 0, 6, 26653, 8, 0 },
+ /* tcId: 249. Signature encoding contains incorrect types: r=-1, s=False */
+ {0, 0, 6, 26661, 8, 0 },
+ /* tcId: 250. Signature encoding contains incorrect types: r=-1, s=Null */
+ {0, 0, 6, 26669, 7, 0 },
+ /* tcId: 251. Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string */
+ {0, 0, 6, 26676, 7, 0 },
+ /* tcId: 252. Signature encoding contains incorrect types: r=-1, s="0" */
+ {0, 0, 6, 26683, 8, 0 },
+ /* tcId: 253. Signature encoding contains incorrect types: r=-1, s=empty list */
+ {0, 0, 6, 26691, 7, 0 },
+ /* tcId: 254. Signature encoding contains incorrect types: r=-1, s=list containing 0 */
+ {0, 0, 6, 26698, 10, 0 },
+ /* tcId: 255. Signature encoding contains incorrect types: r=n, s=0.25 */
+ {0, 0, 6, 26708, 42, 0 },
+ /* tcId: 256. Signature encoding contains incorrect types: r=n, s=nan */
+ {0, 0, 6, 26750, 40, 0 },
+ /* tcId: 257. Signature encoding contains incorrect types: r=n, s=True */
+ {0, 0, 6, 26790, 40, 0 },
+ /* tcId: 258. Signature encoding contains incorrect types: r=n, s=False */
+ {0, 0, 6, 26830, 40, 0 },
+ /* tcId: 259. Signature encoding contains incorrect types: r=n, s=Null */
+ {0, 0, 6, 26870, 39, 0 },
+ /* tcId: 260. Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string */
+ {0, 0, 6, 26909, 39, 0 },
+ /* tcId: 261. Signature encoding contains incorrect types: r=n, s="0" */
+ {0, 0, 6, 26948, 40, 0 },
+ /* tcId: 262. Signature encoding contains incorrect types: r=n, s=empty list */
+ {0, 0, 6, 26988, 39, 0 },
+ /* tcId: 263. Signature encoding contains incorrect types: r=n, s=list containing 0 */
+ {0, 0, 6, 27027, 42, 0 },
+ /* tcId: 264. Signature encoding contains incorrect types: r=p, s=0.25 */
+ {0, 0, 6, 27069, 42, 0 },
+ /* tcId: 265. Signature encoding contains incorrect types: r=p, s=nan */
+ {0, 0, 6, 27111, 40, 0 },
+ /* tcId: 266. Signature encoding contains incorrect types: r=p, s=True */
+ {0, 0, 6, 27151, 40, 0 },
+ /* tcId: 267. Signature encoding contains incorrect types: r=p, s=False */
+ {0, 0, 6, 27191, 40, 0 },
+ /* tcId: 268. Signature encoding contains incorrect types: r=p, s=Null */
+ {0, 0, 6, 27231, 39, 0 },
+ /* tcId: 269. Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string */
+ {0, 0, 6, 27270, 39, 0 },
+ /* tcId: 270. Signature encoding contains incorrect types: r=p, s="0" */
+ {0, 0, 6, 27309, 40, 0 },
+ /* tcId: 271. Signature encoding contains incorrect types: r=p, s=empty list */
+ {0, 0, 6, 27349, 39, 0 },
+ /* tcId: 272. Signature encoding contains incorrect types: r=p, s=list containing 0 */
+ {0, 0, 6, 27388, 42, 0 },
+ /* tcId: 273. Signature encoding contains incorrect types: r=0.25, s=0.25 */
+ {0, 0, 6, 27430, 12, 0 },
+ /* tcId: 274. Signature encoding contains incorrect types: r=nan, s=nan */
+ {0, 0, 6, 27442, 8, 0 },
+ /* tcId: 275. Signature encoding contains incorrect types: r=True, s=True */
+ {0, 0, 6, 27450, 8, 0 },
+ /* tcId: 276. Signature encoding contains incorrect types: r=False, s=False */
+ {0, 0, 6, 27458, 8, 0 },
+ /* tcId: 277. Signature encoding contains incorrect types: r=Null, s=Null */
+ {0, 0, 6, 27466, 6, 0 },
+ /* tcId: 278. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string */
+ {0, 0, 6, 27472, 6, 0 },
+ /* tcId: 279. Signature encoding contains incorrect types: r="0", s="0" */
+ {0, 0, 6, 27478, 8, 0 },
+ /* tcId: 280. Signature encoding contains incorrect types: r=empty list, s=empty list */
+ {0, 0, 6, 27486, 6, 0 },
+ /* tcId: 281. Signature encoding contains incorrect types: r=list containing 0, s=list containing 0 */
+ {0, 0, 6, 27492, 12, 0 },
+ /* tcId: 282. Signature encoding contains incorrect types: r=0.25, s=0 */
+ {0, 0, 6, 27504, 10, 0 },
+ /* tcId: 283. Signature encoding contains incorrect types: r=nan, s=0 */
+ {0, 0, 6, 27514, 8, 0 },
+ /* tcId: 284. Signature encoding contains incorrect types: r=True, s=0 */
+ {0, 0, 6, 27522, 8, 0 },
+ /* tcId: 285. Signature encoding contains incorrect types: r=False, s=0 */
+ {0, 0, 6, 27530, 8, 0 },
+ /* tcId: 286. Signature encoding contains incorrect types: r=Null, s=0 */
+ {0, 0, 6, 27538, 7, 0 },
+ /* tcId: 287. Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0 */
+ {0, 0, 6, 27545, 7, 0 },
+ /* tcId: 288. Signature encoding contains incorrect types: r="0", s=0 */
+ {0, 0, 6, 27552, 8, 0 },
+ /* tcId: 289. Signature encoding contains incorrect types: r=empty list, s=0 */
+ {0, 0, 6, 27560, 7, 0 },
+ /* tcId: 290. Signature encoding contains incorrect types: r=list containing 0, s=0 */
+ {0, 0, 6, 27567, 10, 0 },
+ /* tcId: 291. Edge case for Shamir multiplication */
+ {0, 6, 5, 27577, 71, 1 },
+ /* tcId: 292. special case hash */
+ {0, 11, 9, 27648, 71, 1 },
+ /* tcId: 293. special case hash */
+ {0, 20, 10, 27719, 70, 1 },
+ /* tcId: 294. special case hash */
+ {0, 30, 11, 27789, 71, 1 },
+ /* tcId: 295. special case hash */
+ {0, 41, 10, 27860, 71, 1 },
+ /* tcId: 296. special case hash */
+ {0, 51, 10, 27931, 70, 1 },
+ /* tcId: 297. special case hash */
+ {0, 61, 10, 28001, 71, 1 },
+ /* tcId: 298. special case hash */
+ {0, 71, 9, 28072, 70, 1 },
+ /* tcId: 299. special case hash */
+ {0, 80, 10, 28142, 71, 1 },
+ /* tcId: 300. special case hash */
+ {0, 90, 10, 28213, 71, 1 },
+ /* tcId: 301. special case hash */
+ {0, 100, 10, 28284, 71, 1 },
+ /* tcId: 302. special case hash */
+ {0, 110, 10, 28355, 71, 1 },
+ /* tcId: 303. special case hash */
+ {0, 120, 11, 28426, 70, 1 },
+ /* tcId: 304. special case hash */
+ {0, 131, 10, 28496, 71, 1 },
+ /* tcId: 305. special case hash */
+ {0, 141, 10, 28567, 71, 1 },
+ /* tcId: 306. special case hash */
+ {0, 151, 10, 28638, 70, 1 },
+ /* tcId: 307. special case hash */
+ {0, 161, 10, 28708, 71, 1 },
+ /* tcId: 308. special case hash */
+ {0, 171, 10, 28779, 71, 1 },
+ /* tcId: 309. special case hash */
+ {0, 181, 10, 28850, 70, 1 },
+ /* tcId: 310. special case hash */
+ {0, 191, 10, 28920, 71, 1 },
+ /* tcId: 311. special case hash */
+ {0, 201, 10, 28991, 71, 1 },
+ /* tcId: 312. special case hash */
+ {0, 211, 10, 29062, 71, 1 },
+ /* tcId: 313. special case hash */
+ {0, 221, 10, 29133, 70, 1 },
+ /* tcId: 314. special case hash */
+ {0, 231, 10, 29203, 71, 1 },
+ /* tcId: 315. special case hash */
+ {0, 241, 10, 29274, 71, 1 },
+ /* tcId: 316. special case hash */
+ {0, 251, 10, 29345, 71, 1 },
+ /* tcId: 317. special case hash */
+ {0, 261, 11, 29416, 71, 1 },
+ /* tcId: 318. special case hash */
+ {0, 272, 11, 29487, 70, 1 },
+ /* tcId: 319. special case hash */
+ {0, 283, 9, 29557, 71, 1 },
+ /* tcId: 320. special case hash */
+ {0, 292, 9, 29628, 71, 1 },
+ /* tcId: 321. special case hash */
+ {0, 301, 10, 29699, 71, 1 },
+ /* tcId: 322. special case hash */
+ {0, 311, 10, 29770, 71, 1 },
+ /* tcId: 323. special case hash */
+ {0, 321, 10, 29841, 70, 1 },
+ /* tcId: 324. special case hash */
+ {0, 331, 10, 29911, 70, 1 },
+ /* tcId: 325. special case hash */
+ {0, 341, 10, 29981, 71, 1 },
+ /* tcId: 326. special case hash */
+ {0, 351, 9, 30052, 70, 1 },
+ /* tcId: 327. special case hash */
+ {0, 360, 10, 30122, 70, 1 },
+ /* tcId: 328. special case hash */
+ {0, 370, 10, 30192, 70, 1 },
+ /* tcId: 329. special case hash */
+ {0, 380, 10, 30262, 70, 1 },
+ /* tcId: 330. special case hash */
+ {0, 390, 9, 30332, 71, 1 },
+ /* tcId: 331. special case hash */
+ {0, 399, 11, 30403, 70, 1 },
+ /* tcId: 332. special case hash */
+ {0, 410, 9, 30473, 71, 1 },
+ /* tcId: 333. special case hash */
+ {0, 419, 9, 30544, 71, 1 },
+ /* tcId: 334. special case hash */
+ {0, 428, 11, 30615, 70, 1 },
+ /* tcId: 335. special case hash */
+ {0, 439, 8, 30685, 71, 1 },
+ /* tcId: 336. special case hash */
+ {0, 447, 10, 30756, 70, 1 },
+ /* tcId: 337. special case hash */
+ {0, 457, 10, 30826, 71, 1 },
+ /* tcId: 338. special case hash */
+ {0, 467, 10, 30897, 70, 1 },
+ /* tcId: 339. special case hash */
+ {0, 477, 10, 30967, 70, 1 },
+ /* tcId: 340. special case hash */
+ {0, 487, 10, 31037, 70, 1 },
+ /* tcId: 341. special case hash */
+ {0, 497, 10, 31107, 71, 1 },
+ /* tcId: 342. special case hash */
+ {0, 507, 10, 31178, 70, 1 },
+ /* tcId: 343. special case hash */
+ {0, 517, 10, 31248, 70, 1 },
+ /* tcId: 344. special case hash */
+ {0, 527, 10, 31318, 71, 1 },
+ /* tcId: 345. special case hash */
+ {0, 537, 9, 31389, 70, 1 },
+ /* tcId: 346. k*G has a large x-coordinate */
+ {65, 0, 6, 31459, 24, 1 },
+ /* tcId: 347. r too large */
+ {65, 0, 6, 31483, 40, 0 },
+ /* tcId: 348. r,s are large */
+ {130, 0, 6, 31523, 40, 1 },
+ /* tcId: 349. r and s^-1 have a large Hamming weight */
+ {195, 0, 6, 31563, 70, 1 },
+ /* tcId: 350. r and s^-1 have a large Hamming weight */
+ {260, 0, 6, 31633, 70, 1 },
+ /* tcId: 351. small r and s */
+ {325, 0, 6, 31703, 8, 1 },
+ /* tcId: 352. small r and s */
+ {390, 0, 6, 31711, 8, 1 },
+ /* tcId: 353. small r and s */
+ {455, 0, 6, 31719, 8, 1 },
+ /* tcId: 354. small r and s */
+ {520, 0, 6, 31727, 8, 1 },
+ /* tcId: 355. small r and s */
+ {585, 0, 6, 31735, 8, 1 },
+ /* tcId: 356. small r and s */
+ {650, 0, 6, 31743, 8, 1 },
+ /* tcId: 357. r is larger than n */
+ {650, 0, 6, 31751, 40, 0 },
+ /* tcId: 358. s is larger than n */
+ {715, 0, 6, 31791, 10, 0 },
+ /* tcId: 359. small r and s^-1 */
+ {780, 0, 6, 31801, 40, 1 },
+ /* tcId: 360. smallish r and s^-1 */
+ {845, 0, 6, 31841, 45, 1 },
+ /* tcId: 361. 100-bit r and small s^-1 */
+ {910, 0, 6, 31886, 51, 1 },
+ /* tcId: 362. small r and 100 bit s^-1 */
+ {975, 0, 6, 31937, 40, 1 },
+ /* tcId: 363. 100-bit r and s^-1 */
+ {1040, 0, 6, 31977, 51, 1 },
+ /* tcId: 364. r and s^-1 are close to n */
+ {1105, 0, 6, 32028, 71, 1 },
+ /* tcId: 365. r and s are 64-bit integer */
+ {1170, 0, 6, 32099, 24, 1 },
+ /* tcId: 366. r and s are 100-bit integer */
+ {1235, 0, 6, 32123, 32, 1 },
+ /* tcId: 367. r and s are 128-bit integer */
+ {1300, 0, 6, 32155, 40, 1 },
+ /* tcId: 368. r and s are 160-bit integer */
+ {1365, 0, 6, 32195, 48, 1 },
+ /* tcId: 369. s == 1 */
+ {1430, 0, 6, 32243, 39, 1 },
+ /* tcId: 370. s == 0 */
+ {1430, 0, 6, 32282, 39, 0 },
+ /* tcId: 371. edge case modular inverse */
+ {1495, 0, 6, 32321, 70, 1 },
+ /* tcId: 372. edge case modular inverse */
+ {1560, 0, 6, 32391, 70, 1 },
+ /* tcId: 373. edge case modular inverse */
+ {1625, 0, 6, 32461, 70, 1 },
+ /* tcId: 374. edge case modular inverse */
+ {1690, 0, 6, 32531, 70, 1 },
+ /* tcId: 375. edge case modular inverse */
+ {1755, 0, 6, 32601, 70, 1 },
+ /* tcId: 376. edge case modular inverse */
+ {1820, 0, 6, 32671, 70, 1 },
+ /* tcId: 377. edge case modular inverse */
+ {1885, 0, 6, 32741, 70, 1 },
+ /* tcId: 378. edge case modular inverse */
+ {1950, 0, 6, 32811, 70, 1 },
+ /* tcId: 379. edge case modular inverse */
+ {2015, 0, 6, 32881, 70, 1 },
+ /* tcId: 380. edge case modular inverse */
+ {2080, 0, 6, 32951, 70, 1 },
+ /* tcId: 381. edge case modular inverse */
+ {2145, 0, 6, 33021, 70, 1 },
+ /* tcId: 382. edge case modular inverse */
+ {2210, 0, 6, 33091, 70, 1 },
+ /* tcId: 383. edge case modular inverse */
+ {2275, 0, 6, 33161, 70, 1 },
+ /* tcId: 384. edge case modular inverse */
+ {2340, 0, 6, 33231, 70, 1 },
+ /* tcId: 385. edge case modular inverse */
+ {2405, 0, 6, 33301, 70, 1 },
+ /* tcId: 386. point at infinity during verify */
+ {2470, 0, 6, 33371, 70, 0 },
+ /* tcId: 387. edge case for signature malleability */
+ {2535, 0, 6, 33441, 70, 1 },
+ /* tcId: 388. edge case for signature malleability */
+ {2600, 0, 6, 33511, 70, 0 },
+ /* tcId: 389. u1 == 1 */
+ {2665, 0, 6, 33581, 70, 1 },
+ /* tcId: 390. u1 == n - 1 */
+ {2730, 0, 6, 33651, 70, 1 },
+ /* tcId: 391. u2 == 1 */
+ {2795, 0, 6, 33721, 70, 1 },
+ /* tcId: 392. u2 == n - 1 */
+ {2860, 0, 6, 33791, 70, 1 },
+ /* tcId: 393. edge case for u1 */
+ {2925, 0, 6, 33861, 70, 1 },
+ /* tcId: 394. edge case for u1 */
+ {2990, 0, 6, 33931, 70, 1 },
+ /* tcId: 395. edge case for u1 */
+ {3055, 0, 6, 34001, 70, 1 },
+ /* tcId: 396. edge case for u1 */
+ {3120, 0, 6, 34071, 70, 1 },
+ /* tcId: 397. edge case for u1 */
+ {3185, 0, 6, 34141, 70, 1 },
+ /* tcId: 398. edge case for u1 */
+ {3250, 0, 6, 34211, 70, 1 },
+ /* tcId: 399. edge case for u1 */
+ {3315, 0, 6, 34281, 70, 1 },
+ /* tcId: 400. edge case for u1 */
+ {3380, 0, 6, 34351, 70, 1 },
+ /* tcId: 401. edge case for u1 */
+ {3445, 0, 6, 34421, 70, 1 },
+ /* tcId: 402. edge case for u1 */
+ {3510, 0, 6, 34491, 70, 1 },
+ /* tcId: 403. edge case for u1 */
+ {3575, 0, 6, 34561, 70, 1 },
+ /* tcId: 404. edge case for u1 */
+ {3640, 0, 6, 34631, 70, 1 },
+ /* tcId: 405. edge case for u1 */
+ {3705, 0, 6, 34701, 70, 1 },
+ /* tcId: 406. edge case for u1 */
+ {3770, 0, 6, 34771, 70, 1 },
+ /* tcId: 407. edge case for u1 */
+ {3835, 0, 6, 34841, 70, 1 },
+ /* tcId: 408. edge case for u2 */
+ {3900, 0, 6, 34911, 70, 1 },
+ /* tcId: 409. edge case for u2 */
+ {3965, 0, 6, 34981, 70, 1 },
+ /* tcId: 410. edge case for u2 */
+ {4030, 0, 6, 35051, 70, 1 },
+ /* tcId: 411. edge case for u2 */
+ {4095, 0, 6, 35121, 70, 1 },
+ /* tcId: 412. edge case for u2 */
+ {4160, 0, 6, 35191, 70, 1 },
+ /* tcId: 413. edge case for u2 */
+ {4225, 0, 6, 35261, 69, 1 },
+ /* tcId: 414. edge case for u2 */
+ {4290, 0, 6, 35330, 70, 1 },
+ /* tcId: 415. edge case for u2 */
+ {4355, 0, 6, 35400, 70, 1 },
+ /* tcId: 416. edge case for u2 */
+ {4420, 0, 6, 35470, 70, 1 },
+ /* tcId: 417. edge case for u2 */
+ {4485, 0, 6, 35540, 70, 1 },
+ /* tcId: 418. edge case for u2 */
+ {4550, 0, 6, 35610, 70, 1 },
+ /* tcId: 419. edge case for u2 */
+ {4615, 0, 6, 35680, 70, 1 },
+ /* tcId: 420. edge case for u2 */
+ {4680, 0, 6, 35750, 70, 1 },
+ /* tcId: 421. edge case for u2 */
+ {4745, 0, 6, 35820, 70, 1 },
+ /* tcId: 422. edge case for u2 */
+ {4810, 0, 6, 35890, 70, 1 },
+ /* tcId: 423. point duplication during verification */
+ {4875, 0, 6, 35960, 70, 1 },
+ /* tcId: 424. duplication bug */
+ {4940, 0, 6, 36030, 70, 0 },
+ /* tcId: 425. comparison with point at infinity */
+ {5005, 0, 6, 36100, 70, 0 },
+ /* tcId: 426. extreme value for k and edgecase s */
+ {5070, 0, 6, 36170, 71, 1 },
+ /* tcId: 427. extreme value for k and s^-1 */
+ {5135, 0, 6, 36241, 71, 1 },
+ /* tcId: 428. extreme value for k and s^-1 */
+ {5200, 0, 6, 36312, 71, 1 },
+ /* tcId: 429. extreme value for k and s^-1 */
+ {5265, 0, 6, 36383, 71, 1 },
+ /* tcId: 430. extreme value for k and s^-1 */
+ {5330, 0, 6, 36454, 71, 1 },
+ /* tcId: 431. extreme value for k */
+ {5395, 0, 6, 36525, 71, 1 },
+ /* tcId: 432. extreme value for k and edgecase s */
+ {5460, 0, 6, 36596, 70, 1 },
+ /* tcId: 433. extreme value for k and s^-1 */
+ {5525, 0, 6, 36666, 70, 1 },
+ /* tcId: 434. extreme value for k and s^-1 */
+ {5590, 0, 6, 36736, 70, 1 },
+ /* tcId: 435. extreme value for k and s^-1 */
+ {5655, 0, 6, 36806, 70, 1 },
+ /* tcId: 436. extreme value for k and s^-1 */
+ {5720, 0, 6, 36876, 70, 1 },
+ /* tcId: 437. extreme value for k */
+ {5785, 0, 6, 36946, 70, 1 },
+ /* tcId: 438. public key shares x-coordinate with generator */
+ {5850, 0, 6, 37016, 71, 0 },
+ /* tcId: 439. public key shares x-coordinate with generator */
+ {5850, 0, 6, 37087, 70, 0 },
+ /* tcId: 440. public key shares x-coordinate with generator */
+ {5915, 0, 6, 37157, 71, 0 },
+ /* tcId: 441. public key shares x-coordinate with generator */
+ {5915, 0, 6, 37228, 70, 0 },
+ /* tcId: 442. pseudorandom signature */
+ {5980, 546, 0, 37298, 71, 1 },
+ /* tcId: 443. pseudorandom signature */
+ {5980, 546, 3, 37369, 70, 1 },
+ /* tcId: 444. pseudorandom signature */
+ {5980, 0, 6, 37439, 71, 1 },
+ /* tcId: 445. pseudorandom signature */
+ {5980, 549, 20, 37510, 70, 1 },
+ /* tcId: 446. y-coordinate of the public key is small */
+ {6045, 569, 7, 37580, 70, 1 },
+ /* tcId: 447. y-coordinate of the public key is small */
+ {6045, 569, 7, 37650, 70, 1 },
+ /* tcId: 448. y-coordinate of the public key is small */
+ {6045, 569, 7, 37720, 71, 1 },
+ /* tcId: 449. y-coordinate of the public key is large */
+ {6110, 569, 7, 37791, 70, 1 },
+ /* tcId: 450. y-coordinate of the public key is large */
+ {6110, 569, 7, 37861, 71, 1 },
+ /* tcId: 451. y-coordinate of the public key is large */
+ {6110, 569, 7, 37932, 70, 1 },
+ /* tcId: 452. x-coordinate of the public key is small */
+ {6175, 569, 7, 38002, 70, 1 },
+ /* tcId: 453. x-coordinate of the public key is small */
+ {6175, 569, 7, 38072, 71, 1 },
+ /* tcId: 454. x-coordinate of the public key is small */
+ {6175, 569, 7, 38143, 71, 1 },
+ /* tcId: 455. x-coordinate of the public key has many trailing 1's */
+ {6240, 569, 7, 38214, 70, 1 },
+ /* tcId: 456. x-coordinate of the public key has many trailing 1's */
+ {6240, 569, 7, 38284, 71, 1 },
+ /* tcId: 457. x-coordinate of the public key has many trailing 1's */
+ {6240, 569, 7, 38355, 71, 1 },
+ /* tcId: 458. y-coordinate of the public key has many trailing 1's */
+ {6305, 569, 7, 38426, 70, 1 },
+ /* tcId: 459. y-coordinate of the public key has many trailing 1's */
+ {6305, 569, 7, 38496, 71, 1 },
+ /* tcId: 460. y-coordinate of the public key has many trailing 1's */
+ {6305, 569, 7, 38567, 71, 1 },
+ /* tcId: 461. x-coordinate of the public key has many trailing 0's */
+ {6370, 569, 7, 38638, 70, 1 },
+ /* tcId: 462. x-coordinate of the public key has many trailing 0's */
+ {6370, 569, 7, 38708, 70, 1 },
+ /* tcId: 463. x-coordinate of the public key has many trailing 0's */
+ {6370, 569, 7, 38778, 71, 1 },
+
+};
diff --git a/src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json b/src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
new file mode 100644
index 0000000000..9c90747993
--- /dev/null
+++ b/src/secp256k1/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
@@ -0,0 +1,6360 @@
+{
+ "algorithm" : "ECDSA",
+ "schema" : "ecdsa_bitcoin_verify_schema.json",
+ "generatorVersion" : "0.9rc5",
+ "numberOfTests" : 463,
+ "header" : [
+ "Test vectors of type EcdsaBitcoinVerify are meant for the verification",
+ "of a ECDSA variant used for bitcoin, that add signature non-malleability."
+ ],
+ "notes" : {
+ "ArithmeticError" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "Some implementations of ECDSA have arithmetic errors that occur when intermediate results have extreme values. This test vector has been constructed to test such occurences.",
+ "cves" : [
+ "CVE-2017-18146"
+ ]
+ },
+ "BerEncodedSignature" : {
+ "bugType" : "BER_ENCODING",
+ "description" : "ECDSA signatures are usually DER encoded. This signature contains valid values for r and s, but it uses alternative BER encoding.",
+ "effect" : "Accepting alternative BER encodings may be benign in some cases, or be an issue if protocol requires signature malleability.",
+ "cves" : [
+ "CVE-2020-14966",
+ "CVE-2020-13822",
+ "CVE-2019-14859",
+ "CVE-2016-1000342"
+ ]
+ },
+ "EdgeCasePublicKey" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "The test vector uses a special case public key. "
+ },
+ "EdgeCaseShamirMultiplication" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "Shamir proposed a fast method for computing the sum of two scalar multiplications efficiently. This test vector has been constructed so that an intermediate result is the point at infinity if Shamir's method is used."
+ },
+ "IntegerOverflow" : {
+ "bugType" : "CAN_OF_WORMS",
+ "description" : "The test vector contains an r and s that has been modified, so that the original value is restored if the implementation ignores the most significant bits.",
+ "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures."
+ },
+ "InvalidEncoding" : {
+ "bugType" : "CAN_OF_WORMS",
+ "description" : "ECDSA signatures are encoded using ASN.1. This test vector contains an incorrectly encoded signature. The test vector itself was generated from a valid signature by modifying its encoding.",
+ "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures."
+ },
+ "InvalidSignature" : {
+ "bugType" : "AUTH_BYPASS",
+ "description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.",
+ "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.",
+ "cves" : [
+ "CVE-2022-21449",
+ "CVE-2021-43572",
+ "CVE-2022-24884"
+ ]
+ },
+ "InvalidTypesInSignature" : {
+ "bugType" : "AUTH_BYPASS",
+ "description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.",
+ "effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.",
+ "cves" : [
+ "CVE-2022-21449"
+ ]
+ },
+ "ModifiedInteger" : {
+ "bugType" : "CAN_OF_WORMS",
+ "description" : "The test vector contains an r and s that has been modified. The goal is to check for arithmetic errors.",
+ "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures."
+ },
+ "ModifiedSignature" : {
+ "bugType" : "CAN_OF_WORMS",
+ "description" : "The test vector contains an invalid signature that was generated from a valid signature by modifying it.",
+ "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures."
+ },
+ "ModularInverse" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "The test vectors contains a signature where computing the modular inverse of s hits an edge case.",
+ "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.",
+ "cves" : [
+ "CVE-2019-0865"
+ ]
+ },
+ "PointDuplication" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "Some implementations of ECDSA do not handle duplication and points at infinity correctly. This is a test vector that has been specially crafted to check for such an omission.",
+ "cves" : [
+ "2020-12607",
+ "CVE-2015-2730"
+ ]
+ },
+ "RangeCheck" : {
+ "bugType" : "CAN_OF_WORMS",
+ "description" : "The test vector contains an r and s that has been modified. By adding or subtracting the order of the group (or other values) the test vector checks whether signature verification verifies the range of r and s.",
+ "effect" : "Without further analysis it is unclear if the modification can be used to forge signatures."
+ },
+ "SignatureMalleabilityBitcoin" : {
+ "bugType" : "SIGNATURE_MALLEABILITY",
+ "description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implemenation should be tested with another set of test vectors.",
+ "effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals",
+ "links" : [
+ "https://en.bitcoin.it/wiki/Transaction_malleability",
+ "https://en.bitcoinwiki.org/wiki/Transaction_Malleability"
+ ]
+ },
+ "SmallRandS" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "The test vectors contains a signature where both r and s are small integers. Some libraries cannot verify such signatures.",
+ "effect" : "While the signature in this test vector is constructed and similar cases are unlikely to occur, it is important to determine if the underlying arithmetic error can be used to forge signatures.",
+ "cves" : [
+ "2020-13895"
+ ]
+ },
+ "SpecialCaseHash" : {
+ "bugType" : "EDGE_CASE",
+ "description" : "The test vector contains a signature where the hash of the message is a special case, e.g., contains a long run of 0 or 1 bits."
+ },
+ "ValidSignature" : {
+ "bugType" : "BASIC",
+ "description" : "The test vector contains a valid signature that was generated pseudorandomly. Such signatures should not fail to verify unless some of the parameters (e.g. curve or hash function) are not supported."
+ }
+ },
+ "testGroups" : [
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9",
+ "wx" : "00b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6f",
+ "wy" : "00f0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b838ff44e5bc177bf21189d0766082fc9d843226887fc9760371100b7ee20a6ff0c9d75bfba7b31a6bca1974496eeb56de357071955d83c4b1badaa0b21832e9",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEuDj/ROW8F3vyEYnQdmCC/J2EMiaIf8l2\nA3EQC37iCm/wyddb+6ezGmvKGXRJbutW3jVwcZVdg8Sxutqgshgy6Q==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 1,
+ "comment" : "Signature malleability",
+ "flags" : [
+ "SignatureMalleabilityBitcoin"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022100900e75ad233fcc908509dbff5922647db37c21f4afd3203ae8dc4ae7794b0f87",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 2,
+ "comment" : "valid",
+ "flags" : [
+ "ValidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 3,
+ "comment" : "length of sequence [r, s] uses long form encoding",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "308145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 4,
+ "comment" : "length of sequence [r, s] contains a leading 0",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30820045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 5,
+ "comment" : "length of sequence [r, s] uses 70 instead of 69",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 6,
+ "comment" : "length of sequence [r, s] uses 68 instead of 69",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 7,
+ "comment" : "uint32 overflow in length of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30850100000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 8,
+ "comment" : "uint64 overflow in length of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3089010000000000000045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 9,
+ "comment" : "length of sequence [r, s] = 2**31 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30847fffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 10,
+ "comment" : "length of sequence [r, s] = 2**31",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "308480000000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 11,
+ "comment" : "length of sequence [r, s] = 2**32 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3084ffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 12,
+ "comment" : "length of sequence [r, s] = 2**40 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3085ffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 13,
+ "comment" : "length of sequence [r, s] = 2**64 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3088ffffffffffffffff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 14,
+ "comment" : "incorrect length of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30ff022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 15,
+ "comment" : "replaced sequence [r, s] by an indefinite length tag without termination",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 16,
+ "comment" : "removing sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 17,
+ "comment" : "lonely sequence tag",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 18,
+ "comment" : "appending 0's to sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 19,
+ "comment" : "prepending 0's to sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30470000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 20,
+ "comment" : "appending unused 0's to sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 21,
+ "comment" : "appending null value to sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 22,
+ "comment" : "prepending garbage to sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a4981773045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 23,
+ "comment" : "prepending garbage to sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304925003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 24,
+ "comment" : "appending garbage to sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 25,
+ "comment" : "including undefined tags",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304daa00bb00cd003045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 26,
+ "comment" : "including undefined tags",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d2229aa00bb00cd00022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 27,
+ "comment" : "including undefined tags",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652228aa00bb00cd0002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 28,
+ "comment" : "truncated length of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3081",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 29,
+ "comment" : "including undefined tags to sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304baa02aabb3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 30,
+ "comment" : "using composition with indefinite length for sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30803045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 31,
+ "comment" : "using composition with wrong tag for sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30803145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 32,
+ "comment" : "Replacing sequence [r, s] with NULL",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "0500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 33,
+ "comment" : "changing tag value of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "2e45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 34,
+ "comment" : "changing tag value of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "2f45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 35,
+ "comment" : "changing tag value of sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3145022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 36,
+ "comment" : "changing tag value of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3245022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 37,
+ "comment" : "changing tag value of sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "ff45022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 38,
+ "comment" : "dropping value of sequence [r, s]",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 39,
+ "comment" : "using composition for sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304930010230442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 40,
+ "comment" : "truncated sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 41,
+ "comment" : "truncated sequence [r, s]",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30442100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 42,
+ "comment" : "sequence [r, s] of size 4166 to check for overflows",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30821046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 43,
+ "comment" : "indefinite length",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 44,
+ "comment" : "indefinite length with truncated delimiter",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 45,
+ "comment" : "indefinite length with additional element",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba05000000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 46,
+ "comment" : "indefinite length with truncated element",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba060811220000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 47,
+ "comment" : "indefinite length with garbage",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000fe02beef",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 48,
+ "comment" : "indefinite length with nonempty EOC",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3080022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0002beef",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 49,
+ "comment" : "prepend empty sequence",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30473000022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 50,
+ "comment" : "append empty sequence",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba3000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 51,
+ "comment" : "append zero",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 52,
+ "comment" : "append garbage with high tag number",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31babf7f00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 53,
+ "comment" : "append null with explicit tag",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa0020500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 54,
+ "comment" : "append null with implicit tag",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31baa000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 55,
+ "comment" : "sequence of sequence",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30473045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 56,
+ "comment" : "truncated sequence: removed last 1 elements",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3023022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 57,
+ "comment" : "repeating element in sequence",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3067022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 58,
+ "comment" : "flipped bit 0 in r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 59,
+ "comment" : "flipped bit 32 in r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccac983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 60,
+ "comment" : "flipped bit 48 in r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5133ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 61,
+ "comment" : "flipped bit 64 in r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc08b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 62,
+ "comment" : "length of r uses long form encoding",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304602812100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 63,
+ "comment" : "length of r contains a leading 0",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30470282002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 64,
+ "comment" : "length of r uses 34 instead of 33",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 65,
+ "comment" : "length of r uses 32 instead of 33",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 66,
+ "comment" : "uint32 overflow in length of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a0285010000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 67,
+ "comment" : "uint64 overflow in length of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304e028901000000000000002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 68,
+ "comment" : "length of r = 2**31 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304902847fffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 69,
+ "comment" : "length of r = 2**31",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304902848000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 70,
+ "comment" : "length of r = 2**32 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30490284ffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 71,
+ "comment" : "length of r = 2**40 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a0285ffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 72,
+ "comment" : "length of r = 2**64 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d0288ffffffffffffffff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 73,
+ "comment" : "incorrect length of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304502ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 74,
+ "comment" : "replaced r by an indefinite length tag without termination",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045028000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 75,
+ "comment" : "removing r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "302202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 76,
+ "comment" : "lonely integer tag",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30230202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 77,
+ "comment" : "lonely integer tag",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3024022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 78,
+ "comment" : "appending 0's to r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 79,
+ "comment" : "prepending 0's to r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30470223000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 80,
+ "comment" : "appending unused 0's to r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 81,
+ "comment" : "appending null value to r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022300813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 82,
+ "comment" : "prepending garbage to r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a2226498177022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 83,
+ "comment" : "prepending garbage to r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304922252500022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 84,
+ "comment" : "appending garbage to r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d2223022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650004deadbeef02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 85,
+ "comment" : "truncated length of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3024028102206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 86,
+ "comment" : "including undefined tags to r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304b2227aa02aabb022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 87,
+ "comment" : "using composition with indefinite length for r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30492280022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 88,
+ "comment" : "using composition with wrong tag for r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30492280032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 89,
+ "comment" : "Replacing r with NULL",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3024050002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 90,
+ "comment" : "changing tag value of r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045002100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 91,
+ "comment" : "changing tag value of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045012100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 92,
+ "comment" : "changing tag value of r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045032100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 93,
+ "comment" : "changing tag value of r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045042100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 94,
+ "comment" : "changing tag value of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045ff2100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 95,
+ "comment" : "dropping value of r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3024020002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 96,
+ "comment" : "using composition for r",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304922250201000220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 97,
+ "comment" : "modifying first byte of r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022102813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 98,
+ "comment" : "modifying last byte of r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323e502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 99,
+ "comment" : "truncated r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832302206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 100,
+ "comment" : "truncated r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30440220813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 101,
+ "comment" : "r of size 4130 to check for overflows",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "308210480282102200813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 102,
+ "comment" : "leading ff in r",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30460222ff00813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 103,
+ "comment" : "replaced r by infinity",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "302509018002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 104,
+ "comment" : "replacing r with zero",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "302502010002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 105,
+ "comment" : "flipped bit 0 in s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31bb",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 106,
+ "comment" : "flipped bit 32 in s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a456eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 107,
+ "comment" : "flipped bit 48 in s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f713a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 108,
+ "comment" : "flipped bit 64 in s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3043022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323656ff18a52dcc0336f7af62400a6dd9b810732baf1ff758001d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 109,
+ "comment" : "length of s uses long form encoding",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 110,
+ "comment" : "length of s contains a leading 0",
+ "flags" : [
+ "BerEncodedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028200206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 111,
+ "comment" : "length of s uses 33 instead of 32",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 112,
+ "comment" : "length of s uses 31 instead of 32",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 113,
+ "comment" : "uint32 overflow in length of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028501000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 114,
+ "comment" : "uint64 overflow in length of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304e022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502890100000000000000206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 115,
+ "comment" : "length of s = 2**31 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502847fffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 116,
+ "comment" : "length of s = 2**31",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284800000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 117,
+ "comment" : "length of s = 2**32 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650284ffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 118,
+ "comment" : "length of s = 2**40 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650285ffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 119,
+ "comment" : "length of s = 2**64 - 1",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650288ffffffffffffffff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 120,
+ "comment" : "incorrect length of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 121,
+ "comment" : "replaced s by an indefinite length tag without termination",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502806ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 122,
+ "comment" : "appending 0's to s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 123,
+ "comment" : "prepending 0's to s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365022200006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 124,
+ "comment" : "appending null value to s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3047022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502226ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 125,
+ "comment" : "prepending garbage to s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304a022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222549817702206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 126,
+ "comment" : "prepending garbage to s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652224250002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 127,
+ "comment" : "appending garbage to s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222202206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0004deadbeef",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 128,
+ "comment" : "truncated length of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650281",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 129,
+ "comment" : "including undefined tags to s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304b022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323652226aa02aabb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 130,
+ "comment" : "using composition with indefinite length for s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228002206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 131,
+ "comment" : "using composition with wrong tag for s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365228003206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 132,
+ "comment" : "Replacing s with NULL",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 133,
+ "comment" : "changing tag value of s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236500206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 134,
+ "comment" : "changing tag value of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236501206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 135,
+ "comment" : "changing tag value of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236503206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 136,
+ "comment" : "changing tag value of s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236504206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 137,
+ "comment" : "changing tag value of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365ff206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 138,
+ "comment" : "dropping value of s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650200",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 139,
+ "comment" : "using composition for s",
+ "flags" : [
+ "InvalidEncoding"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3049022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365222402016f021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 140,
+ "comment" : "modifying first byte of s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206df18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 141,
+ "comment" : "modifying last byte of s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb313a",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 142,
+ "comment" : "truncated s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021f6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 143,
+ "comment" : "truncated s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365021ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 144,
+ "comment" : "s of size 4129 to check for overflows",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30821048022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365028210216ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 145,
+ "comment" : "leading ff in s",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc98323650221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 146,
+ "comment" : "replaced s by infinity",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365090180",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 147,
+ "comment" : "replacing s with zero",
+ "flags" : [
+ "ModifiedSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc9832365020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 148,
+ "comment" : "replaced r by r + n",
+ "flags" : [
+ "RangeCheck"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478583b90deabca4b05c4574e49b5899b964a602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 149,
+ "comment" : "replaced r by r - n",
+ "flags" : [
+ "RangeCheck"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30440220813ef79ccefa9a56f7ba805f0e47858643b030ef461f1bcdf53fde3ef94ce22402206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 150,
+ "comment" : "replaced r by r + 256 * n",
+ "flags" : [
+ "RangeCheck"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304602220100813ef79ccefa9a56f7ba805f0e47843fad3bf4853e07f7c98770c99bffc4646502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 151,
+ "comment" : "replaced r by -r",
+ "flags" : [
+ "ModifiedInteger"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221ff7ec10863310565a908457fa0f1b87a7b01a0f22a0a9843f64aedc334367cdc9b02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 152,
+ "comment" : "replaced r by n - r",
+ "flags" : [
+ "ModifiedInteger"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ec10863310565a908457fa0f1b87a79bc4fcf10b9e0e4320ac021c106b31ddc02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 153,
+ "comment" : "replaced r by -n - r",
+ "flags" : [
+ "ModifiedInteger"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221fe7ec10863310565a908457fa0f1b87a7c46f215435b4fa3ba8b1b64a766469b5a02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 154,
+ "comment" : "replaced r by r + 2**256",
+ "flags" : [
+ "IntegerOverflow"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022101813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 155,
+ "comment" : "replaced r by r + 2**320",
+ "flags" : [
+ "IntegerOverflow"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d0229010000000000000000813ef79ccefa9a56f7ba805f0e478584fe5f0dd5f567bc09b5123ccbc983236502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 156,
+ "comment" : "replaced s by s + n",
+ "flags" : [
+ "RangeCheck"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b7fc1e197d8aebe203c96c87232272172fb02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 157,
+ "comment" : "replaced s by s - n",
+ "flags" : [
+ "RangeCheck"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b824c83de0b502cdfc51723b51886b4f07902206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 158,
+ "comment" : "replaced s by s + 256 * n",
+ "flags" : [
+ "RangeCheck"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022201006ff18a52dcc0336f7af62400a6dd9a3bb60fa1a14815bbc0a954a0758d2c72ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 159,
+ "comment" : "replaced s by -s",
+ "flags" : [
+ "ModifiedInteger"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30440220900e75ad233fcc908509dbff5922647ef8cd450e008a7fff2909ec5aa914ce4602206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 160,
+ "comment" : "replaced s by -n - s",
+ "flags" : [
+ "ModifiedInteger"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221fe900e75ad233fcc908509dbff592264803e1e68275141dfc369378dcdd8de8d0502206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 161,
+ "comment" : "replaced s by s + 2**256",
+ "flags" : [
+ "IntegerOverflow"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221016ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 162,
+ "comment" : "replaced s by s - 2**256",
+ "flags" : [
+ "IntegerOverflow"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30450221ff6ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 163,
+ "comment" : "replaced s by s + 2**320",
+ "flags" : [
+ "IntegerOverflow"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304d02290100000000000000006ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba02206ff18a52dcc0336f7af62400a6dd9b810732baf1ff758000d6f613a556eb31ba",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 164,
+ "comment" : "Signature with special case values r=0 and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020100020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 165,
+ "comment" : "Signature with special case values r=0 and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020100020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 166,
+ "comment" : "Signature with special case values r=0 and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201000201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 167,
+ "comment" : "Signature with special case values r=0 and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 168,
+ "comment" : "Signature with special case values r=0 and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 169,
+ "comment" : "Signature with special case values r=0 and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020100022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 170,
+ "comment" : "Signature with special case values r=0 and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 171,
+ "comment" : "Signature with special case values r=0 and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020100022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 172,
+ "comment" : "Signature with special case values r=1 and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 173,
+ "comment" : "Signature with special case values r=1 and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 174,
+ "comment" : "Signature with special case values r=1 and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201010201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 175,
+ "comment" : "Signature with special case values r=1 and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 176,
+ "comment" : "Signature with special case values r=1 and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 177,
+ "comment" : "Signature with special case values r=1 and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020101022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 178,
+ "comment" : "Signature with special case values r=1 and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 179,
+ "comment" : "Signature with special case values r=1 and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 180,
+ "comment" : "Signature with special case values r=-1 and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 181,
+ "comment" : "Signature with special case values r=-1 and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 182,
+ "comment" : "Signature with special case values r=-1 and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff0201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 183,
+ "comment" : "Signature with special case values r=-1 and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 184,
+ "comment" : "Signature with special case values r=-1 and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 185,
+ "comment" : "Signature with special case values r=-1 and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260201ff022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 186,
+ "comment" : "Signature with special case values r=-1 and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 187,
+ "comment" : "Signature with special case values r=-1 and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260201ff022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 188,
+ "comment" : "Signature with special case values r=n and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 189,
+ "comment" : "Signature with special case values r=n and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 190,
+ "comment" : "Signature with special case values r=n and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 191,
+ "comment" : "Signature with special case values r=n and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 192,
+ "comment" : "Signature with special case values r=n and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 193,
+ "comment" : "Signature with special case values r=n and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 194,
+ "comment" : "Signature with special case values r=n and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 195,
+ "comment" : "Signature with special case values r=n and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 196,
+ "comment" : "Signature with special case values r=n - 1 and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 197,
+ "comment" : "Signature with special case values r=n - 1 and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 198,
+ "comment" : "Signature with special case values r=n - 1 and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641400201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 199,
+ "comment" : "Signature with special case values r=n - 1 and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 200,
+ "comment" : "Signature with special case values r=n - 1 and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 201,
+ "comment" : "Signature with special case values r=n - 1 and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 202,
+ "comment" : "Signature with special case values r=n - 1 and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 203,
+ "comment" : "Signature with special case values r=n - 1 and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 204,
+ "comment" : "Signature with special case values r=n + 1 and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 205,
+ "comment" : "Signature with special case values r=n + 1 and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 206,
+ "comment" : "Signature with special case values r=n + 1 and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641420201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 207,
+ "comment" : "Signature with special case values r=n + 1 and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 208,
+ "comment" : "Signature with special case values r=n + 1 and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 209,
+ "comment" : "Signature with special case values r=n + 1 and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 210,
+ "comment" : "Signature with special case values r=n + 1 and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 211,
+ "comment" : "Signature with special case values r=n + 1 and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 212,
+ "comment" : "Signature with special case values r=p and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 213,
+ "comment" : "Signature with special case values r=p and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 214,
+ "comment" : "Signature with special case values r=p and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 215,
+ "comment" : "Signature with special case values r=p and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 216,
+ "comment" : "Signature with special case values r=p and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 217,
+ "comment" : "Signature with special case values r=p and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 218,
+ "comment" : "Signature with special case values r=p and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 219,
+ "comment" : "Signature with special case values r=p and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 220,
+ "comment" : "Signature with special case values r=p + 1 and s=0",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 221,
+ "comment" : "Signature with special case values r=p + 1 and s=1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30020101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 222,
+ "comment" : "Signature with special case values r=p + 1 and s=-1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc300201ff",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 223,
+ "comment" : "Signature with special case values r=p + 1 and s=n",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 224,
+ "comment" : "Signature with special case values r=p + 1 and s=n - 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 225,
+ "comment" : "Signature with special case values r=p + 1 and s=n + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 226,
+ "comment" : "Signature with special case values r=p + 1 and s=p",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 227,
+ "comment" : "Signature with special case values r=p + 1 and s=p + 1",
+ "flags" : [
+ "InvalidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3046022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 228,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=0.25",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3008020100090380fe01",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 229,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=nan",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020100090142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 230,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=True",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020100010101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 231,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=False",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020100010100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 232,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=Null",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201000500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 233,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=empyt UTF-8 string",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201000c00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 234,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=\"0\"",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201000c0130",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 235,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=empty list",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201003000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 236,
+ "comment" : "Signature encoding contains incorrect types: r=0, s=list containing 0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30080201003003020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 237,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=0.25",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3008020101090380fe01",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 238,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=nan",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101090142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 239,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=True",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101010101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 240,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=False",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101010100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 241,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=Null",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201010500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 242,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=empyt UTF-8 string",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201010c00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 243,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=\"0\"",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201010c0130",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 244,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=empty list",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201013000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 245,
+ "comment" : "Signature encoding contains incorrect types: r=1, s=list containing 0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30080201013003020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 246,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=0.25",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30080201ff090380fe01",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 247,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=nan",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff090142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 248,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=True",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff010101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 249,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=False",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff010100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 250,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=Null",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201ff0500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 251,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=empyt UTF-8 string",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201ff0c00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 252,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=\"0\"",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060201ff0c0130",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 253,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=empty list",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050201ff3000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 254,
+ "comment" : "Signature encoding contains incorrect types: r=-1, s=list containing 0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30080201ff3003020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 255,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=0.25",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090380fe01",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 256,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=nan",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141090142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 257,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=True",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 258,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=False",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141010100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 259,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=Null",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 260,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=empyt UTF-8 string",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 261,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=\"0\"",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410c0130",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 262,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=empty list",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 263,
+ "comment" : "Signature encoding contains incorrect types: r=n, s=list containing 0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3028022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641413003020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 264,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=0.25",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090380fe01",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 265,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=nan",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f090142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 266,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=True",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 267,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=False",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f010100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 268,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=Null",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 269,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=empyt UTF-8 string",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 270,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=\"0\"",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0c0130",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 271,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=empty list",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 272,
+ "comment" : "Signature encoding contains incorrect types: r=p, s=list containing 0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3028022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f3003020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 273,
+ "comment" : "Signature encoding contains incorrect types: r=0.25, s=0.25",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "300a090380fe01090380fe01",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 274,
+ "comment" : "Signature encoding contains incorrect types: r=nan, s=nan",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006090142090142",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 275,
+ "comment" : "Signature encoding contains incorrect types: r=True, s=True",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006010101010101",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 276,
+ "comment" : "Signature encoding contains incorrect types: r=False, s=False",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006010100010100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 277,
+ "comment" : "Signature encoding contains incorrect types: r=Null, s=Null",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "300405000500",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 278,
+ "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=empyt UTF-8 string",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30040c000c00",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 279,
+ "comment" : "Signature encoding contains incorrect types: r=\"0\", s=\"0\"",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060c01300c0130",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 280,
+ "comment" : "Signature encoding contains incorrect types: r=empty list, s=empty list",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "300430003000",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 281,
+ "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=list containing 0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "300a30030201003003020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 282,
+ "comment" : "Signature encoding contains incorrect types: r=0.25, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3008090380fe01020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 283,
+ "comment" : "Signature encoding contains incorrect types: r=nan, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006090142020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 284,
+ "comment" : "Signature encoding contains incorrect types: r=True, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006010101020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 285,
+ "comment" : "Signature encoding contains incorrect types: r=False, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006010100020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 286,
+ "comment" : "Signature encoding contains incorrect types: r=Null, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050500020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 287,
+ "comment" : "Signature encoding contains incorrect types: r=empyt UTF-8 string, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30050c00020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 288,
+ "comment" : "Signature encoding contains incorrect types: r=\"0\", s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30060c0130020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 289,
+ "comment" : "Signature encoding contains incorrect types: r=empty list, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30053000020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 290,
+ "comment" : "Signature encoding contains incorrect types: r=list containing 0, s=0",
+ "flags" : [
+ "InvalidTypesInSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30083003020100020100",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 291,
+ "comment" : "Edge case for Shamir multiplication",
+ "flags" : [
+ "EdgeCaseShamirMultiplication"
+ ],
+ "msg" : "3235353835",
+ "sig" : "3045022100dd1b7d09a7bd8218961034a39a87fecf5314f00c4d25eb58a07ac85e85eab516022035138c401ef8d3493d65c9002fe62b43aee568731b744548358996d9cc427e06",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 292,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "343236343739373234",
+ "sig" : "304502210095c29267d972a043d955224546222bba343fc1d4db0fec262a33ac61305696ae02206edfe96713aed56f8a28a6653f57e0b829712e5eddc67f34682b24f0676b2640",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 293,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "37313338363834383931",
+ "sig" : "3044022028f94a894e92024699e345fe66971e3edcd050023386135ab3939d550898fb25022032963e5bd41fa5911ed8f37deb86dae0a762bb6121c894615083c5d95ea01db3",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 294,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3130333539333331363638",
+ "sig" : "3045022100be26b18f9549f89f411a9b52536b15aa270b84548d0e859a1952a27af1a77ac6022070c1d4fa9cd03cc8eaa8d506edb97eed7b8358b453c88aefbb880a3f0e8d472f",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 295,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33393439343031323135",
+ "sig" : "3045022100b1a4b1478e65cc3eafdf225d1298b43f2da19e4bcff7eacc0a2e98cd4b74b1140220179aa31e304cc142cf5073171751b28f3f5e0fa88c994e7c55f1bc07b8d56c16",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 296,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31333434323933303739",
+ "sig" : "30440220325332021261f1bd18f2712aa1e2252da23796da8a4b1ff6ea18cafec7e171f2022040b4f5e287ee61fc3c804186982360891eaa35c75f05a43ecd48b35d984a6648",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 297,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33373036323131373132",
+ "sig" : "3045022100a23ad18d8fc66d81af0903890cbd453a554cb04cdc1a8ca7f7f78e5367ed88a0022023e3eb2ce1c04ea748c389bd97374aa9413b9268851c04dcd9f88e78813fee56",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 298,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "333433363838373132",
+ "sig" : "304402202bdea41cda63a2d14bf47353bd20880a690901de7cd6e3cc6d8ed5ba0cdb109102203cea66bccfc9f9bf8c7ca4e1c1457cc9145e13e936d90b3d9c7786b8b26cf4c7",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 299,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31333531353330333730",
+ "sig" : "3045022100d7cd76ec01c1b1079eba9e2aa2a397243c4758c98a1ba0b7404a340b9b00ced602203575001e19d922e6de8b3d6c84ea43b5c3338106cf29990134e7669a826f78e6",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 300,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "36353533323033313236",
+ "sig" : "3045022100a872c744d936db21a10c361dd5c9063355f84902219652f6fc56dc95a7139d960220400df7575d9756210e9ccc77162c6b593c7746cfb48ac263c42750b421ef4bb9",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 301,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31353634333436363033",
+ "sig" : "30450221009fa9afe07752da10b36d3afcd0fe44bfc40244d75203599cf8f5047fa3453854022050e0a7c013bfbf51819736972d44b4b56bc2a2b2c180df6ec672df171410d77a",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 302,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "34343239353339313137",
+ "sig" : "3045022100885640384d0d910efb177b46be6c3dc5cac81f0b88c3190bb6b5f99c2641f2050220738ed9bff116306d9caa0f8fc608be243e0b567779d8dab03e8e19d553f1dc8e",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 303,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3130393533323631333531",
+ "sig" : "304402202d051f91c5a9d440c5676985710483bc4f1a6c611b10c95a2ff0363d90c2a45802206ddf94e6fba5be586833d0c53cf216ad3948f37953c26c1cf4968e9a9e8243dc",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 304,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "35393837333530303431",
+ "sig" : "3045022100f3ac2523967482f53d508522712d583f4379cd824101ff635ea0935117baa54f022027f10812227397e02cea96fb0e680761636dab2b080d1fc5d11685cbe8500cfe",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 305,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33343633303036383738",
+ "sig" : "304502210096447cf68c3ab7266ed7447de3ac52fed7cc08cbdfea391c18a9b8ab370bc91302200f5e7874d3ac0e918f01c885a1639177c923f8660d1ceba1ca1f301bc675cdbc",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 306,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "39383137333230323837",
+ "sig" : "30440220530a0832b691da0b5619a0b11de6877f3c0971baaa68ed122758c29caaf46b7202206c89e44f5eb33060ea4b46318c39138eaedec72de42ba576579a6a4690e339f3",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 307,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33323232303431303436",
+ "sig" : "30450221009c54c25500bde0b92d72d6ec483dc2482f3654294ca74de796b681255ed58a770220677453c6b56f527631c9f67b3f3eb621fd88582b4aff156d2f1567d6211a2a33",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 308,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "36363636333037313034",
+ "sig" : "3045022100e7909d41439e2f6af29136c7348ca2641a2b070d5b64f91ea9da7070c7a2618b022042d782f132fa1d36c2c88ba27c3d678d80184a5d1eccac7501f0b47e3d205008",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 309,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31303335393531383938",
+ "sig" : "304402205924873209593135a4c3da7bb381227f8a4b6aa9f34fe5bb7f8fbc131a039ffe02201f1bb11b441c8feaa40f44213d9a405ed792d59fb49d5bcdd9a4285ae5693022",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 310,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31383436353937313935",
+ "sig" : "3045022100eeb692c9b262969b231c38b5a7f60649e0c875cd64df88f33aa571fa3d29ab0e0220218b3a1eb06379c2c18cf51b06430786d1c64cd2d24c9b232b23e5bac7989acd",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 311,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33313336303436313839",
+ "sig" : "3045022100a40034177f36091c2b653684a0e3eb5d4bff18e4d09f664c2800e7cafda1daf802203a3ec29853704e52031c58927a800a968353adc3d973beba9172cbbeab4dd149",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 312,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "32363633373834323534",
+ "sig" : "3045022100b5d795cc75cea5c434fa4185180cd6bd21223f3d5a86da6670d71d95680dadbf022054e4d8810a001ecbb9f7ca1c2ebfdb9d009e9031a431aca3c20ab4e0d1374ec1",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 313,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31363532313030353234",
+ "sig" : "3044022007dc2478d43c1232a4595608c64426c35510051a631ae6a5a6eb1161e57e42e102204a59ea0fdb72d12165cea3bf1ca86ba97517bd188db3dbd21a5a157850021984",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 314,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "35373438303831363936",
+ "sig" : "3045022100ddd20c4a05596ca868b558839fce9f6511ddd83d1ccb53f82e5269d559a0155202205b91734729d93093ff22123c4a25819d7feb66a250663fc780cb66fc7b6e6d17",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 315,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "36333433393133343638",
+ "sig" : "30450221009cde6e0ede0a003f02fda0a01b59facfe5dec063318f279ce2de7a9b1062f7b702202886a5b8c679bdf8224c66f908fd6205492cb70b0068d46ae4f33a4149b12a52",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 316,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31353431313033353938",
+ "sig" : "3045022100c5771016d0dd6357143c89f684cd740423502554c0c59aa8c99584f1ff38f609022054b405f4477546686e464c5463b4fd4190572e58d0f7e7357f6e61947d20715c",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 317,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3130343738353830313238",
+ "sig" : "3045022100a24ebc0ec224bd67ae397cbe6fa37b3125adbd34891abe2d7c7356921916dfe6022034f6eb6374731bbbafc4924fb8b0bdcdda49456d724cdae6178d87014cb53d8c",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 318,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3130353336323835353638",
+ "sig" : "304402202557d64a7aee2e0931c012e4fea1cd3a2c334edae68cdeb7158caf21b68e5a2402207f06cdbb6a90023a973882ed97b080fe6b05af3ec93db6f1a4399a69edf7670d",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 319,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "393533393034313035",
+ "sig" : "3045022100c4f2eccbb6a24350c8466450b9d61b207ee359e037b3dcedb42a3f2e6dd6aeb502203263c6b59a2f55cdd1c6e14894d5e5963b28bc3e2469ac9ba1197991ca7ff9c7",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 320,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "393738383438303339",
+ "sig" : "3045022100eff04781c9cbcd162d0a25a6e2ebcca43506c523385cb515d49ea38a1b12fcad022015acd73194c91a95478534f23015b672ebed213e45424dd2c8e26ac8b3eb34a5",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 321,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33363130363732343432",
+ "sig" : "3045022100f58b4e3110a64bf1b5db97639ee0e5a9c8dfa49dc59b679891f520fdf0584c8702202cd8fe51888aee9db3e075440fd4db73b5c732fb87b510e97093d66415f62af7",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 322,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31303534323430373035",
+ "sig" : "3045022100f8abecaa4f0c502de4bf5903d48417f786bf92e8ad72fec0bd7fcb7800c0bbe302204c7f9e231076a30b7ae36b0cebe69ccef1cd194f7cce93a5588fd6814f437c0e",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 323,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "35313734343438313937",
+ "sig" : "304402205d5b38bd37ad498b2227a633268a8cca879a5c7c94a4e416bd0a614d09e606d2022012b8d664ea9991062ecbb834e58400e25c46007af84f6007d7f1685443269afe",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 324,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31393637353631323531",
+ "sig" : "304402200c1cd9fe4034f086a2b52d65b9d3834d72aebe7f33dfe8f976da82648177d8e3022013105782e3d0cfe85c2778dec1a848b27ac0ae071aa6da341a9553a946b41e59",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 325,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33343437323533333433",
+ "sig" : "3045022100ae7935fb96ff246b7b5d5662870d1ba587b03d6e1360baf47988b5c02ccc1a5b02205f00c323272083782d4a59f2dfd65e49de0693627016900ef7e61428056664b3",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 326,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "333638323634333138",
+ "sig" : "3044022000a134b5c6ccbcefd4c882b945baeb4933444172795fa6796aae1490675470980220566e46105d24d890151e3eea3ebf88f5b92b3f5ec93a217765a6dcbd94f2c55b",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 327,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33323631313938363038",
+ "sig" : "304402202e4721363ad3992c139e5a1c26395d2c2d777824aa24fde075e0d7381171309d0220740f7c494418e1300dd4512f782a58800bff6a7abdfdd20fbbd4f05515ca1a4f",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 328,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "39363738373831303934",
+ "sig" : "304402206852e9d3cd9fe373c2d504877967d365ab1456707b6817a042864694e1960ccf0220064b27ea142b30887b84c86adccb2fa39a6911ad21fc7e819f593be52bc4f3bd",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 329,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "34393538383233383233",
+ "sig" : "30440220188a8c5648dc79eace158cf886c62b5468f05fd95f03a7635c5b4c31f09af4c5022036361a0b571a00c6cd5e686ccbfcfa703c4f97e48938346d0c103fdc76dc5867",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 330,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "383234363337383337",
+ "sig" : "3045022100a74f1fb9a8263f62fc4416a5b7d584f4206f3996bb91f6fc8e73b9e92bad0e1302206815032e8c7d76c3ab06a86f33249ce9940148cb36d1f417c2e992e801afa3fa",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 331,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3131303230383333373736",
+ "sig" : "3044022007244865b72ff37e62e3146f0dc14682badd7197799135f0b00ade7671742bfe02200d80c2238edb4e4a7a86a8c57ca9af1711f406f7f5da0299aa04e2932d960754",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 332,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "313333383731363438",
+ "sig" : "3045022100da7fdd05b5badabd619d805c4ee7d9a84f84ddd5cf9c5bf4d4338140d689ef08022028f1cf4fa1c3c5862cfa149c0013cf5fe6cf5076cae000511063e7de25bb38e5",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 333,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "333232313434313632",
+ "sig" : "3045022100d3027c656f6d4fdfd8ede22093e3c303b0133c340d615e7756f6253aea927238022009aef060c8e4cef972974011558df144fed25ca69ae8d0b2eaf1a8feefbec417",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 334,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3130363836363535353436",
+ "sig" : "304402200bf6c0188dc9571cd0e21eecac5fbb19d2434988e9cc10244593ef3a98099f6902204864a562661f9221ec88e3dd0bc2f6e27ac128c30cc1a80f79ec670a22b042ee",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 335,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "3632313535323436",
+ "sig" : "3045022100ae459640d5d1179be47a47fa538e16d94ddea5585e7a244804a51742c686443a02206c8e30e530a634fae80b3ceb062978b39edbe19777e0a24553b68886181fd897",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 336,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "37303330383138373734",
+ "sig" : "304402201cf3517ba3bf2ab8b9ead4ebb6e866cb88a1deacb6a785d3b63b483ca02ac4950220249a798b73606f55f5f1c70de67cb1a0cff95d7dc50b3a617df861bad3c6b1c9",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 337,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "35393234353233373434",
+ "sig" : "3045022100e69b5238265ea35d77e4dd172288d8cea19810a10292617d5976519dc5757cb802204b03c5bc47e826bdb27328abd38d3056d77476b2130f3df6ec4891af08ba1e29",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 338,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31343935353836363231",
+ "sig" : "304402205f9d7d7c870d085fc1d49fff69e4a275812800d2cf8973e7325866cb40fa2b6f02206d1f5491d9f717a597a15fd540406486d76a44697b3f0d9d6dcef6669f8a0a56",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 339,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "34303035333134343036",
+ "sig" : "304402200a7d5b1959f71df9f817146ee49bd5c89b431e7993e2fdecab6858957da685ae02200f8aad2d254690bdc13f34a4fec44a02fd745a422df05ccbb54635a8b86b9609",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 340,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "33303936343537353132",
+ "sig" : "3044022079e88bf576b74bc07ca142395fda28f03d3d5e640b0b4ff0752c6d94cd553408022032cea05bd2d706c8f6036a507e2ab7766004f0904e2e5c5862749c0073245d6a",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 341,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "32373834303235363230",
+ "sig" : "30450221009d54e037a00212b377bc8874798b8da080564bbdf7e07591b861285809d01488022018b4e557667a82bd95965f0706f81a29243fbdd86968a7ebeb43069db3b18c7f",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 342,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "32363138373837343138",
+ "sig" : "304402202664f1ffa982fedbcc7cab1b8bc6e2cb420218d2a6077ad08e591ba9feab33bd022049f5c7cb515e83872a3d41b4cdb85f242ad9d61a5bfc01debfbb52c6c84ba728",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 343,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "31363432363235323632",
+ "sig" : "304402205827518344844fd6a7de73cbb0a6befdea7b13d2dee4475317f0f18ffc81524b02204f5ccb4e0b488b5a5d760aacddb2d791970fe43da61eb30e2e90208a817e46db",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 344,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "36383234313839343336",
+ "sig" : "304502210097ab19bd139cac319325869218b1bce111875d63fb12098a04b0cd59b6fdd3a30220431d9cea3a243847303cebda56476431d034339f31d785ee8852db4f040d4921",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 345,
+ "comment" : "special case hash",
+ "flags" : [
+ "SpecialCaseHash"
+ ],
+ "msg" : "343834323435343235",
+ "sig" : "3044022052c683144e44119ae2013749d4964ef67509278f6d38ba869adcfa69970e123d02203479910167408f45bda420a626ec9c4ec711c1274be092198b4187c018b562ca",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0",
+ "wx" : "07310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc362",
+ "wy" : "26a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000407310f90a9eae149a08402f54194a0f7b4ac427bf8d9bd6c7681071dc47dc36226a6d37ac46d61fd600c0bf1bff87689ed117dda6b0e59318ae010a197a26ca0",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEBzEPkKnq4UmghAL1QZSg97SsQnv42b1s\ndoEHHcR9w2ImptN6xG1h/WAMC/G/+HaJ7RF92msOWTGK4BChl6JsoA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 346,
+ "comment" : "k*G has a large x-coordinate",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30160211014551231950b75fc4402da1722fc9baeb020103",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 347,
+ "comment" : "r too large",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c020103",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5",
+ "wx" : "00bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22",
+ "wy" : "705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bc97e7585eecad48e16683bc4091708e1a930c683fc47001d4b383594f2c4e22705989cf69daeadd4e4e4b8151ed888dfec20fb01728d89d56b3f38f2ae9c8c5",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvJfnWF7srUjhZoO8QJFwjhqTDGg/xHAB\n1LODWU8sTiJwWYnPadrq3U5OS4FR7YiN/sIPsBco2J1Ws/OPKunIxQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 348,
+ "comment" : "r,s are large",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413f020103",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463",
+ "wx" : "44ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252",
+ "wy" : "00b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444ad339afbc21e9abf7b602a5ca535ea378135b6d10d81310bdd8293d1df3252b63ff7d0774770f8fe1d1722fa83acd02f434e4fc110a0cc8f6dddd37d56c463",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERK0zmvvCHpq/e2AqXKU16jeBNbbRDYEx\nC92Ck9HfMlK2P/fQd0dw+P4dFyL6g6zQL0NOT8EQoMyPbd3TfVbEYw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 349,
+ "comment" : "r and s^-1 have a large Hamming weight",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e9a7582886089c62fb840cf3b83061cd1cff3ae4341808bb5bdee6191174177",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0",
+ "wx" : "1260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c",
+ "wy" : "5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041260c2122c9e244e1af5151bede0c3ae23b54d7c596881d3eebad21f37dd878c5c9a0c1a9ade76737a8811bd6a7f9287c978ee396aa89c11e47229d2ccb552f0",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEmDCEiyeJE4a9RUb7eDDriO1TXxZaIHT\n7rrSHzfdh4xcmgwamt52c3qIEb1qf5KHyXjuOWqonBHkcinSzLVS8A==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 350,
+ "comment" : "r and s^-1 have a large Hamming weight",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022024238e70b431b1a64efdf9032669939d4b77f249503fc6905feb7540dea3e6d2",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159",
+ "wx" : "1877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce",
+ "wy" : "00821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041877045be25d34a1d0600f9d5c00d0645a2a54379b6ceefad2e6bf5c2a3352ce821a532cc1751ee1d36d41c3d6ab4e9b143e44ec46d73478ea6a79a5c0e54159",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGHcEW+JdNKHQYA+dXADQZFoqVDebbO76\n0ua/XCozUs6CGlMswXUe4dNtQcPWq06bFD5E7EbXNHjqanmlwOVBWQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 351,
+ "comment" : "small r and s",
+ "flags" : [
+ "SmallRandS",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101020101",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77",
+ "wx" : "455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50",
+ "wy" : "00aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004455439fcc3d2deeceddeaece60e7bd17304f36ebb602adf5a22e0b8f1db46a50aec38fb2baf221e9a8d1887c7bf6222dd1834634e77263315af6d23609d04f77",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERVQ5/MPS3uzt3q7OYOe9FzBPNuu2Aq31\noi4Ljx20alCuw4+yuvIh6ajRiHx79iIt0YNGNOdyYzFa9tI2CdBPdw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 352,
+ "comment" : "small r and s",
+ "flags" : [
+ "SmallRandS",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101020102",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d",
+ "wx" : "2e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece718",
+ "wy" : "0449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042e1f466b024c0c3ace2437de09127fed04b706f94b19a21bb1c2acf35cece7180449ae3523d72534e964972cfd3b38af0bddd9619e5af223e4d1a40f34cf9f1d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELh9GawJMDDrOJDfeCRJ/7QS3BvlLGaIb\nscKs81zs5xgESa41I9clNOlklyz9OzivC93ZYZ5a8iPk0aQPNM+fHQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 353,
+ "comment" : "small r and s",
+ "flags" : [
+ "SmallRandS",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020101020103",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3",
+ "wx" : "008e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a23373",
+ "wy" : "26ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048e7abdbbd18de7452374c1879a1c3b01d13261e7d4571c3b47a1c76c55a2337326ed897cd517a4f5349db809780f6d2f2b9f6299d8b5a89077f1119a718fd7b3",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjnq9u9GN50UjdMGHmhw7AdEyYefUVxw7\nR6HHbFWiM3Mm7Yl81Rek9TSduAl4D20vK59imdi1qJB38RGacY/Xsw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 354,
+ "comment" : "small r and s",
+ "flags" : [
+ "SmallRandS",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020102020101",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b",
+ "wx" : "7b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af19",
+ "wy" : "42117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047b333d4340d3d718dd3e6aff7de7bbf8b72bfd616c8420056052842376b9af1942117c5afeac755d6f376fc6329a7d76051b87123a4a5d0bc4a539380f03de7b",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEezM9Q0DT1xjdPmr/fee7+Lcr/WFshCAF\nYFKEI3a5rxlCEXxa/qx1XW83b8Yymn12BRuHEjpKXQvEpTk4DwPeew==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 355,
+ "comment" : "small r and s",
+ "flags" : [
+ "SmallRandS",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020102020102",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff",
+ "wx" : "00d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e5",
+ "wy" : "03a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d30ca4a0ddb6616c851d30ced682c40f83c62758a1f2759988d6763a88f1c0e503a80d5415650d41239784e8e2fb1235e9fe991d112ebb81186cbf0da2de3aff",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0wykoN22YWyFHTDO1oLED4PGJ1ih8nWZ\niNZ2OojxwOUDqA1UFWUNQSOXhOji+xI16f6ZHREuu4EYbL8Not46/w==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 356,
+ "comment" : "small r and s",
+ "flags" : [
+ "SmallRandS",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3006020102020103",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 357,
+ "comment" : "r is larger than n",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364143020103",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec",
+ "wx" : "48969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24",
+ "wy" : "00b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000448969b39991297b332a652d3ee6e01e909b39904e71fa2354a7830c7750baf24b4012d1b830d199ccb1fc972b32bfded55f09cd62d257e5e844e27e57a1594ec",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAESJabOZkSl7MyplLT7m4B6QmzmQTnH6I1\nSngwx3ULryS0AS0bgw0ZnMsfyXKzK/3tVfCc1i0lfl6ETiflehWU7A==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 358,
+ "comment" : "s is larger than n",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30080201020203ed2979",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866",
+ "wx" : "02ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee77",
+ "wy" : "7eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000402ef4d6d6cfd5a94f1d7784226e3e2a6c0a436c55839619f38fb4472b5f9ee777eb4acd4eebda5cd72875ffd2a2f26229c2dc6b46500919a432c86739f3ae866",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAu9NbWz9WpTx13hCJuPipsCkNsVYOWGf\nOPtEcrX57nd+tKzU7r2lzXKHX/0qLyYinC3GtGUAkZpDLIZznzroZg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 359,
+ "comment" : "small r and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260202010102203a74e9d3a74e9d3a74e9d3a74e9d3a749f8ab3732a0a89604a09bce5b2916da4",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08",
+ "wx" : "464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584",
+ "wy" : "00b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004464f4ff715729cae5072ca3bd801d3195b67aec65e9b01aad20a2943dcbcb584b1afd29d31a39a11d570aa1597439b3b2d1971bf2f1abf15432d0207b10d1d08",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERk9P9xVynK5Qcso72AHTGVtnrsZemwGq\n0gopQ9y8tYSxr9KdMaOaEdVwqhWXQ5s7LRlxvy8avxVDLQIHsQ0dCA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 360,
+ "comment" : "smallish r and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "302b02072d9b4d347952cc02200343aefc2f25d98b882e86eb9e30d55a6eb508b516510b34024ae4b6362330b3",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f",
+ "wx" : "157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4c",
+ "wy" : "00deadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004157f8fddf373eb5f49cfcf10d8b853cf91cbcd7d665c3522ba7dd738ddb79a4cdeadf1a5c448ea3c9f4191a8999abfcc757ac6d64567ef072c47fec613443b8f",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEFX+P3fNz619Jz88Q2LhTz5HLzX1mXDUi\nun3XON23mkzerfGlxEjqPJ9BkaiZmr/MdXrG1kVn7wcsR/7GE0Q7jw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 361,
+ "comment" : "100-bit r and small s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3031020d1033e67e37b32b445580bf4efc02206f906f906f906f906f906f906f906f8fe1cab5eefdb214061dce3b22789f1d6f",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa",
+ "wx" : "0934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0",
+ "wy" : "00d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200040934a537466c07430e2c48feb990bb19fb78cecc9cee424ea4d130291aa237f0d4f92d23b462804b5b68c52558c01c9996dbf727fccabbeedb9621a400535afa",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAECTSlN0ZsB0MOLEj+uZC7Gft4zsyc7kJO\npNEwKRqiN/DU+S0jtGKAS1toxSVYwByZltv3J/zKu+7bliGkAFNa+g==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 362,
+ "comment" : "small r and 100 bit s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3026020201010220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265",
+ "wx" : "00d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c65",
+ "wy" : "4a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d6ef20be66c893f741a9bf90d9b74675d1c2a31296397acb3ef174fd0b300c654a0c95478ca00399162d7f0f2dc89efdc2b28a30fbabe285857295a4b0c4e265",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1u8gvmbIk/dBqb+Q2bdGddHCoxKWOXrL\nPvF0/QswDGVKDJVHjKADmRYtfw8tyJ79wrKKMPur4oWFcpWksMTiZQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 363,
+ "comment" : "100-bit r and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3031020d062522bbd3ecbe7c39e93e7c260220783266e90f43dafe5cd9b3b0be86de22f9de83677d0f50713a468ec72fcf5d57",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829",
+ "wx" : "00b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee06",
+ "wy" : "29c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004b7291d1404e0c0c07dab9372189f4bd58d2ceaa8d15ede544d9514545ba9ee0629c9a63d5e308769cc30ec276a410e6464a27eeafd9e599db10f053a4fe4a829",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEtykdFATgwMB9q5NyGJ9L1Y0s6qjRXt5U\nTZUUVFup7gYpyaY9XjCHacww7CdqQQ5kZKJ+6v2eWZ2xDwU6T+SoKQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 364,
+ "comment" : "r and s^-1 are close to n",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03640c1022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6",
+ "wx" : "6e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8",
+ "wy" : "186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e28303305d642ccb923b722ea86b2a0bc8e3735ecb26e849b19c9f76b2fdbb8186e80d64d8cab164f5238f5318461bf89d4d96ee6544c816c7566947774e0f6",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbigwMwXWQsy5I7ci6oayoLyONzXssm6E\nmxnJ92sv27gYboDWTYyrFk9SOPUxhGG/idTZbuZUTIFsdWaUd3Tg9g==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 365,
+ "comment" : "r and s are 64-bit integer",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30160209009c44febf31c3594d020900839ed28247c2b06b",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd",
+ "wx" : "375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9",
+ "wy" : "00a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004375bda93f6af92fb5f8f4b1b5f0534e3bafab34cb7ad9fb9d0b722e4a5c302a9a00b9f387a5a396097aa2162fc5bbcf4a5263372f681c94da51e9799120990fd",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEN1vak/avkvtfj0sbXwU047r6s0y3rZ+5\n0Lci5KXDAqmgC584elo5YJeqIWL8W7z0pSYzcvaByU2lHpeZEgmQ/Q==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 366,
+ "comment" : "r and s are 100-bit integer",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "301e020d09df8b682430beef6f5fd7c7cf020d0fd0a62e13778f4222a0d61c8a",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44",
+ "wx" : "00d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197",
+ "wy" : "00da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d75b68216babe03ae257e94b4e3bf1c52f44e3df266d1524ff8c5ea69da73197da4bff9ed1c53f44917a67d7b978598e89df359e3d5913eaea24f3ae259abc44",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE11toIWur4DriV+lLTjvxxS9E498mbRUk\n/4xepp2nMZfaS/+e0cU/RJF6Z9e5eFmOid81nj1ZE+rqJPOuJZq8RA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 367,
+ "comment" : "r and s are 128-bit integer",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "30260211008a598e563a89f526c32ebec8de26367a02110084f633e2042630e99dd0f1e16f7a04bf",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e",
+ "wx" : "78bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653",
+ "wy" : "118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000478bcda140aed23d430cb23c3dc0d01f423db134ee94a3a8cb483f2deac2ac653118114f6f33045d4e9ed9107085007bfbddf8f58fe7a1a2445d66a990045476e",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeLzaFArtI9QwyyPD3A0B9CPbE07pSjqM\ntIPy3qwqxlMRgRT28zBF1OntkQcIUAe/vd+PWP56GiRF1mqZAEVHbg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 368,
+ "comment" : "r and s are 160-bit integer",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "302e021500aa6eeb5823f7fa31b466bb473797f0d0314c0bdf021500e2977c479e6d25703cebbc6bd561938cc9d1bfb9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677",
+ "wx" : "00bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c",
+ "wy" : "1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bb79f61857f743bfa1b6e7111ce4094377256969e4e15159123d9548acc3be6c1f9d9f8860dcffd3eb36dd6c31ff2e7226c2009c4c94d8d7d2b5686bf7abd677",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEu3n2GFf3Q7+htucRHOQJQ3claWnk4VFZ\nEj2VSKzDvmwfnZ+IYNz/0+s23Wwx/y5yJsIAnEyU2NfStWhr96vWdw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 369,
+ "comment" : "s == 1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020101",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 370,
+ "comment" : "s == 0",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3025022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1020100",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518",
+ "wx" : "0093591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36",
+ "wy" : "073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000493591827d9e6713b4e9faea62c72b28dfefa68e0c05160b5d6aae88fd2e36c36073f5545ad5af410af26afff68654cf72d45e493489311203247347a890f4518",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEk1kYJ9nmcTtOn66mLHKyjf76aODAUWC1\n1qroj9LjbDYHP1VFrVr0EK8mr/9oZUz3LUXkk0iTESAyRzR6iQ9FGA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 371,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220419d981c515af8cc82545aac0c85e9e308fbb2eab6acd7ed497e0b4145a18fd9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f",
+ "wx" : "31ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0da",
+ "wy" : "00da01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000431ed3081aefe001eb6402069ee2ccc1862937b85995144dba9503943587bf0dada01b8cc4df34f5ab3b1a359615208946e5ee35f98ee775b8ccecd86ccc1650f",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMe0wga7+AB62QCBp7izMGGKTe4WZUUTb\nqVA5Q1h78NraAbjMTfNPWrOxo1lhUgiUbl7jX5jud1uMzs2GzMFlDw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 372,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102201b21717ad71d23bbac60a9ad0baf75b063c9fdf52a00ebf99d022172910993c9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4",
+ "wx" : "7dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea8",
+ "wy" : "54c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047dff66fa98509ff3e2e51045f4390523dccda43a3bc2885e58c248090990eea854c76c2b9adeb6bb571823e07fd7c65c8639cf9d905260064c8e7675ce6d98b4",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEff9m+phQn/Pi5RBF9DkFI9zNpDo7wohe\nWMJICQmQ7qhUx2wrmt62u1cYI+B/18ZchjnPnZBSYAZMjnZ1zm2YtA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 373,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202f588f66018f3dd14db3e28e77996487e32486b521ed8e5a20f06591951777e9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1",
+ "wx" : "4280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a",
+ "wy" : "2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044280509aab64edfc0b4a2967e4cbce849cb544e4a77313c8e6ece579fbd7420a2e89fe5cc1927d554e6a3bb14033ea7c922cd75cba2c7415fdab52f20b1860f1",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEQoBQmqtk7fwLSiln5MvOhJy1ROSncxPI\n5uzlefvXQgouif5cwZJ9VU5qO7FAM+p8kizXXLosdBX9q1LyCxhg8Q==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 374,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220091a08870ff4daf9123b30c20e8c4fc8505758dcf4074fcaff2170c9bfcf74f4",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db",
+ "wx" : "4f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb",
+ "wy" : "2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f8df145194e3c4fc3eea26d43ce75b402d6b17472ddcbb254b8a79b0bf3d9cb2aa20d82844cb266344e71ca78f2ad27a75a09e5bc0fa57e4efd9d465a0888db",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAET43xRRlOPE/D7qJtQ851tALWsXRy3cuy\nVLinmwvz2csqog2ChEyyZjROccp48q0np1oJ5bwPpX5O/Z1GWgiI2w==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 375,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207c370dc0ce8c59a8b273cba44a7c1191fc3186dc03cab96b0567312df0d0b250",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207",
+ "wx" : "009598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14",
+ "wy" : "122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049598a57dd67ec3e16b587a338aa3a10a3a3913b41a3af32e3ed3ff01358c6b14122819edf8074bbc521f7d4cdce82fef7a516706affba1d93d9dea9ccae1a207",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElZilfdZ+w+FrWHoziqOhCjo5E7QaOvMu\nPtP/ATWMaxQSKBnt+AdLvFIffUzc6C/velFnBq/7odk9neqcyuGiBw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 376,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022070b59a7d1ee77a2f9e0491c2a7cfcd0ed04df4a35192f6132dcc668c79a6160e",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330",
+ "wx" : "009171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e",
+ "wy" : "634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049171fec3ca20806bc084f12f0760911b60990bd80e5b2a71ca03a048b20f837e634fd17863761b2958d2be4e149f8d3d7abbdc18be03f451ab6c17fa0a1f8330",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkXH+w8oggGvAhPEvB2CRG2CZC9gOWypx\nygOgSLIPg35jT9F4Y3YbKVjSvk4Un409ervcGL4D9FGrbBf6Ch+DMA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 377,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102202736d76e412246e097148e2bf62915614eb7c428913a58eb5e9cd4674a9423de",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d",
+ "wx" : "777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9",
+ "wy" : "00ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004777c8930b6e1d271100fe68ce93f163fa37612c5fff67f4a62fc3bafaf3d17a9ed73d86f60a51b5ed91353a3b054edc0aa92c9ebcbd0b75d188fdc882791d68d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEd3yJMLbh0nEQD+aM6T8WP6N2EsX/9n9K\nYvw7r689F6ntc9hvYKUbXtkTU6OwVO3AqpLJ68vQt10Yj9yIJ5HWjQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 378,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204a1e12831fbe93627b02d6e7f24bccdd6ef4b2d0f46739eaf3b1eaf0ca117770",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000",
+ "wx" : "00eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf470",
+ "wy" : "0603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004eabc248f626e0a63e1eb81c43d461a39a1dba881eb6ee2152b07c32d71bcf4700603caa8b9d33db13af44c6efbec8a198ed6124ac9eb17eaafd2824a545ec000",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE6rwkj2JuCmPh64HEPUYaOaHbqIHrbuIV\nKwfDLXG89HAGA8qoudM9sTr0TG777IoZjtYSSsnrF+qv0oJKVF7AAA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 379,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022006c778d4dfff7dee06ed88bc4e0ed34fc553aad67caf796f2a1c6487c1b2e877",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73",
+ "wx" : "009f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001",
+ "wy" : "00f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049f7a13ada158a55f9ddf1a45f044f073d9b80030efdcfc9f9f58418fbceaf001f8ada0175090f80d47227d6713b6740f9a0091d88a837d0a1cd77b58a8f28d73",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEn3oTraFYpV+d3xpF8ETwc9m4ADDv3Pyf\nn1hBj7zq8AH4raAXUJD4DUcifWcTtnQPmgCR2IqDfQoc13tYqPKNcw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 380,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102204de459ef9159afa057feb3ec40fef01c45b809f4ab296ea48c206d4249a2b451",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb",
+ "wx" : "11c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4db",
+ "wy" : "00bbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000411c4f3e461cd019b5c06ea0cea4c4090c3cc3e3c5d9f3c6d65b436826da9b4dbbbeb7a77e4cbfda207097c43423705f72c80476da3dac40a483b0ab0f2ead1cb",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEcTz5GHNAZtcBuoM6kxAkMPMPjxdnzxt\nZbQ2gm2ptNu763p35Mv9ogcJfENCNwX3LIBHbaPaxApIOwqw8urRyw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 381,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c10220745d294978007302033502e1acc48b63ae6500be43adbea1b258d6b423dbb416",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb",
+ "wx" : "00e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4",
+ "wy" : "161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e2e18682d53123aa01a6c5d00b0c623d671b462ea80bddd65227fd5105988aa4161907b3fd25044a949ea41c8e2ea8459dc6f1654856b8b61b31543bb1b45bdb",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE4uGGgtUxI6oBpsXQCwxiPWcbRi6oC93W\nUif9UQWYiqQWGQez/SUESpSepByOLqhFncbxZUhWuLYbMVQ7sbRb2w==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 382,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102207b2a785e3896f59b2d69da57648e80ad3c133a750a2847fd2098ccd902042b6c",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d",
+ "wx" : "0090f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197da",
+ "wy" : "00fadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000490f8d4ca73de08a6564aaf005247b6f0ffe978504dce52605f46b7c3e56197dafadbe528eb70d9ee7ea0e70702db54f721514c7b8604ac2cb214f1decb7e383d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEkPjUynPeCKZWSq8AUke28P/peFBNzlJg\nX0a3w+Vhl9r62+Uo63DZ7n6g5wcC21T3IVFMe4YErCyyFPHey344PQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 383,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c1022071ae94a72ca896875e7aa4a4c3d29afdb4b35b6996273e63c47ac519256c5eb1",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc",
+ "wx" : "00824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e",
+ "wy" : "3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004824c195c73cffdf038d101bce1687b5c3b6146f395c885976f7753b2376b948e3cdefa6fc347d13e4dcbc63a0b03a165180cd2be1431a0cf74ce1ea25082d2bc",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEgkwZXHPP/fA40QG84Wh7XDthRvOVyIWX\nb3dTsjdrlI483vpvw0fRPk3LxjoLA6FlGAzSvhQxoM90zh6iUILSvA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 384,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102200fa527fa7343c0bc9ec35a6278bfbff4d83301b154fc4bd14aee7eb93445b5f9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f",
+ "wx" : "2788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f",
+ "wy" : "30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042788a52f078eb3f202c4fa73e0d3386faf3df6be856003636f599922d4f5268f30b4f207c919bbdf5e67a8be4265a8174754b3aba8f16e575b77ff4d5a7eb64f",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ4ilLweOs/ICxPpz4NM4b6899r6FYANj\nb1mZItT1Jo8wtPIHyRm7315nqL5CZagXR1Szq6jxbldbd/9NWn62Tw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 385,
+ "comment" : "edge case modular inverse",
+ "flags" : [
+ "ModularInverse",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c102206539c0adadd0525ff42622164ce9314348bd0863b4c80e936b23ca0414264671",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4",
+ "wx" : "00d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b4150874",
+ "wy" : "01b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d533b789a4af890fa7a82a1fae58c404f9a62a50b49adafab349c513b415087401b4171b803e76b34a9861e10f7bc289a066fd01bd29f84c987a10a5fb18c2d4",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1TO3iaSviQ+nqCofrljEBPmmKlC0mtr6\ns0nFE7QVCHQBtBcbgD52s0qYYeEPe8KJoGb9Ab0p+EyYehCl+xjC1A==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 386,
+ "comment" : "point at infinity during verify",
+ "flags" : [
+ "PointDuplication",
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a",
+ "wx" : "3a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4",
+ "wy" : "221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043a3150798c8af69d1e6e981f3a45402ba1d732f4be8330c5164f49e10ec555b4221bd842bc5e4d97eff37165f60e3998a424d72a450cf95ea477c78287d0343a",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOjFQeYyK9p0ebpgfOkVAK6HXMvS+gzDF\nFk9J4Q7FVbQiG9hCvF5Nl+/zcWX2DjmYpCTXKkUM+V6kd8eCh9A0Og==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 387,
+ "comment" : "edge case for signature malleability",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026",
+ "wx" : "3b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e80",
+ "wy" : "0de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043b37df5fb347c69a0f17d85c0c7ca83736883a825e13143d0fcfc8101e851e800de3c090b6ca21ba543517330c04b12f948c6badf14a63abffdf4ef8c7537026",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOzffX7NHxpoPF9hcDHyoNzaIOoJeExQ9\nD8/IEB6FHoAN48CQtsohulQ1FzMMBLEvlIxrrfFKY6v/3074x1NwJg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 388,
+ "comment" : "edge case for signature malleability",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a002207fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e",
+ "wx" : "00feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82c",
+ "wy" : "00e87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004feb5163b0ece30ff3e03c7d55c4380fa2fa81ee2c0354942ff6f08c99d0cd82ce87de05ee1bda089d3e4e248fa0f721102acfffdf50e654be281433999df897e",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/rUWOw7OMP8+A8fVXEOA+i+oHuLANUlC\n/28IyZ0M2CzofeBe4b2gidPk4kj6D3IRAqz//fUOZUvigUM5md+Jfg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 389,
+ "comment" : "u1 == 1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2",
+ "wx" : "238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd4149228976",
+ "wy" : "40683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004238ced001cf22b8853e02edc89cbeca5050ba7e042a7a77f9382cd414922897640683d3094643840f295890aa4c18aa39b41d77dd0fb3bb2700e4f9ec284ffc2",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEI4ztABzyK4hT4C7cicvspQULp+BCp6d/\nk4LNQUkiiXZAaD0wlGQ4QPKViQqkwYqjm0HXfdD7O7JwDk+ewoT/wg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 390,
+ "comment" : "u1 == n - 1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf",
+ "wx" : "00961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35e",
+ "wy" : "00d2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004961cf64817c06c0e51b3c2736c922fde18bd8c4906fcd7f5ef66c4678508f35ed2c5d18168cfbe70f2f123bd7419232bb92dd69113e2941061889481c5a027bf",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAElhz2SBfAbA5Rs8JzbJIv3hi9jEkG/Nf1\n72bEZ4UI817SxdGBaM++cPLxI710GSMruS3WkRPilBBhiJSBxaAnvw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 391,
+ "comment" : "u2 == 1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384",
+ "wx" : "13681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b10288",
+ "wy" : "16528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000413681eae168cd4ea7cf2e2a45d052742d10a9f64e796867dbdcb829fe0b1028816528760d177376c09df79de39557c329cc1753517acffe8fa2ec298026b8384",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEE2gerhaM1Op88uKkXQUnQtEKn2TnloZ9\nvcuCn+CxAogWUodg0Xc3bAnfed45VXwynMF1NRes/+j6LsKYAmuDhA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 392,
+ "comment" : "u2 == n - 1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215b8",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b",
+ "wx" : "5aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c2",
+ "wy" : "0091c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045aa7abfdb6b4086d543325e5d79c6e95ce42f866d2bb84909633a04bb1aa31c291c80088794905e1da33336d874e2f91ccf45cc59185bede5dd6f3f7acaae18b",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWqer/ba0CG1UMyXl15xulc5C+GbSu4SQ\nljOgS7GqMcKRyACIeUkF4dozM22HTi+RzPRcxZGFvt5d1vP3rKrhiw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 393,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41",
+ "wx" : "277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e4",
+ "wy" : "64108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000400277791b305a45b2b39590b2f05d3392a6c8182cef4eb540120e0f5c206c3e464108233fb0b8c3ac892d79ef8e0fbf92ed133addb4554270132584dc52eef41",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEACd3kbMFpFsrOVkLLwXTOSpsgYLO9OtU\nASDg9cIGw+RkEIIz+wuMOsiS15744Pv5LtEzrdtFVCcBMlhNxS7vQQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 394,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02201c940f313f92647be257eccd7ed08b0baef3f0478f25871b53635302c5f6314a",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49",
+ "wx" : "6efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1a",
+ "wy" : "00c75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046efa092b68de9460f0bcc919005a5f6e80e19de98968be3cd2c770a9949bfb1ac75e6e5087d6550d5f9beb1e79e5029307bc255235e2d5dc99241ac3ab886c49",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbvoJK2jelGDwvMkZAFpfboDhnemJaL48\n0sdwqZSb+xrHXm5Qh9ZVDV+b6x555QKTB7wlUjXi1dyZJBrDq4hsSQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 395,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022015d94a85077b493f91cb7101ec63e1b01be58b594e855f45050a8c14062d689b",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942",
+ "wx" : "72d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058",
+ "wy" : "00e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000472d4a19c4f9d2cf5848ea40445b70d4696b5f02d632c0c654cc7d7eeb0c6d058e8c4cd9943e459174c7ac01fa742198e47e6c19a6bdb0c4f6c237831c1b3f942",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEctShnE+dLPWEjqQERbcNRpa18C1jLAxl\nTMfX7rDG0FjoxM2ZQ+RZF0x6wB+nQhmOR+bBmmvbDE9sI3gxwbP5Qg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 396,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b1d27a7694c146244a5ad0bd0636d9d9ef3b9fb58385418d9c982105077d1b7",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec",
+ "wx" : "2a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e7402",
+ "wy" : "58f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042a8ea2f50dcced0c217575bdfa7cd47d1c6f100041ec0e35512794c1be7e740258f8c17122ed303fda7143eb58bede70295b653266013b0b0ebd3f053137f6ec",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEKo6i9Q3M7QwhdXW9+nzUfRxvEABB7A41\nUSeUwb5+dAJY+MFxIu0wP9pxQ+tYvt5wKVtlMmYBOwsOvT8FMTf27A==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 397,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202d85896b3eb9dbb5a52f42f9c9261ed3fc46644ec65f06ade3fd78f257e43432",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946",
+ "wx" : "0088de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b8",
+ "wy" : "0c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000488de689ce9af1e94be6a2089c8a8b1253ffdbb6c8e9c86249ba220001a4ad3b80c4998e54842f413b9edb1825acbb6335e81e4d184b2b01c8bebdc85d1f28946",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiN5onOmvHpS+aiCJyKixJT/9u2yOnIYk\nm6IgABpK07gMSZjlSEL0E7ntsYJay7YzXoHk0YSysByL69yF0fKJRg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 398,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205b0b12d67d73b76b4a5e85f3924c3da7f88cc89d8cbe0d5bc7faf1e4afc86864",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9",
+ "wx" : "00fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7",
+ "wy" : "00b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004fea2d31f70f90d5fb3e00e186ac42ab3c1615cee714e0b4e1131b3d4d8225bf7b037a18df2ac15343f30f74067ddf29e817d5f77f8dce05714da59c094f0cda9",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE/qLTH3D5DV+z4A4YasQqs8FhXO5xTgtO\nETGz1NgiW/ewN6GN8qwVND8w90Bn3fKegX1fd/jc4FcU2lnAlPDNqQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 399,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220694c146244a5ad0bd0636d9e12bc9e09e60e68b90d0b5e6c5dddd0cb694d8799",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0",
+ "wx" : "7258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db",
+ "wy" : "17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200047258911e3d423349166479dbe0b8341af7fbd03d0a7e10edccb36b6ceea5a3db17ac2b8992791128fa3b96dc2fbd4ca3bfa782ef2832fc6656943db18e7346b0",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcliRHj1CM0kWZHnb4Lg0Gvf70D0KfhDt\nzLNrbO6lo9sXrCuJknkRKPo7ltwvvUyjv6eC7ygy/GZWlD2xjnNGsA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 400,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203d7f487c07bfc5f30846938a3dcef696444707cf9677254a92b06c63ab867d22",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470",
+ "wx" : "4f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914",
+ "wy" : "00c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200044f28461dea64474d6bb34d1499c97d37b9e95633df1ceeeaacd45016c98b3914c8818810b8cc06ddb40e8a1261c528faa589455d5a6df93b77bc5e0e493c7470",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAETyhGHepkR01rs00Umcl9N7npVjPfHO7q\nrNRQFsmLORTIgYgQuMwG3bQOihJhxSj6pYlFXVpt+Tt3vF4OSTx0cA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 401,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206c7648fc0fbf8a06adb8b839f97b4ff7a800f11b1e37c593b261394599792ba4",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b",
+ "wx" : "74f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66",
+ "wy" : "00eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000474f2a814fb5d8eca91a69b5e60712732b3937de32829be974ed7b68c5c2f5d66eff0f07c56f987a657f42196205f588c0f1d96fd8a63a5f238b48f478788fe3b",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEdPKoFPtdjsqRppteYHEnMrOTfeMoKb6X\nTte2jFwvXWbv8PB8VvmHplf0IZYgX1iMDx2W/YpjpfI4tI9Hh4j+Ow==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 402,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220641c9c5d790dc09cdd3dfabb62cdf453e69747a7e3d7aa1a714189ef53171a99",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad",
+ "wx" : "195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6a",
+ "wy" : "00b2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004195b51a7cc4a21b8274a70a90de779814c3c8ca358328208c09a29f336b82d6ab2416b7c92fffdc29c3b1282dd2a77a4d04df7f7452047393d849989c5cee9ad",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGVtRp8xKIbgnSnCpDed5gUw8jKNYMoII\nwJop8za4LWqyQWt8kv/9wpw7EoLdKnek0E3390UgRzk9hJmJxc7prQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 403,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022029798c5c45bdf58b4a7b2fdc2c46ab4af1218c7eeb9f0f27a88f1267674de3b0",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0",
+ "wx" : "622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa",
+ "wy" : "736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004622fc74732034bec2ddf3bc16d34b3d1f7a327dd2a8c19bab4bb4fe3a24b58aa736b2f2fae76f4dfaecc9096333b01328d51eb3fda9c9227e90d0b449983c4f0",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYi/HRzIDS+wt3zvBbTSz0fejJ90qjBm6\ntLtP46JLWKpzay8vrnb0367MkJYzOwEyjVHrP9qckifpDQtEmYPE8A==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 404,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02200b70f22ca2bb3cefadca1a5711fa3a59f4695385eb5aedf3495d0b6d00f8fd85",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93",
+ "wx" : "1f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c7",
+ "wy" : "0827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f7f85caf2d7550e7af9b65023ebb4dce3450311692309db269969b834b611c70827f45b78020ecbbaf484fdd5bfaae6870f1184c21581baf6ef82bd7b530f93",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH3+FyvLXVQ56+bZQI+u03ONFAxFpIwnb\nJplpuDS2EccIJ/RbeAIOy7r0hP3Vv6rmhw8RhMIVgbr274K9e1MPkw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 405,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022016e1e459457679df5b9434ae23f474b3e8d2a70bd6b5dbe692ba16da01f1fb0a",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d",
+ "wx" : "49c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377a",
+ "wy" : "00efc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000449c197dc80ad1da47a4342b93893e8e1fb0bb94fc33a83e783c00b24c781377aefc20da92bac762951f72474becc734d4cc22ba81b895e282fdac4df7af0f37d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEScGX3ICtHaR6Q0K5OJPo4fsLuU/DOoPn\ng8ALJMeBN3rvwg2pK6x2KVH3JHS+zHNNTMIrqBuJXigv2sTfevDzfQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 406,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202252d685e831b6cf095e4f0535eeaf0ddd3bfa91c210c9d9dc17224702eaf88f",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c",
+ "wx" : "00d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe",
+ "wy" : "7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d8cb68517b616a56400aa3868635e54b6f699598a2f6167757654980baf6acbe7ec8cf449c849aa03461a30efada41453c57c6e6fbc93bbc6fa49ada6dc0555c",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2MtoUXthalZACqOGhjXlS29plZii9hZ3\nV2VJgLr2rL5+yM9EnISaoDRhow762kFFPFfG5vvJO7xvpJrabcBVXA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 407,
+ "comment" : "edge case for u1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022075135abd7c425b60371a477f09ce0f274f64a8c6b061a07b5d63e93c65046c53",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750",
+ "wx" : "030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3",
+ "wy" : "00b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004030713fb63f2aa6fe2cadf1b20efc259c77445dafa87dac398b84065ca347df3b227818de1a39b589cb071d83e5317cccdc2338e51e312fe31d8dc34a4801750",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAwcT+2Pyqm/iyt8bIO/CWcd0Rdr6h9rD\nmLhAZco0ffOyJ4GN4aObWJywcdg+UxfMzcIzjlHjEv4x2Nw0pIAXUA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 408,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950",
+ "wx" : "00babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7",
+ "wy" : "252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004babb3677b0955802d8e929a41355640eaf1ea1353f8a771331c4946e3480afa7252f196c87ed3d2a59d3b1b559137fed0013fecefc19fb5a92682b9bca51b950",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEurs2d7CVWALY6SmkE1VkDq8eoTU/incT\nMcSUbjSAr6clLxlsh+09KlnTsbVZE3/tABP+zvwZ+1qSaCubylG5UA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 409,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203e888377ac6c71ac9dec3fdb9b56c9feaf0cfaca9f827fc5eb65fc3eac811210",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9",
+ "wx" : "1aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60",
+ "wy" : "00bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041aab2018793471111a8a0e9b143fde02fc95920796d3a63de329b424396fba60bbe4130705174792441b318d3aa31dfe8577821e9b446ec573d272e036c4ebe9",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGqsgGHk0cREaig6bFD/eAvyVkgeW06Y9\n4ym0JDlvumC75BMHBRdHkkQbMY06ox3+hXeCHptEbsVz0nLgNsTr6Q==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 410,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022030bbb794db588363b40679f6c182a50d3ce9679acdd3ffbe36d7813dacbdc818",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75",
+ "wx" : "008cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff",
+ "wy" : "47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048cb0b909499c83ea806cd885b1dd467a0119f06a88a0276eb0cfda274535a8ff47b5428833bc3f2c8bf9d9041158cf33718a69961cd01729bc0011d1e586ab75",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjLC5CUmcg+qAbNiFsd1GegEZ8GqIoCdu\nsM/aJ0U1qP9HtUKIM7w/LIv52QQRWM8zcYpplhzQFym8ABHR5YardQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 411,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202c37fd995622c4fb7fffffffffffffffc7cee745110cb45ab558ed7c90c15a2f",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0",
+ "wx" : "008f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d",
+ "wy" : "3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048f03cf1a42272bb1532723093f72e6feeac85e1700e9fbe9a6a2dd642d74bf5d3b89a7189dad8cf75fc22f6f158aa27f9c2ca00daca785be3358f2bda3862ca0",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjwPPGkInK7FTJyMJP3Lm/urIXhcA6fvp\npqLdZC10v107iacYna2M91/CL28ViqJ/nCygDaynhb4zWPK9o4YsoA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 412,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02207fd995622c4fb7ffffffffffffffffff5d883ffab5b32652ccdcaa290fccb97d",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12",
+ "wx" : "44de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8ace",
+ "wy" : "00a2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000444de3b9c7a57a8c9e820952753421e7d987bb3d79f71f013805c897e018f8acea2460758c8f98d3fdce121a943659e372c326fff2e5fc2ae7fa3f79daae13c12",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAERN47nHpXqMnoIJUnU0IefZh7s9efcfAT\ngFyJfgGPis6iRgdYyPmNP9zhIalDZZ43LDJv/y5fwq5/o/edquE8Eg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 413,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304302207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc021f4cd53ba7608fffffffffffffffffffff9e5cf143e2539626190a3ab09cce47",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204",
+ "wx" : "6fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a",
+ "wy" : "0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046fb8b2b48e33031268ad6a517484dc8839ea90f6669ea0c7ac3233e2ac31394a0ac8bbe7f73c2ff4df9978727ac1dfc2fd58647d20f31f99105316b64671f204",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEb7iytI4zAxJorWpRdITciDnqkPZmnqDH\nrDIz4qwxOUoKyLvn9zwv9N+ZeHJ6wd/C/VhkfSDzH5kQUxa2RnHyBA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 414,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02205622c4fb7fffffffffffffffffffffff928a8f1c7ac7bec1808b9f61c01ec327",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c",
+ "wx" : "00bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6",
+ "wy" : "00f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004bea71122a048693e905ff602b3cf9dd18af69b9fc9d8431d2b1dd26b942c95e6f43c7b8b95eb62082c12db9dbda7fe38e45cbe4a4886907fb81bdb0c5ea9246c",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEvqcRIqBIaT6QX/YCs8+d0Yr2m5/J2EMd\nKx3Sa5Qsleb0PHuLletiCCwS2529p/445Fy+SkiGkH+4G9sMXqkkbA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 415,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc022044104104104104104104104104104103b87853fd3b7d3f8e175125b4382f25ed",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391",
+ "wx" : "00da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156",
+ "wy" : "00e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004da918c731ba06a20cb94ef33b778e981a404a305f1941fe33666b45b03353156e2bb2694f575b45183be78e5c9b5210bf3bf488fd4c8294516d89572ca4f5391",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE2pGMcxugaiDLlO8zt3jpgaQEowXxlB/j\nNma0WwM1MVbiuyaU9XW0UYO+eOXJtSEL879Ij9TIKUUW2JVyyk9TkQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 416,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202739ce739ce739ce739ce739ce739ce705560298d1f2f08dc419ac273a5b54d9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5",
+ "wx" : "3007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d",
+ "wy" : "5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043007e92c3937dade7964dfa35b0eff031f7eb02aed0a0314411106cdeb70fe3d5a7546fc0552997b20e3d6f413e75e2cb66e116322697114b79bac734bfc4dc5",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEMAfpLDk32t55ZN+jWw7/Ax9+sCrtCgMU\nQREGzetw/j1adUb8BVKZeyDj1vQT514stm4RYyJpcRS3m6xzS/xNxQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 417,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02204888888888888888888888888888888831c83ae82ebe0898776b4c69d11f88de",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567",
+ "wx" : "60e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9b",
+ "wy" : "00d2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000460e734ef5624d3cbf0ddd375011bd663d6d6aebc644eb599fdf98dbdcd18ce9bd2d90b3ac31f139af832cccf6ccbbb2c6ea11fa97370dc9906da474d7d8a7567",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYOc071Yk08vw3dN1ARvWY9bWrrxkTrWZ\n/fmNvc0YzpvS2Qs6wx8TmvgyzM9sy7ssbqEfqXNw3JkG2kdNfYp1Zw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 418,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206492492492492492492492492492492406dd3a19b8d5fb875235963c593bd2d3",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c",
+ "wx" : "0085a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba337",
+ "wy" : "69744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000485a900e97858f693c0b7dfa261e380dad6ea046d1f65ddeeedd5f7d8af0ba33769744d15add4f6c0bc3b0da2aec93b34cb8c65f9340ddf74e7b0009eeeccce3c",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhakA6XhY9pPAt9+iYeOA2tbqBG0fZd3u\n7dX32K8LozdpdE0VrdT2wLw7DaKuyTs0y4xl+TQN33TnsACe7szOPA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 419,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02206aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b15",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed",
+ "wx" : "38066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046",
+ "wy" : "00a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000438066f75d88efc4c93de36f49e037b234cc18b1de5608750a62cab0345401046a3e84bed8cfcb819ef4d550444f2ce4b651766b69e2e2901f88836ff90034fed",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEOAZvddiO/EyT3jb0ngN7I0zBix3lYIdQ\npiyrA0VAEEaj6EvtjPy4Ge9NVQRE8s5LZRdmtp4uKQH4iDb/kANP7Q==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 420,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02202aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa3e3a49a23a6d8abe95461f8445676b17",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89",
+ "wx" : "0098f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabf",
+ "wy" : "00a33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000498f68177dc95c1b4cbfa5245488ca523a7d5629470d035d621a443c72f39aabfa33d29546fa1c648f2c7d5ccf70cf1ce4ab79b5db1ac059dbecd068dbdff1b89",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmPaBd9yVwbTL+lJFSIylI6fVYpRw0DXW\nIaRDxy85qr+jPSlUb6HGSPLH1cz3DPHOSrebXbGsBZ2+zQaNvf8biQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 421,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc02203ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191",
+ "wx" : "5c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277",
+ "wy" : "00e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200045c2bbfa23c9b9ad07f038aa89b4930bf267d9401e4255de9e8da0a5078ec8277e3e882a31d5e6a379e0793983ccded39b95c4353ab2ff01ea5369ba47b0c3191",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEXCu/ojybmtB/A4qom0kwvyZ9lAHkJV3p\n6NoKUHjsgnfj6IKjHV5qN54Hk5g8ze05uVxDU6sv8B6lNpukewwxkQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 422,
+ "comment" : "edge case for u2",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "304402207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0220185ddbca6dac41b1da033cfb60c152869e74b3cd66e9ffdf1b6bc09ed65ee40c",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc",
+ "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385",
+ "wy" : "3547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a3853547808298448edb5e701ade84cd5fb1ac9567ba5e8fb68a6b933ec4b5cc84cc",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4U1R4CCmESO215wGt6EzV+xrJVnul6Ptoprkz7EtcyEzA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 423,
+ "comment" : "point duplication during verification",
+ "flags" : [
+ "PointDuplication"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763",
+ "wx" : "2ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385",
+ "wy" : "00cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200042ea7133432339c69d27f9b267281bd2ddd5f19d6338d400a05cd3647b157a385cab87f7d67bb7124a18fe5217b32a04e536a9845a1704975946cc13a4a337763",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELqcTNDIznGnSf5smcoG9Ld1fGdYzjUAK\nBc02R7FXo4XKuH99Z7txJKGP5SF7MqBOU2qYRaFwSXWUbME6SjN3Yw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 424,
+ "comment" : "duplication bug",
+ "flags" : [
+ "PointDuplication"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022032b0d10d8d0e04bc8d4d064d270699e87cffc9b49c5c20730e1c26f6105ddcda022029ed3d67b3d505be95580d77d5b792b436881179b2b6b2e04c5fe592d38d82d9",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff",
+ "wx" : "008aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e",
+ "wy" : "1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048aa2c64fa9c6437563abfbcbd00b2048d48c18c152a2a6f49036de7647ebe82e1ce64387995c68a060fa3bc0399b05cc06eec7d598f75041a4917e692b7f51ff",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEiqLGT6nGQ3Vjq/vL0AsgSNSMGMFSoqb0\nkDbedkfr6C4c5kOHmVxooGD6O8A5mwXMBu7H1Zj3UEGkkX5pK39R/w==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 425,
+ "comment" : "comparison with point at infinity ",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0022033333333333333333333333333333332f222f8faefdb533f265d461c29a47373",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd",
+ "wx" : "391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71f",
+ "wy" : "00dd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004391427ff7ee78013c14aec7d96a8a062209298a783835e94fd6549d502fff71fdd6624ec343ad9fcf4d9872181e59f842f9ba4cccae09a6c0972fb6ac6b4c6bd",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEORQn/37ngBPBSux9lqigYiCSmKeDg16U\n/WVJ1QL/9x/dZiTsNDrZ/PTZhyGB5Z+EL5ukzMrgmmwJcvtqxrTGvQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 426,
+ "comment" : "extreme value for k and edgecase s",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e",
+ "wx" : "00e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138e",
+ "wy" : "00c1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004e762b8a219b4f180219cc7a9059245e4961bd191c03899789c7a34b89e8c138ec1533ef0419bb7376e0bfde9319d10a06968791d9ea0eed9c1ce6345aed9759e",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE52K4ohm08YAhnMepBZJF5JYb0ZHAOJl4\nnHo0uJ6ME47BUz7wQZu3N24L/ekxnRCgaWh5HZ6g7tnBzmNFrtl1ng==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 427,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175",
+ "wx" : "009aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952",
+ "wy" : "00fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200049aedb0d281db164e130000c5697fae0f305ef848be6fffb43ac593fbb950e952fa6f633359bdcd82b56b0b9f965b037789d46b9a8141b791b2aefa713f96c175",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEmu2w0oHbFk4TAADFaX+uDzBe+Ei+b/+0\nOsWT+7lQ6VL6b2MzWb3NgrVrC5+WWwN3idRrmoFBt5GyrvpxP5bBdQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 428,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd",
+ "wx" : "008ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee",
+ "wy" : "1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048ad445db62816260e4e687fd1884e48b9fc0636d031547d63315e792e19bfaee1de64f99d5f1cd8b6ec9cb0f787a654ae86993ba3db1008ef43cff0684cb22bd",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEitRF22KBYmDk5of9GITki5/AY20DFUfW\nMxXnkuGb+u4d5k+Z1fHNi27Jyw94emVK6GmTuj2xAI70PP8GhMsivQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 429,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566",
+ "wx" : "1f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32",
+ "wy" : "00e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200041f5799c95be89063b24f26e40cb928c1a868a76fb0094607e8043db409c91c32e75724e813a4191e3a839007f08e2e897388b06d4a00de6de60e536d91fab566",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEH1eZyVvokGOyTybkDLkowahop2+wCUYH\n6AQ9tAnJHDLnVyToE6QZHjqDkAfwji6Jc4iwbUoA3m3mDlNtkfq1Zg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 430,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d",
+ "wx" : "00a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc",
+ "wy" : "28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004a3331a4e1b4223ec2c027edd482c928a14ed358d93f1d4217d39abf69fcb5ccc28d684d2aaabcd6383775caa6239de26d4c6937bb603ecb4196082f4cffd509d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEozMaThtCI+wsAn7dSCySihTtNY2T8dQh\nfTmr9p/LXMwo1oTSqqvNY4N3XKpiOd4m1MaTe7YD7LQZYIL0z/1QnQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 431,
+ "comment" : "extreme value for k",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee502200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d",
+ "wx" : "3f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb24818",
+ "wy" : "5ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200043f3952199774c7cf39b38b66cb1042a6260d8680803845e4d433adba3bb248185ea495b68cbc7ed4173ee63c9042dc502625c7eb7e21fb02ca9a9114e0a3a18d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEPzlSGZd0x885s4tmyxBCpiYNhoCAOEXk\n1DOtujuySBhepJW2jLx+1Bc+5jyQQtxQJiXH634h+wLKmpEU4KOhjQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 432,
+ "comment" : "extreme value for k and edgecase s",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022055555555555555555555555555555554e8e4f44ce51835693ff0ca2ef01215c0",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698",
+ "wx" : "00cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e",
+ "wy" : "054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004cdfb8c0f422e144e137c2412c86c171f5fe3fa3f5bbb544e9076288f3ced786e054fd0721b77c11c79beacb3c94211b0a19bda08652efeaf92513a3b0a163698",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzfuMD0IuFE4TfCQSyGwXH1/j+j9bu1RO\nkHYojzzteG4FT9ByG3fBHHm+rLPJQhGwoZvaCGUu/q+SUTo7ChY2mA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 433,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d",
+ "wx" : "73598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3",
+ "wy" : "00cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000473598a6a1c68278fa6bfd0ce4064e68235bc1c0f6b20a928108be336730f87e3cbae612519b5032ecc85aed811271a95fe7939d5d3460140ba318f4d14aba31d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEc1mKahxoJ4+mv9DOQGTmgjW8HA9rIKko\nEIvjNnMPh+PLrmElGbUDLsyFrtgRJxqV/nk51dNGAUC6MY9NFKujHQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 434,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d",
+ "wx" : "58debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a1",
+ "wy" : "6773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000458debd9a7ee2c9d59132478a5440ae4d5d7ed437308369f92ea86c82183f10a16773e76f5edbf4da0e4f1bdffac0f57257e1dfa465842931309a24245fda6a5d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEWN69mn7iydWRMkeKVECuTV1+1Dcwg2n5\nLqhsghg/EKFnc+dvXtv02g5PG9/6wPVyV+HfpGWEKTEwmiQkX9pqXQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 435,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022066666666666666666666666666666665e445f1f5dfb6a67e4cba8c385348e6e7",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f",
+ "wx" : "008b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b",
+ "wy" : "00950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200048b904de47967340c5f8c3572a720924ef7578637feab1949acb241a5a6ac3f5b950904496f9824b1d63f3313bae21b89fae89afdfc811b5ece03fd5aa301864f",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEi5BN5HlnNAxfjDVypyCSTvdXhjf+qxlJ\nrLJBpaasP1uVCQRJb5gksdY/MxO64huJ+uia/fyBG17OA/1aowGGTw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 436,
+ "comment" : "extreme value for k and s^-1",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798022049249249249249249249249249249248c79facd43214c011123c1b03a93412a5",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b",
+ "wx" : "00f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a",
+ "wy" : "346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004f4892b6d525c771e035f2a252708f3784e48238604b4f94dc56eaa1e546d941a346b1aa0bce68b1c50e5b52f509fb5522e5c25e028bc8f863402edb7bcad8b1b",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE9IkrbVJcdx4DXyolJwjzeE5II4YEtPlN\nxW6qHlRtlBo0axqgvOaLHFDltS9Qn7VSLlwl4Ci8j4Y0Au23vK2LGw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 437,
+ "comment" : "extreme value for k",
+ "flags" : [
+ "ArithmeticError"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179802200eb10e5ab95f2f275348d82ad2e4d7949c8193800d8c9c75df58e343f0ebba7b",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "wy" : "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0SKaFVBmcR9CP+xDUuA==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 438,
+ "comment" : "public key shares x-coordinate with generator",
+ "flags" : [
+ "PointDuplication"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 439,
+ "comment" : "public key shares x-coordinate with generator",
+ "flags" : [
+ "PointDuplication"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777",
+ "wx" : "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "wy" : "00b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeb5mfvncu6xVoGKVzocLBwKb/NstzijZ\nWfKBWxb4F5i3xSWI2Vw7mqJbBAPx7vdXAuhLt1l6q+ZjuC9vBO8ndw==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 440,
+ "comment" : "public key shares x-coordinate with generator",
+ "flags" : [
+ "PointDuplication"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca60502302202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952",
+ "result" : "invalid"
+ },
+ {
+ "tcId" : 441,
+ "comment" : "public key shares x-coordinate with generator",
+ "flags" : [
+ "PointDuplication"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3044022044a5ad0bd0636d9e12bc9e0a6bdd5e1bba77f523842193b3b82e448e05d5f11e02202492492492492492492492492492492463cfd66a190a6008891e0d81d49a0952",
+ "result" : "invalid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152",
+ "wx" : "782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963",
+ "wy" : "00af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004782c8ed17e3b2a783b5464f33b09652a71c678e05ec51e84e2bcfc663a3de963af9acb4280b8c7f7c42f4ef9aba6245ec1ec1712fd38a0fa96418d8cd6aa6152",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEeCyO0X47Kng7VGTzOwllKnHGeOBexR6E\n4rz8Zjo96WOvmstCgLjH98QvTvmrpiRewewXEv04oPqWQY2M1qphUg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 442,
+ "comment" : "pseudorandom signature",
+ "flags" : [
+ "ValidSignature"
+ ],
+ "msg" : "",
+ "sig" : "3045022100f80ae4f96cdbc9d853f83d47aae225bf407d51c56b7776cd67d0dc195d99a9dc02204cfc1d941e08cb9aceadde0f4ccead76b30d332fc442115d50e673e28686b70b",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 443,
+ "comment" : "pseudorandom signature",
+ "flags" : [
+ "ValidSignature"
+ ],
+ "msg" : "4d7367",
+ "sig" : "30440220109cd8ae0374358984a8249c0a843628f2835ffad1df1a9a69aa2fe72355545c02205390ff250ac4274e1cb25cd6ca6491f6b91281e32f5b264d87977aed4a94e77b",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 444,
+ "comment" : "pseudorandom signature",
+ "flags" : [
+ "ValidSignature"
+ ],
+ "msg" : "313233343030",
+ "sig" : "3045022100d035ee1f17fdb0b2681b163e33c359932659990af77dca632012b30b27a057b302201939d9f3b2858bc13e3474cb50e6a82be44faa71940f876c1cba4c3e989202b6",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 445,
+ "comment" : "pseudorandom signature",
+ "flags" : [
+ "ValidSignature"
+ ],
+ "msg" : "0000000000000000000000000000000000000000",
+ "sig" : "304402204f053f563ad34b74fd8c9934ce59e79c2eb8e6eca0fef5b323ca67d5ac7ed23802204d4b05daa0719e773d8617dce5631c5fd6f59c9bdc748e4b55c970040af01be5",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1",
+ "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff",
+ "wy" : "01060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff00000001060492d5a5673e0f25d8d50fb7e58c49d86d46d4216955e0aa3d40e1",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv8AAAABBgSS1aVnPg8l2NUPt+WMSdhtRtQhaVXgqj1A4Q==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 446,
+ "comment" : "y-coordinate of the public key is small",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "304402206d6a4f556ccce154e7fb9f19e76c3deca13d59cc2aeb4ecad968aab2ded45965022053b9fa74803ede0fc4441bf683d56c564d3e274e09ccf47390badd1471c05fb7",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 447,
+ "comment" : "y-coordinate of the public key is small",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3044022100aad503de9b9fd66b948e9acf596f0a0e65e700b28b26ec56e6e45e846489b3c4021f0ddc3a2f89abb817bb85c062ce02f823c63fc26b269e0bc9b84d81a5aa123d",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 448,
+ "comment" : "y-coordinate of the public key is small",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "30450221009182cebd3bb8ab572e167174397209ef4b1d439af3b200cdf003620089e43225022054477c982ea019d2e1000497fc25fcee1bccae55f2ac27530ae53b29c4b356a4",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e",
+ "wx" : "6e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40caff",
+ "wy" : "00fffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046e823555452914099182c6b2c1d6f0b5d28d50ccd005af2ce1bba541aa40cafffffffffef9fb6d2a5a98c1f0da272af0481a73b62792b92bde96aa1e55c2bb4e",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEboI1VUUpFAmRgsaywdbwtdKNUMzQBa8s\n4bulQapAyv/////++fttKlqYwfDaJyrwSBpztieSuSvelqoeVcK7Tg==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 449,
+ "comment" : "y-coordinate of the public key is large",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "304402203854a3998aebdf2dbc28adac4181462ccac7873907ab7f212c42db0e69b56ed802203ed3f6b8a388d02f3e4df9f2ae9c1bd2c3916a686460dffcd42909cd7f82058e",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 450,
+ "comment" : "y-coordinate of the public key is large",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100e94dbdc38795fe5c904d8f16d969d3b587f0a25d2de90b6d8c5c53ff887e360702207a947369c164972521bb8af406813b2d9f94d2aeaa53d4c215aaa0a2578a2c5d",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 451,
+ "comment" : "y-coordinate of the public key is large",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3044022049fc102a08ca47b60e0858cd0284d22cddd7233f94aaffbb2db1dd2cf08425e102205b16fca5a12cdb39701697ad8e39ffd6bdec0024298afaa2326aea09200b14d6",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d",
+ "wx" : "013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0",
+ "wy" : "00f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004000000013fd22248d64d95f73c29b48ab48631850be503fd00f8468b5f0f70e0f6ee7aa43bc2c6fd25b1d8269241cbdd9dbb0dac96dc96231f430705f838717d",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEAAAAAT/SIkjWTZX3PCm0irSGMYUL5QP9\nAPhGi18PcOD27nqkO8LG/SWx2CaSQcvdnbsNrJbcliMfQwcF+DhxfQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 452,
+ "comment" : "x-coordinate of the public key is small",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3044022041efa7d3f05a0010675fcb918a45c693da4b348df21a59d6f9cd73e0d831d67a02204454ada693e5e26b7bd693236d340f80545c834577b6f73d378c7bcc534244da",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 453,
+ "comment" : "x-coordinate of the public key is small",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100b615698c358b35920dd883eca625a6c5f7563970cdfc378f8fe0cee17092144c022025f47b326b5be1fb610b885153ea84d41eb4716be66a994e8779989df1c863d4",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 454,
+ "comment" : "x-coordinate of the public key is small",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "304502210087cf8c0eb82d44f69c60a2ff5457d3aaa322e7ec61ae5aecfd678ae1c1932b0e02203add3b115815047d6eb340a3e008989eaa0f8708d1794814729094d08d2460d3",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "0425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35",
+ "wx" : "25afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dffffffff",
+ "wy" : "00fa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a0342000425afd689acabaed67c1f296de59406f8c550f57146a0b4ec2c97876dfffffffffa46a76e520322dfbc491ec4f0cc197420fc4ea5883d8f6dd53c354bc4f67c35",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJa/WiayrrtZ8Hylt5ZQG+MVQ9XFGoLTs\nLJeHbf/////6RqduUgMi37xJHsTwzBl0IPxOpYg9j23VPDVLxPZ8NQ==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 455,
+ "comment" : "x-coordinate of the public key has many trailing 1's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3044022062f48ef71ace27bf5a01834de1f7e3f948b9dce1ca1e911d5e13d3b104471d8202205ea8f33f0c778972c4582080deda9b341857dd64514f0849a05f6964c2e34022",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 456,
+ "comment" : "x-coordinate of the public key has many trailing 1's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100f6b0e2f6fe020cf7c0c20137434344ed7add6c4be51861e2d14cbda472a6ffb402206416c8dd3e5c5282b306e8dc8ff34ab64cc99549232d678d714402eb6ca7aa0f",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 457,
+ "comment" : "x-coordinate of the public key has many trailing 1's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100db09d8460f05eff23bc7e436b67da563fa4b4edb58ac24ce201fa8a358125057022046da116754602940c8999c8d665f786c50f5772c0a3cdbda075e77eabc64df16",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "04d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff",
+ "wx" : "00d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb9",
+ "wy" : "3f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a03420004d12e6c66b67734c3c84d2601cf5d35dc097e27637f0aca4a4fdb74b6aadd3bb93f5bdff88bd5736df898e699006ed750f11cf07c5866cd7ad70c7121ffffffff",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0S5sZrZ3NMPITSYBz1013Al+J2N/CspK\nT9t0tqrdO7k/W9/4i9VzbfiY5pkAbtdQ8RzwfFhmzXrXDHEh/////w==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 458,
+ "comment" : "y-coordinate of the public key has many trailing 1's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "30440220592c41e16517f12fcabd98267674f974b588e9f35d35406c1a7bb2ed1d19b7b802203e65a06bd9f83caaeb7b00f2368d7e0dece6b12221269a9b5b765198f840a3a1",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 459,
+ "comment" : "y-coordinate of the public key has many trailing 1's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100be0d70887d5e40821a61b68047de4ea03debfdf51cdf4d4b195558b959a032b202207d994b2d8f1dbbeb13534eb3f6e5dccd85f5c4133c27d9e64271b1826ce1f67d",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 460,
+ "comment" : "y-coordinate of the public key has many trailing 1's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100fae92dfcb2ee392d270af3a5739faa26d4f97bfd39ed3cbee4d29e26af3b206a02206c9ba37f9faa6a1fd3f65f23b4e853d4692a7274240a12db7ba3884830630d16",
+ "result" : "valid"
+ }
+ ]
+ },
+ {
+ "type" : "EcdsaBitcoinVerify",
+ "publicKey" : {
+ "type" : "EcPublicKey",
+ "curve" : "secp256k1",
+ "keySize" : 256,
+ "uncompressed" : "046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb",
+ "wx" : "6d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000",
+ "wy" : "00e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb"
+ },
+ "publicKeyDer" : "3056301006072a8648ce3d020106052b8104000a034200046d4a7f60d4774a4f0aa8bbdedb953c7eea7909407e3164755664bc2800000000e659d34e4df38d9e8c9eaadfba36612c769195be86c77aac3f36e78b538680fb",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEbUp/YNR3Sk8KqLve25U8fup5CUB+MWR1\nVmS8KAAAAADmWdNOTfONnoyeqt+6NmEsdpGVvobHeqw/NueLU4aA+w==\n-----END PUBLIC KEY-----\n",
+ "sha" : "SHA-256",
+ "tests" : [
+ {
+ "tcId" : 461,
+ "comment" : "x-coordinate of the public key has many trailing 0's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "30440220176a2557566ffa518b11226694eb9802ed2098bfe278e5570fe1d5d7af18a94302201291df6a0ed5fc0d15098e70bcf13a009284dfd0689d3bb4be6ceeb9be1487c4",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 462,
+ "comment" : "x-coordinate of the public key has many trailing 0's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3044022060be20c3dbc162dd34d26780621c104bbe5dace630171b2daef0d826409ee5c20220427f7e4d889d549170bda6a9409fb1cb8b0e763d13eea7bd97f64cf41dc6e497",
+ "result" : "valid"
+ },
+ {
+ "tcId" : 463,
+ "comment" : "x-coordinate of the public key has many trailing 0's",
+ "flags" : [
+ "EdgeCasePublicKey"
+ ],
+ "msg" : "4d657373616765",
+ "sig" : "3045022100edf03cf63f658883289a1a593d1007895b9f236d27c9c1f1313089aaed6b16ae02201a4dd6fc0814dc523d1fefa81c64fbf5e618e651e7096fccadbb94cd48e5e0cd",
+ "result" : "valid"
+ }
+ ]
+ }
+ ]
+}
diff --git a/src/secp256k1/tools/tests_wycheproof_generate.py b/src/secp256k1/tools/tests_wycheproof_generate.py
new file mode 100755
index 0000000000..b26dfa89d6
--- /dev/null
+++ b/src/secp256k1/tools/tests_wycheproof_generate.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 Random "Randy" Lattice and Sean Andersen
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://www.opensource.org/licenses/mit-license.php.
+'''
+Generate a C file with ECDSA testvectors from the Wycheproof project.
+'''
+
+import json
+import sys
+
+filename_input = sys.argv[1]
+
+with open(filename_input) as f:
+ doc = json.load(f)
+
+num_groups = len(doc['testGroups'])
+
+def to_c_array(x):
+ if x == "":
+ return ""
+ s = ',0x'.join(a+b for a,b in zip(x[::2], x[1::2]))
+ return "0x" + s
+
+
+num_vectors = 0
+offset_msg_running, offset_pk_running, offset_sig = 0, 0, 0
+out = ""
+messages = ""
+signatures = ""
+public_keys = ""
+cache_msgs = {}
+cache_public_keys = {}
+
+for i in range(num_groups):
+ group = doc['testGroups'][i]
+ num_tests = len(group['tests'])
+ public_key = group['publicKey']
+ for j in range(num_tests):
+ test_vector = group['tests'][j]
+ # // 2 to convert hex to byte length
+ sig_size = len(test_vector['sig']) // 2
+ msg_size = len(test_vector['msg']) // 2
+
+ if test_vector['result'] == "invalid":
+ expected_verify = 0
+ elif test_vector['result'] == "valid":
+ expected_verify = 1
+ else:
+ raise ValueError("invalid result field")
+
+ if num_vectors != 0 and sig_size != 0:
+ signatures += ",\n "
+
+ new_msg = False
+ msg = to_c_array(test_vector['msg'])
+ msg_offset = offset_msg_running
+ # check for repeated msg
+ if msg not in cache_msgs:
+ if num_vectors != 0 and msg_size != 0:
+ messages += ",\n "
+ cache_msgs[msg] = offset_msg_running
+ messages += msg
+ new_msg = True
+ else:
+ msg_offset = cache_msgs[msg]
+
+ new_pk = False
+ pk = to_c_array(public_key['uncompressed'])
+ pk_offset = offset_pk_running
+ # check for repeated pk
+ if pk not in cache_public_keys:
+ if num_vectors != 0:
+ public_keys += ",\n "
+ cache_public_keys[pk] = offset_pk_running
+ public_keys += pk
+ new_pk = True
+ else:
+ pk_offset = cache_public_keys[pk]
+
+ signatures += to_c_array(test_vector['sig'])
+
+ out += " /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n"
+ out += f" {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n"
+ if new_msg:
+ offset_msg_running += msg_size
+ if new_pk:
+ offset_pk_running += 65
+ offset_sig += sig_size
+ num_vectors += 1
+
+struct_definition = """
+typedef struct {
+ size_t pk_offset;
+ size_t msg_offset;
+ size_t msg_len;
+ size_t sig_offset;
+ size_t sig_len;
+ int expected_verify;
+} wycheproof_ecdsa_testvector;
+"""
+
+
+print("/* Note: this file was autogenerated using tests_wycheproof_generate.py. Do not edit. */")
+print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})")
+
+print(struct_definition)
+
+print("static const unsigned char wycheproof_ecdsa_messages[] = { " + messages + "};\n")
+print("static const unsigned char wycheproof_ecdsa_public_keys[] = { " + public_keys + "};\n")
+print("static const unsigned char wycheproof_ecdsa_signatures[] = { " + signatures + "};\n")
+
+print("static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {")
+print(out)
+print("};")
diff --git a/src/shutdown.cpp b/src/shutdown.cpp
index 2fffc0663c..d70017d734 100644
--- a/src/shutdown.cpp
+++ b/src/shutdown.cpp
@@ -11,6 +11,7 @@
#include <logging.h>
#include <node/interface_ui.h>
+#include <util/check.h>
#include <util/tokenpipe.h>
#include <warnings.h>
@@ -20,6 +21,8 @@
#include <condition_variable>
#endif
+static std::atomic<int>* g_exit_status{nullptr};
+
bool AbortNode(const std::string& strMessage, bilingual_str user_message)
{
SetMiscWarning(Untranslated(strMessage));
@@ -28,6 +31,7 @@ bool AbortNode(const std::string& strMessage, bilingual_str user_message)
user_message = _("A fatal internal error occurred, see debug.log for details");
}
InitError(user_message);
+ Assert(g_exit_status)->store(EXIT_FAILURE);
StartShutdown();
return false;
}
@@ -44,8 +48,9 @@ static TokenPipeEnd g_shutdown_r;
static TokenPipeEnd g_shutdown_w;
#endif
-bool InitShutdownState()
+bool InitShutdownState(std::atomic<int>& exit_status)
{
+ g_exit_status = &exit_status;
#ifndef WIN32
std::optional<TokenPipe> pipe = TokenPipe::Make();
if (!pipe) return false;
diff --git a/src/shutdown.h b/src/shutdown.h
index 07a8315788..c119bee96f 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -8,13 +8,15 @@
#include <util/translation.h> // For bilingual_str
+#include <atomic>
+
/** Abort with a message */
bool AbortNode(const std::string& strMessage, bilingual_str user_message = bilingual_str{});
/** Initialize shutdown state. This must be called before using either StartShutdown(),
* AbortShutdown() or WaitForShutdown(). Calling ShutdownRequested() is always safe.
*/
-bool InitShutdownState();
+bool InitShutdownState(std::atomic<int>& exit_status);
/** Request shutdown of the application. */
void StartShutdown();
diff --git a/src/signet.cpp b/src/signet.cpp
index 747bd1b0a8..b73d82bb2e 100644
--- a/src/signet.cpp
+++ b/src/signet.cpp
@@ -8,20 +8,21 @@
#include <cstdint>
#include <vector>
+#include <common/system.h>
#include <consensus/merkle.h>
#include <consensus/params.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <hash.h>
+#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
-#include <span.h>
#include <script/interpreter.h>
#include <script/standard.h>
+#include <span.h>
#include <streams.h>
-#include <util/strencodings.h>
-#include <util/system.h>
#include <uint256.h>
+#include <util/strencodings.h>
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
diff --git a/src/span.h b/src/span.h
index 4692eca7fb..c98784aee4 100644
--- a/src/span.h
+++ b/src/span.h
@@ -274,6 +274,7 @@ Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
// 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 unsigned char* UCharCast(std::byte* c) { return (unsigned char*)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); }
diff --git a/src/streams.h b/src/streams.h
index 8788343809..03df20b5db 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -293,14 +293,6 @@ public:
vch.insert(vch.end(), src.begin(), src.end());
}
- template<typename Stream>
- void Serialize(Stream& s) const
- {
- // Special case: stream << stream concatenates like stream += stream
- if (!vch.empty())
- s.write(MakeByteSpan(vch));
- }
-
template<typename T>
DataStream& operator<<(const T& obj)
{
@@ -756,15 +748,25 @@ public:
}
//! search for a given byte in the stream, and remain positioned on it
- void FindByte(uint8_t ch)
+ void FindByte(std::byte byte)
{
+ // For best performance, avoid mod operation within the loop.
+ size_t buf_offset{size_t(m_read_pos % uint64_t(vchBuf.size()))};
while (true) {
- if (m_read_pos == nSrcPos)
+ if (m_read_pos == nSrcPos) {
+ // No more bytes available; read from the file into the buffer,
+ // setting nSrcPos to one beyond the end of the new data.
+ // Throws exception if end-of-file reached.
Fill();
- if (vchBuf[m_read_pos % vchBuf.size()] == std::byte{ch}) {
- break;
}
- m_read_pos++;
+ const size_t len{std::min<size_t>(vchBuf.size() - buf_offset, nSrcPos - m_read_pos)};
+ const auto it_start{vchBuf.begin() + buf_offset};
+ const auto it_find{std::find(it_start, it_start + len, byte)};
+ const size_t inc{size_t(std::distance(it_start, it_find))};
+ m_read_pos += inc;
+ if (inc < len) break;
+ buf_offset += inc;
+ if (buf_offset >= vchBuf.size()) buf_offset = 0;
}
}
};
diff --git a/src/support/allocators/pool.h b/src/support/allocators/pool.h
new file mode 100644
index 0000000000..c8e70ebacf
--- /dev/null
+++ b/src/support/allocators/pool.h
@@ -0,0 +1,349 @@
+// Copyright (c) 2022 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_SUPPORT_ALLOCATORS_POOL_H
+#define BITCOIN_SUPPORT_ALLOCATORS_POOL_H
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <list>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+/**
+ * A memory resource similar to std::pmr::unsynchronized_pool_resource, but
+ * optimized for node-based containers. It has the following properties:
+ *
+ * * Owns the allocated memory and frees it on destruction, even when deallocate
+ * has not been called on the allocated blocks.
+ *
+ * * Consists of a number of pools, each one for a different block size.
+ * Each pool holds blocks of uniform size in a freelist.
+ *
+ * * Exhausting memory in a freelist causes a new allocation of a fixed size chunk.
+ * This chunk is used to carve out blocks.
+ *
+ * * Block sizes or alignments that can not be served by the pools are allocated
+ * and deallocated by operator new().
+ *
+ * PoolResource is not thread-safe. It is intended to be used by PoolAllocator.
+ *
+ * @tparam MAX_BLOCK_SIZE_BYTES Maximum size to allocate with the pool. If larger
+ * sizes are requested, allocation falls back to new().
+ *
+ * @tparam ALIGN_BYTES Required alignment for the allocations.
+ *
+ * An example: If you create a PoolResource<128, 8>(262144) and perform a bunch of
+ * allocations and deallocate 2 blocks with size 8 bytes, and 3 blocks with size 16,
+ * the members will look like this:
+ *
+ * m_free_lists m_allocated_chunks
+ * ┌───┐ ┌───┐ ┌────────────-------──────┐
+ * │ │ blocks │ ├─►│ 262144 B │
+ * │ │ ┌─────┐ ┌─────┐ └─┬─┘ └────────────-------──────┘
+ * │ 1 ├─►│ 8 B ├─►│ 8 B │ │
+ * │ │ └─────┘ └─────┘ :
+ * │ │ │
+ * │ │ ┌─────┐ ┌─────┐ ┌─────┐ ▼
+ * │ 2 ├─►│16 B ├─►│16 B ├─►│16 B │ ┌───┐ ┌─────────────────────────┐
+ * │ │ └─────┘ └─────┘ └─────┘ │ ├─►│ ▲ │ ▲
+ * │ │ └───┘ └──────────┬──────────────┘ │
+ * │ . │ │ m_available_memory_end
+ * │ . │ m_available_memory_it
+ * │ . │
+ * │ │
+ * │ │
+ * │16 │
+ * └───┘
+ *
+ * Here m_free_lists[1] holds the 2 blocks of size 8 bytes, and m_free_lists[2]
+ * holds the 3 blocks of size 16. The blocks came from the data stored in the
+ * m_allocated_chunks list. Each chunk has bytes 262144. The last chunk has still
+ * some memory available for the blocks, and when m_available_memory_it is at the
+ * end, a new chunk will be allocated and added to the list.
+ */
+template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+class PoolResource final
+{
+ static_assert(ALIGN_BYTES > 0, "ALIGN_BYTES must be nonzero");
+ static_assert((ALIGN_BYTES & (ALIGN_BYTES - 1)) == 0, "ALIGN_BYTES must be a power of two");
+
+ /**
+ * In-place linked list of the allocations, used for the freelist.
+ */
+ struct ListNode {
+ ListNode* m_next;
+
+ explicit ListNode(ListNode* next) : m_next(next) {}
+ };
+ static_assert(std::is_trivially_destructible_v<ListNode>, "Make sure we don't need to manually call a destructor");
+
+ /**
+ * Internal alignment value. The larger of the requested ALIGN_BYTES and alignof(FreeList).
+ */
+ static constexpr std::size_t ELEM_ALIGN_BYTES = std::max(alignof(ListNode), ALIGN_BYTES);
+ static_assert((ELEM_ALIGN_BYTES & (ELEM_ALIGN_BYTES - 1)) == 0, "ELEM_ALIGN_BYTES must be a power of two");
+ static_assert(sizeof(ListNode) <= ELEM_ALIGN_BYTES, "Units of size ELEM_SIZE_ALIGN need to be able to store a ListNode");
+ static_assert((MAX_BLOCK_SIZE_BYTES & (ELEM_ALIGN_BYTES - 1)) == 0, "MAX_BLOCK_SIZE_BYTES needs to be a multiple of the alignment.");
+
+ /**
+ * Size in bytes to allocate per chunk
+ */
+ const size_t m_chunk_size_bytes;
+
+ /**
+ * Contains all allocated pools of memory, used to free the data in the destructor.
+ */
+ std::list<std::byte*> m_allocated_chunks{};
+
+ /**
+ * Single linked lists of all data that came from deallocating.
+ * m_free_lists[n] will serve blocks of size n*ELEM_ALIGN_BYTES.
+ */
+ std::array<ListNode*, MAX_BLOCK_SIZE_BYTES / ELEM_ALIGN_BYTES + 1> m_free_lists{};
+
+ /**
+ * Points to the beginning of available memory for carving out allocations.
+ */
+ std::byte* m_available_memory_it = nullptr;
+
+ /**
+ * Points to the end of available memory for carving out allocations.
+ *
+ * That member variable is redundant, and is always equal to `m_allocated_chunks.back() + m_chunk_size_bytes`
+ * whenever it is accessed, but `m_available_memory_end` caches this for clarity and efficiency.
+ */
+ std::byte* m_available_memory_end = nullptr;
+
+ /**
+ * How many multiple of ELEM_ALIGN_BYTES are necessary to fit bytes. We use that result directly as an index
+ * into m_free_lists. Round up for the special case when bytes==0.
+ */
+ [[nodiscard]] static constexpr std::size_t NumElemAlignBytes(std::size_t bytes)
+ {
+ return (bytes + ELEM_ALIGN_BYTES - 1) / ELEM_ALIGN_BYTES + (bytes == 0);
+ }
+
+ /**
+ * True when it is possible to make use of the freelist
+ */
+ [[nodiscard]] static constexpr bool IsFreeListUsable(std::size_t bytes, std::size_t alignment)
+ {
+ return alignment <= ELEM_ALIGN_BYTES && bytes <= MAX_BLOCK_SIZE_BYTES;
+ }
+
+ /**
+ * Replaces node with placement constructed ListNode that points to the previous node
+ */
+ void PlacementAddToList(void* p, ListNode*& node)
+ {
+ node = new (p) ListNode{node};
+ }
+
+ /**
+ * Allocate one full memory chunk which will be used to carve out allocations.
+ * Also puts any leftover bytes into the freelist.
+ *
+ * Precondition: leftover bytes are either 0 or few enough to fit into a place in the freelist
+ */
+ void AllocateChunk()
+ {
+ // if there is still any available memory left, put it into the freelist.
+ size_t remaining_available_bytes = std::distance(m_available_memory_it, m_available_memory_end);
+ if (0 != remaining_available_bytes) {
+ PlacementAddToList(m_available_memory_it, m_free_lists[remaining_available_bytes / ELEM_ALIGN_BYTES]);
+ }
+
+ void* storage = ::operator new (m_chunk_size_bytes, std::align_val_t{ELEM_ALIGN_BYTES});
+ m_available_memory_it = new (storage) std::byte[m_chunk_size_bytes];
+ m_available_memory_end = m_available_memory_it + m_chunk_size_bytes;
+ m_allocated_chunks.emplace_back(m_available_memory_it);
+ }
+
+ /**
+ * Access to internals for testing purpose only
+ */
+ friend class PoolResourceTester;
+
+public:
+ /**
+ * Construct a new PoolResource object which allocates the first chunk.
+ * chunk_size_bytes will be rounded up to next multiple of ELEM_ALIGN_BYTES.
+ */
+ explicit PoolResource(std::size_t chunk_size_bytes)
+ : m_chunk_size_bytes(NumElemAlignBytes(chunk_size_bytes) * ELEM_ALIGN_BYTES)
+ {
+ assert(m_chunk_size_bytes >= MAX_BLOCK_SIZE_BYTES);
+ AllocateChunk();
+ }
+
+ /**
+ * Construct a new Pool Resource object, defaults to 2^18=262144 chunk size.
+ */
+ PoolResource() : PoolResource(262144) {}
+
+ /**
+ * Disable copy & move semantics, these are not supported for the resource.
+ */
+ PoolResource(const PoolResource&) = delete;
+ PoolResource& operator=(const PoolResource&) = delete;
+ PoolResource(PoolResource&&) = delete;
+ PoolResource& operator=(PoolResource&&) = delete;
+
+ /**
+ * Deallocates all memory allocated associated with the memory resource.
+ */
+ ~PoolResource()
+ {
+ for (std::byte* chunk : m_allocated_chunks) {
+ std::destroy(chunk, chunk + m_chunk_size_bytes);
+ ::operator delete ((void*)chunk, std::align_val_t{ELEM_ALIGN_BYTES});
+ }
+ }
+
+ /**
+ * Allocates a block of bytes. If possible the freelist is used, otherwise allocation
+ * is forwarded to ::operator new().
+ */
+ void* Allocate(std::size_t bytes, std::size_t alignment)
+ {
+ if (IsFreeListUsable(bytes, alignment)) {
+ const std::size_t num_alignments = NumElemAlignBytes(bytes);
+ if (nullptr != m_free_lists[num_alignments]) {
+ // we've already got data in the pool's freelist, unlink one element and return the pointer
+ // to the unlinked memory. Since FreeList is trivially destructible we can just treat it as
+ // uninitialized memory.
+ return std::exchange(m_free_lists[num_alignments], m_free_lists[num_alignments]->m_next);
+ }
+
+ // freelist is empty: get one allocation from allocated chunk memory.
+ const std::ptrdiff_t round_bytes = static_cast<std::ptrdiff_t>(num_alignments * ELEM_ALIGN_BYTES);
+ if (round_bytes > m_available_memory_end - m_available_memory_it) {
+ // slow path, only happens when a new chunk needs to be allocated
+ AllocateChunk();
+ }
+
+ // Make sure we use the right amount of bytes for that freelist (might be rounded up),
+ return std::exchange(m_available_memory_it, m_available_memory_it + round_bytes);
+ }
+
+ // Can't use the pool => use operator new()
+ return ::operator new (bytes, std::align_val_t{alignment});
+ }
+
+ /**
+ * Returns a block to the freelists, or deletes the block when it did not come from the chunks.
+ */
+ void Deallocate(void* p, std::size_t bytes, std::size_t alignment) noexcept
+ {
+ if (IsFreeListUsable(bytes, alignment)) {
+ const std::size_t num_alignments = NumElemAlignBytes(bytes);
+ // put the memory block into the linked list. We can placement construct the FreeList
+ // into the memory since we can be sure the alignment is correct.
+ PlacementAddToList(p, m_free_lists[num_alignments]);
+ } else {
+ // Can't use the pool => forward deallocation to ::operator delete().
+ ::operator delete (p, std::align_val_t{alignment});
+ }
+ }
+
+ /**
+ * Number of allocated chunks
+ */
+ [[nodiscard]] std::size_t NumAllocatedChunks() const
+ {
+ return m_allocated_chunks.size();
+ }
+
+ /**
+ * Size in bytes to allocate per chunk, currently hardcoded to a fixed size.
+ */
+ [[nodiscard]] size_t ChunkSizeBytes() const
+ {
+ return m_chunk_size_bytes;
+ }
+};
+
+
+/**
+ * Forwards all allocations/deallocations to the PoolResource.
+ */
+template <class T, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+class PoolAllocator
+{
+ PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>* m_resource;
+
+ template <typename U, std::size_t M, std::size_t A>
+ friend class PoolAllocator;
+
+public:
+ using value_type = T;
+ using ResourceType = PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>;
+
+ /**
+ * Not explicit so we can easily construct it with the correct resource
+ */
+ PoolAllocator(ResourceType* resource) noexcept
+ : m_resource(resource)
+ {
+ }
+
+ PoolAllocator(const PoolAllocator& other) noexcept = default;
+ PoolAllocator& operator=(const PoolAllocator& other) noexcept = default;
+
+ template <class U>
+ PoolAllocator(const PoolAllocator<U, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& other) noexcept
+ : m_resource(other.resource())
+ {
+ }
+
+ /**
+ * The rebind struct here is mandatory because we use non type template arguments for
+ * PoolAllocator. See https://en.cppreference.com/w/cpp/named_req/Allocator#cite_note-2
+ */
+ template <typename U>
+ struct rebind {
+ using other = PoolAllocator<U, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>;
+ };
+
+ /**
+ * Forwards each call to the resource.
+ */
+ T* allocate(size_t n)
+ {
+ return static_cast<T*>(m_resource->Allocate(n * sizeof(T), alignof(T)));
+ }
+
+ /**
+ * Forwards each call to the resource.
+ */
+ void deallocate(T* p, size_t n) noexcept
+ {
+ m_resource->Deallocate(p, n * sizeof(T), alignof(T));
+ }
+
+ ResourceType* resource() const noexcept
+ {
+ return m_resource;
+ }
+};
+
+template <class T1, class T2, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+bool operator==(const PoolAllocator<T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& a,
+ const PoolAllocator<T2, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& b) noexcept
+{
+ return a.resource() == b.resource();
+}
+
+template <class T1, class T2, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+bool operator!=(const PoolAllocator<T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& a,
+ const PoolAllocator<T2, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& b) noexcept
+{
+ return !(a == b);
+}
+
+#endif // BITCOIN_SUPPORT_ALLOCATORS_POOL_H
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index a0918bf463..b2076bea07 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -32,9 +32,9 @@ struct secure_allocator : public std::allocator<T> {
{
}
~secure_allocator() noexcept {}
- template <typename _Other>
+ template <typename Other>
struct rebind {
- typedef secure_allocator<_Other> other;
+ typedef secure_allocator<Other> other;
};
T* allocate(std::size_t n, const void* hint = nullptr)
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 795eea3bc0..2dc644c242 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -27,9 +27,9 @@ struct zero_after_free_allocator : public std::allocator<T> {
{
}
~zero_after_free_allocator() noexcept {}
- template <typename _Other>
+ template <typename Other>
struct rebind {
- typedef zero_after_free_allocator<_Other> other;
+ typedef zero_after_free_allocator<Other> other;
};
void deallocate(T* p, std::size_t n)
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 758691cfde..328e7f81a0 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -33,16 +33,16 @@ static int32_t GetCheckRatio(const NodeContext& node_ctx)
static CNetAddr ResolveIP(const std::string& ip)
{
- CNetAddr addr;
- BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), strprintf("failed to resolve: %s", ip));
- return addr;
+ const std::optional<CNetAddr> addr{LookupHost(ip, false)};
+ BOOST_CHECK_MESSAGE(addr.has_value(), strprintf("failed to resolve: %s", ip));
+ return addr.value_or(CNetAddr{});
}
static CService ResolveService(const std::string& ip, uint16_t port = 0)
{
- CService serv;
- BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), strprintf("failed to resolve: %s:%i", ip, port));
- return serv;
+ const std::optional<CService> serv{Lookup(ip, port, false)};
+ BOOST_CHECK_MESSAGE(serv.has_value(), strprintf("failed to resolve: %s:%i", ip, port));
+ return serv.value_or(CService{});
}
@@ -127,46 +127,45 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
// the specified port to tried, but not the other.
addrman->Good(CAddress(addr1_port, NODE_NONE));
BOOST_CHECK_EQUAL(addrman->Size(), 2U);
- bool newOnly = true;
- auto addr_ret3 = addrman->Select(newOnly).first;
+ bool new_only = true;
+ auto addr_ret3 = addrman->Select(new_only).first;
BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
}
-
BOOST_AUTO_TEST_CASE(addrman_select)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
+ BOOST_CHECK(!addrman->Select(false).first.IsValid());
+ BOOST_CHECK(!addrman->Select(true).first.IsValid());
CNetAddr source = ResolveIP("252.2.2.2");
- // Test: Select from new with 1 addr in new.
+ // Add 1 address to the new table
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
- bool newOnly = true;
- auto addr_ret1 = addrman->Select(newOnly).first;
- BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");
+ BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr1);
+ BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);
- // Test: move addr to tried, select from new expected nothing returned.
+ // Move address to the tried table
BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
- BOOST_CHECK_EQUAL(addrman->Size(), 1U);
- auto addr_ret2 = addrman->Select(newOnly).first;
- BOOST_CHECK_EQUAL(addr_ret2.ToStringAddrPort(), "[::]:0");
-
- auto addr_ret3 = addrman->Select().first;
- BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
+ BOOST_CHECK(!addrman->Select(/*new_only=*/true).first.IsValid());
+ BOOST_CHECK(addrman->Select().first == addr1);
+ BOOST_CHECK_EQUAL(addrman->Size(), 1U);
-
- // Add three addresses to new table.
+ // Add one address to the new table
CService addr2 = ResolveService("250.3.1.1", 8333);
+ BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, addr2));
+ BOOST_CHECK(addrman->Select(/*new_only=*/true).first == addr2);
+
+ // Add two more addresses to the new table
CService addr3 = ResolveService("250.3.2.2", 9999);
CService addr4 = ResolveService("250.3.3.3", 9999);
- BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
- BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
+ BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, addr2));
BOOST_CHECK(addrman->Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333)));
// Add three addresses to tried table.
@@ -174,17 +173,17 @@ BOOST_AUTO_TEST_CASE(addrman_select)
CService addr6 = ResolveService("250.4.5.5", 7777);
CService addr7 = ResolveService("250.4.6.6", 8333);
- BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
+ BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, addr3));
BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE)));
- BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, ResolveService("250.3.1.1", 8333)));
+ BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, addr3));
BOOST_CHECK(addrman->Good(CAddress(addr6, NODE_NONE)));
BOOST_CHECK(addrman->Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333)));
BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE)));
- // Test: 6 addrs + 1 addr from last test = 7.
+ // 6 addrs + 1 addr from last test = 7.
BOOST_CHECK_EQUAL(addrman->Size(), 7U);
- // Test: Select pulls from new and tried regardless of port number.
+ // Select pulls from new and tried regardless of port number.
std::set<uint16_t> ports;
for (int i = 0; i < 20; ++i) {
ports.insert(addrman->Select().first.GetPort());
@@ -192,6 +191,89 @@ BOOST_AUTO_TEST_CASE(addrman_select)
BOOST_CHECK_EQUAL(ports.size(), 3U);
}
+BOOST_AUTO_TEST_CASE(addrman_select_by_network)
+{
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
+ BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_IPV4).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV4).first.IsValid());
+
+ // add ipv4 address to the new table
+ CNetAddr source = ResolveIP("252.2.2.2");
+ CService addr1 = ResolveService("250.1.1.1", 8333);
+ BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
+
+ BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_IPV4).first == addr1);
+ BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1);
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV6).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_ONION).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_I2P).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_CJDNS).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_CJDNS).first.IsValid());
+ BOOST_CHECK(addrman->Select(/*new_only=*/false).first == addr1);
+
+ // add I2P address to the new table
+ CAddress i2p_addr;
+ i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
+ BOOST_CHECK(addrman->Add({i2p_addr}, source));
+
+ BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_I2P).first == i2p_addr);
+ BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_I2P).first == i2p_addr);
+ BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1);
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_IPV6).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_ONION).first.IsValid());
+ BOOST_CHECK(!addrman->Select(/*new_only=*/false, NET_CJDNS).first.IsValid());
+
+ // bump I2P address to tried table
+ BOOST_CHECK(addrman->Good(i2p_addr));
+
+ BOOST_CHECK(!addrman->Select(/*new_only=*/true, NET_I2P).first.IsValid());
+ BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_I2P).first == i2p_addr);
+
+ // add another I2P address to the new table
+ CAddress i2p_addr2;
+ i2p_addr2.SetSpecial("c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p");
+ BOOST_CHECK(addrman->Add({i2p_addr2}, source));
+
+ BOOST_CHECK(addrman->Select(/*new_only=*/true, NET_I2P).first == i2p_addr2);
+
+ // ensure that both new and tried table are selected from
+ bool new_selected{false};
+ bool tried_selected{false};
+
+ while (!new_selected || !tried_selected) {
+ const CAddress selected{addrman->Select(/*new_only=*/false, NET_I2P).first};
+ BOOST_REQUIRE(selected == i2p_addr || selected == i2p_addr2);
+ if (selected == i2p_addr) {
+ tried_selected = true;
+ } else {
+ new_selected = true;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(addrman_select_special)
+{
+ // use a non-deterministic addrman to ensure a passing test isn't due to setup
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, /*deterministic=*/false, GetCheckRatio(m_node));
+
+ CNetAddr source = ResolveIP("252.2.2.2");
+
+ // add I2P address to the tried table
+ CAddress i2p_addr;
+ i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
+ BOOST_CHECK(addrman->Add({i2p_addr}, source));
+ BOOST_CHECK(addrman->Good(i2p_addr));
+
+ // add ipv4 address to the new table
+ CService addr1 = ResolveService("250.1.1.3", 8333);
+ BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
+
+ // since the only ipv4 address is on the new table, ensure that the new
+ // table gets selected even if new_only is false. if the table was being
+ // selected at random, this test will sporadically fail
+ BOOST_CHECK(addrman->Select(/*new_only=*/false, NET_IPV4).first == addr1);
+}
+
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
@@ -866,18 +948,23 @@ BOOST_AUTO_TEST_CASE(load_addrman)
{
AddrMan addrman{EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)};
- CService addr1, addr2, addr3;
- BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
- BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false));
- BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false));
- BOOST_CHECK(Lookup("250.7.3.3"s, addr3, 9999, false));
- BOOST_CHECK(!Lookup("250.7.3.3\0example.com"s, addr3, 9999, false));
+ std::optional<CService> addr1, addr2, addr3, addr4;
+ addr1 = Lookup("250.7.1.1", 8333, false);
+ BOOST_CHECK(addr1.has_value());
+ addr2 = Lookup("250.7.2.2", 9999, false);
+ BOOST_CHECK(addr2.has_value());
+ addr3 = Lookup("250.7.3.3", 9999, false);
+ BOOST_CHECK(addr3.has_value());
+ addr3 = Lookup("250.7.3.3"s, 9999, false);
+ BOOST_CHECK(addr3.has_value());
+ addr4 = Lookup("250.7.3.3\0example.com"s, 9999, false);
+ BOOST_CHECK(!addr4.has_value());
// Add three addresses to new table.
- CService source;
- BOOST_CHECK(Lookup("252.5.1.1", source, 8333, false));
- std::vector<CAddress> addresses{CAddress(addr1, NODE_NONE), CAddress(addr2, NODE_NONE), CAddress(addr3, NODE_NONE)};
- BOOST_CHECK(addrman.Add(addresses, source));
+ const std::optional<CService> source{Lookup("252.5.1.1", 8333, false)};
+ BOOST_CHECK(source.has_value());
+ std::vector<CAddress> addresses{CAddress(addr1.value(), NODE_NONE), CAddress(addr2.value(), NODE_NONE), CAddress(addr3.value(), NODE_NONE)};
+ BOOST_CHECK(addrman.Add(addresses, source.value()));
BOOST_CHECK(addrman.Size() == 3);
// Test that the de-serialization does not throw an exception.
@@ -922,12 +1009,12 @@ static CDataStream MakeCorruptPeersDat()
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
- CService serv;
- BOOST_CHECK(Lookup("252.1.1.1", serv, 7777, false));
- CAddress addr = CAddress(serv, NODE_NONE);
- CNetAddr resolved;
- BOOST_CHECK(LookupHost("252.2.2.2", resolved, false));
- AddrInfo info = AddrInfo(addr, resolved);
+ const std::optional<CService> serv{Lookup("252.1.1.1", 7777, false)};
+ BOOST_REQUIRE(serv.has_value());
+ CAddress addr = CAddress(serv.value(), NODE_NONE);
+ std::optional<CNetAddr> resolved{LookupHost("252.2.2.2", false)};
+ BOOST_REQUIRE(resolved.has_value());
+ AddrInfo info = AddrInfo(addr, resolved.value());
s << info;
return s;
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 715ce0a5b4..8c0af6f26f 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <support/lockedpool.h>
-#include <util/system.h>
#include <limits>
#include <memory>
@@ -77,6 +77,7 @@ BOOST_AUTO_TEST_CASE(arena_tests)
b.walk();
#endif
// Sweeping allocate all memory
+ addr.reserve(2048);
for (int x=0; x<1024; ++x)
addr.push_back(b.alloc(1024));
BOOST_CHECK(b.stats().free == 0);
diff --git a/src/test/argsman_tests.cpp b/src/test/argsman_tests.cpp
index d00876bc70..0b789e7f5c 100644
--- a/src/test/argsman_tests.cpp
+++ b/src/test/argsman_tests.cpp
@@ -2,14 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/system.h>
-#include <fs.h>
+#include <common/args.h>
#include <sync.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
#include <test/util/str.h>
-#include <util/strencodings.h>
#include <univalue.h>
+#include <util/chaintype.h>
+#include <util/fs.h>
+#include <util/strencodings.h>
#include <array>
#include <optional>
@@ -84,7 +85,7 @@ class CheckValueTest : public TestChain100Setup
{
public:
struct Expect {
- util::SettingsValue setting;
+ common::SettingsValue setting;
bool default_string = false;
bool default_int = false;
bool default_bool = false;
@@ -94,7 +95,7 @@ public:
std::optional<std::vector<std::string>> list_value;
const char* error = nullptr;
- explicit Expect(util::SettingsValue s) : setting(std::move(s)) {}
+ explicit Expect(common::SettingsValue s) : setting(std::move(s)) {}
Expect& DefaultString() { default_string = true; return *this; }
Expect& DefaultInt() { default_int = true; return *this; }
Expect& DefaultBool() { default_bool = true; return *this; }
@@ -254,7 +255,7 @@ BOOST_AUTO_TEST_CASE(util_ParseInvalidParameters)
BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
BOOST_CHECK_EQUAL(error, "Invalid parameter -unregistered");
- // Make sure registered parameters prefixed with a chain name trigger errors.
+ // Make sure registered parameters prefixed with a chain type trigger errors.
// (Previously, they were accepted and ignored.)
argv[1] = "-test.registered";
BOOST_CHECK(!test.ParseParameters(2, (char**)argv, error));
@@ -580,7 +581,7 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
test_args.SetNetworkOnlyArg("-ccc");
test_args.SetNetworkOnlyArg("-h");
- test_args.SelectConfigNetwork(CBaseChainParams::MAIN);
+ test_args.SelectConfigNetwork(ChainTypeToString(ChainType::MAIN));
BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
@@ -637,7 +638,7 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
}
-BOOST_AUTO_TEST_CASE(util_GetChainName)
+BOOST_AUTO_TEST_CASE(util_GetChainTypeString)
{
TestArgsManager test_args;
const auto testnet = std::make_pair("-testnet", ArgsManager::ALLOW_ANY);
@@ -655,39 +656,39 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
std::string error;
BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "main");
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "regtest");
BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+ BOOST_CHECK_THROW(test_args.GetChainTypeString(), std::runtime_error);
BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+ BOOST_CHECK_THROW(test_args.GetChainTypeString(), std::runtime_error);
BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+ BOOST_CHECK_THROW(test_args.GetChainTypeString(), std::runtime_error);
// check setting the network to test (and thus making
// [test] regtest=1 potentially relevant) doesn't break things
@@ -695,23 +696,23 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+ BOOST_CHECK_THROW(test_args.GetChainTypeString(), std::runtime_error);
BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+ BOOST_CHECK_EQUAL(test_args.GetChainTypeString(), "test");
BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error));
test_args.ReadConfigString(testnetconf);
- BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+ BOOST_CHECK_THROW(test_args.GetChainTypeString(), std::runtime_error);
}
// Test different ways settings can be merged, and verify results. This test can
@@ -755,8 +756,8 @@ struct ArgsMergeTestingSetup : public BasicTestingSetup {
ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
for (bool soft_set : {false, true}) {
for (bool force_set : {false, true}) {
- for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
- for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET}) {
+ for (const std::string& section : {ChainTypeToString(ChainType::MAIN), ChainTypeToString(ChainType::TESTNET), ChainTypeToString(ChainType::SIGNET)}) {
+ for (const std::string& network : {ChainTypeToString(ChainType::MAIN), ChainTypeToString(ChainType::TESTNET), ChainTypeToString(ChainType::SIGNET)}) {
for (bool net_specific : {false, true}) {
fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
}
@@ -913,7 +914,7 @@ BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
BOOST_CHECK_EQUAL(out_sha_hex, "d1e436c1cd510d0ec44d5205d4b4e3bee6387d316e0075c58206cb16603f3d82");
}
-// Similar test as above, but for ArgsManager::GetChainName function.
+// Similar test as above, but for ArgsManager::GetChainTypeString function.
struct ChainMergeTestingSetup : public BasicTestingSetup {
static constexpr int MAX_ACTIONS = 2;
@@ -982,7 +983,7 @@ BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
desc += " || ";
try {
- desc += parser.GetChainName();
+ desc += parser.GetChainTypeString();
} catch (const std::runtime_error& e) {
desc += "error: ";
desc += e.what();
@@ -1021,14 +1022,14 @@ BOOST_AUTO_TEST_CASE(util_ReadWriteSettings)
// Test writing setting.
TestArgsManager args1;
args1.ForceSetArg("-datadir", fs::PathToString(m_path_root));
- args1.LockSettings([&](util::Settings& settings) { settings.rw_settings["name"] = "value"; });
+ args1.LockSettings([&](common::Settings& settings) { settings.rw_settings["name"] = "value"; });
args1.WriteSettingsFile();
// Test reading setting.
TestArgsManager args2;
args2.ForceSetArg("-datadir", fs::PathToString(m_path_root));
args2.ReadSettingsFile();
- args2.LockSettings([&](util::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
+ args2.LockSettings([&](common::Settings& settings) { BOOST_CHECK_EQUAL(settings.rw_settings["name"].get_str(), "value"); });
// Test error logging, and remove previously written setting.
{
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index a572bb02b9..1ff5d6cf59 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -19,6 +19,7 @@
#include <boost/test/unit_test.hpp>
using node::BlockAssembler;
+using node::BlockManager;
using node::CBlockTemplate;
BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)
@@ -29,10 +30,10 @@ struct BuildChainTestingSetup : public TestChain100Setup {
};
static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex* block_index,
- uint256& last_header)
+ uint256& last_header, const BlockManager& blockman)
{
BlockFilter expected_filter;
- if (!ComputeFilter(filter_index.GetFilterType(), block_index, expected_filter)) {
+ if (!ComputeFilter(filter_index.GetFilterType(), *block_index, expected_filter, blockman)) {
BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
return false;
}
@@ -141,10 +142,10 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
BOOST_REQUIRE(filter_index.Start());
// Allow filter index to catch up with the block index.
- constexpr int64_t timeout_ms = 10 * 1000;
- int64_t time_start = GetTimeMillis();
+ constexpr auto timeout{10s};
+ const auto time_start{SteadyClock::now()};
while (!filter_index.BlockUntilSyncedToCurrentChain()) {
- BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
+ BOOST_REQUIRE(time_start + timeout > SteadyClock::now());
UninterruptibleSleep(std::chrono::milliseconds{100});
}
@@ -155,7 +156,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
for (block_index = m_node.chainman->ActiveChain().Genesis();
block_index != nullptr;
block_index = m_node.chainman->ActiveChain().Next(block_index)) {
- CheckFilterLookups(filter_index, block_index, last_header);
+ CheckFilterLookups(filter_index, block_index, last_header, m_node.chainman->m_blockman);
}
}
@@ -189,7 +190,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
}
BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
- CheckFilterLookups(filter_index, block_index, chainA_last_header);
+ CheckFilterLookups(filter_index, block_index, chainA_last_header, m_node.chainman->m_blockman);
}
// Reorg to chain B.
@@ -207,7 +208,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
}
BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
- CheckFilterLookups(filter_index, block_index, chainB_last_header);
+ CheckFilterLookups(filter_index, block_index, chainB_last_header, m_node.chainman->m_blockman);
}
// Check that filters for stale blocks on A can be retrieved.
@@ -221,7 +222,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
}
BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
- CheckFilterLookups(filter_index, block_index, chainA_last_header);
+ CheckFilterLookups(filter_index, block_index, chainA_last_header, m_node.chainman->m_blockman);
}
// Reorg back to chain A.
@@ -241,14 +242,14 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainA[i]->GetHash());
}
BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
- CheckFilterLookups(filter_index, block_index, chainA_last_header);
+ CheckFilterLookups(filter_index, block_index, chainA_last_header, m_node.chainman->m_blockman);
{
LOCK(cs_main);
block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainB[i]->GetHash());
}
BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
- CheckFilterLookups(filter_index, block_index, chainB_last_header);
+ CheckFilterLookups(filter_index, block_index, chainB_last_header, m_node.chainman->m_blockman);
}
// Test lookups for a range of filters/hashes.
diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp
index 2118f476cd..f094766886 100644
--- a/src/test/blockmanager_tests.cpp
+++ b/src/test/blockmanager_tests.cpp
@@ -5,6 +5,7 @@
#include <chainparams.h>
#include <node/blockstorage.h>
#include <node/context.h>
+#include <util/chaintype.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
@@ -13,31 +14,34 @@
using node::BlockManager;
using node::BLOCK_SERIALIZATION_HEADER_SIZE;
using node::MAX_BLOCKFILE_SIZE;
-using node::OpenBlockFile;
// use BasicTestingSetup here for the data directory configuration, setup, and cleanup
BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
{
- const auto params {CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN)};
- BlockManager blockman{{}};
+ const auto params {CreateChainParams(ArgsManager{}, ChainType::MAIN)};
+ const BlockManager::Options blockman_opts{
+ .chainparams = *params,
+ .blocks_dir = m_args.GetBlocksDirPath(),
+ };
+ BlockManager blockman{blockman_opts};
CChain chain {};
// simulate adding a genesis block normally
- BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, *params, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
+ BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
// simulate what happens during reindex
// simulate a well-formed genesis block being found at offset 8 in the blk00000.dat file
// the block is found at offset 8 because there is an 8 byte serialization header
// consisting of 4 magic bytes + 4 length bytes before each block in a well-formed blk file.
FlatFilePos pos{0, BLOCK_SERIALIZATION_HEADER_SIZE};
- BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, *params, &pos).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
+ BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, &pos).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
// now simulate what happens after reindex for the first new block processed
// the actual block contents don't matter, just that it's a block.
// verify that the write position is at offset 0x12d.
// this is a check to make sure that https://github.com/bitcoin/bitcoin/issues/21379 does not recur
// 8 bytes (for serialization header) + 285 (for serialized genesis block) = 293
// add another 8 bytes for the second block's serialization header and we get 293 + 8 = 301
- FlatFilePos actual{blockman.SaveBlockToDisk(params->GenesisBlock(), 1, chain, *params, nullptr)};
+ FlatFilePos actual{blockman.SaveBlockToDisk(params->GenesisBlock(), 1, chain, nullptr)};
BOOST_CHECK_EQUAL(actual.nPos, BLOCK_SERIALIZATION_HEADER_SIZE + ::GetSerializeSize(params->GenesisBlock(), CLIENT_VERSION) + BLOCK_SERIALIZATION_HEADER_SIZE);
}
@@ -63,13 +67,13 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_scan_unlink_already_pruned_files, TestChain
// Check that the file is not unlinked after ScanAndUnlinkAlreadyPrunedFiles
// if m_have_pruned is not yet set
WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
- BOOST_CHECK(!AutoFile(OpenBlockFile(pos, true)).IsNull());
+ BOOST_CHECK(!AutoFile(blockman.OpenBlockFile(pos, true)).IsNull());
// Check that the file is unlinked after ScanAndUnlinkAlreadyPrunedFiles
// once m_have_pruned is set
blockman.m_have_pruned = true;
WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
- BOOST_CHECK(AutoFile(OpenBlockFile(pos, true)).IsNull());
+ BOOST_CHECK(AutoFile(blockman.OpenBlockFile(pos, true)).IsNull());
// Check that calling with already pruned files doesn't cause an error
WITH_LOCK(chainman->GetMutex(), blockman.ScanAndUnlinkAlreadyPrunedFiles());
@@ -79,7 +83,7 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_scan_unlink_already_pruned_files, TestChain
BOOST_CHECK_NE(old_tip, new_tip);
const int new_file_number{WITH_LOCK(chainman->GetMutex(), return new_tip->GetBlockPos().nFile)};
const FlatFilePos new_pos(new_file_number, 0);
- BOOST_CHECK(!AutoFile(OpenBlockFile(new_pos, true)).IsNull());
+ BOOST_CHECK(!AutoFile(blockman.OpenBlockFile(new_pos, true)).IsNull());
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 5d4c5eea0e..93c0412593 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -5,6 +5,7 @@
#include <common/bloom.h>
#include <clientversion.h>
+#include <common/system.h>
#include <key.h>
#include <key_io.h>
#include <merkleblock.h>
@@ -16,7 +17,6 @@
#include <test/util/setup_common.h>
#include <uint256.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <vector>
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 6bc4770f9b..cb3831071a 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -3,10 +3,11 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <checkqueue.h>
+#include <common/args.h>
#include <sync.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
+#include <util/chaintype.h>
#include <util/time.h>
#include <boost/test/unit_test.hpp>
@@ -27,9 +28,9 @@
struct NoLockLoggingTestingSetup : public TestingSetup {
NoLockLoggingTestingSetup()
#ifdef DEBUG_LOCKCONTENTION
- : TestingSetup{CBaseChainParams::MAIN, /*extra_args=*/{"-debugexclude=lock"}} {}
+ : TestingSetup{ChainType::MAIN, /*extra_args=*/{"-debugexclude=lock"}} {}
#else
- : TestingSetup{CBaseChainParams::MAIN} {}
+ : TestingSetup{ChainType::MAIN} {}
#endif
};
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index e082800fc3..853dc6dc1e 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -6,6 +6,7 @@
#include <coins.h>
#include <script/standard.h>
#include <streams.h>
+#include <test/util/poolresourcetester.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <txdb.h>
@@ -612,7 +613,8 @@ void GetCoinsMapEntry(const CCoinsMap& map, CAmount& value, char& flags, const C
void WriteCoinsViewEntry(CCoinsView& view, CAmount value, char flags)
{
- CCoinsMap map;
+ CCoinsMapMemoryResource resource;
+ CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
InsertCoinsMapEntry(map, value, flags);
BOOST_CHECK(view.BatchWrite(map, {}));
}
@@ -911,6 +913,7 @@ void TestFlushBehavior(
CAmount value;
char flags;
size_t cache_usage;
+ size_t cache_size;
auto flush_all = [&all_caches](bool erase) {
// Flush in reverse order to ensure that flushes happen from children up.
@@ -935,6 +938,8 @@ void TestFlushBehavior(
view->AddCoin(outp, Coin(coin), false);
cache_usage = view->DynamicMemoryUsage();
+ cache_size = view->map().size();
+
// `base` shouldn't have coin (no flush yet) but `view` should have cached it.
BOOST_CHECK(!base.HaveCoin(outp));
BOOST_CHECK(view->HaveCoin(outp));
@@ -949,6 +954,7 @@ void TestFlushBehavior(
// CoinsMap usage should be unchanged since we didn't erase anything.
BOOST_CHECK_EQUAL(cache_usage, view->DynamicMemoryUsage());
+ BOOST_CHECK_EQUAL(cache_size, view->map().size());
// --- 3. Ensuring the entry still exists in the cache and has been written to parent
//
@@ -965,8 +971,10 @@ void TestFlushBehavior(
//
flush_all(/*erase=*/ true);
- // Memory usage should have gone down.
- BOOST_CHECK(view->DynamicMemoryUsage() < cache_usage);
+ // Memory does not necessarily go down due to the map using a memory pool
+ BOOST_TEST(view->DynamicMemoryUsage() <= cache_usage);
+ // Size of the cache must go down though
+ BOOST_TEST(view->map().size() < cache_size);
// --- 5. Ensuring the entry is no longer in the cache
//
@@ -1076,4 +1084,29 @@ BOOST_AUTO_TEST_CASE(ccoins_flush_behavior)
}
}
+BOOST_AUTO_TEST_CASE(coins_resource_is_used)
+{
+ CCoinsMapMemoryResource resource;
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+
+ {
+ CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
+ BOOST_TEST(memusage::DynamicUsage(map) >= resource.ChunkSizeBytes());
+
+ map.reserve(1000);
+
+ // The resource has preallocated a chunk, so we should have space for at several nodes without the need to allocate anything else.
+ const auto usage_before = memusage::DynamicUsage(map);
+
+ COutPoint out_point{};
+ for (size_t i = 0; i < 1000; ++i) {
+ out_point.n = i;
+ map[out_point];
+ }
+ BOOST_TEST(usage_before == memusage::DynamicUsage(map));
+ }
+
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index aca2b8eff0..1a06f16155 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -6,6 +6,7 @@
#include <banman.h>
#include <chainparams.h>
+#include <common/args.h>
#include <net.h>
#include <net_processing.h>
#include <pubkey.h>
@@ -17,7 +18,6 @@
#include <test/util/setup_common.h>
#include <timedata.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/time.h>
#include <validation.h>
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index c4b2b4c63b..7a7790e2ae 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -127,7 +127,7 @@ std::set<std::pair<CPubKey, KeyOriginInfo>> GetKeyOriginData(const FlatSigningPr
return ret;
}
-void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_pub, int flags,
+void DoCheck(std::string prv, std::string pub, const std::string& norm_pub, int flags,
const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type,
const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, bool replace_apostrophe_with_h_in_prv=false,
bool replace_apostrophe_with_h_in_pub=false, uint32_t spender_nlocktime=0, uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL,
@@ -141,16 +141,14 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
std::unique_ptr<Descriptor> parse_pub;
// Check that parsing succeeds.
if (replace_apostrophe_with_h_in_prv) {
- parse_priv = Parse(UseHInsteadOfApostrophe(prv), keys_priv, error);
- } else {
- parse_priv = Parse(prv, keys_priv, error);
+ prv = UseHInsteadOfApostrophe(prv);
}
+ parse_priv = Parse(prv, keys_priv, error);
BOOST_CHECK_MESSAGE(parse_priv, error);
if (replace_apostrophe_with_h_in_pub) {
- parse_pub = Parse(UseHInsteadOfApostrophe(pub), keys_pub, error);
- } else {
- parse_pub = Parse(pub, keys_pub, error);
+ pub = UseHInsteadOfApostrophe(pub);
}
+ parse_pub = Parse(pub, keys_pub, error);
BOOST_CHECK_MESSAGE(parse_pub, error);
// Check that the correct OutputType is inferred
@@ -171,19 +169,19 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
if (!(flags & MISSING_PRIVKEYS)) {
std::string prv1;
BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1));
- BOOST_CHECK(EqualDescriptor(prv, prv1));
+ BOOST_CHECK_MESSAGE(EqualDescriptor(prv, prv1), "Private ser: " + prv1 + " Private desc: " + prv);
BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1));
BOOST_CHECK(parse_pub->ToPrivateString(keys_priv, prv1));
- BOOST_CHECK(EqualDescriptor(prv, prv1));
+ BOOST_CHECK_MESSAGE(EqualDescriptor(prv, prv1), "Private ser: " + prv1 + " Private desc: " + prv);
BOOST_CHECK(!parse_pub->ToPrivateString(keys_pub, prv1));
}
// Check that private can produce the normalized descriptors
std::string norm1;
BOOST_CHECK(parse_priv->ToNormalizedString(keys_priv, norm1));
- BOOST_CHECK(EqualDescriptor(norm1, norm_pub));
+ BOOST_CHECK_MESSAGE(EqualDescriptor(norm1, norm_pub), "priv->ToNormalizedString(): " + norm1 + " Norm. desc: " + norm_pub);
BOOST_CHECK(parse_pub->ToNormalizedString(keys_priv, norm1));
- BOOST_CHECK(EqualDescriptor(norm1, norm_pub));
+ BOOST_CHECK_MESSAGE(EqualDescriptor(norm1, norm_pub), "pub->ToNormalizedString(): " + norm1 + " Norm. desc: " + norm_pub);
// Check whether IsRange on both returns the expected result
BOOST_CHECK_EQUAL(parse_pub->IsRange(), (flags & RANGE) != 0);
@@ -357,32 +355,13 @@ void Check(const std::string& prv, const std::string& pub, const std::string& no
const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, uint32_t spender_nlocktime=0,
uint32_t spender_nsequence=CTxIn::SEQUENCE_FINAL, std::map<std::vector<uint8_t>, std::vector<uint8_t>> preimages={})
{
- bool found_apostrophes_in_prv = false;
- bool found_apostrophes_in_pub = false;
-
// Do not replace apostrophes with 'h' in prv and pub
DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/false,
/*replace_apostrophe_with_h_in_pub=*/false, /*spender_nlocktime=*/spender_nlocktime,
/*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
- // Replace apostrophes with 'h' in prv but not in pub, if apostrophes are found in prv
- if (prv.find('\'') != std::string::npos) {
- found_apostrophes_in_prv = true;
- DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/true,
- /*replace_apostrophe_with_h_in_pub=*/false, /*spender_nlocktime=*/spender_nlocktime,
- /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
- }
-
- // Replace apostrophes with 'h' in pub but not in prv, if apostrophes are found in pub
- if (pub.find('\'') != std::string::npos) {
- found_apostrophes_in_pub = true;
- DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/false,
- /*replace_apostrophe_with_h_in_pub=*/true, /*spender_nlocktime=*/spender_nlocktime,
- /*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
- }
-
// Replace apostrophes with 'h' both in prv and in pub, if apostrophes are found in both
- if (found_apostrophes_in_prv && found_apostrophes_in_pub) {
+ if (prv.find('\'') != std::string::npos && pub.find('\'') != std::string::npos) {
DoCheck(prv, pub, norm_pub, flags, scripts, type, paths, /*replace_apostrophe_with_h_in_prv=*/true,
/*replace_apostrophe_with_h_in_pub=*/true, /*spender_nlocktime=*/spender_nlocktime,
/*spender_nsequence=*/spender_nsequence, /*preimages=*/preimages);
@@ -398,12 +377,12 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
// Basic single-key compressed
Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, std::nullopt);
Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}}, std::nullopt);
- Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, {{1,0x80000002UL,3,0x80000004UL}});
+ Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh([deadbeef/1/2h/3/4h]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, OutputType::LEGACY, {{1,0x80000002UL,3,0x80000004UL}});
Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}}, OutputType::BECH32);
Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}}, OutputType::P2SH_SEGWIT);
Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE | XONLY_KEYS, {{"512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11"}}, OutputType::BECH32M);
CheckUnparsable("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY2))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5))", "wpkh(): Pubkey '03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5' is invalid"); // Invalid pubkey
- CheckUnparsable("pkh(deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh(deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Key origin start '[ character expected but not found, got 'd' instead"); // Missing start bracket in key origin
+ CheckUnparsable("pkh(deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh(deadbeef/1/2h/3/4h]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Key origin start '[ character expected but not found, got 'd' instead"); // Missing start bracket in key origin
CheckUnparsable("pkh([deadbeef]/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef]/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "pkh(): Multiple ']' characters found for a single pubkey"); // Multiple end brackets in key origin
// Basic single-key uncompressed
@@ -426,10 +405,10 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
// Versions with BIP32 derivations
Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}}, std::nullopt);
Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, std::nullopt, {{0}});
- Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{0xFFFFFFFFUL,0}});
+ Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{0xFFFFFFFFUL,0}});
- Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
- Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
+ Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
+ Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, {{0}, {1}});
Check("tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", "tr(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/0/*,pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*))", XONLY_KEYS | RANGE, {{"512078bc707124daa551b65af74de2ec128b7525e10f374dc67b64e00ce0ab8b3e12"}, {"512001f0a02a17808c20134b78faab80ef93ffba82261ccef0a2314f5d62b6438f11"}, {"512021024954fcec88237a9386fce80ef2ced5f1e91b422b26c59ccfc174c8d1ad25"}}, OutputType::BECH32M, {{0, 0}, {0, 1}, {0, 2}, {1, 0}, {1, 1}, {1, 2}});
// Mixed xpubs and const pubkeys
@@ -440,23 +419,23 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
CheckUnparsable("combo([012345678]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([012345678]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "combo(): Fingerprint is not 4 bytes (9 characters instead of 8 characters)"); // Too long key fingerprint
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483648)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483648)", "pkh(): Key path value 2147483648 is out of range"); // BIP 32 path element overflow
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1aa)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1aa)", "pkh(): Key path value '1aa' is not a valid uint32"); // Path is not valid uint
- Check("pkh([01234567/10/20]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh([01234567/10/20]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([01234567/10/20/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{10, 20, 0xFFFFFFFFUL, 0}});
+ Check("pkh([01234567/10/20]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh([01234567/10/20]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", "pkh([01234567/10/20/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, OutputType::LEGACY, {{10, 20, 0xFFFFFFFFUL, 0}});
// Multisig constructions
Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}, std::nullopt);
- Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
+ Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, std::nullopt, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}});
- Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
+ Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "wsh(multi(2,[bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", HARDENED | RANGE | DERIVE_HARDENED, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, OutputType::BECH32, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}}, OutputType::P2SH_SEGWIT);
Check("tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,pk(KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))", SIGNABLE | XONLY_KEYS, {{"512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754"}}, OutputType::BECH32M);
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript
- CheckUnparsable("wsh(multi(2,[aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa][aaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: Multiple ']' characters found for a single pubkey"); // Double key origin descriptor
- CheckUnparsable("wsh(multi(2,[aaaagaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaagaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: Fingerprint 'aaagaaaa' is not hex"); // Non hex fingerprint
- CheckUnparsable("wsh(multi(2,[aaaaaaaa],xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa],xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: No key provided"); // No public key with origin
- CheckUnparsable("wsh(multi(2,[aaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: Fingerprint is not 4 bytes (7 characters instead of 8 characters)"); // Too short fingerprint
- CheckUnparsable("wsh(multi(2,[aaaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "Multi: Fingerprint is not 4 bytes (9 characters instead of 8 characters)"); // Too long fingerprint
+ CheckUnparsable("wsh(multi(2,[aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa][aaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647h/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", "Multi: Multiple ']' characters found for a single pubkey"); // Double key origin descriptor
+ CheckUnparsable("wsh(multi(2,[aaaagaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaagaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647h/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", "Multi: Fingerprint 'aaagaaaa' is not hex"); // Non hex fingerprint
+ CheckUnparsable("wsh(multi(2,[aaaaaaaa],xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa],xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", "Multi: No key provided"); // No public key with origin
+ CheckUnparsable("wsh(multi(2,[aaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647h/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", "Multi: Fingerprint is not 4 bytes (7 characters instead of 8 characters)"); // Too short fingerprint
+ CheckUnparsable("wsh(multi(2,[aaaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647h/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*h))", "Multi: Fingerprint is not 4 bytes (9 characters instead of 8 characters)"); // Too long fingerprint
CheckUnparsable("multi(a,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(a,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multi threshold 'a' is not valid"); // Invalid threshold
CheckUnparsable("multi(0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be 0, must be at least 1"); // Threshold of 0
CheckUnparsable("multi(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(3,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be larger than the number of keys; threshold is 3 but only 2 keys specified"); // Threshold larger than number of keys
@@ -474,8 +453,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
CheckUnparsable("wsh(wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "wsh(wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", "Can only have wsh() at top level or inside sh()"); // Cannot embed P2WSH inside P2WSH
// Checksums
- Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
- Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
+ Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfy", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5t", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#hgmsckna", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
+ Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", "sh(multi(2,[00000000/111h/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, OutputType::LEGACY, {{0x8000006FUL,222},{0}});
CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#", "Expected 8 character checksum, not 0 characters"); // Empty checksum
CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxfyq", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5tq", "Expected 8 character checksum, not 9 characters"); // Too long checksum
CheckUnparsable("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))#ggrsrxf", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))#tjg09x5", "Expected 8 character checksum, not 7 characters"); // Too short checksum
@@ -491,13 +470,12 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check(
"rawtr(xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/86'/1'/0'/1/*)#a5gn3t7k",
"rawtr(xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/86'/1'/0'/1/*)#4ur3xhft",
- "rawtr([5a61ff8e/86'/1'/0']xpub6DtZpc9PRL2B6pwoNGysmHAaBofDmWv5S6KQEKKGPKhf5fV62ywDtSziSApYVK3JnYY5KUSgiCwiXW5wtd8z7LNBxT9Mu5sEro8itdGfTeA/1/*)#llheyd9x",
+ "rawtr([5a61ff8e/86h/1h/0h]xpub6DtZpc9PRL2B6pwoNGysmHAaBofDmWv5S6KQEKKGPKhf5fV62ywDtSziSApYVK3JnYY5KUSgiCwiXW5wtd8z7LNBxT9Mu5sEro8itdGfTeA/1/*)#vwgx7hj9",
RANGE | HARDENED | XONLY_KEYS,
{{"51205172af752f057d543ce8e4a6f8dcf15548ec6be44041bfa93b72e191cfc8c1ee"}, {"51201b66f20b86f700c945ecb9ad9b0ad1662b73084e2bfea48bee02126350b8a5b1"}, {"512063e70f66d815218abcc2306aa930aaca07c5cde73b75127eb27b5e8c16b58a25"}},
OutputType::BECH32M,
{{0x80000056, 0x80000001, 0x80000000, 1, 0}, {0x80000056, 0x80000001, 0x80000000, 1, 1}, {0x80000056, 0x80000001, 0x80000000, 1, 2}});
-
Check(
"rawtr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)",
"rawtr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)",
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 54c30ed314..3874b38f61 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -3,10 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <clientversion.h>
+#include <common/args.h>
#include <flatfile.h>
#include <streams.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 7e7d630daa..7cfecb2b22 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
-#include <fs.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/getuniquepath.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index a59e41dbb5..7218bb82d1 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -6,6 +6,7 @@
#include <addrman.h>
#include <addrman_impl.h>
#include <chainparams.h>
+#include <common/args.h>
#include <merkleblock.h>
#include <random.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -15,7 +16,7 @@
#include <test/util/setup_common.h>
#include <time.h>
#include <util/asmap.h>
-#include <util/system.h>
+#include <util/chaintype.h>
#include <cassert>
#include <cstdint>
@@ -34,7 +35,7 @@ int32_t GetCheckRatio()
void initialize_addrman()
{
- static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::REGTEST);
+ static const auto testing_setup = MakeNoLogFileContext<>(ChainType::REGTEST);
g_setup = testing_setup.get();
}
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index 273dcfd850..cb5d29d9b8 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -3,15 +3,15 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <banman.h>
-#include <fs.h>
+#include <common/args.h>
#include <netaddress.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
+#include <util/fs.h>
#include <util/readwritefile.h>
-#include <util/system.h>
#include <cassert>
#include <cstdint>
diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp
index c3e17724eb..e90dcc189a 100644
--- a/src/test/fuzz/block.cpp
+++ b/src/test/fuzz/block.cpp
@@ -11,6 +11,7 @@
#include <pubkey.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
+#include <util/chaintype.h>
#include <validation.h>
#include <version.h>
@@ -19,7 +20,7 @@
void initialize_block()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(block, initialize_block)
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index 67cac8fa4e..2f7ce60c7f 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -53,7 +53,7 @@ FUZZ_TARGET(buffered_file)
return;
}
try {
- opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ opt_buffered_file->FindByte(std::byte(fuzzed_data_provider.ConsumeIntegral<uint8_t>()));
} catch (const std::ios_base::failure&) {
}
},
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index e80c772aa4..fc7e000dc7 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <chainparamsbase.h>
#include <coins.h>
#include <consensus/amount.h>
#include <consensus/tx_check.h>
@@ -115,7 +114,8 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
random_mutable_transaction = *opt_mutable_transaction;
},
[&] {
- CCoinsMap coins_map;
+ CCoinsMapMemoryResource resource;
+ CCoinsMap coins_map{0, SaltedOutpointHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CCoinsCacheEntry coins_cache_entry;
coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>();
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index 798c14030c..f81658b832 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -4,7 +4,7 @@
#include <addrman.h>
#include <chainparams.h>
-#include <chainparamsbase.h>
+#include <common/args.h>
#include <net.h>
#include <netaddress.h>
#include <protocol.h>
@@ -13,7 +13,6 @@
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/translation.h>
#include <cstdint>
@@ -125,7 +124,6 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
std::vector<CNodeStats> stats;
connman.GetNodeStats(stats);
(void)connman.GetOutboundTargetBytesLeft();
- (void)connman.GetReceiveFloodSize();
(void)connman.GetTotalBytesRecv();
(void)connman.GetTotalBytesSent();
(void)connman.GetTryNewOutboundPeer();
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index 1f5601ca9f..12c22ef2ed 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -6,11 +6,12 @@
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/fuzz.h>
+#include <util/chaintype.h>
void initialize_descriptor_parse()
{
ECC_Start();
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(ChainType::MAIN);
}
FUZZ_TARGET_INIT(descriptor_parse, initialize_descriptor_parse)
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 7cd78e0461..177711c6e4 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -9,6 +9,7 @@
#include <blockfilter.h>
#include <chain.h>
#include <coins.h>
+#include <common/args.h>
#include <compressor.h>
#include <consensus/merkle.h>
#include <key.h>
@@ -25,7 +26,6 @@
#include <streams.h>
#include <test/util/setup_common.h>
#include <undo.h>
-#include <util/system.h>
#include <version.h>
#include <exception>
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
index 9683f32d84..44ba8bc254 100644
--- a/src/test/fuzz/fuzz.cpp
+++ b/src/test/fuzz/fuzz.cpp
@@ -4,24 +4,29 @@
#include <test/fuzz/fuzz.h>
-#include <fs.h>
#include <netaddress.h>
#include <netbase.h>
#include <test/util/setup_common.h>
#include <util/check.h>
+#include <util/fs.h>
#include <util/sock.h>
#include <util/time.h>
#include <csignal>
#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
#include <exception>
#include <fstream>
#include <functional>
+#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <unistd.h>
+#include <utility>
#include <vector>
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
@@ -77,13 +82,13 @@ void initialize()
return WrappedGetAddrInfo(name, false);
};
- bool should_abort{false};
+ bool should_exit{false};
if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) {
for (const auto& t : FuzzTargets()) {
if (std::get<2>(t.second)) continue;
std::cout << t.first << std::endl;
}
- should_abort = true;
+ should_exit = true;
}
if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) {
std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl;
@@ -92,13 +97,23 @@ void initialize()
if (std::get<2>(t.second)) continue;
out_stream << t.first << std::endl;
}
- should_abort = true;
+ should_exit= true;
+ }
+ if (should_exit){
+ std::exit(EXIT_SUCCESS);
+ }
+ if (const auto* env_fuzz{std::getenv("FUZZ")}) {
+ // To allow for easier fuzz executable binary modification,
+ static std::string g_copy{env_fuzz}; // create copy to avoid compiler optimizations, and
+ g_fuzz_target = g_copy.c_str(); // strip string after the first null-char.
+ } else {
+ std::cerr << "Must select fuzz target with the FUZZ env var." << std::endl;
+ std::cerr << "Hint: Set the PRINT_ALL_FUZZ_TARGETS_AND_ABORT=1 env var to see all compiled targets." << std::endl;
+ std::exit(EXIT_FAILURE);
}
- Assert(!should_abort);
- g_fuzz_target = Assert(std::getenv("FUZZ"));
const auto it = FuzzTargets().find(g_fuzz_target);
if (it == FuzzTargets().end()) {
- std::cerr << "No fuzzer for " << g_fuzz_target << "." << std::endl;
+ std::cerr << "No fuzz target compiled for " << g_fuzz_target << "." << std::endl;
std::exit(EXIT_FAILURE);
}
Assert(!g_test_one_input);
diff --git a/src/test/fuzz/headerssync.cpp b/src/test/fuzz/headerssync.cpp
new file mode 100644
index 0000000000..c1a187038b
--- /dev/null
+++ b/src/test/fuzz/headerssync.cpp
@@ -0,0 +1,118 @@
+#include <arith_uint256.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <headerssync.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <uint256.h>
+#include <util/chaintype.h>
+#include <util/time.h>
+#include <validation.h>
+
+#include <iterator>
+#include <vector>
+
+static void initialize_headers_sync_state_fuzz()
+{
+ static const auto testing_setup = MakeNoLogFileContext<>(
+ /*chain_type=*/ChainType::MAIN);
+}
+
+void MakeHeadersContinuous(
+ const CBlockHeader& genesis_header,
+ const std::vector<CBlockHeader>& all_headers,
+ std::vector<CBlockHeader>& new_headers)
+{
+ Assume(!new_headers.empty());
+
+ const CBlockHeader* prev_header{
+ all_headers.empty() ? &genesis_header : &all_headers.back()};
+
+ for (auto& header : new_headers) {
+ header.hashPrevBlock = prev_header->GetHash();
+
+ prev_header = &header;
+ }
+}
+
+class FuzzedHeadersSyncState : public HeadersSyncState
+{
+public:
+ FuzzedHeadersSyncState(const unsigned commit_offset, const CBlockIndex* chain_start, const arith_uint256& minimum_required_work)
+ : HeadersSyncState(/*id=*/0, Params().GetConsensus(), chain_start, minimum_required_work)
+ {
+ const_cast<unsigned&>(m_commit_offset) = commit_offset;
+ }
+};
+
+FUZZ_TARGET_INIT(headers_sync_state, initialize_headers_sync_state_fuzz)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ auto mock_time{ConsumeTime(fuzzed_data_provider)};
+
+ CBlockHeader genesis_header{Params().GenesisBlock()};
+ CBlockIndex start_index(genesis_header);
+
+ if (mock_time < start_index.GetMedianTimePast()) return;
+ SetMockTime(mock_time);
+
+ const uint256 genesis_hash = genesis_header.GetHash();
+ start_index.phashBlock = &genesis_hash;
+
+ arith_uint256 min_work{UintToArith256(ConsumeUInt256(fuzzed_data_provider))};
+ FuzzedHeadersSyncState headers_sync(
+ /*commit_offset=*/fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(1, 1024),
+ /*chain_start=*/&start_index,
+ /*minimum_required_work=*/min_work);
+
+ // Store headers for potential redownload phase.
+ std::vector<CBlockHeader> all_headers;
+ std::vector<CBlockHeader>::const_iterator redownloaded_it;
+ bool presync{true};
+ bool requested_more{true};
+
+ while (requested_more) {
+ std::vector<CBlockHeader> headers;
+
+ // Consume headers from fuzzer or maybe replay headers if we got to the
+ // redownload phase.
+ if (presync || fuzzed_data_provider.ConsumeBool()) {
+ auto deser_headers = ConsumeDeserializable<std::vector<CBlockHeader>>(fuzzed_data_provider);
+ if (!deser_headers || deser_headers->empty()) return;
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ MakeHeadersContinuous(genesis_header, all_headers, *deser_headers);
+ }
+
+ headers.swap(*deser_headers);
+ } else if (auto num_headers_left{std::distance(redownloaded_it, all_headers.cend())}; num_headers_left > 0) {
+ // Consume some headers from the redownload buffer (At least one
+ // header is consumed).
+ auto begin_it{redownloaded_it};
+ std::advance(redownloaded_it, fuzzed_data_provider.ConsumeIntegralInRange<int>(1, num_headers_left));
+ headers.insert(headers.cend(), begin_it, redownloaded_it);
+ }
+
+ if (headers.empty()) return;
+ auto result = headers_sync.ProcessNextHeaders(headers, fuzzed_data_provider.ConsumeBool());
+ requested_more = result.request_more;
+
+ if (result.request_more) {
+ if (presync) {
+ all_headers.insert(all_headers.cend(), headers.cbegin(), headers.cend());
+
+ if (headers_sync.GetState() == HeadersSyncState::State::REDOWNLOAD) {
+ presync = false;
+ redownloaded_it = all_headers.cbegin();
+
+ // If we get to redownloading, the presynced headers need
+ // to have the min amount of work on them.
+ assert(CalculateHeadersWork(all_headers) >= min_work);
+ }
+ }
+
+ (void)headers_sync.NextHeadersRequestLocator();
+ }
+ }
+}
diff --git a/src/test/fuzz/i2p.cpp b/src/test/fuzz/i2p.cpp
index 6c2321cd68..3c6db96446 100644
--- a/src/test/fuzz/i2p.cpp
+++ b/src/test/fuzz/i2p.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <i2p.h>
#include <netaddress.h>
#include <netbase.h>
@@ -10,7 +11,6 @@
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
void initialize_i2p()
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index c0aefe6067..edb1dca457 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <arith_uint256.h>
+#include <common/args.h>
+#include <common/system.h>
#include <compressor.h>
#include <consensus/amount.h>
#include <consensus/merkle.h>
@@ -25,12 +27,12 @@
#include <test/fuzz/util.h>
#include <uint256.h>
#include <univalue.h>
+#include <util/chaintype.h>
#include <util/check.h>
#include <util/moneystr.h>
#include <util/overflow.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <version.h>
#include <cassert>
@@ -41,7 +43,7 @@
void initialize_integer()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(integer, initialize_integer)
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index ea6883c08d..25ea547435 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <chainparamsbase.h>
#include <key.h>
#include <key_io.h>
#include <outputtype.h>
@@ -16,19 +15,24 @@
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <util/chaintype.h>
#include <util/strencodings.h>
+#include <array>
#include <cassert>
+#include <cstddef>
#include <cstdint>
#include <numeric>
+#include <optional>
#include <string>
#include <vector>
void initialize_key()
{
ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(key, initialize_key)
@@ -303,3 +307,79 @@ FUZZ_TARGET_INIT(key, initialize_key)
}
}
}
+
+FUZZ_TARGET_INIT(ellswift_roundtrip, initialize_key)
+{
+ FuzzedDataProvider fdp{buffer.data(), buffer.size()};
+
+ auto key_bytes = fdp.ConsumeBytes<uint8_t>(32);
+ key_bytes.resize(32);
+ CKey key;
+ key.Set(key_bytes.begin(), key_bytes.end(), true);
+ if (!key.IsValid()) return;
+
+ auto ent32 = fdp.ConsumeBytes<std::byte>(32);
+ ent32.resize(32);
+
+ auto encoded_ellswift = key.EllSwiftCreate(ent32);
+ auto decoded_pubkey = encoded_ellswift.Decode();
+
+ assert(key.VerifyPubKey(decoded_pubkey));
+}
+
+FUZZ_TARGET_INIT(bip324_ecdh, initialize_key)
+{
+ FuzzedDataProvider fdp{buffer.data(), buffer.size()};
+
+ // We generate private key, k1.
+ auto rnd32 = fdp.ConsumeBytes<uint8_t>(32);
+ rnd32.resize(32);
+ CKey k1;
+ k1.Set(rnd32.begin(), rnd32.end(), true);
+ if (!k1.IsValid()) return;
+
+ // They generate private key, k2.
+ rnd32 = fdp.ConsumeBytes<uint8_t>(32);
+ rnd32.resize(32);
+ CKey k2;
+ k2.Set(rnd32.begin(), rnd32.end(), true);
+ if (!k2.IsValid()) return;
+
+ // We construct an ellswift encoding for our key, k1_ellswift.
+ auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
+ ent32_1.resize(32);
+ auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
+
+ // They construct an ellswift encoding for their key, k2_ellswift.
+ auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
+ ent32_2.resize(32);
+ auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
+
+ // They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
+ auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
+ ent32_2_bad.resize(32);
+ auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
+ assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
+
+ // Determine who is who.
+ bool initiating = fdp.ConsumeBool();
+
+ // We compute our shared secret using our key and their public key.
+ auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
+ // They compute their shared secret using their key and our public key.
+ auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
+ // Those must match, as everyone is behaving correctly.
+ assert(ecdh_secret_1 == ecdh_secret_2);
+
+ if (k1_ellswift != k2_ellswift) {
+ // Unless the two keys are exactly identical, acting as the wrong party breaks things.
+ auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
+ assert(ecdh_secret_bad != ecdh_secret_1);
+ }
+
+ if (k2_ellswift_bad != k2_ellswift) {
+ // Unless both encodings created by them are identical, using the second one breaks things.
+ auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
+ assert(ecdh_secret_bad != ecdh_secret_1);
+ }
+}
diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp
index 29c6996365..a1c587a75b 100644
--- a/src/test/fuzz/key_io.cpp
+++ b/src/test/fuzz/key_io.cpp
@@ -5,6 +5,7 @@
#include <chainparams.h>
#include <key_io.h>
#include <test/fuzz/fuzz.h>
+#include <util/chaintype.h>
#include <cassert>
#include <cstdint>
@@ -14,7 +15,7 @@
void initialize_key_io()
{
ECC_Start();
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(ChainType::MAIN);
}
FUZZ_TARGET_INIT(key_io, initialize_key_io)
diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp
index 63e24aacdd..8b7e3f11cc 100644
--- a/src/test/fuzz/message.cpp
+++ b/src/test/fuzz/message.cpp
@@ -7,6 +7,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <util/chaintype.h>
#include <util/message.h>
#include <util/strencodings.h>
@@ -19,7 +20,7 @@
void initialize_message()
{
ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(message, initialize_message)
diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp
new file mode 100644
index 0000000000..2b371f6d5f
--- /dev/null
+++ b/src/test/fuzz/mini_miner.cpp
@@ -0,0 +1,193 @@
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/fuzz/util/mempool.h>
+#include <test/util/script.h>
+#include <test/util/setup_common.h>
+#include <test/util/txmempool.h>
+#include <test/util/mining.h>
+
+#include <node/mini_miner.h>
+#include <node/miner.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <txmempool.h>
+
+#include <deque>
+#include <vector>
+
+namespace {
+
+const TestingSetup* g_setup;
+std::deque<COutPoint> g_available_coins;
+void initialize_miner()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+ for (uint32_t i = 0; i < uint32_t{100}; ++i) {
+ g_available_coins.push_back(COutPoint{uint256::ZERO, i});
+ }
+}
+
+// Test that the MiniMiner can run with various outpoints and feerates.
+FUZZ_TARGET_INIT(mini_miner, initialize_miner)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ CTxMemPool pool{CTxMemPool::Options{}};
+ std::vector<COutPoint> outpoints;
+ std::deque<COutPoint> available_coins = g_available_coins;
+ LOCK2(::cs_main, pool.cs);
+ // Cluster size cannot exceed 500
+ LIMITED_WHILE(!available_coins.empty(), 500)
+ {
+ CMutableTransaction mtx = CMutableTransaction();
+ const size_t num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, available_coins.size());
+ const size_t num_outputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50);
+ for (size_t n{0}; n < num_inputs; ++n) {
+ auto prevout = available_coins.front();
+ mtx.vin.push_back(CTxIn(prevout, CScript()));
+ available_coins.pop_front();
+ }
+ for (uint32_t n{0}; n < num_outputs; ++n) {
+ mtx.vout.push_back(CTxOut(100, P2WSH_OP_TRUE));
+ }
+ CTransactionRef tx = MakeTransactionRef(mtx);
+ TestMemPoolEntryHelper entry;
+ const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/100000)};
+ assert(MoneyRange(fee));
+ pool.addUnchecked(entry.Fee(fee).FromTx(tx));
+
+ // All outputs are available to spend
+ for (uint32_t n{0}; n < num_outputs; ++n) {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ available_coins.push_back(COutPoint{tx->GetHash(), n});
+ }
+ }
+
+ if (fuzzed_data_provider.ConsumeBool() && !tx->vout.empty()) {
+ // Add outpoint from this tx (may or not be spent by a later tx)
+ outpoints.push_back(COutPoint{tx->GetHash(),
+ (uint32_t)fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, tx->vout.size())});
+ } else {
+ // Add some random outpoint (will be interpreted as confirmed or not yet submitted
+ // to mempool).
+ auto outpoint = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (outpoint.has_value() && std::find(outpoints.begin(), outpoints.end(), *outpoint) == outpoints.end()) {
+ outpoints.push_back(*outpoint);
+ }
+ }
+
+ }
+
+ const CFeeRate target_feerate{CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/1000)}};
+ std::optional<CAmount> total_bumpfee;
+ CAmount sum_fees = 0;
+ {
+ node::MiniMiner mini_miner{pool, outpoints};
+ assert(mini_miner.IsReadyToCalculate());
+ const auto bump_fees = mini_miner.CalculateBumpFees(target_feerate);
+ for (const auto& outpoint : outpoints) {
+ auto it = bump_fees.find(outpoint);
+ assert(it != bump_fees.end());
+ assert(it->second >= 0);
+ sum_fees += it->second;
+ }
+ assert(!mini_miner.IsReadyToCalculate());
+ }
+ {
+ node::MiniMiner mini_miner{pool, outpoints};
+ assert(mini_miner.IsReadyToCalculate());
+ total_bumpfee = mini_miner.CalculateTotalBumpFees(target_feerate);
+ assert(total_bumpfee.has_value());
+ assert(!mini_miner.IsReadyToCalculate());
+ }
+ // Overlapping ancestry across multiple outpoints can only reduce the total bump fee.
+ assert (sum_fees >= *total_bumpfee);
+}
+
+// Test that MiniMiner and BlockAssembler build the same block given the same transactions and constraints.
+FUZZ_TARGET_INIT(mini_miner_selection, initialize_miner)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ CTxMemPool pool{CTxMemPool::Options{}};
+ // Make a copy to preserve determinism.
+ std::deque<COutPoint> available_coins = g_available_coins;
+ std::vector<CTransactionRef> transactions;
+
+ LOCK2(::cs_main, pool.cs);
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100)
+ {
+ CMutableTransaction mtx = CMutableTransaction();
+ assert(!available_coins.empty());
+ const size_t num_inputs = std::min(size_t{2}, available_coins.size());
+ const size_t num_outputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(2, 5);
+ for (size_t n{0}; n < num_inputs; ++n) {
+ auto prevout = available_coins.at(0);
+ mtx.vin.push_back(CTxIn(prevout, CScript()));
+ available_coins.pop_front();
+ }
+ for (uint32_t n{0}; n < num_outputs; ++n) {
+ mtx.vout.push_back(CTxOut(100, P2WSH_OP_TRUE));
+ }
+ CTransactionRef tx = MakeTransactionRef(mtx);
+
+ // First 2 outputs are available to spend. The rest are added to outpoints to calculate bumpfees.
+ // There is no overlap between spendable coins and outpoints passed to MiniMiner because the
+ // MiniMiner interprets spent coins as to-be-replaced and excludes them.
+ for (uint32_t n{0}; n < num_outputs - 1; ++n) {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ available_coins.push_front(COutPoint{tx->GetHash(), n});
+ } else {
+ available_coins.push_back(COutPoint{tx->GetHash(), n});
+ }
+ }
+
+ // Stop if pool reaches DEFAULT_BLOCK_MAX_WEIGHT because BlockAssembler will stop when the
+ // block template reaches that, but the MiniMiner will keep going.
+ if (pool.GetTotalTxSize() + GetVirtualTransactionSize(*tx) >= DEFAULT_BLOCK_MAX_WEIGHT) break;
+ TestMemPoolEntryHelper entry;
+ const CAmount fee{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/100000)};
+ assert(MoneyRange(fee));
+ pool.addUnchecked(entry.Fee(fee).FromTx(tx));
+ transactions.push_back(tx);
+ }
+ std::vector<COutPoint> outpoints;
+ for (const auto& coin : g_available_coins) {
+ if (!pool.GetConflictTx(coin)) outpoints.push_back(coin);
+ }
+ for (const auto& tx : transactions) {
+ assert(pool.exists(GenTxid::Txid(tx->GetHash())));
+ for (uint32_t n{0}; n < tx->vout.size(); ++n) {
+ COutPoint coin{tx->GetHash(), n};
+ if (!pool.GetConflictTx(coin)) outpoints.push_back(coin);
+ }
+ }
+ const CFeeRate target_feerate{ConsumeMoney(fuzzed_data_provider, /*max=*/MAX_MONEY/100000)};
+
+ node::BlockAssembler::Options miner_options;
+ miner_options.blockMinFeeRate = target_feerate;
+ miner_options.nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
+ miner_options.test_block_validity = false;
+
+ node::BlockAssembler miner{g_setup->m_node.chainman->ActiveChainstate(), &pool, miner_options};
+ node::MiniMiner mini_miner{pool, outpoints};
+ assert(mini_miner.IsReadyToCalculate());
+
+ CScript spk_placeholder = CScript() << OP_0;
+ // Use BlockAssembler as oracle. BlockAssembler and MiniMiner should select the same
+ // transactions, stopping once packages do not meet target_feerate.
+ const auto blocktemplate{miner.CreateNewBlock(spk_placeholder)};
+ mini_miner.BuildMockTemplate(target_feerate);
+ assert(!mini_miner.IsReadyToCalculate());
+ auto mock_template_txids = mini_miner.GetMockTemplateTxids();
+ // MiniMiner doesn't add a coinbase tx.
+ assert(mock_template_txids.count(blocktemplate->block.vtx[0]->GetHash()) == 0);
+ mock_template_txids.emplace(blocktemplate->block.vtx[0]->GetHash());
+ assert(mock_template_txids.size() <= blocktemplate->block.vtx.size());
+ assert(mock_template_txids.size() >= blocktemplate->block.vtx.size());
+ assert(mock_template_txids.size() == blocktemplate->block.vtx.size());
+ for (const auto& tx : blocktemplate->block.vtx) {
+ assert(mock_template_txids.count(tx->GetHash()));
+ }
+}
+} // namespace
diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp
index 6ea8a3f185..81c6f076b2 100644
--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -248,8 +248,6 @@ using Fragment = miniscript::Fragment;
using NodeRef = miniscript::NodeRef<CPubKey>;
using Node = miniscript::Node<CPubKey>;
using Type = miniscript::Type;
-// https://github.com/llvm/llvm-project/issues/53444
-// NOLINTNEXTLINE(misc-unused-using-decls)
using miniscript::operator"" _mst;
//! Construct a miniscript node as a shared_ptr.
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 13b4638688..e090f13061 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <chainparamsbase.h>
#include <net.h>
#include <net_permissions.h>
#include <netaddress.h>
@@ -16,6 +15,7 @@
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <util/asmap.h>
+#include <util/chaintype.h>
#include <cstdint>
#include <optional>
@@ -24,7 +24,7 @@
void initialize_net()
{
- static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::MAIN);
+ static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN);
}
FUZZ_TARGET_INIT(net, initialize_net)
diff --git a/src/test/fuzz/netbase_dns_lookup.cpp b/src/test/fuzz/netbase_dns_lookup.cpp
index 81e216b358..dcf500acc3 100644
--- a/src/test/fuzz/netbase_dns_lookup.cpp
+++ b/src/test/fuzz/netbase_dns_lookup.cpp
@@ -29,33 +29,29 @@ FUZZ_TARGET(netbase_dns_lookup)
};
{
- std::vector<CNetAddr> resolved_addresses;
- if (LookupHost(name, resolved_addresses, max_results, allow_lookup, fuzzed_dns_lookup_function)) {
- for (const CNetAddr& resolved_address : resolved_addresses) {
- assert(!resolved_address.IsInternal());
- }
+ const std::vector<CNetAddr> resolved_addresses{LookupHost(name, max_results, allow_lookup, fuzzed_dns_lookup_function)};
+ for (const CNetAddr& resolved_address : resolved_addresses) {
+ assert(!resolved_address.IsInternal());
}
assert(resolved_addresses.size() <= max_results || max_results == 0);
}
{
- CNetAddr resolved_address;
- if (LookupHost(name, resolved_address, allow_lookup, fuzzed_dns_lookup_function)) {
- assert(!resolved_address.IsInternal());
+ const std::optional<CNetAddr> resolved_address{LookupHost(name, allow_lookup, fuzzed_dns_lookup_function)};
+ if (resolved_address.has_value()) {
+ assert(!resolved_address.value().IsInternal());
}
}
{
- std::vector<CService> resolved_services;
- if (Lookup(name, resolved_services, default_port, allow_lookup, max_results, fuzzed_dns_lookup_function)) {
- for (const CNetAddr& resolved_service : resolved_services) {
- assert(!resolved_service.IsInternal());
- }
+ const std::vector<CService> resolved_services{Lookup(name, default_port, allow_lookup, max_results, fuzzed_dns_lookup_function)};
+ for (const CNetAddr& resolved_service : resolved_services) {
+ assert(!resolved_service.IsInternal());
}
assert(resolved_services.size() <= max_results || max_results == 0);
}
{
- CService resolved_service;
- if (Lookup(name, resolved_service, default_port, allow_lookup, fuzzed_dns_lookup_function)) {
- assert(!resolved_service.IsInternal());
+ const std::optional<CService> resolved_service{Lookup(name, default_port, allow_lookup, fuzzed_dns_lookup_function)};
+ if (resolved_service.has_value()) {
+ assert(!resolved_service.value().IsInternal());
}
}
{
diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp
index 96254aa222..ec3cdbff5a 100644
--- a/src/test/fuzz/p2p_transport_serialization.cpp
+++ b/src/test/fuzz/p2p_transport_serialization.cpp
@@ -9,6 +9,7 @@
#include <protocol.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <util/chaintype.h>
#include <cassert>
#include <cstdint>
@@ -18,7 +19,7 @@
void initialize_p2p_transport_serialization()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(p2p_transport_serialization, initialize_p2p_transport_serialization)
diff --git a/src/test/fuzz/parse_hd_keypath.cpp b/src/test/fuzz/parse_hd_keypath.cpp
index 411b70230a..9a2d9a73da 100644
--- a/src/test/fuzz/parse_hd_keypath.cpp
+++ b/src/test/fuzz/parse_hd_keypath.cpp
@@ -18,6 +18,6 @@ FUZZ_TARGET(parse_hd_keypath)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const std::vector<uint32_t> random_keypath = ConsumeRandomLengthIntegralVector<uint32_t>(fuzzed_data_provider);
- (void)FormatHDKeypath(random_keypath);
+ (void)FormatHDKeypath(random_keypath, /*apostrophe=*/true); // WriteHDKeypath calls this with false
(void)WriteHDKeypath(random_keypath);
}
diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
index 16486f6b96..6d33c1a8cc 100644
--- a/src/test/fuzz/parse_univalue.cpp
+++ b/src/test/fuzz/parse_univalue.cpp
@@ -7,13 +7,14 @@
#include <rpc/client.h>
#include <rpc/util.h>
#include <test/fuzz/fuzz.h>
+#include <util/chaintype.h>
#include <limits>
#include <string>
void initialize_parse_univalue()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue)
@@ -21,12 +22,9 @@ FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue)
const std::string random_string(buffer.begin(), buffer.end());
bool valid = true;
const UniValue univalue = [&] {
- try {
- return ParseNonRFCJSONValue(random_string);
- } catch (const std::runtime_error&) {
- valid = false;
- return UniValue{};
- }
+ UniValue uv;
+ if (!uv.read(random_string)) valid = false;
+ return valid ? uv : UniValue{};
}();
if (!valid) {
return;
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 116fbd9015..aa3cfe81df 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -31,7 +31,7 @@ void initialize_policy_estimator()
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
+ CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
fuzzed_data_provider,
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 7c3289cd26..3df40197d8 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -28,7 +28,7 @@ FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()};
// Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
- static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
+ static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES};
if (block_policy_estimator.Read(fuzzed_auto_file)) {
block_policy_estimator.Write(fuzzed_auto_file);
}
diff --git a/src/test/fuzz/poolresource.cpp b/src/test/fuzz/poolresource.cpp
new file mode 100644
index 0000000000..ce64ef6472
--- /dev/null
+++ b/src/test/fuzz/poolresource.cpp
@@ -0,0 +1,174 @@
+// Copyright (c) 2022 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 <span.h>
+#include <support/allocators/pool.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/poolresourcetester.h>
+#include <test/util/xoroshiro128plusplus.h>
+
+#include <cstdint>
+#include <tuple>
+#include <vector>
+
+namespace {
+
+template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+class PoolResourceFuzzer
+{
+ FuzzedDataProvider& m_provider;
+ PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES> m_test_resource;
+ uint64_t m_sequence{0};
+ size_t m_total_allocated{};
+
+ struct Entry {
+ Span<std::byte> span;
+ size_t alignment;
+ uint64_t seed;
+
+ Entry(Span<std::byte> s, size_t a, uint64_t se) : span(s), alignment(a), seed(se) {}
+ };
+
+ std::vector<Entry> m_entries;
+
+public:
+ PoolResourceFuzzer(FuzzedDataProvider& provider)
+ : m_provider{provider},
+ m_test_resource{provider.ConsumeIntegralInRange<size_t>(MAX_BLOCK_SIZE_BYTES, 262144)}
+ {
+ }
+
+ void Allocate(size_t size, size_t alignment)
+ {
+ assert(size > 0); // Must allocate at least 1 byte.
+ assert(alignment > 0); // Alignment must be at least 1.
+ assert((alignment & (alignment - 1)) == 0); // Alignment must be power of 2.
+ assert((size & (alignment - 1)) == 0); // Size must be a multiple of alignment.
+
+ auto span = Span(static_cast<std::byte*>(m_test_resource.Allocate(size, alignment)), size);
+ m_total_allocated += size;
+
+ auto ptr_val = reinterpret_cast<std::uintptr_t>(span.data());
+ assert((ptr_val & (alignment - 1)) == 0);
+
+ uint64_t seed = m_sequence++;
+ RandomContentFill(m_entries.emplace_back(span, alignment, seed));
+ }
+
+ void
+ Allocate()
+ {
+ if (m_total_allocated > 0x1000000) return;
+ size_t alignment_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 7);
+ size_t alignment = 1 << alignment_bits;
+ size_t size_bits = m_provider.ConsumeIntegralInRange<size_t>(0, 16 - alignment_bits);
+ size_t size = m_provider.ConsumeIntegralInRange<size_t>(1U << size_bits, (1U << (size_bits + 1)) - 1U) << alignment_bits;
+ Allocate(size, alignment);
+ }
+
+ void RandomContentFill(Entry& entry)
+ {
+ XoRoShiRo128PlusPlus rng(entry.seed);
+ auto ptr = entry.span.data();
+ auto size = entry.span.size();
+
+ while (size >= 8) {
+ auto r = rng();
+ std::memcpy(ptr, &r, 8);
+ size -= 8;
+ ptr += 8;
+ }
+ if (size > 0) {
+ auto r = rng();
+ std::memcpy(ptr, &r, size);
+ }
+ }
+
+ void RandomContentCheck(const Entry& entry)
+ {
+ XoRoShiRo128PlusPlus rng(entry.seed);
+ auto ptr = entry.span.data();
+ auto size = entry.span.size();
+
+ std::byte buf[8];
+ while (size >= 8) {
+ auto r = rng();
+ std::memcpy(buf, &r, 8);
+ assert(std::memcmp(buf, ptr, 8) == 0);
+ size -= 8;
+ ptr += 8;
+ }
+ if (size > 0) {
+ auto r = rng();
+ std::memcpy(buf, &r, size);
+ assert(std::memcmp(buf, ptr, size) == 0);
+ }
+ }
+
+ void Deallocate(const Entry& entry)
+ {
+ auto ptr_val = reinterpret_cast<std::uintptr_t>(entry.span.data());
+ assert((ptr_val & (entry.alignment - 1)) == 0);
+ RandomContentCheck(entry);
+ m_total_allocated -= entry.span.size();
+ m_test_resource.Deallocate(entry.span.data(), entry.span.size(), entry.alignment);
+ }
+
+ void Deallocate()
+ {
+ if (m_entries.empty()) {
+ return;
+ }
+
+ size_t idx = m_provider.ConsumeIntegralInRange<size_t>(0, m_entries.size() - 1);
+ Deallocate(m_entries[idx]);
+ if (idx != m_entries.size() - 1) {
+ m_entries[idx] = std::move(m_entries.back());
+ }
+ m_entries.pop_back();
+ }
+
+ void Clear()
+ {
+ while (!m_entries.empty()) {
+ Deallocate();
+ }
+
+ PoolResourceTester::CheckAllDataAccountedFor(m_test_resource);
+ }
+
+ void Fuzz()
+ {
+ LIMITED_WHILE(m_provider.ConsumeBool(), 10000)
+ {
+ CallOneOf(
+ m_provider,
+ [&] { Allocate(); },
+ [&] { Deallocate(); });
+ }
+ Clear();
+ }
+};
+
+
+} // namespace
+
+FUZZ_TARGET(pool_resource)
+{
+ FuzzedDataProvider provider(buffer.data(), buffer.size());
+ CallOneOf(
+ provider,
+ [&] { PoolResourceFuzzer<128, 1>{provider}.Fuzz(); },
+ [&] { PoolResourceFuzzer<128, 2>{provider}.Fuzz(); },
+ [&] { PoolResourceFuzzer<128, 4>{provider}.Fuzz(); },
+ [&] { PoolResourceFuzzer<128, 8>{provider}.Fuzz(); },
+
+ [&] { PoolResourceFuzzer<8, 8>{provider}.Fuzz(); },
+ [&] { PoolResourceFuzzer<16, 16>{provider}.Fuzz(); },
+
+ [&] { PoolResourceFuzzer<256, alignof(max_align_t)>{provider}.Fuzz(); },
+ [&] { PoolResourceFuzzer<256, 64>{provider}.Fuzz(); });
+}
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index e5a3a6e68a..6d584c9f10 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -9,6 +9,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <util/chaintype.h>
#include <util/check.h>
#include <util/overflow.h>
@@ -19,7 +20,7 @@
void initialize_pow()
{
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(ChainType::MAIN);
}
FUZZ_TARGET_INIT(pow, initialize_pow)
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 0a7924f226..744ff4701d 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -2,15 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <banman.h>
-#include <chainparams.h>
#include <consensus/consensus.h>
#include <net.h>
#include <net_processing.h>
+#include <primitives/transaction.h>
#include <protocol.h>
-#include <scheduler.h>
#include <script/script.h>
+#include <serialize.h>
+#include <span.h>
#include <streams.h>
+#include <sync.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@@ -19,45 +20,36 @@
#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
+#include <util/chaintype.h>
+#include <util/check.h>
+#include <util/time.h>
+#include <validation.h>
#include <validationinterface.h>
#include <version.h>
+
#include <atomic>
-#include <cassert>
-#include <chrono>
-#include <cstdint>
-#include <iosfwd>
+#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
+#include <string_view>
+#include <vector>
namespace {
const TestingSetup* g_setup;
+std::string_view LIMIT_TO_MESSAGE_TYPE{};
} // namespace
-size_t& GetNumMsgTypes()
-{
- static size_t g_num_msg_types{0};
- return g_num_msg_types;
-}
-#define FUZZ_TARGET_MSG(msg_type) \
- struct msg_type##_Count_Before_Main { \
- msg_type##_Count_Before_Main() \
- { \
- ++GetNumMsgTypes(); \
- } \
- } const static g_##msg_type##_count_before_main; \
- FUZZ_TARGET_INIT(process_message_##msg_type, initialize_process_message) \
- { \
- fuzz_target(buffer, #msg_type); \
- }
-
void initialize_process_message()
{
- Assert(GetNumMsgTypes() == getAllNetMessageTypes().size()); // If this fails, add or remove the message type below
+ if (const auto val{std::getenv("LIMIT_TO_MESSAGE_TYPE")}) {
+ LIMIT_TO_MESSAGE_TYPE = val;
+ Assert(std::count(getAllNetMessageTypes().begin(), getAllNetMessageTypes().end(), LIMIT_TO_MESSAGE_TYPE)); // Unknown message type passed
+ }
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(
- /*chain_name=*/CBaseChainParams::REGTEST,
+ /*chain_type=*/ChainType::REGTEST,
/*extra_args=*/{"-txreconciliation"});
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
@@ -66,7 +58,7 @@ void initialize_process_message()
SyncWithValidationInterfaceQueue();
}
-void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE)
+FUZZ_TARGET_INIT(process_message, initialize_process_message)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
@@ -100,40 +92,3 @@ void fuzz_target(FuzzBufferType buffer, const std::string& LIMIT_TO_MESSAGE_TYPE
SyncWithValidationInterfaceQueue();
g_setup->m_node.connman->StopNodes();
}
-
-FUZZ_TARGET_INIT(process_message, initialize_process_message) { fuzz_target(buffer, ""); }
-FUZZ_TARGET_MSG(addr);
-FUZZ_TARGET_MSG(addrv2);
-FUZZ_TARGET_MSG(block);
-FUZZ_TARGET_MSG(blocktxn);
-FUZZ_TARGET_MSG(cfcheckpt);
-FUZZ_TARGET_MSG(cfheaders);
-FUZZ_TARGET_MSG(cfilter);
-FUZZ_TARGET_MSG(cmpctblock);
-FUZZ_TARGET_MSG(feefilter);
-FUZZ_TARGET_MSG(filteradd);
-FUZZ_TARGET_MSG(filterclear);
-FUZZ_TARGET_MSG(filterload);
-FUZZ_TARGET_MSG(getaddr);
-FUZZ_TARGET_MSG(getblocks);
-FUZZ_TARGET_MSG(getblocktxn);
-FUZZ_TARGET_MSG(getcfcheckpt);
-FUZZ_TARGET_MSG(getcfheaders);
-FUZZ_TARGET_MSG(getcfilters);
-FUZZ_TARGET_MSG(getdata);
-FUZZ_TARGET_MSG(getheaders);
-FUZZ_TARGET_MSG(headers);
-FUZZ_TARGET_MSG(inv);
-FUZZ_TARGET_MSG(mempool);
-FUZZ_TARGET_MSG(merkleblock);
-FUZZ_TARGET_MSG(notfound);
-FUZZ_TARGET_MSG(ping);
-FUZZ_TARGET_MSG(pong);
-FUZZ_TARGET_MSG(sendaddrv2);
-FUZZ_TARGET_MSG(sendcmpct);
-FUZZ_TARGET_MSG(sendheaders);
-FUZZ_TARGET_MSG(sendtxrcncl);
-FUZZ_TARGET_MSG(tx);
-FUZZ_TARGET_MSG(verack);
-FUZZ_TARGET_MSG(version);
-FUZZ_TARGET_MSG(wtxidrelay);
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index 96339743ba..68d4e02a26 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -24,7 +24,7 @@ const TestingSetup* g_setup;
void initialize_process_messages()
{
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(
- /*chain_name=*/CBaseChainParams::REGTEST,
+ /*chain_type=*/ChainType::REGTEST,
/*extra_args=*/{"-txreconciliation"});
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index 2578137471..b1858a1800 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -23,6 +23,7 @@
#include <test/util/setup_common.h>
#include <tinyformat.h>
#include <univalue.h>
+#include <util/chaintype.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/time.h>
@@ -37,7 +38,7 @@
namespace {
struct RPCFuzzTestingSetup : public TestingSetup {
- RPCFuzzTestingSetup(const std::string& chain_name, const std::vector<const char*>& extra_args) : TestingSetup{chain_name, extra_args}
+ RPCFuzzTestingSetup(const ChainType chain_type, const std::vector<const char*>& extra_args) : TestingSetup{chain_type, extra_args}
{
}
@@ -70,7 +71,6 @@ const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
"addconnection", // avoid DNS lookups
"addnode", // avoid DNS lookups
"addpeeraddress", // avoid DNS lookups
- "analyzepsbt", // avoid signed integer overflow in CFeeRate::GetFee(unsigned long) (https://github.com/bitcoin/bitcoin/issues/20607)
"dumptxoutset", // avoid writing to disk
"dumpwallet", // avoid writing to disk
"echoipc", // avoid assertion failure (Assertion `"EnsureAnyNodeContext(request.context).init" && check' failed.)
@@ -79,7 +79,6 @@ const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
"gettxoutproof", // avoid prohibitively slow execution
"importwallet", // avoid reading from disk
"loadwallet", // avoid reading from disk
- "prioritisetransaction", // avoid signed integer overflow in CTxMemPool::PrioritiseTransaction(uint256 const&, long const&) (https://github.com/bitcoin/bitcoin/issues/20626)
"savemempool", // disabled as a precautionary measure: may take a file path argument in the future
"setban", // avoid DNS lookups
"stop", // avoid shutdown state
@@ -87,6 +86,7 @@ const std::vector<std::string> RPC_COMMANDS_NOT_SAFE_FOR_FUZZING{
// RPC commands which are safe for fuzzing.
const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
+ "analyzepsbt",
"clearbanned",
"combinepsbt",
"combinerawtransaction",
@@ -98,6 +98,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"decoderawtransaction",
"decodescript",
"deriveaddresses",
+ "descriptorprocesspsbt",
"disconnectnode",
"echo",
"echojson",
@@ -112,9 +113,9 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"getblockchaininfo",
"getblockcount",
"getblockfilter",
+ "getblockfrompeer", // when no peers are connected, no p2p message is sent
"getblockhash",
"getblockheader",
- "getblockfrompeer", // when no peers are connected, no p2p message is sent
"getblockstats",
"getblocktemplate",
"getchaintips",
@@ -128,7 +129,6 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"getmempoolancestors",
"getmempooldescendants",
"getmempoolentry",
- "gettxspendingprevout",
"getmempoolinfo",
"getmininginfo",
"getnettotals",
@@ -136,11 +136,13 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"getnetworkinfo",
"getnodeaddresses",
"getpeerinfo",
+ "getprioritisedtransactions",
"getrawmempool",
"getrawtransaction",
"getrpcinfo",
"gettxout",
"gettxoutsetinfo",
+ "gettxspendingprevout",
"help",
"invalidateblock",
"joinpsbts",
@@ -149,6 +151,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"mockscheduler",
"ping",
"preciousblock",
+ "prioritisetransaction",
"pruneblockchain",
"reconsiderblock",
"scanblocks",
@@ -363,7 +366,7 @@ FUZZ_TARGET_INIT(rpc, initialize_rpc)
try {
rpc_testing_setup->CallRPC(rpc_command, arguments);
} catch (const UniValue& json_rpc_error) {
- const std::string error_msg{find_value(json_rpc_error, "message").get_str()};
+ const std::string error_msg{json_rpc_error.find_value("message").get_str()};
// Once c++20 is allowed, starts_with can be used.
// if (error_msg.starts_with("Internal bug detected")) {
if (0 == error_msg.rfind("Internal bug detected", 0)) {
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 1037dd934a..8a88c1107a 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -22,6 +22,7 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
+#include <util/chaintype.h>
#include <algorithm>
#include <cassert>
@@ -32,7 +33,7 @@
void initialize_script()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(script, initialize_script)
diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp
index 9186746bcf..5aa0ea58ff 100644
--- a/src/test/fuzz/script_format.cpp
+++ b/src/test/fuzz/script_format.cpp
@@ -11,10 +11,11 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
+#include <util/chaintype.h>
void initialize_script_format()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(script_format, initialize_script_format)
diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp
index de895cc69c..f332987987 100644
--- a/src/test/fuzz/script_sigcache.cpp
+++ b/src/test/fuzz/script_sigcache.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <chainparamsbase.h>
#include <key.h>
#include <pubkey.h>
#include <script/sigcache.h>
diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp
index c78c22e6cc..8b62daf162 100644
--- a/src/test/fuzz/script_sign.cpp
+++ b/src/test/fuzz/script_sign.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <chainparamsbase.h>
#include <key.h>
#include <psbt.h>
#include <pubkey.h>
@@ -14,6 +13,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <util/chaintype.h>
#include <util/translation.h>
#include <cassert>
@@ -27,7 +27,7 @@
void initialize_script_sign()
{
ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(script_sign, initialize_script_sign)
diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp
index 303dcf13e3..e9af93c639 100644
--- a/src/test/fuzz/signet.cpp
+++ b/src/test/fuzz/signet.cpp
@@ -11,6 +11,7 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#include <cstdint>
#include <optional>
@@ -18,7 +19,7 @@
void initialize_signet()
{
- static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::SIGNET);
+ static const auto testing_setup = MakeNoLogFileContext<>(ChainType::SIGNET);
}
FUZZ_TARGET_INIT(signet, initialize_signet)
diff --git a/src/test/fuzz/socks5.cpp b/src/test/fuzz/socks5.cpp
index 97f643db49..73235b7ced 100644
--- a/src/test/fuzz/socks5.cpp
+++ b/src/test/fuzz/socks5.cpp
@@ -14,12 +14,12 @@
#include <string>
#include <vector>
+extern std::chrono::milliseconds g_socks5_recv_timeout;
+
namespace {
-int default_socks5_recv_timeout;
+decltype(g_socks5_recv_timeout) default_socks5_recv_timeout;
};
-extern int g_socks5_recv_timeout;
-
void initialize_socks5()
{
static const auto testing_setup = MakeNoLogFileContext<const BasicTestingSetup>();
@@ -35,7 +35,7 @@ FUZZ_TARGET_INIT(socks5, initialize_socks5)
InterruptSocks5(fuzzed_data_provider.ConsumeBool());
// Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This
// will slow down fuzzing.
- g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1 : default_socks5_recv_timeout;
+ g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1ms : default_socks5_recv_timeout;
FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider);
// This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within
// a few seconds of fuzzing.
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index 9890e4c0e5..e81efac6e0 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -4,9 +4,10 @@
#include <blockfilter.h>
#include <clientversion.h>
+#include <common/args.h>
+#include <common/settings.h>
+#include <common/system.h>
#include <common/url.h>
-#include <logging.h>
-#include <netaddress.h>
#include <netbase.h>
#include <outputtype.h>
#include <rpc/client.h>
@@ -22,113 +23,19 @@
#include <test/fuzz/util.h>
#include <util/error.h>
#include <util/fees.h>
-#include <util/message.h>
-#include <util/settings.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
-#include <version.h>
+#include <cassert>
#include <cstdint>
#include <cstdlib>
+#include <ios>
+#include <stdexcept>
#include <string>
#include <vector>
-namespace {
-bool LegacyParsePrechecks(const std::string& str)
-{
- if (str.empty()) // No empty string allowed
- return false;
- if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size() - 1]))) // No padding allowed
- return false;
- if (!ContainsNoNUL(str)) // No embedded NUL characters allowed
- return false;
- return true;
-}
-
-bool LegacyParseInt32(const std::string& str, int32_t* out)
-{
- if (!LegacyParsePrechecks(str))
- return false;
- char* endp = nullptr;
- errno = 0; // strtol will not set errno if valid
- long int n = strtol(str.c_str(), &endp, 10);
- if (out) *out = (int32_t)n;
- // Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow
- // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
- // platforms the size of these types may be different.
- return endp && *endp == 0 && !errno &&
- n >= std::numeric_limits<int32_t>::min() &&
- n <= std::numeric_limits<int32_t>::max();
-}
-
-bool LegacyParseInt64(const std::string& str, int64_t* out)
-{
- if (!LegacyParsePrechecks(str))
- return false;
- char* endp = nullptr;
- errno = 0; // strtoll will not set errno if valid
- long long int n = strtoll(str.c_str(), &endp, 10);
- if (out) *out = (int64_t)n;
- // Note that strtoll returns a *long long int*, so even if strtol doesn't report an over/underflow
- // we still have to check that the returned value is within the range of an *int64_t*.
- return endp && *endp == 0 && !errno &&
- n >= std::numeric_limits<int64_t>::min() &&
- n <= std::numeric_limits<int64_t>::max();
-}
-
-bool LegacyParseUInt32(const std::string& str, uint32_t* out)
-{
- if (!LegacyParsePrechecks(str))
- return false;
- if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range
- return false;
- char* endp = nullptr;
- errno = 0; // strtoul will not set errno if valid
- unsigned long int n = strtoul(str.c_str(), &endp, 10);
- if (out) *out = (uint32_t)n;
- // Note that strtoul returns a *unsigned long int*, so even if it doesn't report an over/underflow
- // we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
- // platforms the size of these types may be different.
- return endp && *endp == 0 && !errno &&
- n <= std::numeric_limits<uint32_t>::max();
-}
-
-bool LegacyParseUInt8(const std::string& str, uint8_t* out)
-{
- uint32_t u32;
- if (!LegacyParseUInt32(str, &u32) || u32 > std::numeric_limits<uint8_t>::max()) {
- return false;
- }
- if (out != nullptr) {
- *out = static_cast<uint8_t>(u32);
- }
- return true;
-}
-
-bool LegacyParseUInt64(const std::string& str, uint64_t* out)
-{
- if (!LegacyParsePrechecks(str))
- return false;
- if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoull accepts these by default if they fit in the range
- return false;
- char* endp = nullptr;
- errno = 0; // strtoull will not set errno if valid
- unsigned long long int n = strtoull(str.c_str(), &endp, 10);
- if (out) *out = (uint64_t)n;
- // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report an over/underflow
- // we still have to check that the returned value is within the range of an *uint64_t*.
- return endp && *endp == 0 && !errno &&
- n <= std::numeric_limits<uint64_t>::max();
-}
-
-// For backwards compatibility checking.
-int64_t atoi64_legacy(const std::string& str)
-{
- return strtoll(str.c_str(), nullptr, 10);
-}
-}; // namespace
+enum class FeeEstimateMode;
FUZZ_TARGET(string)
{
@@ -156,13 +63,9 @@ FUZZ_TARGET(string)
(void)IsDeprecatedRPCEnabled(random_string_1);
(void)Join(random_string_vector, random_string_1);
(void)JSONRPCError(fuzzed_data_provider.ConsumeIntegral<int>(), random_string_1);
- const util::Settings settings;
+ const common::Settings settings;
(void)OnlyHasDefaultSectionSetting(settings, random_string_1, random_string_2);
(void)ParseNetwork(random_string_1);
- try {
- (void)ParseNonRFCJSONValue(random_string_1);
- } catch (const std::runtime_error&) {
- }
(void)ParseOutputType(random_string_1);
(void)RemovePrefix(random_string_1, random_string_2);
(void)ResolveErrMsg(random_string_1, random_string_2);
@@ -236,61 +139,4 @@ FUZZ_TARGET(string)
const bilingual_str bs2{random_string_2, random_string_1};
(void)(bs1 + bs2);
}
- {
- int32_t i32;
- int64_t i64;
- uint32_t u32;
- uint64_t u64;
- uint8_t u8;
- const bool ok_i32 = ParseInt32(random_string_1, &i32);
- const bool ok_i64 = ParseInt64(random_string_1, &i64);
- const bool ok_u32 = ParseUInt32(random_string_1, &u32);
- const bool ok_u64 = ParseUInt64(random_string_1, &u64);
- const bool ok_u8 = ParseUInt8(random_string_1, &u8);
-
- int32_t i32_legacy;
- int64_t i64_legacy;
- uint32_t u32_legacy;
- uint64_t u64_legacy;
- uint8_t u8_legacy;
- const bool ok_i32_legacy = LegacyParseInt32(random_string_1, &i32_legacy);
- const bool ok_i64_legacy = LegacyParseInt64(random_string_1, &i64_legacy);
- const bool ok_u32_legacy = LegacyParseUInt32(random_string_1, &u32_legacy);
- const bool ok_u64_legacy = LegacyParseUInt64(random_string_1, &u64_legacy);
- const bool ok_u8_legacy = LegacyParseUInt8(random_string_1, &u8_legacy);
-
- assert(ok_i32 == ok_i32_legacy);
- assert(ok_i64 == ok_i64_legacy);
- assert(ok_u32 == ok_u32_legacy);
- assert(ok_u64 == ok_u64_legacy);
- assert(ok_u8 == ok_u8_legacy);
-
- if (ok_i32) {
- assert(i32 == i32_legacy);
- }
- if (ok_i64) {
- assert(i64 == i64_legacy);
- }
- if (ok_u32) {
- assert(u32 == u32_legacy);
- }
- if (ok_u64) {
- assert(u64 == u64_legacy);
- }
- if (ok_u8) {
- assert(u8 == u8_legacy);
- }
- }
-
- {
- const int locale_independent_atoi_result = LocaleIndependentAtoi<int>(random_string_1);
- const int64_t atoi64_result = atoi64_legacy(random_string_1);
- assert(locale_independent_atoi_result == std::clamp<int64_t>(atoi64_result, std::numeric_limits<int>::min(), std::numeric_limits<int>::max()));
- }
-
- {
- const int64_t atoi64_result = atoi64_legacy(random_string_1);
- const int64_t locale_independent_atoi_result = LocaleIndependentAtoi<int64_t>(random_string_1);
- assert(atoi64_result == locale_independent_atoi_result);
- }
}
diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index dc3f9c8b8f..73c01d9297 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <cstdint>
#include <string>
@@ -55,7 +55,7 @@ FUZZ_TARGET_INIT(system, initialize_system)
[&] {
const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN});
// Avoid hitting:
- // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
+ // common/args.cpp:563: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
if (args_manager.GetArgFlags(argument_name) != std::nullopt) {
return;
@@ -64,7 +64,7 @@ FUZZ_TARGET_INIT(system, initialize_system)
},
[&] {
// Avoid hitting:
- // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
+ // common/args.cpp:563: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider);
std::vector<std::string> hidden_arguments;
for (const std::string& name : names) {
@@ -108,7 +108,7 @@ FUZZ_TARGET_INIT(system, initialize_system)
(void)args_manager.GetArgs(s1);
(void)args_manager.GetBoolArg(s1, b);
try {
- (void)args_manager.GetChainName();
+ (void)args_manager.GetChainTypeString();
} catch (const std::runtime_error&) {
}
(void)args_manager.GetHelpMessage();
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index bacb178b44..c561675d1a 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -15,6 +15,7 @@
#include <streams.h>
#include <test/fuzz/fuzz.h>
#include <univalue.h>
+#include <util/chaintype.h>
#include <util/rbf.h>
#include <validation.h>
#include <version.h>
@@ -23,7 +24,7 @@
void initialize_transaction()
{
- SelectParams(CBaseChainParams::REGTEST);
+ SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET_INIT(transaction, initialize_transaction)
@@ -100,7 +101,14 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)AreInputsStandard(tx, coins_view_cache);
(void)IsWitnessStandard(tx, coins_view_cache);
- UniValue u(UniValue::VOBJ);
- TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u);
- TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u);
+ if (tx.GetTotalSize() < 250'000) { // Avoid high memory usage (with msan) due to json encoding
+ {
+ UniValue u{UniValue::VOBJ};
+ TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u);
+ }
+ {
+ UniValue u{UniValue::VOBJ};
+ TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u);
+ }
+ }
}
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 0cabaf323b..b758c715ef 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -42,12 +42,12 @@ void initialize_tx_pool()
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
- CTxIn in = MineBlock(g_setup->m_node, P2WSH_OP_TRUE);
+ COutPoint prevout{MineBlock(g_setup->m_node, P2WSH_OP_TRUE)};
// Remember the txids to avoid expensive disk access later on
auto& outpoints = i < COINBASE_MATURITY ?
g_outpoints_coinbase_init_mature :
g_outpoints_coinbase_init_immature;
- outpoints.push_back(in.prevout);
+ outpoints.push_back(prevout);
}
SyncWithValidationInterfaceQueue();
}
@@ -316,6 +316,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
MockTime(fuzzed_data_provider, chainstate);
std::vector<uint256> txids;
+ txids.reserve(g_outpoints_coinbase_init_mature.size());
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
txids.push_back(outpoint.hash);
}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index c14f633029..5f2aff08da 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -6,7 +6,6 @@
#define BITCOIN_TEST_FUZZ_UTIL_H
#include <arith_uint256.h>
-#include <chainparamsbase.h>
#include <coins.h>
#include <compat/compat.h>
#include <consensus/amount.h>
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 7119643b45..b4ef0c7a3e 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -4,13 +4,14 @@
#include <chainparams.h>
#include <consensus/validation.h>
-#include <fs.h>
#include <node/utxo_snapshot.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/mining.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
+#include <util/fs.h>
#include <validation.h>
#include <validationinterface.h>
@@ -22,7 +23,7 @@ const std::vector<std::shared_ptr<CBlock>>* g_chain;
void initialize_chain()
{
- const auto params{CreateChainParams(ArgsManager{}, CBaseChainParams::REGTEST)};
+ const auto params{CreateChainParams(ArgsManager{}, ChainType::REGTEST)};
static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)};
g_chain = &chain;
}
diff --git a/src/test/fuzz/utxo_total_supply.cpp b/src/test/fuzz/utxo_total_supply.cpp
new file mode 100644
index 0000000000..318797faf2
--- /dev/null
+++ b/src/test/fuzz/utxo_total_supply.cpp
@@ -0,0 +1,168 @@
+// Copyright (c) 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.
+
+#include <chainparams.h>
+#include <consensus/consensus.h>
+#include <consensus/merkle.h>
+#include <kernel/coinstats.h>
+#include <node/miner.h>
+#include <script/interpreter.h>
+#include <streams.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/mining.h>
+#include <test/util/setup_common.h>
+#include <util/chaintype.h>
+#include <validation.h>
+#include <version.h>
+
+FUZZ_TARGET(utxo_total_supply)
+{
+ /** The testing setup that creates a chainman only (no chainstate) */
+ ChainTestingSetup test_setup{
+ ChainType::REGTEST,
+ {
+ "-testactivationheight=bip34@2",
+ },
+ };
+ // Create chainstate
+ test_setup.LoadVerifyActivateChainstate();
+ auto& node{test_setup.m_node};
+ auto& chainman{*Assert(test_setup.m_node.chainman)};
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
+ const auto ActiveHeight = [&]() {
+ LOCK(chainman.GetMutex());
+ return chainman.ActiveHeight();
+ };
+ const auto PrepareNextBlock = [&]() {
+ // Use OP_FALSE to avoid BIP30 check from hitting early
+ auto block = PrepareBlock(node, CScript{} << OP_FALSE);
+ // Replace OP_FALSE with OP_TRUE
+ {
+ CMutableTransaction tx{*block->vtx.back()};
+ tx.vout.at(0).scriptPubKey = CScript{} << OP_TRUE;
+ block->vtx.back() = MakeTransactionRef(tx);
+ }
+ return block;
+ };
+
+ /** The block template this fuzzer is working on */
+ auto current_block = PrepareNextBlock();
+ /** Append-only set of tx outpoints, entries are not removed when spent */
+ std::vector<std::pair<COutPoint, CTxOut>> txos;
+ /** The utxo stats at the chain tip */
+ kernel::CCoinsStats utxo_stats;
+ /** The total amount of coins in the utxo set */
+ CAmount circulation{0};
+
+
+ // Store the tx out in the txo map
+ const auto StoreLastTxo = [&]() {
+ // get last tx
+ const CTransaction& tx = *current_block->vtx.back();
+ // get last out
+ const uint32_t i = tx.vout.size() - 1;
+ // store it
+ txos.emplace_back(COutPoint{tx.GetHash(), i}, tx.vout.at(i));
+ if (current_block->vtx.size() == 1 && tx.vout.at(i).scriptPubKey[0] == OP_RETURN) {
+ // also store coinbase
+ const uint32_t i = tx.vout.size() - 2;
+ txos.emplace_back(COutPoint{tx.GetHash(), i}, tx.vout.at(i));
+ }
+ };
+ const auto AppendRandomTxo = [&](CMutableTransaction& tx) {
+ const auto& txo = txos.at(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, txos.size() - 1));
+ tx.vin.emplace_back(txo.first);
+ tx.vout.emplace_back(txo.second.nValue, txo.second.scriptPubKey); // "Forward" coin with no fee
+ };
+ const auto UpdateUtxoStats = [&]() {
+ LOCK(chainman.GetMutex());
+ chainman.ActiveChainstate().ForceFlushStateToDisk();
+ utxo_stats = std::move(
+ *Assert(kernel::ComputeUTXOStats(kernel::CoinStatsHashType::NONE, &chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, {})));
+ // Check that miner can't print more money than they are allowed to
+ assert(circulation == utxo_stats.total_amount);
+ };
+
+
+ // Update internal state to chain tip
+ StoreLastTxo();
+ UpdateUtxoStats();
+ assert(ActiveHeight() == 0);
+ // Get at which height we duplicate the coinbase
+ // Assuming that the fuzzer will mine relatively short chains (less than 200 blocks), we want the duplicate coinbase to be not too high.
+ // Up to 2000 seems reasonable.
+ int64_t duplicate_coinbase_height = fuzzed_data_provider.ConsumeIntegralInRange(0, 20 * COINBASE_MATURITY);
+ // Always pad with OP_0 at the end to avoid bad-cb-length error
+ const CScript duplicate_coinbase_script = CScript() << duplicate_coinbase_height << OP_0;
+ // Mine the first block with this duplicate
+ current_block = PrepareNextBlock();
+ StoreLastTxo();
+
+ {
+ // Create duplicate (CScript should match exact format as in CreateNewBlock)
+ CMutableTransaction tx{*current_block->vtx.front()};
+ tx.vin.at(0).scriptSig = duplicate_coinbase_script;
+
+ // Mine block and create next block template
+ current_block->vtx.front() = MakeTransactionRef(tx);
+ }
+ current_block->hashMerkleRoot = BlockMerkleRoot(*current_block);
+ assert(!MineBlock(node, current_block).IsNull());
+ circulation += GetBlockSubsidy(ActiveHeight(), Params().GetConsensus());
+
+ assert(ActiveHeight() == 1);
+ UpdateUtxoStats();
+ current_block = PrepareNextBlock();
+ StoreLastTxo();
+
+ // Limit to avoid timeout, but enough to cover duplicate_coinbase_height
+ // and CVE-2018-17144.
+ LIMITED_WHILE(fuzzed_data_provider.remaining_bytes(), 2'000)
+ {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ // Append an input-output pair to the last tx in the current block
+ CMutableTransaction tx{*current_block->vtx.back()};
+ AppendRandomTxo(tx);
+ current_block->vtx.back() = MakeTransactionRef(tx);
+ StoreLastTxo();
+ },
+ [&] {
+ // Append a tx to the list of txs in the current block
+ CMutableTransaction tx{};
+ AppendRandomTxo(tx);
+ current_block->vtx.push_back(MakeTransactionRef(tx));
+ StoreLastTxo();
+ },
+ [&] {
+ // Append the current block to the active chain
+ node::RegenerateCommitments(*current_block, chainman);
+ const bool was_valid = !MineBlock(node, current_block).IsNull();
+
+ const auto prev_utxo_stats = utxo_stats;
+ if (was_valid) {
+ if (duplicate_coinbase_height == ActiveHeight()) {
+ // we mined the duplicate coinbase
+ assert(current_block->vtx.at(0)->vin.at(0).scriptSig == duplicate_coinbase_script);
+ }
+
+ circulation += GetBlockSubsidy(ActiveHeight(), Params().GetConsensus());
+ }
+
+ UpdateUtxoStats();
+
+ if (!was_valid) {
+ // utxo stats must not change
+ assert(prev_utxo_stats.hashSerialized == utxo_stats.hashSerialized);
+ }
+
+ current_block = PrepareNextBlock();
+ StoreLastTxo();
+ });
+ }
+}
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index 817593cf6e..4e2ca6d903 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -4,7 +4,6 @@
#include <kernel/mempool_persist.h>
-#include <chainparamsbase.h>
#include <node/mempool_args.h>
#include <node/mempool_persist_args.h>
#include <test/fuzz/FuzzedDataProvider.h>
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
index 143027662f..b3df4dadd2 100644
--- a/src/test/fuzz/versionbits.cpp
+++ b/src/test/fuzz/versionbits.cpp
@@ -4,9 +4,10 @@
#include <chain.h>
#include <chainparams.h>
+#include <common/args.h>
#include <consensus/params.h>
#include <primitives/block.h>
-#include <util/system.h>
+#include <util/chaintype.h>
#include <versionbits.h>
#include <test/fuzz/FuzzedDataProvider.h>
@@ -104,7 +105,7 @@ std::unique_ptr<const CChainParams> g_params;
void initialize()
{
// this is actually comparatively slow, so only do it once
- g_params = CreateChainParams(ArgsManager{}, CBaseChainParams::MAIN);
+ g_params = CreateChainParams(ArgsManager{}, ChainType::MAIN);
assert(g_params != nullptr);
}
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 9c2d8a4dad..c73b675388 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -2,11 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
+#include <common/settings.h>
+#include <logging.h>
#include <test/util/setup_common.h>
#include <univalue.h>
-#include <util/settings.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <limits>
#include <string>
@@ -29,6 +30,7 @@ void ResetArgs(ArgsManager& local_args, const std::string& strArg)
// Convert to char*:
std::vector<const char*> vecChar;
+ vecChar.reserve(vecArg.size());
for (const std::string& s : vecArg)
vecChar.push_back(s.c_str());
@@ -55,8 +57,8 @@ BOOST_AUTO_TEST_CASE(setting_args)
ArgsManager args;
SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}});
- auto set_foo = [&](const util::SettingsValue& value) {
- args.LockSettings([&](util::Settings& settings) {
+ auto set_foo = [&](const common::SettingsValue& value) {
+ args.LockSettings([&](common::Settings& settings) {
settings.rw_settings["foo"] = value;
});
};
diff --git a/src/test/httpserver_tests.cpp b/src/test/httpserver_tests.cpp
index ee59ec6967..c95a777e80 100644
--- a/src/test/httpserver_tests.cpp
+++ b/src/test/httpserver_tests.cpp
@@ -34,5 +34,9 @@ BOOST_AUTO_TEST_CASE(test_query_parameters)
// Invalid query string syntax is the same as not having parameters
uri = "/rest/endpoint/someresource.json&p1=v1&p2=v2";
BOOST_CHECK(!GetQueryParameterFromUri(uri.c_str(), "p1").has_value());
+
+ // URI with invalid characters (%) raises a runtime error regardless of which query parameter is queried
+ uri = "/rest/endpoint/someresource.json&p1=v1&p2=v2%";
+ BOOST_CHECK_EXCEPTION(GetQueryParameterFromUri(uri.c_str(), "p1"), std::runtime_error, HasReason("URI parsing failed, it likely contained RFC 3986 invalid characters"));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
index 3e20b527b5..b2e1ae43be 100644
--- a/src/test/i2p_tests.cpp
+++ b/src/test/i2p_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <i2p.h>
#include <logging.h>
#include <netaddress.h>
#include <test/util/logging.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp
index d37fe35a11..68377e197f 100644
--- a/src/test/interfaces_tests.cpp
+++ b/src/test/interfaces_tests.cpp
@@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(findAncestorByHash)
BOOST_AUTO_TEST_CASE(findCommonAncestor)
{
auto& chain = m_node.chain;
- const CChain& active = WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return Assert(m_node.chainman)->ActiveChain());
+ const CChain& active{*WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return &Assert(m_node.chainman)->ActiveChain())};
auto* orig_tip = active.Tip();
for (int i = 0; i < 10; ++i) {
BlockValidationState state;
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index a400afee71..92bdbae3c4 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.cpp
@@ -10,6 +10,7 @@
#include <script/script.h>
#include <test/util/json.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#include <util/strencodings.h>
#include <boost/test/unit_test.hpp>
@@ -24,7 +25,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse)
UniValue tests = read_json(std::string(json_tests::key_io_valid, json_tests::key_io_valid + sizeof(json_tests::key_io_valid)));
CKey privkey;
CTxDestination destination;
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(ChainType::MAIN);
for (unsigned int idx = 0; idx < tests.size(); idx++) {
const UniValue& test = tests[idx];
@@ -36,11 +37,11 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse)
std::string exp_base58string = test[0].get_str();
const std::vector<std::byte> exp_payload{ParseHex<std::byte>(test[1].get_str())};
const UniValue &metadata = test[2].get_obj();
- bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
- SelectParams(find_value(metadata, "chain").get_str());
- bool try_case_flip = find_value(metadata, "tryCaseFlip").isNull() ? false : find_value(metadata, "tryCaseFlip").get_bool();
+ bool isPrivkey = metadata.find_value("isPrivkey").get_bool();
+ SelectParams(ChainTypeFromString(metadata.find_value("chain").get_str()).value());
+ bool try_case_flip = metadata.find_value("tryCaseFlip").isNull() ? false : metadata.find_value("tryCaseFlip").get_bool();
if (isPrivkey) {
- bool isCompressed = find_value(metadata, "isCompressed").get_bool();
+ bool isCompressed = metadata.find_value("isCompressed").get_bool();
// Must be valid private key
privkey = DecodeSecret(exp_base58string);
BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
@@ -95,10 +96,10 @@ BOOST_AUTO_TEST_CASE(key_io_valid_gen)
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
const UniValue &metadata = test[2].get_obj();
- bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
- SelectParams(find_value(metadata, "chain").get_str());
+ bool isPrivkey = metadata.find_value("isPrivkey").get_bool();
+ SelectParams(ChainTypeFromString(metadata.find_value("chain").get_str()).value());
if (isPrivkey) {
- bool isCompressed = find_value(metadata, "isCompressed").get_bool();
+ bool isCompressed = metadata.find_value("isCompressed").get_bool();
CKey key;
key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
assert(key.IsValid());
@@ -113,7 +114,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_gen)
}
}
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(ChainType::MAIN);
}
@@ -135,7 +136,7 @@ BOOST_AUTO_TEST_CASE(key_io_invalid)
std::string exp_base58string = test[0].get_str();
// must be invalid as public and as private key
- for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST }) {
+ for (const auto& chain : {ChainType::MAIN, ChainType::TESTNET, ChainType::SIGNET, ChainType::REGTEST}) {
SelectParams(chain);
destination = DecodeDestination(exp_base58string);
BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index ea5b94f3a5..86a8d17a76 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -4,6 +4,7 @@
#include <key.h>
+#include <common/system.h>
#include <key_io.h>
#include <streams.h>
#include <test/util/random.h>
@@ -11,7 +12,6 @@
#include <uint256.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <string>
#include <vector>
@@ -344,4 +344,24 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
}
}
+BOOST_AUTO_TEST_CASE(key_ellswift)
+{
+ for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
+ CKey key = DecodeSecret(secret);
+ BOOST_CHECK(key.IsValid());
+
+ uint256 ent32 = InsecureRand256();
+ auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
+
+ CPubKey decoded_pubkey = ellswift.Decode();
+ if (!key.IsCompressed()) {
+ // The decoding constructor returns a compressed pubkey. If the
+ // original was uncompressed, we must decompress the decoded one
+ // to compare.
+ decoded_pubkey.Decompress();
+ }
+ BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp
index beb9398c74..2699d316da 100644
--- a/src/test/logging_tests.cpp
+++ b/src/test/logging_tests.cpp
@@ -200,7 +200,9 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
const char* argv_test[] = {"bitcoind", "-loglevel=debug"};
std::string err;
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
- init::SetLoggingLevel(args);
+
+ auto result = init::SetLoggingLevel(args);
+ BOOST_REQUIRE(result);
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
}
@@ -212,7 +214,9 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
const char* argv_test[] = {"bitcoind", "-loglevel=net:trace"};
std::string err;
BOOST_REQUIRE(args.ParseParameters(2, argv_test, err));
- init::SetLoggingLevel(args);
+
+ auto result = init::SetLoggingLevel(args);
+ BOOST_REQUIRE(result);
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::DEFAULT_LOG_LEVEL);
const auto& category_levels{LogInstance().CategoryLevels()};
@@ -229,7 +233,9 @@ BOOST_FIXTURE_TEST_CASE(logging_Conf, LogSetup)
const char* argv_test[] = {"bitcoind", "-loglevel=debug", "-loglevel=net:trace", "-loglevel=http:info"};
std::string err;
BOOST_REQUIRE(args.ParseParameters(4, argv_test, err));
- init::SetLoggingLevel(args);
+
+ auto result = init::SetLoggingLevel(args);
+ BOOST_REQUIRE(result);
BOOST_CHECK_EQUAL(LogInstance().LogLevel(), BCLog::Level::Debug);
const auto& category_levels{LogInstance().CategoryLevels()};
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 94e553a304..db58a0baec 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <policy/policy.h>
#include <test/util/txmempool.h>
#include <txmempool.h>
-#include <util/system.h>
#include <util/time.h>
#include <test/util/setup_common.h>
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index cfab762307..94e3f27930 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <coins.h>
+#include <common/system.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
@@ -15,7 +16,6 @@
#include <txmempool.h>
#include <uint256.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/time.h>
#include <validation.h>
#include <versionbits.h>
diff --git a/src/test/miniminer_tests.cpp b/src/test/miniminer_tests.cpp
new file mode 100644
index 0000000000..b26f7dafe3
--- /dev/null
+++ b/src/test/miniminer_tests.cpp
@@ -0,0 +1,476 @@
+// 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 <node/mini_miner.h>
+#include <txmempool.h>
+#include <util/time.h>
+
+#include <test/util/setup_common.h>
+#include <test/util/txmempool.h>
+
+#include <boost/test/unit_test.hpp>
+#include <optional>
+#include <vector>
+
+BOOST_FIXTURE_TEST_SUITE(miniminer_tests, TestingSetup)
+
+static inline CTransactionRef make_tx(const std::vector<COutPoint>& inputs, size_t num_outputs)
+{
+ CMutableTransaction tx = CMutableTransaction();
+ tx.vin.resize(inputs.size());
+ tx.vout.resize(num_outputs);
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ tx.vin[i].prevout = inputs[i];
+ }
+ for (size_t i = 0; i < num_outputs; ++i) {
+ tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ // The actual input and output values of these transactions don't really
+ // matter, since all accounting will use the entries' cached fees.
+ tx.vout[i].nValue = COIN;
+ }
+ return MakeTransactionRef(tx);
+}
+
+static inline bool sanity_check(const std::vector<CTransactionRef>& transactions,
+ const std::map<COutPoint, CAmount>& bumpfees)
+{
+ // No negative bumpfees.
+ for (const auto& [outpoint, fee] : bumpfees) {
+ if (fee < 0) return false;
+ if (fee == 0) continue;
+ auto outpoint_ = outpoint; // structured bindings can't be captured in C++17, so we need to use a variable
+ const bool found = std::any_of(transactions.cbegin(), transactions.cend(), [&](const auto& tx) {
+ return outpoint_.hash == tx->GetHash() && outpoint_.n < tx->vout.size();
+ });
+ if (!found) return false;
+ }
+ for (const auto& tx : transactions) {
+ // If tx has multiple outputs, they must all have the same bumpfee (if they exist).
+ if (tx->vout.size() > 1) {
+ std::set<CAmount> distinct_bumpfees;
+ for (size_t i{0}; i < tx->vout.size(); ++i) {
+ const auto bumpfee = bumpfees.find(COutPoint{tx->GetHash(), static_cast<uint32_t>(i)});
+ if (bumpfee != bumpfees.end()) distinct_bumpfees.insert(bumpfee->second);
+ }
+ if (distinct_bumpfees.size() > 1) return false;
+ }
+ }
+ return true;
+}
+
+template <typename Key, typename Value>
+Value Find(const std::map<Key, Value>& map, const Key& key)
+{
+ auto it = map.find(key);
+ BOOST_CHECK_MESSAGE(it != map.end(), strprintf("Cannot find %s", key.ToString()));
+ return it->second;
+}
+
+BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup)
+{
+ CTxMemPool& pool = *Assert(m_node.mempool);
+ LOCK2(::cs_main, pool.cs);
+ TestMemPoolEntryHelper entry;
+
+ const CAmount low_fee{CENT/2000};
+ const CAmount normal_fee{CENT/200};
+ const CAmount high_fee{CENT/10};
+
+ // Create a parent tx1 and child tx2 with normal fees:
+ const auto tx1 = make_tx({COutPoint{m_coinbase_txns[0]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx1));
+ const auto tx2 = make_tx({COutPoint{tx1->GetHash(), 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));
+
+ // Create a low-feerate parent tx3 and high-feerate child tx4 (cpfp)
+ const auto tx3 = make_tx({COutPoint{m_coinbase_txns[1]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx3));
+ const auto tx4 = make_tx({COutPoint{tx3->GetHash(), 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx4));
+
+ // Create a parent tx5 and child tx6 where both have low fees
+ const auto tx5 = make_tx({COutPoint{m_coinbase_txns[2]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx5));
+ const auto tx6 = make_tx({COutPoint{tx5->GetHash(), 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx6));
+ // Make tx6's modified fee much higher than its base fee. This should cause it to pass
+ // the fee-related checks despite being low-feerate.
+ pool.PrioritiseTransaction(tx6->GetHash(), CENT/100);
+
+ // Create a high-feerate parent tx7, low-feerate child tx8
+ const auto tx7 = make_tx({COutPoint{m_coinbase_txns[3]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx7));
+ const auto tx8 = make_tx({COutPoint{tx7->GetHash(), 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx8));
+
+ std::vector<COutPoint> all_unspent_outpoints({
+ COutPoint{tx1->GetHash(), 1},
+ COutPoint{tx2->GetHash(), 0},
+ COutPoint{tx3->GetHash(), 1},
+ COutPoint{tx4->GetHash(), 0},
+ COutPoint{tx5->GetHash(), 1},
+ COutPoint{tx6->GetHash(), 0},
+ COutPoint{tx7->GetHash(), 1},
+ COutPoint{tx8->GetHash(), 0}
+ });
+ for (const auto& outpoint : all_unspent_outpoints) BOOST_CHECK(!pool.isSpent(outpoint));
+
+ std::vector<COutPoint> all_spent_outpoints({
+ COutPoint{tx1->GetHash(), 0},
+ COutPoint{tx3->GetHash(), 0},
+ COutPoint{tx5->GetHash(), 0},
+ COutPoint{tx7->GetHash(), 0}
+ });
+ for (const auto& outpoint : all_spent_outpoints) BOOST_CHECK(pool.GetConflictTx(outpoint) != nullptr);
+
+ std::vector<COutPoint> all_parent_outputs({
+ COutPoint{tx1->GetHash(), 0},
+ COutPoint{tx1->GetHash(), 1},
+ COutPoint{tx3->GetHash(), 0},
+ COutPoint{tx3->GetHash(), 1},
+ COutPoint{tx5->GetHash(), 0},
+ COutPoint{tx5->GetHash(), 1},
+ COutPoint{tx7->GetHash(), 0},
+ COutPoint{tx7->GetHash(), 1}
+ });
+
+
+ std::vector<CTransactionRef> all_transactions{tx1, tx2, tx3, tx4, tx5, tx6, tx7, tx8};
+ struct TxDimensions {
+ int32_t vsize; CAmount mod_fee; CFeeRate feerate;
+ };
+ std::map<uint256, TxDimensions> tx_dims;
+ for (const auto& tx : all_transactions) {
+ const auto it = pool.GetIter(tx->GetHash()).value();
+ tx_dims.emplace(tx->GetHash(), TxDimensions{it->GetTxSize(), it->GetModifiedFee(),
+ CFeeRate(it->GetModifiedFee(), it->GetTxSize())});
+ }
+
+ const std::vector<CFeeRate> various_normal_feerates({CFeeRate(0), CFeeRate(500), CFeeRate(999),
+ CFeeRate(1000), CFeeRate(2000), CFeeRate(2500),
+ CFeeRate(3333), CFeeRate(7800), CFeeRate(11199),
+ CFeeRate(23330), CFeeRate(50000), CFeeRate(5*CENT)});
+
+ // All nonexistent entries have a bumpfee of zero, regardless of feerate
+ std::vector<COutPoint> nonexistent_outpoints({ COutPoint{GetRandHash(), 0}, COutPoint{GetRandHash(), 3} });
+ for (const auto& outpoint : nonexistent_outpoints) BOOST_CHECK(!pool.isSpent(outpoint));
+ for (const auto& feerate : various_normal_feerates) {
+ node::MiniMiner mini_miner(pool, nonexistent_outpoints);
+ BOOST_CHECK(mini_miner.IsReadyToCalculate());
+ auto bump_fees = mini_miner.CalculateBumpFees(feerate);
+ BOOST_CHECK(!mini_miner.IsReadyToCalculate());
+ BOOST_CHECK(sanity_check(all_transactions, bump_fees));
+ BOOST_CHECK(bump_fees.size() == nonexistent_outpoints.size());
+ for (const auto& outpoint: nonexistent_outpoints) {
+ auto it = bump_fees.find(outpoint);
+ BOOST_CHECK(it != bump_fees.end());
+ BOOST_CHECK_EQUAL(it->second, 0);
+ }
+ }
+
+ // Gather bump fees for all available UTXOs.
+ for (const auto& target_feerate : various_normal_feerates) {
+ node::MiniMiner mini_miner(pool, all_unspent_outpoints);
+ BOOST_CHECK(mini_miner.IsReadyToCalculate());
+ auto bump_fees = mini_miner.CalculateBumpFees(target_feerate);
+ BOOST_CHECK(!mini_miner.IsReadyToCalculate());
+ BOOST_CHECK(sanity_check(all_transactions, bump_fees));
+ BOOST_CHECK_EQUAL(bump_fees.size(), all_unspent_outpoints.size());
+
+ // Check tx1 bumpfee: no other bumper.
+ const TxDimensions& tx1_dimensions = tx_dims.find(tx1->GetHash())->second;
+ CAmount bumpfee1 = Find(bump_fees, COutPoint{tx1->GetHash(), 1});
+ if (target_feerate <= tx1_dimensions.feerate) {
+ BOOST_CHECK_EQUAL(bumpfee1, 0);
+ } else {
+ // Difference is fee to bump tx1 from current to target feerate.
+ BOOST_CHECK_EQUAL(bumpfee1, target_feerate.GetFee(tx1_dimensions.vsize) - tx1_dimensions.mod_fee);
+ }
+
+ // Check tx3 bumpfee: assisted by tx4.
+ const TxDimensions& tx3_dimensions = tx_dims.find(tx3->GetHash())->second;
+ const TxDimensions& tx4_dimensions = tx_dims.find(tx4->GetHash())->second;
+ const CFeeRate tx3_feerate = CFeeRate(tx3_dimensions.mod_fee + tx4_dimensions.mod_fee, tx3_dimensions.vsize + tx4_dimensions.vsize);
+ CAmount bumpfee3 = Find(bump_fees, COutPoint{tx3->GetHash(), 1});
+ if (target_feerate <= tx3_feerate) {
+ // As long as target feerate is below tx4's ancestor feerate, there is no bump fee.
+ BOOST_CHECK_EQUAL(bumpfee3, 0);
+ } else {
+ // Difference is fee to bump tx3 from current to target feerate, without tx4.
+ BOOST_CHECK_EQUAL(bumpfee3, target_feerate.GetFee(tx3_dimensions.vsize) - tx3_dimensions.mod_fee);
+ }
+
+ // If tx6’s modified fees are sufficient for tx5 and tx6 to be picked
+ // into the block, our prospective new transaction would not need to
+ // bump tx5 when using tx5’s second output. If however even tx6’s
+ // modified fee (which essentially indicates "effective feerate") is
+ // not sufficient to bump tx5, using the second output of tx5 would
+ // require our transaction to bump tx5 from scratch since we evaluate
+ // transaction packages per ancestor sets and do not consider multiple
+ // children’s fees.
+ const TxDimensions& tx5_dimensions = tx_dims.find(tx5->GetHash())->second;
+ const TxDimensions& tx6_dimensions = tx_dims.find(tx6->GetHash())->second;
+ const CFeeRate tx5_feerate = CFeeRate(tx5_dimensions.mod_fee + tx6_dimensions.mod_fee, tx5_dimensions.vsize + tx6_dimensions.vsize);
+ CAmount bumpfee5 = Find(bump_fees, COutPoint{tx5->GetHash(), 1});
+ if (target_feerate <= tx5_feerate) {
+ // As long as target feerate is below tx6's ancestor feerate, there is no bump fee.
+ BOOST_CHECK_EQUAL(bumpfee5, 0);
+ } else {
+ // Difference is fee to bump tx5 from current to target feerate, without tx6.
+ BOOST_CHECK_EQUAL(bumpfee5, target_feerate.GetFee(tx5_dimensions.vsize) - tx5_dimensions.mod_fee);
+ }
+ }
+ // Spent outpoints should usually not be requested as they would not be
+ // considered available. However, when they are explicitly requested, we
+ // can calculate their bumpfee to facilitate RBF-replacements
+ for (const auto& target_feerate : various_normal_feerates) {
+ node::MiniMiner mini_miner_all_spent(pool, all_spent_outpoints);
+ BOOST_CHECK(mini_miner_all_spent.IsReadyToCalculate());
+ auto bump_fees_all_spent = mini_miner_all_spent.CalculateBumpFees(target_feerate);
+ BOOST_CHECK(!mini_miner_all_spent.IsReadyToCalculate());
+ BOOST_CHECK_EQUAL(bump_fees_all_spent.size(), all_spent_outpoints.size());
+ node::MiniMiner mini_miner_all_parents(pool, all_parent_outputs);
+ BOOST_CHECK(mini_miner_all_parents.IsReadyToCalculate());
+ auto bump_fees_all_parents = mini_miner_all_parents.CalculateBumpFees(target_feerate);
+ BOOST_CHECK(!mini_miner_all_parents.IsReadyToCalculate());
+ BOOST_CHECK_EQUAL(bump_fees_all_parents.size(), all_parent_outputs.size());
+ for (auto& bump_fees : {bump_fees_all_parents, bump_fees_all_spent}) {
+ // For all_parents case, both outputs from the parent should have the same bump fee,
+ // even though only one of them is in a to-be-replaced transaction.
+ BOOST_CHECK(sanity_check(all_transactions, bump_fees));
+
+ // Check tx1 bumpfee: no other bumper.
+ const TxDimensions& tx1_dimensions = tx_dims.find(tx1->GetHash())->second;
+ CAmount it1_spent = Find(bump_fees, COutPoint{tx1->GetHash(), 0});
+ if (target_feerate <= tx1_dimensions.feerate) {
+ BOOST_CHECK_EQUAL(it1_spent, 0);
+ } else {
+ // Difference is fee to bump tx1 from current to target feerate.
+ BOOST_CHECK_EQUAL(it1_spent, target_feerate.GetFee(tx1_dimensions.vsize) - tx1_dimensions.mod_fee);
+ }
+
+ // Check tx3 bumpfee: no other bumper, because tx4 is to-be-replaced.
+ const TxDimensions& tx3_dimensions = tx_dims.find(tx3->GetHash())->second;
+ const CFeeRate tx3_feerate_unbumped = tx3_dimensions.feerate;
+ auto it3_spent = Find(bump_fees, COutPoint{tx3->GetHash(), 0});
+ if (target_feerate <= tx3_feerate_unbumped) {
+ BOOST_CHECK_EQUAL(it3_spent, 0);
+ } else {
+ // Difference is fee to bump tx3 from current to target feerate, without tx4.
+ BOOST_CHECK_EQUAL(it3_spent, target_feerate.GetFee(tx3_dimensions.vsize) - tx3_dimensions.mod_fee);
+ }
+
+ // Check tx5 bumpfee: no other bumper, because tx6 is to-be-replaced.
+ const TxDimensions& tx5_dimensions = tx_dims.find(tx5->GetHash())->second;
+ const CFeeRate tx5_feerate_unbumped = tx5_dimensions.feerate;
+ auto it5_spent = Find(bump_fees, COutPoint{tx5->GetHash(), 0});
+ if (target_feerate <= tx5_feerate_unbumped) {
+ BOOST_CHECK_EQUAL(it5_spent, 0);
+ } else {
+ // Difference is fee to bump tx5 from current to target feerate, without tx6.
+ BOOST_CHECK_EQUAL(it5_spent, target_feerate.GetFee(tx5_dimensions.vsize) - tx5_dimensions.mod_fee);
+ }
+ }
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(miniminer_overlap, TestChain100Setup)
+{
+ CTxMemPool& pool = *Assert(m_node.mempool);
+ LOCK2(::cs_main, pool.cs);
+ TestMemPoolEntryHelper entry;
+
+ const CAmount low_fee{CENT/2000};
+ const CAmount med_fee{CENT/200};
+ const CAmount high_fee{CENT/10};
+
+ // Create 3 parents of different feerates, and 1 child spending from all 3.
+ const auto tx1 = make_tx({COutPoint{m_coinbase_txns[0]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx1));
+ const auto tx2 = make_tx({COutPoint{m_coinbase_txns[1]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(med_fee).FromTx(tx2));
+ const auto tx3 = make_tx({COutPoint{m_coinbase_txns[2]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx3));
+ const auto tx4 = make_tx({COutPoint{tx1->GetHash(), 0}, COutPoint{tx2->GetHash(), 0}, COutPoint{tx3->GetHash(), 0}}, /*num_outputs=*/3);
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx4));
+
+ // Create 1 grandparent and 1 parent, then 2 children.
+ const auto tx5 = make_tx({COutPoint{m_coinbase_txns[3]->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx5));
+ const auto tx6 = make_tx({COutPoint{tx5->GetHash(), 0}}, /*num_outputs=*/3);
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx6));
+ const auto tx7 = make_tx({COutPoint{tx6->GetHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(med_fee).FromTx(tx7));
+ const auto tx8 = make_tx({COutPoint{tx6->GetHash(), 1}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx8));
+
+ std::vector<CTransactionRef> all_transactions{tx1, tx2, tx3, tx4, tx5, tx6, tx7, tx8};
+ std::vector<int64_t> tx_vsizes;
+ tx_vsizes.reserve(all_transactions.size());
+ for (const auto& tx : all_transactions) tx_vsizes.push_back(GetVirtualTransactionSize(*tx));
+
+ std::vector<COutPoint> all_unspent_outpoints({
+ COutPoint{tx1->GetHash(), 1},
+ COutPoint{tx2->GetHash(), 1},
+ COutPoint{tx3->GetHash(), 1},
+ COutPoint{tx4->GetHash(), 0},
+ COutPoint{tx4->GetHash(), 1},
+ COutPoint{tx4->GetHash(), 2},
+ COutPoint{tx5->GetHash(), 1},
+ COutPoint{tx6->GetHash(), 2},
+ COutPoint{tx7->GetHash(), 0},
+ COutPoint{tx8->GetHash(), 0}
+ });
+ for (const auto& outpoint : all_unspent_outpoints) BOOST_CHECK(!pool.isSpent(outpoint));
+
+ const auto tx3_feerate = CFeeRate(high_fee, tx_vsizes[2]);
+ const auto tx4_feerate = CFeeRate(high_fee, tx_vsizes[3]);
+ // tx4's feerate is lower than tx3's. same fee, different weight.
+ BOOST_CHECK(tx3_feerate > tx4_feerate);
+ const auto tx4_anc_feerate = CFeeRate(low_fee + med_fee + high_fee, tx_vsizes[0] + tx_vsizes[1] + tx_vsizes[3]);
+ const auto tx5_feerate = CFeeRate(high_fee, tx_vsizes[4]);
+ const auto tx7_anc_feerate = CFeeRate(low_fee + med_fee, tx_vsizes[5] + tx_vsizes[6]);
+ const auto tx8_anc_feerate = CFeeRate(low_fee + high_fee, tx_vsizes[5] + tx_vsizes[7]);
+ BOOST_CHECK(tx5_feerate > tx7_anc_feerate);
+ BOOST_CHECK(tx5_feerate > tx8_anc_feerate);
+
+ // Extremely high feerate: everybody's bumpfee is from their full ancestor set.
+ {
+ node::MiniMiner mini_miner(pool, all_unspent_outpoints);
+ const CFeeRate very_high_feerate(COIN);
+ BOOST_CHECK(tx4_anc_feerate < very_high_feerate);
+ BOOST_CHECK(mini_miner.IsReadyToCalculate());
+ auto bump_fees = mini_miner.CalculateBumpFees(very_high_feerate);
+ BOOST_CHECK_EQUAL(bump_fees.size(), all_unspent_outpoints.size());
+ BOOST_CHECK(!mini_miner.IsReadyToCalculate());
+ BOOST_CHECK(sanity_check(all_transactions, bump_fees));
+ const auto tx1_bumpfee = bump_fees.find(COutPoint{tx1->GetHash(), 1});
+ BOOST_CHECK(tx1_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx1_bumpfee->second, very_high_feerate.GetFee(tx_vsizes[0]) - low_fee);
+ const auto tx4_bumpfee = bump_fees.find(COutPoint{tx4->GetHash(), 0});
+ BOOST_CHECK(tx4_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx4_bumpfee->second,
+ very_high_feerate.GetFee(tx_vsizes[0] + tx_vsizes[1] + tx_vsizes[2] + tx_vsizes[3]) - (low_fee + med_fee + high_fee + high_fee));
+ const auto tx7_bumpfee = bump_fees.find(COutPoint{tx7->GetHash(), 0});
+ BOOST_CHECK(tx7_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx7_bumpfee->second,
+ very_high_feerate.GetFee(tx_vsizes[4] + tx_vsizes[5] + tx_vsizes[6]) - (high_fee + low_fee + med_fee));
+ const auto tx8_bumpfee = bump_fees.find(COutPoint{tx8->GetHash(), 0});
+ BOOST_CHECK(tx8_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx8_bumpfee->second,
+ very_high_feerate.GetFee(tx_vsizes[4] + tx_vsizes[5] + tx_vsizes[7]) - (high_fee + low_fee + high_fee));
+ // Total fees: if spending multiple outputs from tx4 don't double-count fees.
+ node::MiniMiner mini_miner_total_tx4(pool, {COutPoint{tx4->GetHash(), 0}, COutPoint{tx4->GetHash(), 1}});
+ BOOST_CHECK(mini_miner_total_tx4.IsReadyToCalculate());
+ const auto tx4_bump_fee = mini_miner_total_tx4.CalculateTotalBumpFees(very_high_feerate);
+ BOOST_CHECK(!mini_miner_total_tx4.IsReadyToCalculate());
+ BOOST_CHECK(tx4_bump_fee.has_value());
+ BOOST_CHECK_EQUAL(tx4_bump_fee.value(),
+ very_high_feerate.GetFee(tx_vsizes[0] + tx_vsizes[1] + tx_vsizes[2] + tx_vsizes[3]) - (low_fee + med_fee + high_fee + high_fee));
+ // Total fees: if spending both tx7 and tx8, don't double-count fees.
+ node::MiniMiner mini_miner_tx7_tx8(pool, {COutPoint{tx7->GetHash(), 0}, COutPoint{tx8->GetHash(), 0}});
+ BOOST_CHECK(mini_miner_tx7_tx8.IsReadyToCalculate());
+ const auto tx7_tx8_bumpfee = mini_miner_tx7_tx8.CalculateTotalBumpFees(very_high_feerate);
+ BOOST_CHECK(!mini_miner_tx7_tx8.IsReadyToCalculate());
+ BOOST_CHECK(tx7_tx8_bumpfee.has_value());
+ BOOST_CHECK_EQUAL(tx7_tx8_bumpfee.value(),
+ very_high_feerate.GetFee(tx_vsizes[4] + tx_vsizes[5] + tx_vsizes[6] + tx_vsizes[7]) - (high_fee + low_fee + med_fee + high_fee));
+ }
+ // Feerate just below tx5: tx7 and tx8 have different bump fees.
+ {
+ const auto just_below_tx5 = CFeeRate(tx5_feerate.GetFeePerK() - 5);
+ node::MiniMiner mini_miner(pool, all_unspent_outpoints);
+ BOOST_CHECK(mini_miner.IsReadyToCalculate());
+ auto bump_fees = mini_miner.CalculateBumpFees(just_below_tx5);
+ BOOST_CHECK(!mini_miner.IsReadyToCalculate());
+ BOOST_CHECK_EQUAL(bump_fees.size(), all_unspent_outpoints.size());
+ BOOST_CHECK(sanity_check(all_transactions, bump_fees));
+ const auto tx7_bumpfee = bump_fees.find(COutPoint{tx7->GetHash(), 0});
+ BOOST_CHECK(tx7_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx7_bumpfee->second, just_below_tx5.GetFee(tx_vsizes[5] + tx_vsizes[6]) - (low_fee + med_fee));
+ const auto tx8_bumpfee = bump_fees.find(COutPoint{tx8->GetHash(), 0});
+ BOOST_CHECK(tx8_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx8_bumpfee->second, just_below_tx5.GetFee(tx_vsizes[5] + tx_vsizes[7]) - (low_fee + high_fee));
+ // Total fees: if spending both tx7 and tx8, don't double-count fees.
+ node::MiniMiner mini_miner_tx7_tx8(pool, {COutPoint{tx7->GetHash(), 0}, COutPoint{tx8->GetHash(), 0}});
+ BOOST_CHECK(mini_miner_tx7_tx8.IsReadyToCalculate());
+ const auto tx7_tx8_bumpfee = mini_miner_tx7_tx8.CalculateTotalBumpFees(just_below_tx5);
+ BOOST_CHECK(!mini_miner_tx7_tx8.IsReadyToCalculate());
+ BOOST_CHECK(tx7_tx8_bumpfee.has_value());
+ BOOST_CHECK_EQUAL(tx7_tx8_bumpfee.value(), just_below_tx5.GetFee(tx_vsizes[5] + tx_vsizes[6]) - (low_fee + med_fee));
+ }
+ // Feerate between tx7 and tx8's ancestor feerates: don't need to bump tx6 because tx8 already does.
+ {
+ const auto just_above_tx7 = CFeeRate(med_fee + 10, tx_vsizes[6]);
+ BOOST_CHECK(just_above_tx7 <= CFeeRate(low_fee + high_fee, tx_vsizes[5] + tx_vsizes[7]));
+ node::MiniMiner mini_miner(pool, all_unspent_outpoints);
+ BOOST_CHECK(mini_miner.IsReadyToCalculate());
+ auto bump_fees = mini_miner.CalculateBumpFees(just_above_tx7);
+ BOOST_CHECK(!mini_miner.IsReadyToCalculate());
+ BOOST_CHECK_EQUAL(bump_fees.size(), all_unspent_outpoints.size());
+ BOOST_CHECK(sanity_check(all_transactions, bump_fees));
+ const auto tx7_bumpfee = bump_fees.find(COutPoint{tx7->GetHash(), 0});
+ BOOST_CHECK(tx7_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx7_bumpfee->second, just_above_tx7.GetFee(tx_vsizes[6]) - (med_fee));
+ const auto tx8_bumpfee = bump_fees.find(COutPoint{tx8->GetHash(), 0});
+ BOOST_CHECK(tx8_bumpfee != bump_fees.end());
+ BOOST_CHECK_EQUAL(tx8_bumpfee->second, 0);
+ }
+}
+BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
+{
+ CTxMemPool& pool = *Assert(m_node.mempool);
+ LOCK2(cs_main, pool.cs);
+
+ // Add chain of size 500
+ TestMemPoolEntryHelper entry;
+ std::vector<uint256> chain_txids;
+ auto& lasttx = m_coinbase_txns[0];
+ for (auto i{0}; i < 500; ++i) {
+ const auto tx = make_tx({COutPoint{lasttx->GetHash(), 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(CENT).FromTx(tx));
+ chain_txids.push_back(tx->GetHash());
+ lasttx = tx;
+ }
+ const auto cluster_500tx = pool.GatherClusters({lasttx->GetHash()});
+ CTxMemPool::setEntries cluster_500tx_set{cluster_500tx.begin(), cluster_500tx.end()};
+ BOOST_CHECK_EQUAL(cluster_500tx.size(), cluster_500tx_set.size());
+ const auto vec_iters_500 = pool.GetIterVec(chain_txids);
+ for (const auto& iter : vec_iters_500) BOOST_CHECK(cluster_500tx_set.count(iter));
+
+ // GatherClusters stops at 500 transactions.
+ const auto tx_501 = make_tx({COutPoint{lasttx->GetHash(), 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(CENT).FromTx(tx_501));
+ const auto cluster_501 = pool.GatherClusters({tx_501->GetHash()});
+ BOOST_CHECK_EQUAL(cluster_501.size(), 0);
+
+ // Zig Zag cluster:
+ // txp0 txp1 txp2 ... txp48 txp49
+ // \ / \ / \ \ /
+ // txc0 txc1 txc2 ... txc48
+ // Note that each transaction's ancestor size is 1 or 3, and each descendant size is 1, 2 or 3.
+ // However, all of these transactions are in the same cluster.
+ std::vector<uint256> zigzag_txids;
+ for (auto p{0}; p < 50; ++p) {
+ const auto txp = make_tx({COutPoint{GetRandHash(), 0}}, /*num_outputs=*/2);
+ pool.addUnchecked(entry.Fee(CENT).FromTx(txp));
+ zigzag_txids.push_back(txp->GetHash());
+ }
+ for (auto c{0}; c < 49; ++c) {
+ const auto txc = make_tx({COutPoint{zigzag_txids[c], 1}, COutPoint{zigzag_txids[c+1], 0}}, /*num_outputs=*/1);
+ pool.addUnchecked(entry.Fee(CENT).FromTx(txc));
+ zigzag_txids.push_back(txc->GetHash());
+ }
+ const auto vec_iters_zigzag = pool.GetIterVec(zigzag_txids);
+ // It doesn't matter which tx we calculate cluster for, everybody is in it.
+ const std::vector<size_t> indeces{0, 22, 72, zigzag_txids.size() - 1};
+ for (const auto index : indeces) {
+ const auto cluster = pool.GatherClusters({zigzag_txids[index]});
+ BOOST_CHECK_EQUAL(cluster.size(), zigzag_txids.size());
+ CTxMemPool::setEntries clusterset{cluster.begin(), cluster.end()};
+ BOOST_CHECK_EQUAL(cluster.size(), clusterset.size());
+ for (const auto& iter : vec_iters_zigzag) BOOST_CHECK(clusterset.count(iter));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index 655d6d7828..42e441c41a 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -241,8 +241,6 @@ const KeyConverter CONVERTER{};
using Fragment = miniscript::Fragment;
using NodeRef = miniscript::NodeRef<CPubKey>;
-// https://github.com/llvm/llvm-project/issues/53444
-// NOLINTNEXTLINE(misc-unused-using-decls)
using miniscript::operator"" _mst;
using Node = miniscript::Node<CPubKey>;
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 4fbd9b3a6e..aa577f7b27 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <clientversion.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <cstdint>
#include <net.h>
@@ -19,7 +20,6 @@
#include <timedata.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <validation.h>
#include <version.h>
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
CNetAddr addr;
// IPv4, INADDR_ANY
- BOOST_REQUIRE(LookupHost("0.0.0.0", addr, false));
+ addr = LookupHost("0.0.0.0", false).value();
BOOST_REQUIRE(!addr.IsValid());
BOOST_REQUIRE(addr.IsIPv4());
@@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "0.0.0.0");
// IPv4, INADDR_NONE
- BOOST_REQUIRE(LookupHost("255.255.255.255", addr, false));
+ addr = LookupHost("255.255.255.255", false).value();
BOOST_REQUIRE(!addr.IsValid());
BOOST_REQUIRE(addr.IsIPv4());
@@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "255.255.255.255");
// IPv4, casual
- BOOST_REQUIRE(LookupHost("12.34.56.78", addr, false));
+ addr = LookupHost("12.34.56.78", false).value();
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv4());
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "12.34.56.78");
// IPv6, in6addr_any
- BOOST_REQUIRE(LookupHost("::", addr, false));
+ addr = LookupHost("::", false).value();
BOOST_REQUIRE(!addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
@@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK_EQUAL(addr.ToStringAddr(), "::");
// IPv6, casual
- BOOST_REQUIRE(LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", addr, false));
+ addr = LookupHost("1122:3344:5566:7788:9900:aabb:ccdd:eeff", false).value();
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
@@ -186,14 +186,14 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
// id of "32", return the address as "fe80::1%32".
const std::string link_local{"fe80::1"};
const std::string scoped_addr{link_local + "%32"};
- BOOST_REQUIRE(LookupHost(scoped_addr, addr, false));
+ addr = LookupHost(scoped_addr, false).value();
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK_EQUAL(addr.ToStringAddr(), scoped_addr);
// Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope.
- BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false));
+ addr = LookupHost(link_local + "%0", false).value();
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsIPv6());
BOOST_CHECK(!addr.IsBindAny());
@@ -318,10 +318,9 @@ BOOST_AUTO_TEST_CASE(cnetaddr_tostring_canonical_ipv6)
{"2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa", "2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"},
};
for (const auto& [input_address, expected_canonical_representation_output] : canonical_representations_ipv6) {
- CNetAddr net_addr;
- BOOST_REQUIRE(LookupHost(input_address, net_addr, false));
- BOOST_REQUIRE(net_addr.IsIPv6());
- BOOST_CHECK_EQUAL(net_addr.ToStringAddr(), expected_canonical_representation_output);
+ const std::optional<CNetAddr> net_addr{LookupHost(input_address, false)};
+ BOOST_REQUIRE(net_addr.value().IsIPv6());
+ BOOST_CHECK_EQUAL(net_addr.value().ToStringAddr(), expected_canonical_representation_output);
}
}
@@ -334,12 +333,12 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000000000000000");
s.clear();
- BOOST_REQUIRE(LookupHost("1.2.3.4", addr, false));
+ addr = LookupHost("1.2.3.4", false).value();
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "00000000000000000000ffff01020304");
s.clear();
- BOOST_REQUIRE(LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", addr, false));
+ addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
s.clear();
@@ -370,12 +369,12 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
BOOST_CHECK_EQUAL(HexStr(s), "021000000000000000000000000000000000");
s.clear();
- BOOST_REQUIRE(LookupHost("1.2.3.4", addr, false));
+ addr = LookupHost("1.2.3.4", false).value();
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "010401020304");
s.clear();
- BOOST_REQUIRE(LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", addr, false));
+ addr = LookupHost("1a1b:2a2b:3a3b:4a4b:5a5b:6a6b:7a7b:8a8b", false).value();
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
s.clear();
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 7e91819ddc..05953bfd10 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -24,9 +24,7 @@ BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup)
static CNetAddr ResolveIP(const std::string& ip)
{
- CNetAddr addr;
- LookupHost(ip, addr, false);
- return addr;
+ return LookupHost(ip, false).value_or(CNetAddr{});
}
static CSubNet ResolveSubNet(const std::string& subnet)
@@ -477,11 +475,10 @@ BOOST_AUTO_TEST_CASE(netpermissions_test)
BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
{
- CNetAddr addr;
- BOOST_CHECK(LookupHost("127.0.0.1"s, addr, false));
- BOOST_CHECK(!LookupHost("127.0.0.1\0"s, addr, false));
- BOOST_CHECK(!LookupHost("127.0.0.1\0example.com"s, addr, false));
- BOOST_CHECK(!LookupHost("127.0.0.1\0example.com\0"s, addr, false));
+ BOOST_CHECK(LookupHost("127.0.0.1"s, false).has_value());
+ BOOST_CHECK(!LookupHost("127.0.0.1\0"s, false).has_value());
+ BOOST_CHECK(!LookupHost("127.0.0.1\0example.com"s, false).has_value());
+ BOOST_CHECK(!LookupHost("127.0.0.1\0example.com\0"s, false).has_value());
CSubNet ret;
BOOST_CHECK(LookupSubNet("1.2.3.0/24"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret));
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 75ba9972f6..bc9c672560 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -24,6 +24,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
CAmount basefee(2000);
CAmount deltaFee(100);
std::vector<CAmount> feeV;
+ feeV.reserve(10);
// Populate vectors of increasing fees
for (int j = 0; j < 10; j++) {
diff --git a/src/test/pool_tests.cpp b/src/test/pool_tests.cpp
new file mode 100644
index 0000000000..8a07e09a44
--- /dev/null
+++ b/src/test/pool_tests.cpp
@@ -0,0 +1,190 @@
+// Copyright (c) 2022 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 <memusage.h>
+#include <support/allocators/pool.h>
+#include <test/util/poolresourcetester.h>
+#include <test/util/random.h>
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+#include <cstddef>
+#include <cstdint>
+#include <unordered_map>
+#include <vector>
+
+BOOST_FIXTURE_TEST_SUITE(pool_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(basic_allocating)
+{
+ auto resource = PoolResource<8, 8>();
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+
+ // first chunk is already allocated
+ size_t expected_bytes_available = resource.ChunkSizeBytes();
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ // chunk is used, no more allocation
+ void* block = resource.Allocate(8, 8);
+ expected_bytes_available -= 8;
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ BOOST_TEST(0 == PoolResourceTester::FreeListSizes(resource)[1]);
+ resource.Deallocate(block, 8, 8);
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+
+ // alignment is too small, but the best fitting freelist is used. Nothing is allocated.
+ void* b = resource.Allocate(8, 1);
+ BOOST_TEST(b == block); // we got the same block of memory as before
+ BOOST_TEST(0 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ resource.Deallocate(block, 8, 1);
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ // can't use resource because alignment is too big, allocate system memory
+ b = resource.Allocate(8, 16);
+ BOOST_TEST(b != block);
+ block = b;
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ resource.Deallocate(block, 8, 16);
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ // can't use chunk because size is too big
+ block = resource.Allocate(16, 8);
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ resource.Deallocate(block, 16, 8);
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ // it's possible that 0 bytes are allocated, make sure this works. In that case the call is forwarded to operator new
+ // 0 bytes takes one entry from the first freelist
+ void* p = resource.Allocate(0, 1);
+ BOOST_TEST(0 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+
+ resource.Deallocate(p, 0, 1);
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+ BOOST_TEST(1 == PoolResourceTester::FreeListSizes(resource)[1]);
+ BOOST_TEST(expected_bytes_available == PoolResourceTester::AvailableMemoryFromChunk(resource));
+}
+
+// Allocates from 0 to n bytes were n > the PoolResource's data, and each should work
+BOOST_AUTO_TEST_CASE(allocate_any_byte)
+{
+ auto resource = PoolResource<128, 8>(1024);
+
+ uint8_t num_allocs = 200;
+
+ auto data = std::vector<Span<uint8_t>>();
+
+ // allocate an increasing number of bytes
+ for (uint8_t num_bytes = 0; num_bytes < num_allocs; ++num_bytes) {
+ uint8_t* bytes = new (resource.Allocate(num_bytes, 1)) uint8_t[num_bytes];
+ BOOST_TEST(bytes != nullptr);
+ data.emplace_back(bytes, num_bytes);
+
+ // set each byte to num_bytes
+ std::fill(bytes, bytes + num_bytes, num_bytes);
+ }
+
+ // now that we got all allocated, test if all still have the correct values, and give everything back to the allocator
+ uint8_t val = 0;
+ for (auto const& span : data) {
+ for (auto x : span) {
+ BOOST_TEST(val == x);
+ }
+ std::destroy(span.data(), span.data() + span.size());
+ resource.Deallocate(span.data(), span.size(), 1);
+ ++val;
+ }
+
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+}
+
+BOOST_AUTO_TEST_CASE(random_allocations)
+{
+ struct PtrSizeAlignment {
+ void* ptr;
+ size_t bytes;
+ size_t alignment;
+ };
+
+ // makes a bunch of random allocations and gives all of them back in random order.
+ auto resource = PoolResource<128, 8>(65536);
+ std::vector<PtrSizeAlignment> ptr_size_alignment{};
+ for (size_t i = 0; i < 1000; ++i) {
+ // make it a bit more likely to allocate than deallocate
+ if (ptr_size_alignment.empty() || 0 != InsecureRandRange(4)) {
+ // allocate a random item
+ std::size_t alignment = std::size_t{1} << InsecureRandRange(8); // 1, 2, ..., 128
+ std::size_t size = (InsecureRandRange(200) / alignment + 1) * alignment; // multiple of alignment
+ void* ptr = resource.Allocate(size, alignment);
+ BOOST_TEST(ptr != nullptr);
+ BOOST_TEST((reinterpret_cast<uintptr_t>(ptr) & (alignment - 1)) == 0);
+ ptr_size_alignment.push_back({ptr, size, alignment});
+ } else {
+ // deallocate a random item
+ auto& x = ptr_size_alignment[InsecureRandRange(ptr_size_alignment.size())];
+ resource.Deallocate(x.ptr, x.bytes, x.alignment);
+ x = ptr_size_alignment.back();
+ ptr_size_alignment.pop_back();
+ }
+ }
+
+ // deallocate all the rest
+ for (auto const& x : ptr_size_alignment) {
+ resource.Deallocate(x.ptr, x.bytes, x.alignment);
+ }
+
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+}
+
+BOOST_AUTO_TEST_CASE(memusage_test)
+{
+ auto std_map = std::unordered_map<int, int>{};
+
+ using Map = std::unordered_map<int,
+ int,
+ std::hash<int>,
+ std::equal_to<int>,
+ PoolAllocator<std::pair<const int, int>,
+ sizeof(std::pair<const int, int>) + sizeof(void*) * 4,
+ alignof(void*)>>;
+ auto resource = Map::allocator_type::ResourceType(1024);
+
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+
+ {
+ auto resource_map = Map{0, std::hash<int>{}, std::equal_to<int>{}, &resource};
+
+ // can't have the same resource usage
+ BOOST_TEST(memusage::DynamicUsage(std_map) != memusage::DynamicUsage(resource_map));
+
+ for (size_t i = 0; i < 10000; ++i) {
+ std_map[i];
+ resource_map[i];
+ }
+
+ // Eventually the resource_map should have a much lower memory usage because it has less malloc overhead
+ BOOST_TEST(memusage::DynamicUsage(resource_map) <= memusage::DynamicUsage(std_map) * 90 / 100);
+ }
+
+ PoolResourceTester::CheckAllDataAccountedFor(resource);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index addc925bab..5bd14f22c6 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -7,6 +7,7 @@
#include <pow.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#include <boost/test/unit_test.hpp>
@@ -15,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup)
/* Test calculation of next difficulty target with no constraints applying */
BOOST_AUTO_TEST_CASE(get_next_work)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
int64_t nLastRetargetTime = 1261130161; // Block #30240
CBlockIndex pindexLast;
pindexLast.nHeight = 32255;
@@ -34,7 +35,7 @@ BOOST_AUTO_TEST_CASE(get_next_work)
/* Test the constraint on the upper bound for next work */
BOOST_AUTO_TEST_CASE(get_next_work_pow_limit)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
int64_t nLastRetargetTime = 1231006505; // Block #0
CBlockIndex pindexLast;
pindexLast.nHeight = 2015;
@@ -48,7 +49,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit)
/* Test the constraint on the lower bound for actual time taken */
BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
int64_t nLastRetargetTime = 1279008237; // Block #66528
CBlockIndex pindexLast;
pindexLast.nHeight = 68543;
@@ -65,7 +66,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual)
/* Test the constraint on the upper bound for actual time taken */
BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time
CBlockIndex pindexLast;
pindexLast.nHeight = 46367;
@@ -81,7 +82,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_negative_target)
{
- const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus();
+ const auto consensus = CreateChainParams(*m_node.args, ChainType::MAIN)->GetConsensus();
uint256 hash;
unsigned int nBits;
nBits = UintToArith256(consensus.powLimit).GetCompact(true);
@@ -91,7 +92,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_negative_target)
BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_overflow_target)
{
- const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus();
+ const auto consensus = CreateChainParams(*m_node.args, ChainType::MAIN)->GetConsensus();
uint256 hash;
unsigned int nBits{~0x00800000U};
hash.SetHex("0x1");
@@ -100,7 +101,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_overflow_target)
BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_too_easy_target)
{
- const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus();
+ const auto consensus = CreateChainParams(*m_node.args, ChainType::MAIN)->GetConsensus();
uint256 hash;
unsigned int nBits;
arith_uint256 nBits_arith = UintToArith256(consensus.powLimit);
@@ -112,7 +113,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_too_easy_target)
BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_biger_hash_than_target)
{
- const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus();
+ const auto consensus = CreateChainParams(*m_node.args, ChainType::MAIN)->GetConsensus();
uint256 hash;
unsigned int nBits;
arith_uint256 hash_arith = UintToArith256(consensus.powLimit);
@@ -124,7 +125,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_biger_hash_than_target)
BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_zero_target)
{
- const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus();
+ const auto consensus = CreateChainParams(*m_node.args, ChainType::MAIN)->GetConsensus();
uint256 hash;
unsigned int nBits;
arith_uint256 hash_arith{0};
@@ -135,7 +136,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_zero_target)
BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
std::vector<CBlockIndex> blocks(10000);
for (int i = 0; i < 10000; i++) {
blocks[i].pprev = i ? &blocks[i - 1] : nullptr;
@@ -155,9 +156,9 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
}
}
-void sanity_check_chainparams(const ArgsManager& args, std::string chainName)
+void sanity_check_chainparams(const ArgsManager& args, ChainType chain_type)
{
- const auto chainParams = CreateChainParams(args, chainName);
+ const auto chainParams = CreateChainParams(args, chain_type);
const auto consensus = chainParams->GetConsensus();
// hash genesis is correct
@@ -184,22 +185,22 @@ void sanity_check_chainparams(const ArgsManager& args, std::string chainName)
BOOST_AUTO_TEST_CASE(ChainParams_MAIN_sanity)
{
- sanity_check_chainparams(*m_node.args, CBaseChainParams::MAIN);
+ sanity_check_chainparams(*m_node.args, ChainType::MAIN);
}
BOOST_AUTO_TEST_CASE(ChainParams_REGTEST_sanity)
{
- sanity_check_chainparams(*m_node.args, CBaseChainParams::REGTEST);
+ sanity_check_chainparams(*m_node.args, ChainType::REGTEST);
}
BOOST_AUTO_TEST_CASE(ChainParams_TESTNET_sanity)
{
- sanity_check_chainparams(*m_node.args, CBaseChainParams::TESTNET);
+ sanity_check_chainparams(*m_node.args, ChainType::TESTNET);
}
BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity)
{
- sanity_check_chainparams(*m_node.args, CBaseChainParams::SIGNET);
+ sanity_check_chainparams(*m_node.args, ChainType::SIGNET);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index e5cf767614..414e4509f5 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -5,6 +5,7 @@
#include <random.h>
#include <test/util/setup_common.h>
+#include <util/time.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp
index 0ec253747b..10205cd641 100644
--- a/src/test/rbf_tests.cpp
+++ b/src/test/rbf_tests.cpp
@@ -1,11 +1,11 @@
// Copyright (c) 2021-2022 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 <common/system.h>
#include <policy/rbf.h>
#include <random.h>
#include <test/util/txmempool.h>
#include <txmempool.h>
-#include <util/system.h>
#include <util/time.h>
#include <test/util/setup_common.h>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 791c9ddf31..2f783a4b95 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -42,11 +42,11 @@ private:
class RPCTestingSetup : public TestingSetup
{
public:
- UniValue TransformParams(const UniValue& params, std::vector<std::string> arg_names) const;
+ UniValue TransformParams(const UniValue& params, std::vector<std::pair<std::string, bool>> arg_names) const;
UniValue CallRPC(std::string args);
};
-UniValue RPCTestingSetup::TransformParams(const UniValue& params, std::vector<std::string> arg_names) const
+UniValue RPCTestingSetup::TransformParams(const UniValue& params, std::vector<std::pair<std::string, bool>> arg_names) const
{
UniValue transformed_params;
CRPCTable table;
@@ -75,7 +75,7 @@ UniValue RPCTestingSetup::CallRPC(std::string args)
return result;
}
catch (const UniValue& objError) {
- throw std::runtime_error(find_value(objError, "message").get_str());
+ throw std::runtime_error(objError.find_value("message").get_str());
}
}
@@ -84,7 +84,7 @@ BOOST_FIXTURE_TEST_SUITE(rpc_tests, RPCTestingSetup)
BOOST_AUTO_TEST_CASE(rpc_namedparams)
{
- const std::vector<std::string> arg_names{"arg1", "arg2", "arg3", "arg4", "arg5"};
+ const std::vector<std::pair<std::string, bool>> arg_names{{"arg1", false}, {"arg2", false}, {"arg3", false}, {"arg4", false}, {"arg5", false}};
// Make sure named arguments are transformed into positional arguments in correct places separated by nulls
BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg4": 4})"), arg_names).write(), "[null,2,null,4]");
@@ -109,6 +109,28 @@ BOOST_AUTO_TEST_CASE(rpc_namedparams)
BOOST_CHECK_EQUAL(TransformParams(JSON(R"([1,2,3,4,5,6,7,8,9,10])"), arg_names).write(), "[1,2,3,4,5,6,7,8,9,10]");
}
+BOOST_AUTO_TEST_CASE(rpc_namedonlyparams)
+{
+ const std::vector<std::pair<std::string, bool>> arg_names{{"arg1", false}, {"arg2", false}, {"opt1", true}, {"opt2", true}, {"options", false}};
+
+ // Make sure optional parameters are really optional.
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg1": 1, "arg2": 2})"), arg_names).write(), "[1,2]");
+
+ // Make sure named-only parameters are passed as options.
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg1": 1, "arg2": 2, "opt1": 10, "opt2": 20})"), arg_names).write(), R"([1,2,{"opt1":10,"opt2":20}])");
+
+ // Make sure options can be passed directly.
+ BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg1": 1, "arg2": 2, "options":{"opt1": 10, "opt2": 20}})"), arg_names).write(), R"([1,2,{"opt1":10,"opt2":20}])");
+
+ // Make sure options and named parameters conflict.
+ BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg1": 1, "arg2": 2, "opt1": 10, "options":{"opt1": 10}})"), arg_names), UniValue,
+ HasJSON(R"({"code":-8,"message":"Parameter options conflicts with parameter opt1"})"));
+
+ // Make sure options object specified through args array conflicts.
+ BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"args": [1, 2, {"opt1": 10}], "opt2": 20})"), arg_names), UniValue,
+ HasJSON(R"({"code":-8,"message":"Parameter options specified twice both as positional and named argument"})"));
+}
+
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
// Test raw transaction API argument handling
@@ -130,9 +152,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error);
std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx));
- BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").getInt<int>(), 193);
- BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").getInt<int>(), 1);
- BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").getInt<int>(), 0);
+ BOOST_CHECK_EQUAL(r.get_obj().find_value("size").getInt<int>(), 193);
+ BOOST_CHECK_EQUAL(r.get_obj().find_value("version").getInt<int>(), 1);
+ BOOST_CHECK_EQUAL(r.get_obj().find_value("locktime").getInt<int>(), 0);
BOOST_CHECK_THROW(CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error);
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false"));
BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" false extra"), std::runtime_error);
@@ -149,20 +171,20 @@ BOOST_AUTO_TEST_CASE(rpc_togglenetwork)
UniValue r;
r = CallRPC("getnetworkinfo");
- bool netState = find_value(r.get_obj(), "networkactive").get_bool();
+ bool netState = r.get_obj().find_value("networkactive").get_bool();
BOOST_CHECK_EQUAL(netState, true);
BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive false"));
r = CallRPC("getnetworkinfo");
- int numConnection = find_value(r.get_obj(), "connections").getInt<int>();
+ int numConnection = r.get_obj().find_value("connections").getInt<int>();
BOOST_CHECK_EQUAL(numConnection, 0);
- netState = find_value(r.get_obj(), "networkactive").get_bool();
+ netState = r.get_obj().find_value("networkactive").get_bool();
BOOST_CHECK_EQUAL(netState, false);
BOOST_CHECK_NO_THROW(CallRPC("setnetworkactive true"));
r = CallRPC("getnetworkinfo");
- netState = find_value(r.get_obj(), "networkactive").get_bool();
+ netState = r.get_obj().find_value("networkactive").get_bool();
BOOST_CHECK_EQUAL(netState, true);
}
@@ -180,9 +202,9 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
std::string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
std::string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" [] "+prevout);
- BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
+ BOOST_CHECK(r.get_obj().find_value("complete").get_bool() == false);
r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" ["+privkey1+","+privkey2+"] "+prevout);
- BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
+ BOOST_CHECK(r.get_obj().find_value("complete").get_bool() == true);
}
BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
@@ -278,6 +300,7 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); //should pass, cut trailing 0
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); //should fail
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); //should pass, leading 0 is present
+ BOOST_CHECK_EXCEPTION(AmountFromValue(".19e-6"), UniValue, HasJSON(R"({"code":-3,"message":"Invalid amount"})")); //should fail, no leading 0
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); //overflow error
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); //overflow error
@@ -285,36 +308,6 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); //overflow error
}
-BOOST_AUTO_TEST_CASE(json_parse_errors)
-{
- // Valid
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("true").get_bool(), true);
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("[false]")[0].get_bool(), false);
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"a\": true}")["a"].get_bool(), true);
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"1\": \"true\"}")["1"].get_str(), "true");
- // Valid, with leading or trailing whitespace
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
- BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
-
- BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON
- BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1);
- // Invalid, initial garbage
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);
- // Invalid, trailing garbage
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
- // Invalid, keys have to be names
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("{1: \"true\"}"), std::runtime_error);
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("{true: 1}"), std::runtime_error);
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("{[1]: 1}"), std::runtime_error);
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("{{\"a\": \"a\"}: 1}"), std::runtime_error);
- // BTC addresses should fail parsing
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
- BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
-}
-
BOOST_AUTO_TEST_CASE(rpc_ban)
{
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
@@ -325,7 +318,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
UniValue ar = r.get_array();
UniValue o1 = ar[0].get_obj();
- UniValue adr = find_value(o1, "address");
+ UniValue adr = o1.find_value("address");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32");
BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0 remove")));
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
@@ -336,8 +329,8 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
- adr = find_value(o1, "address");
- int64_t banned_until{find_value(o1, "banned_until").getInt<int64_t>()};
+ adr = o1.find_value("address");
+ int64_t banned_until{o1.find_value("banned_until").getInt<int64_t>()};
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
BOOST_CHECK_EQUAL(banned_until, 9907731200); // absolute time check
@@ -351,11 +344,11 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
- adr = find_value(o1, "address");
- banned_until = find_value(o1, "banned_until").getInt<int64_t>();
- const int64_t ban_created{find_value(o1, "ban_created").getInt<int64_t>()};
- const int64_t ban_duration{find_value(o1, "ban_duration").getInt<int64_t>()};
- const int64_t time_remaining{find_value(o1, "time_remaining").getInt<int64_t>()};
+ adr = o1.find_value("address");
+ banned_until = o1.find_value("banned_until").getInt<int64_t>();
+ const int64_t ban_created{o1.find_value("ban_created").getInt<int64_t>()};
+ const int64_t ban_duration{o1.find_value("ban_duration").getInt<int64_t>()};
+ const int64_t time_remaining{o1.find_value("time_remaining").getInt<int64_t>()};
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
BOOST_CHECK_EQUAL(banned_until, time_remaining_expected + now.count());
BOOST_CHECK_EQUAL(ban_duration, banned_until - ban_created);
@@ -385,7 +378,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
- adr = find_value(o1, "address");
+ adr = o1.find_value("address");
BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128");
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
@@ -393,7 +386,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
- adr = find_value(o1, "address");
+ adr = o1.find_value("address");
BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30");
BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned")));
@@ -401,7 +394,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned")));
ar = r.get_array();
o1 = ar[0].get_obj();
- adr = find_value(o1, "address");
+ adr = o1.find_value("address");
BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128");
}
@@ -506,6 +499,53 @@ BOOST_AUTO_TEST_CASE(rpc_getblockstats_calculate_percentiles_by_weight)
}
}
+// Make sure errors are triggered appropriately if parameters have the same names.
+BOOST_AUTO_TEST_CASE(check_dup_param_names)
+{
+ enum ParamType { POSITIONAL, NAMED, NAMED_ONLY };
+ auto make_rpc = [](std::vector<std::tuple<std::string, ParamType>> param_names) {
+ std::vector<RPCArg> params;
+ std::vector<RPCArg> options;
+ auto push_options = [&] { if (!options.empty()) params.emplace_back(RPCArg{strprintf("options%i", params.size()), RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", std::move(options)}); };
+ for (auto& [param_name, param_type] : param_names) {
+ if (param_type == POSITIONAL) {
+ push_options();
+ params.emplace_back(std::move(param_name), RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "description");
+ } else {
+ options.emplace_back(std::move(param_name), RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "description", RPCArgOptions{.also_positional = param_type == NAMED});
+ }
+ }
+ push_options();
+ return RPCHelpMan{"method_name", "description", params, RPCResults{}, RPCExamples{""}};
+ };
+
+ // No errors if parameter names are unique.
+ make_rpc({{"p1", POSITIONAL}, {"p2", POSITIONAL}});
+ make_rpc({{"p1", POSITIONAL}, {"p2", NAMED}});
+ make_rpc({{"p1", POSITIONAL}, {"p2", NAMED_ONLY}});
+ make_rpc({{"p1", NAMED}, {"p2", POSITIONAL}});
+ make_rpc({{"p1", NAMED}, {"p2", NAMED}});
+ make_rpc({{"p1", NAMED}, {"p2", NAMED_ONLY}});
+ make_rpc({{"p1", NAMED_ONLY}, {"p2", POSITIONAL}});
+ make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED}});
+ make_rpc({{"p1", NAMED_ONLY}, {"p2", NAMED_ONLY}});
+
+ // Error if parameters names are duplicates, unless one parameter is
+ // positional and the other is named and .also_positional is true.
+ BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", POSITIONAL}}), NonFatalCheckError);
+ make_rpc({{"p1", POSITIONAL}, {"p1", NAMED}});
+ BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
+ make_rpc({{"p1", NAMED}, {"p1", POSITIONAL}});
+ BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED}}), NonFatalCheckError);
+ BOOST_CHECK_THROW(make_rpc({{"p1", NAMED}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
+ BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", POSITIONAL}}), NonFatalCheckError);
+ BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED}}), NonFatalCheckError);
+ BOOST_CHECK_THROW(make_rpc({{"p1", NAMED_ONLY}, {"p1", NAMED_ONLY}}), NonFatalCheckError);
+
+ // Make sure duplicate aliases are detected too.
+ BOOST_CHECK_THROW(make_rpc({{"p1", POSITIONAL}, {"p2|p1", NAMED_ONLY}}), NonFatalCheckError);
+}
+
BOOST_AUTO_TEST_CASE(help_example)
{
// test different argument types
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 1301a1b219..3fb3378598 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -71,6 +71,7 @@ BOOST_AUTO_TEST_CASE(manythreads)
// As soon as these are created they will start running and servicing the queue
std::vector<std::thread> microThreads;
+ microThreads.reserve(10);
for (int i = 0; i < 5; i++)
microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks));
@@ -136,6 +137,7 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
// the extra threads should effectively be doing nothing
// if they don't we'll get out of order behaviour
std::vector<std::thread> threads;
+ threads.reserve(5);
for (int i = 0; i < 5; ++i) {
threads.emplace_back([&] { scheduler.serviceQueue(); });
}
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index c9f002b324..739ab75de3 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -156,6 +156,7 @@ BOOST_AUTO_TEST_CASE(set)
FillableSigningProvider keystore;
CKey key[4];
std::vector<CPubKey> keys;
+ keys.reserve(4);
for (int i = 0; i < 4; i++)
{
key[i].MakeNewKey(true);
@@ -270,12 +271,13 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CCoinsViewCache coins(&coinsDummy);
FillableSigningProvider keystore;
CKey key[6];
- std::vector<CPubKey> keys;
for (int i = 0; i < 6; i++)
{
key[i].MakeNewKey(true);
BOOST_CHECK(keystore.AddKey(key[i]));
}
+ std::vector<CPubKey> keys;
+ keys.reserve(3);
for (int i = 0; i < 3; i++)
keys.push_back(key[i].GetPubKey());
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 45d9f2cf29..c89f2c1f5b 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -5,8 +5,8 @@
#include <test/data/script_tests.json.h>
#include <test/data/bip341_wallet_vectors.json.h>
+#include <common/system.h>
#include <core_io.h>
-#include <fs.h>
#include <key.h>
#include <rpc/util.h>
#include <script/script.h>
@@ -19,8 +19,8 @@
#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <test/util/transaction_utils.h>
+#include <util/fs.h>
#include <util/strencodings.h>
-#include <util/system.h>
#if defined(HAVE_CONSENSUS_LIB)
#include <script/bitcoinconsensus.h>
diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp
index ad12c46561..eb11df0497 100644
--- a/src/test/settings_tests.cpp
+++ b/src/test/settings_tests.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/settings.h>
+#include <common/settings.h>
-#include <fs.h>
#include <test/util/setup_common.h>
#include <test/util/str.h>
-
#include <boost/test/unit_test.hpp>
+#include <common/args.h>
#include <univalue.h>
+#include <util/chaintype.h>
+#include <util/fs.h>
#include <util/strencodings.h>
#include <util/string.h>
-#include <util/system.h>
#include <fstream>
#include <map>
@@ -21,21 +21,21 @@
#include <system_error>
#include <vector>
-inline bool operator==(const util::SettingsValue& a, const util::SettingsValue& b)
+inline bool operator==(const common::SettingsValue& a, const common::SettingsValue& b)
{
return a.write() == b.write();
}
-inline std::ostream& operator<<(std::ostream& os, const util::SettingsValue& value)
+inline std::ostream& operator<<(std::ostream& os, const common::SettingsValue& value)
{
os << value.write();
return os;
}
-inline std::ostream& operator<<(std::ostream& os, const std::pair<std::string, util::SettingsValue>& kv)
+inline std::ostream& operator<<(std::ostream& os, const std::pair<std::string, common::SettingsValue>& kv)
{
- util::SettingsValue out(util::SettingsValue::VOBJ);
- out.__pushKV(kv.first, kv.second);
+ common::SettingsValue out(common::SettingsValue::VOBJ);
+ out.pushKVEnd(kv.first, kv.second);
os << out.write();
return os;
}
@@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
"null": null
})");
- std::map<std::string, util::SettingsValue> expected{
+ std::map<std::string, common::SettingsValue> expected{
{"string", "string"},
{"num", 5},
{"bool", true},
@@ -68,15 +68,15 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
};
// Check file read.
- std::map<std::string, util::SettingsValue> values;
+ std::map<std::string, common::SettingsValue> values;
std::vector<std::string> errors;
- BOOST_CHECK(util::ReadSettings(path, values, errors));
+ BOOST_CHECK(common::ReadSettings(path, values, errors));
BOOST_CHECK_EQUAL_COLLECTIONS(values.begin(), values.end(), expected.begin(), expected.end());
BOOST_CHECK(errors.empty());
// Check no errors if file doesn't exist.
fs::remove(path);
- BOOST_CHECK(util::ReadSettings(path, values, errors));
+ BOOST_CHECK(common::ReadSettings(path, values, errors));
BOOST_CHECK(values.empty());
BOOST_CHECK(errors.empty());
@@ -85,29 +85,29 @@ BOOST_AUTO_TEST_CASE(ReadWrite)
"dupe": "string",
"dupe": "dupe"
})");
- BOOST_CHECK(!util::ReadSettings(path, values, errors));
+ BOOST_CHECK(!common::ReadSettings(path, values, errors));
std::vector<std::string> dup_keys = {strprintf("Found duplicate key dupe in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), dup_keys.begin(), dup_keys.end());
BOOST_CHECK(values.empty());
// Check non-kv json files not allowed
WriteText(path, R"("non-kv")");
- BOOST_CHECK(!util::ReadSettings(path, values, errors));
+ BOOST_CHECK(!common::ReadSettings(path, values, errors));
std::vector<std::string> non_kv = {strprintf("Found non-object value \"non-kv\" in settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), non_kv.begin(), non_kv.end());
// Check invalid json not allowed
WriteText(path, R"(invalid json)");
- BOOST_CHECK(!util::ReadSettings(path, values, errors));
+ BOOST_CHECK(!common::ReadSettings(path, values, errors));
std::vector<std::string> fail_parse = {strprintf("Unable to parse settings file %s", fs::PathToString(path))};
BOOST_CHECK_EQUAL_COLLECTIONS(errors.begin(), errors.end(), fail_parse.begin(), fail_parse.end());
}
//! Check settings struct contents against expected json strings.
-static void CheckValues(const util::Settings& settings, const std::string& single_val, const std::string& list_val)
+static void CheckValues(const common::Settings& settings, const std::string& single_val, const std::string& list_val)
{
- util::SettingsValue single_value = GetSetting(settings, "section", "name", false, false, false);
- util::SettingsValue list_value(util::SettingsValue::VARR);
+ common::SettingsValue single_value = GetSetting(settings, "section", "name", false, false, false);
+ common::SettingsValue list_value(common::SettingsValue::VARR);
for (const auto& item : GetSettingsList(settings, "section", "name", false)) {
list_value.push_back(item);
}
@@ -118,7 +118,7 @@ static void CheckValues(const util::Settings& settings, const std::string& singl
// Simple settings merge test case.
BOOST_AUTO_TEST_CASE(Simple)
{
- util::Settings settings;
+ common::Settings settings;
settings.command_line_options["name"].push_back("val1");
settings.command_line_options["name"].push_back("val2");
settings.ro_config["section"]["name"].push_back(2);
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(Simple)
// The last given arg takes precedence when specified via commandline.
CheckValues(settings, R"("val2")", R"(["val1","val2",2])");
- util::Settings settings2;
+ common::Settings settings2;
settings2.ro_config["section"]["name"].push_back("val2");
settings2.ro_config["section"]["name"].push_back("val3");
@@ -140,7 +140,7 @@ BOOST_AUTO_TEST_CASE(Simple)
// its default value.
BOOST_AUTO_TEST_CASE(NullOverride)
{
- util::Settings settings;
+ common::Settings settings;
settings.command_line_options["name"].push_back("value");
BOOST_CHECK_EQUAL(R"("value")", GetSetting(settings, "section", "name", false, false, false).write().c_str());
settings.forced_settings["name"] = {};
@@ -190,16 +190,16 @@ BOOST_FIXTURE_TEST_CASE(Merge, MergeTestingSetup)
if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
}
- const std::string& network = CBaseChainParams::MAIN;
+ const std::string& network = ChainTypeToString(ChainType::MAIN);
ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool force_set,
bool ignore_default_section_config) {
std::string desc;
int value_suffix = 0;
- util::Settings settings;
+ common::Settings settings;
const std::string& name = ignore_default_section_config ? "wallet" : "server";
auto push_values = [&](Action action, const char* value_prefix, const std::string& name_prefix,
- std::vector<util::SettingsValue>& dest) {
+ std::vector<common::SettingsValue>& dest) {
if (action == SET || action == SECTION_SET) {
for (int i = 0; i < 2; ++i) {
dest.push_back(value_prefix + ToString(++value_suffix));
@@ -225,7 +225,7 @@ BOOST_FIXTURE_TEST_CASE(Merge, MergeTestingSetup)
}
desc += " || ";
- desc += GetSetting(settings, network, name, ignore_default_section_config, /*ignore_nonpersistent=*/false, /*get_chain_name=*/false).write();
+ desc += GetSetting(settings, network, name, ignore_default_section_config, /*ignore_nonpersistent=*/false, /*get_chain_type=*/false).write();
desc += " |";
for (const auto& s : GetSettingsList(settings, network, name, ignore_default_section_config)) {
desc += " ";
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index e2d11afa6a..68ef719c71 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <consensus/tx_check.h>
#include <consensus/validation.h>
#include <hash.h>
@@ -14,7 +15,6 @@
#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <version.h>
#include <iostream>
diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp
index 9e6f73745e..26ee724bf8 100644
--- a/src/test/sock_tests.cpp
+++ b/src/test/sock_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <compat/compat.h>
#include <test/util/setup_common.h>
#include <util/sock.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index a9b5251ad3..55e4f200b1 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <fs.h>
#include <streams.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
+#include <util/fs.h>
#include <boost/test/unit_test.hpp>
@@ -463,7 +463,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
size_t find = currentPos + InsecureRandRange(8);
if (find >= fileSize)
find = fileSize - 1;
- bf.FindByte(uint8_t(find));
+ bf.FindByte(std::byte(find));
// The value at each offset is the offset.
BOOST_CHECK_EQUAL(bf.GetPos(), find);
currentPos = find;
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index c0a2566959..7ce350b84b 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(run_command)
const UniValue result = RunCommandParseJSON("echo \"{\"success\": true}\"");
#endif
BOOST_CHECK(result.isObject());
- const UniValue& success = find_value(result, "success");
+ const UniValue& success = result.find_value("success");
BOOST_CHECK(!success.isNull());
BOOST_CHECK_EQUAL(success.get_bool(), true);
}
@@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(run_command)
{
const UniValue result = RunCommandParseJSON("cat", "{\"success\": true}");
BOOST_CHECK(result.isObject());
- const UniValue& success = find_value(result, "success");
+ const UniValue& success = result.find_value("success");
BOOST_CHECK(!success.isNull());
BOOST_CHECK_EQUAL(success.get_bool(), true);
}
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index b9bfa65c0a..b666517ae2 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -32,10 +32,10 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
BOOST_REQUIRE(txindex.Start());
// Allow tx index to catch up with the block index.
- constexpr int64_t timeout_ms = 10 * 1000;
- int64_t time_start = GetTimeMillis();
+ constexpr auto timeout{10s};
+ const auto time_start{SteadyClock::now()};
while (!txindex.BlockUntilSyncedToCurrentChain()) {
- BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
+ BOOST_REQUIRE(time_start + timeout > SteadyClock::now());
UninterruptibleSleep(std::chrono::milliseconds{100});
}
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index 024526497c..c08d2748a6 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -16,6 +16,9 @@
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(txpackage_tests)
+// A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these
+// unit tests.
+static const CAmount low_fee_amt{200};
// Create placeholder transactions that have no meaning.
inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
@@ -373,6 +376,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
{
// Mine blocks to mature coinbases.
mineBlocks(5);
+ MockMempoolMinFee(CFeeRate(5000));
LOCK(cs_main);
// Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
@@ -560,13 +564,15 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
BOOST_CHECK(parent2_v2_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
package_mixed.push_back(ptx_parent2_v1);
- // parent3 will be a new transaction. Put 0 fees on it to make it invalid on its own.
+ // parent3 will be a new transaction. Put a low feerate to make it invalid on its own.
auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[3], /*input_vout=*/0,
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
/*output_destination=*/acs_spk,
- /*output_amount=*/CAmount(50 * COIN), /*submit=*/false);
+ /*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false);
CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3);
package_mixed.push_back(ptx_parent3);
+ BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*ptx_parent3)) > low_fee_amt);
+ BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*ptx_parent3)) <= low_fee_amt);
// child spends parent1, parent2, and parent3
CKey mixed_grandchild_key;
@@ -627,6 +633,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
{
mineBlocks(5);
+ MockMempoolMinFee(CFeeRate(5000));
LOCK(::cs_main);
size_t expected_pool_size = m_node.mempool->size();
CKey child_key;
@@ -636,9 +643,9 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
grandchild_key.MakeNewKey(true);
CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
- // zero-fee parent and high-fee child package
+ // low-fee parent and high-fee child package
const CAmount coinbase_value{50 * COIN};
- const CAmount parent_value{coinbase_value - 0};
+ const CAmount parent_value{coinbase_value - low_fee_amt};
const CAmount child_value{parent_value - COIN};
Package package_cpfp;
@@ -657,17 +664,20 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
package_cpfp.push_back(tx_child);
// Package feerate is calculated using modified fees, and prioritisetransaction accepts negative
- // fee deltas. This should be taken into account. De-prioritise the parent transaction by -1BTC,
- // bringing the package feerate to 0.
- m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), -1 * COIN);
+ // fee deltas. This should be taken into account. De-prioritise the parent transaction
+ // to bring the package feerate to 0.
+ m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), child_value - coinbase_value);
{
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
package_cpfp, /*test_accept=*/ false);
- BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
- BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_state.IsInvalid(),
- "Package validation unexpectedly succeeded: " << submit_cpfp_deprio.m_state.GetRejectReason());
- BOOST_CHECK(submit_cpfp_deprio.m_tx_results.empty());
+ BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_state.GetResult(), PackageValidationResult::PCKG_TX);
+ BOOST_CHECK(submit_cpfp_deprio.m_state.IsInvalid());
+ BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetResult(),
+ TxValidationResult::TX_MEMPOOL_POLICY);
+ BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_child->GetWitnessHash())->second.m_state.GetResult(),
+ TxValidationResult::TX_MISSING_INPUTS);
+ BOOST_CHECK(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetRejectReason() == "min relay fee not met");
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
const CFeeRate expected_feerate(0, GetVirtualTransactionSize(*tx_parent) + GetVirtualTransactionSize(*tx_child));
}
@@ -675,8 +685,8 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
// Clear the prioritisation of the parent transaction.
WITH_LOCK(m_node.mempool->cs, m_node.mempool->ClearPrioritisation(tx_parent->GetHash()));
- // Package CPFP: Even though the parent pays 0 absolute fees, the child pays 1 BTC which is
- // enough for the package feerate to meet the threshold.
+ // Package CPFP: Even though the parent's feerate is below the mempool minimum feerate, the
+ // child pays enough for the package feerate to meet the threshold.
{
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
const auto submit_cpfp = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
@@ -689,7 +699,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end());
BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
- BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
+ BOOST_CHECK(it_parent->second.m_base_fees.value() == coinbase_value - parent_value);
BOOST_CHECK(it_child != submit_cpfp.m_tx_results.end());
BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
BOOST_CHECK(it_child->second.m_base_fees.value() == COIN);
@@ -709,22 +719,28 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
}
// Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
- // This package just pays 200 satoshis total. This would be enough to pay for the child alone,
- // but isn't enough for the entire package to meet the 1sat/vbyte minimum.
+ // The mempool minimum feerate is 5sat/vB, but this package just pays 800 satoshis total.
+ // The child fees would be able to pay for itself, but isn't enough for the entire package.
Package package_still_too_low;
+ const CAmount parent_fee{200};
+ const CAmount child_fee{600};
auto mtx_parent_cheap = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
/*output_destination=*/parent_spk,
- /*output_amount=*/coinbase_value, /*submit=*/false);
+ /*output_amount=*/coinbase_value - parent_fee, /*submit=*/false);
CTransactionRef tx_parent_cheap = MakeTransactionRef(mtx_parent_cheap);
package_still_too_low.push_back(tx_parent_cheap);
+ BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) > parent_fee);
+ BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) <= parent_fee);
auto mtx_child_cheap = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_cheap, /*input_vout=*/0,
/*input_height=*/101, /*input_signing_key=*/child_key,
/*output_destination=*/child_spk,
- /*output_amount=*/coinbase_value - 200, /*submit=*/false);
+ /*output_amount=*/coinbase_value - parent_fee - child_fee, /*submit=*/false);
CTransactionRef tx_child_cheap = MakeTransactionRef(mtx_child_cheap);
package_still_too_low.push_back(tx_child_cheap);
+ BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_child_cheap)) <= child_fee);
+ BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)) > parent_fee + child_fee);
// Cheap package should fail with package-fee-too-low.
{
@@ -735,11 +751,6 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(), "package-fee-too-low");
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
- const CFeeRate child_feerate(200, GetVirtualTransactionSize(*tx_child_cheap));
- BOOST_CHECK(child_feerate.GetFeePerK() > 1000);
- const CFeeRate expected_feerate(200,
- GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
- BOOST_CHECK(expected_feerate.GetFeePerK() < 1000);
}
// Package feerate includes the modified fees of the transactions.
@@ -752,18 +763,18 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
expected_pool_size += 2;
BOOST_CHECK_MESSAGE(submit_prioritised_package.m_state.IsValid(),
"Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason());
- const CFeeRate expected_feerate(1 * COIN + 200,
+ const CFeeRate expected_feerate(1 * COIN + parent_fee + child_fee,
GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
BOOST_CHECK(it_parent != submit_prioritised_package.m_tx_results.end());
BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
- BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
+ BOOST_CHECK(it_parent->second.m_base_fees.value() == parent_fee);
BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
BOOST_CHECK(it_child != submit_prioritised_package.m_tx_results.end());
BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
- BOOST_CHECK(it_child->second.m_base_fees.value() == 200);
+ BOOST_CHECK(it_child->second.m_base_fees.value() == child_fee);
BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
std::vector<uint256> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
@@ -800,8 +811,8 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
BOOST_CHECK_MESSAGE(submit_rich_parent.m_state.IsInvalid(), "Package validation unexpectedly succeeded");
// The child would have been validated on its own and failed, then submitted as a "package" of 1.
- BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
- BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "package-fee-too-low");
+ BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetResult(), PackageValidationResult::PCKG_TX);
+ BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(), "transaction failed");
auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
BOOST_CHECK(it_parent != submit_rich_parent.m_tx_results.end());
@@ -810,6 +821,11 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
strprintf("rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
BOOST_CHECK(it_parent->second.m_effective_feerate == CFeeRate(high_parent_fee, GetVirtualTransactionSize(*tx_parent_rich)));
+ auto it_child = submit_rich_parent.m_tx_results.find(tx_child_poor->GetWitnessHash());
+ BOOST_CHECK(it_child != submit_rich_parent.m_tx_results.end());
+ BOOST_CHECK_EQUAL(it_child->second.m_result_type, MempoolAcceptResult::ResultType::INVALID);
+ BOOST_CHECK_EQUAL(it_child->second.m_state.GetResult(), TxValidationResult::TX_MEMPOOL_POLICY);
+ BOOST_CHECK(it_child->second.m_state.GetRejectReason() == "min relay fee not met");
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_parent_rich->GetHash())));
diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp
index 17a55d5ab5..dc257a0d51 100644
--- a/src/test/txrequest_tests.cpp
+++ b/src/test/txrequest_tests.cpp
@@ -386,6 +386,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers)
}
// Make a list of all peers, in order of intended request order (concatenation of pref_peers and npref_peers).
std::vector<NodeId> request_order;
+ request_order.reserve(num_pref + num_npref);
for (int i = 0; i < num_pref; ++i) request_order.push_back(pref_peers[i]);
for (int i = 0; i < num_npref; ++i) request_order.push_back(npref_peers[i]);
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 8cdea3890e..8f8628169f 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -9,13 +9,14 @@
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
+#include <util/chaintype.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
struct Dersig100Setup : public TestChain100Setup {
Dersig100Setup()
- : TestChain100Setup{CBaseChainParams::REGTEST, {"-testactivationheight=dersig@102"}} {}
+ : TestChain100Setup{ChainType::REGTEST, {"-testactivationheight=dersig@102"}} {}
};
bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
diff --git a/src/test/util/blockfilter.cpp b/src/test/util/blockfilter.cpp
index ec703c6a7b..a806844e34 100644
--- a/src/test/util/blockfilter.cpp
+++ b/src/test/util/blockfilter.cpp
@@ -8,20 +8,19 @@
#include <node/blockstorage.h>
#include <validation.h>
-using node::ReadBlockFromDisk;
-using node::UndoReadFromDisk;
+using node::BlockManager;
-bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index, BlockFilter& filter)
+bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex& block_index, BlockFilter& filter, const BlockManager& blockman)
{
LOCK(::cs_main);
CBlock block;
- if (!ReadBlockFromDisk(block, block_index->GetBlockPos(), Params().GetConsensus())) {
+ if (!blockman.ReadBlockFromDisk(block, block_index.GetBlockPos())) {
return false;
}
CBlockUndo block_undo;
- if (block_index->nHeight > 0 && !UndoReadFromDisk(block_undo, block_index)) {
+ if (block_index.nHeight > 0 && !blockman.UndoReadFromDisk(block_undo, block_index)) {
return false;
}
diff --git a/src/test/util/blockfilter.h b/src/test/util/blockfilter.h
index 79d11dcad8..789ce5d3aa 100644
--- a/src/test/util/blockfilter.h
+++ b/src/test/util/blockfilter.h
@@ -6,8 +6,12 @@
#define BITCOIN_TEST_UTIL_BLOCKFILTER_H
#include <blockfilter.h>
+
class CBlockIndex;
+namespace node {
+class BlockManager;
+}
-bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index, BlockFilter& filter);
+bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex& block_index, BlockFilter& filter, const node::BlockManager& blockman);
#endif // BITCOIN_TEST_UTIL_BLOCKFILTER_H
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index e664435e03..bf8f8b5819 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -6,12 +6,12 @@
#define BITCOIN_TEST_UTIL_CHAINSTATE_H
#include <clientversion.h>
-#include <fs.h>
#include <logging.h>
#include <node/context.h>
#include <node/utxo_snapshot.h>
#include <rpc/blockchain.h>
#include <test/util/setup_common.h>
+#include <util/fs.h>
#include <validation.h>
#include <univalue.h>
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index 0df1db84c4..51f4b89512 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -6,19 +6,22 @@
#include <chainparams.h>
#include <consensus/merkle.h>
+#include <consensus/validation.h>
#include <key_io.h>
#include <node/context.h>
#include <pow.h>
+#include <primitives/transaction.h>
#include <script/standard.h>
#include <test/util/script.h>
#include <util/check.h>
#include <validation.h>
+#include <validationinterface.h>
#include <versionbits.h>
using node::BlockAssembler;
using node::NodeContext;
-CTxIn generatetoaddress(const NodeContext& node, const std::string& address)
+COutPoint generatetoaddress(const NodeContext& node, const std::string& address)
{
const auto dest = DecodeDestination(address);
assert(IsValidDestination(dest));
@@ -58,19 +61,52 @@ std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const
return ret;
}
-CTxIn MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
+COutPoint MineBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey)
{
auto block = PrepareBlock(node, coinbase_scriptPubKey);
+ auto valid = MineBlock(node, block);
+ assert(!valid.IsNull());
+ return valid;
+}
+
+struct BlockValidationStateCatcher : public CValidationInterface {
+ const uint256 m_hash;
+ std::optional<BlockValidationState> m_state;
+ BlockValidationStateCatcher(const uint256& hash)
+ : m_hash{hash},
+ m_state{} {}
+
+protected:
+ void BlockChecked(const CBlock& block, const BlockValidationState& state) override
+ {
+ if (block.GetHash() != m_hash) return;
+ m_state = state;
+ }
+};
+
+COutPoint MineBlock(const NodeContext& node, std::shared_ptr<CBlock>& block)
+{
while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) {
++block->nNonce;
assert(block->nNonce);
}
- bool processed{Assert(node.chainman)->ProcessNewBlock(block, true, true, nullptr)};
- assert(processed);
-
- return CTxIn{block->vtx[0]->GetHash(), 0};
+ auto& chainman{*Assert(node.chainman)};
+ const auto old_height = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight());
+ bool new_block;
+ BlockValidationStateCatcher bvsc{block->GetHash()};
+ RegisterValidationInterface(&bvsc);
+ const bool processed{chainman.ProcessNewBlock(block, true, true, &new_block)};
+ const bool duplicate{!new_block && processed};
+ assert(!duplicate);
+ UnregisterValidationInterface(&bvsc);
+ SyncWithValidationInterfaceQueue();
+ const bool was_valid{bvsc.m_state && bvsc.m_state->IsValid()};
+ assert(old_height + was_valid == WITH_LOCK(chainman.GetMutex(), return chainman.ActiveHeight()));
+
+ if (was_valid) return {block->vtx[0]->GetHash(), 0};
+ return {};
}
std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coinbase_scriptPubKey,
diff --git a/src/test/util/mining.h b/src/test/util/mining.h
index 70b1f7b3fb..3f071257f1 100644
--- a/src/test/util/mining.h
+++ b/src/test/util/mining.h
@@ -13,8 +13,8 @@
class CBlock;
class CChainParams;
+class COutPoint;
class CScript;
-class CTxIn;
namespace node {
struct NodeContext;
} // namespace node
@@ -23,7 +23,13 @@ struct NodeContext;
std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params);
/** Returns the generated coin */
-CTxIn MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
+COutPoint MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
+
+/**
+ * Returns the generated coin (or Null if the block was invalid).
+ * It is recommended to call RegenerateCommitments before mining the block to avoid merkle tree mismatches.
+ **/
+COutPoint MineBlock(const node::NodeContext&, std::shared_ptr<CBlock>& block);
/** Prepare a block to be mined */
std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey);
@@ -31,6 +37,6 @@ std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext& node, const CScrip
const node::BlockAssembler::Options& assembler_options);
/** RPC-like helper function, returns the generated coin */
-CTxIn generatetoaddress(const node::NodeContext&, const std::string& address);
+COutPoint generatetoaddress(const node::NodeContext&, const std::string& address);
#endif // BITCOIN_TEST_UTIL_MINING_H
diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp
index 070a6a1c50..3f72384b3b 100644
--- a/src/test/util/net.cpp
+++ b/src/test/util/net.cpp
@@ -66,7 +66,7 @@ void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, Span<const uint8_t> msg_by
{
assert(node.ReceiveMsgBytes(msg_bytes, complete));
if (complete) {
- node.MarkReceivedMsgsForProcessing(nReceiveFloodSize);
+ node.MarkReceivedMsgsForProcessing();
}
}
@@ -84,6 +84,7 @@ bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg& ser_msg) con
std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(int n_candidates, FastRandomContext& random_context)
{
std::vector<NodeEvictionCandidate> candidates;
+ candidates.reserve(n_candidates);
for (int id = 0; id < n_candidates; ++id) {
candidates.push_back({
/*id=*/id,
diff --git a/src/test/util/poolresourcetester.h b/src/test/util/poolresourcetester.h
new file mode 100644
index 0000000000..93f62eb2a9
--- /dev/null
+++ b/src/test/util/poolresourcetester.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2022 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_TEST_UTIL_POOLRESOURCETESTER_H
+#define BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
+
+#include <support/allocators/pool.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+/**
+ * Helper to get access to private parts of PoolResource. Used in unit tests and in the fuzzer
+ */
+class PoolResourceTester
+{
+ struct PtrAndBytes {
+ uintptr_t ptr;
+ std::size_t size;
+
+ PtrAndBytes(const void* p, std::size_t s)
+ : ptr(reinterpret_cast<uintptr_t>(p)), size(s)
+ {
+ }
+
+ /**
+ * defines a sort ordering by the pointer value
+ */
+ friend bool operator<(PtrAndBytes const& a, PtrAndBytes const& b)
+ {
+ return a.ptr < b.ptr;
+ }
+ };
+
+public:
+ /**
+ * Extracts the number of elements per freelist
+ */
+ template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+ static std::vector<std::size_t> FreeListSizes(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
+ {
+ auto sizes = std::vector<std::size_t>();
+ for (const auto* ptr : resource.m_free_lists) {
+ size_t size = 0;
+ while (ptr != nullptr) {
+ ++size;
+ ptr = ptr->m_next;
+ }
+ sizes.push_back(size);
+ }
+ return sizes;
+ }
+
+ /**
+ * How many bytes are still available from the last allocated chunk
+ */
+ template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+ static std::size_t AvailableMemoryFromChunk(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
+ {
+ return resource.m_available_memory_end - resource.m_available_memory_it;
+ }
+
+ /**
+ * Once all blocks are given back to the resource, tests that the freelists are consistent:
+ *
+ * * All data in the freelists must come from the chunks
+ * * Memory doesn't overlap
+ * * Each byte in the chunks can be accounted for in either the freelist or as available bytes.
+ */
+ template <std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+ static void CheckAllDataAccountedFor(const PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>& resource)
+ {
+ // collect all free blocks by iterating all freelists
+ std::vector<PtrAndBytes> free_blocks;
+ for (std::size_t freelist_idx = 0; freelist_idx < resource.m_free_lists.size(); ++freelist_idx) {
+ std::size_t bytes = freelist_idx * resource.ELEM_ALIGN_BYTES;
+ auto* ptr = resource.m_free_lists[freelist_idx];
+ while (ptr != nullptr) {
+ free_blocks.emplace_back(ptr, bytes);
+ ptr = ptr->m_next;
+ }
+ }
+ // also add whatever has not yet been used for blocks
+ auto num_available_bytes = resource.m_available_memory_end - resource.m_available_memory_it;
+ if (num_available_bytes > 0) {
+ free_blocks.emplace_back(resource.m_available_memory_it, num_available_bytes);
+ }
+
+ // collect all chunks
+ std::vector<PtrAndBytes> chunks;
+ for (const std::byte* ptr : resource.m_allocated_chunks) {
+ chunks.emplace_back(ptr, resource.ChunkSizeBytes());
+ }
+
+ // now we have all the data from all freelists on the one hand side, and all chunks on the other hand side.
+ // To check if all of them match, sort by address and iterate.
+ std::sort(free_blocks.begin(), free_blocks.end());
+ std::sort(chunks.begin(), chunks.end());
+
+ auto chunk_it = chunks.begin();
+ auto chunk_ptr_remaining = chunk_it->ptr;
+ auto chunk_size_remaining = chunk_it->size;
+ for (const auto& free_block : free_blocks) {
+ if (chunk_size_remaining == 0) {
+ assert(chunk_it != chunks.end());
+ ++chunk_it;
+ assert(chunk_it != chunks.end());
+ chunk_ptr_remaining = chunk_it->ptr;
+ chunk_size_remaining = chunk_it->size;
+ }
+ assert(free_block.ptr == chunk_ptr_remaining); // ensure addresses match
+ assert(free_block.size <= chunk_size_remaining); // ensure no overflow
+ assert((free_block.ptr & (resource.ELEM_ALIGN_BYTES - 1)) == 0); // ensure correct alignment
+ chunk_ptr_remaining += free_block.size;
+ chunk_size_remaining -= free_block.size;
+ }
+ // ensure we are at the end of the chunks
+ assert(chunk_ptr_remaining == chunk_it->ptr + chunk_it->size);
+ ++chunk_it;
+ assert(chunk_it == chunks.end());
+ assert(chunk_size_remaining == 0);
+ }
+};
+
+#endif // BITCOIN_TEST_UTIL_POOLRESOURCETESTER_H
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 58593c9d5b..93a60db832 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -9,6 +9,7 @@
#include <addrman.h>
#include <banman.h>
#include <chainparams.h>
+#include <common/system.h>
#include <common/url.h>
#include <consensus/consensus.h>
#include <consensus/params.h>
@@ -23,6 +24,7 @@
#include <node/blockstorage.h>
#include <node/chainstate.h>
#include <node/context.h>
+#include <node/kernel_notifications.h>
#include <node/mempool_args.h>
#include <node/miner.h>
#include <node/validation_cache_args.h>
@@ -42,6 +44,7 @@
#include <timedata.h>
#include <txdb.h>
#include <txmempool.h>
+#include <util/chaintype.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/thread.h>
@@ -60,7 +63,9 @@
using kernel::ValidationCacheSizes;
using node::ApplyArgsManOptions;
using node::BlockAssembler;
+using node::BlockManager;
using node::CalculateCacheSizes;
+using node::KernelNotifications;
using node::LoadChainstate;
using node::RegenerateCommitments;
using node::VerifyLoadedChainstate;
@@ -97,7 +102,7 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
return os;
}
-BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args)
+BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args)
: m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME / g_insecure_rand_ctx_temp_path.rand256().ToString()},
m_args{}
{
@@ -131,7 +136,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
throw std::runtime_error{error};
}
}
- SelectParams(chainName);
+ SelectParams(chainType);
SeedInsecureRand();
if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN);
InitLogging(*m_node.args);
@@ -152,6 +157,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
noui_connect();
noui_connected = true;
}
+ node::g_indexes_ready_to_sync = true;
}
BasicTestingSetup::~BasicTestingSetup()
@@ -162,8 +168,8 @@ BasicTestingSetup::~BasicTestingSetup()
gArgs.ClearArgs();
}
-ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args)
- : BasicTestingSetup(chainName, extra_args)
+ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vector<const char*>& extra_args)
+ : BasicTestingSetup(chainType, extra_args)
{
const CChainParams& chainparams = Params();
@@ -173,18 +179,25 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); });
GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
- m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args));
+ m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(*m_node.args), DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
m_node.mempool = std::make_unique<CTxMemPool>(MemPoolOptionsForTest(m_node));
m_cache_sizes = CalculateCacheSizes(m_args);
+ m_node.notifications = std::make_unique<KernelNotifications>();
+
const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
.datadir = m_args.GetDataDirNet(),
.adjusted_time_callback = GetAdjustedTime,
.check_block_index = true,
+ .notifications = *m_node.notifications,
+ };
+ const BlockManager::Options blockman_opts{
+ .chainparams = chainman_opts.chainparams,
+ .blocks_dir = m_args.GetBlocksDirPath(),
};
- m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, node::BlockManager::Options{});
+ m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(DBParams{
.path = m_args.GetDataDirNet() / "blocks" / "index",
.cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),
@@ -210,7 +223,7 @@ ChainTestingSetup::~ChainTestingSetup()
m_node.chainman.reset();
}
-void TestingSetup::LoadVerifyActivateChainstate()
+void ChainTestingSetup::LoadVerifyActivateChainstate()
{
auto& chainman{*Assert(m_node.chainman)};
node::ChainstateLoadOptions options;
@@ -236,14 +249,14 @@ void TestingSetup::LoadVerifyActivateChainstate()
}
TestingSetup::TestingSetup(
- const std::string& chainName,
+ const ChainType chainType,
const std::vector<const char*>& extra_args,
const bool coins_db_in_memory,
const bool block_tree_db_in_memory)
- : ChainTestingSetup(chainName, extra_args),
- m_coins_db_in_memory(coins_db_in_memory),
- m_block_tree_db_in_memory(block_tree_db_in_memory)
+ : ChainTestingSetup(chainType, extra_args)
{
+ m_coins_db_in_memory = coins_db_in_memory;
+ m_block_tree_db_in_memory = block_tree_db_in_memory;
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC);
@@ -267,11 +280,11 @@ TestingSetup::TestingSetup(
}
TestChain100Setup::TestChain100Setup(
- const std::string& chain_name,
+ const ChainType chain_type,
const std::vector<const char*>& extra_args,
const bool coins_db_in_memory,
const bool block_tree_db_in_memory)
- : TestingSetup{CBaseChainParams::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory}
+ : TestingSetup{ChainType::REGTEST, extra_args, coins_db_in_memory, block_tree_db_in_memory}
{
SetMockTime(1598887952);
constexpr std::array<unsigned char, 32> vchKey = {
@@ -432,6 +445,33 @@ std::vector<CTransactionRef> TestChain100Setup::PopulateMempool(FastRandomContex
return mempool_transactions;
}
+void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate)
+{
+ LOCK2(cs_main, m_node.mempool->cs);
+ // Transactions in the mempool will affect the new minimum feerate.
+ assert(m_node.mempool->size() == 0);
+ // The target feerate cannot be too low...
+ // ...otherwise the transaction's feerate will need to be negative.
+ assert(target_feerate > m_node.mempool->m_incremental_relay_feerate);
+ // ...otherwise this is not meaningful. The feerate policy uses the maximum of both feerates.
+ assert(target_feerate > m_node.mempool->m_min_relay_feerate);
+
+ // Manually create an invalid transaction. Manually set the fee in the CTxMemPoolEntry to
+ // achieve the exact target feerate.
+ CMutableTransaction mtx = CMutableTransaction();
+ mtx.vin.push_back(CTxIn{COutPoint{g_insecure_rand_ctx.rand256(), 0}});
+ mtx.vout.push_back(CTxOut(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE))));
+ const auto tx{MakeTransactionRef(mtx)};
+ LockPoints lp;
+ // The new mempool min feerate is equal to the removed package's feerate + incremental feerate.
+ const auto tx_fee = target_feerate.GetFee(GetVirtualTransactionSize(*tx)) -
+ m_node.mempool->m_incremental_relay_feerate.GetFee(GetVirtualTransactionSize(*tx));
+ m_node.mempool->addUnchecked(CTxMemPoolEntry(tx, /*fee=*/tx_fee,
+ /*time=*/0, /*entry_height=*/1,
+ /*spends_coinbase=*/true, /*sigops_cost=*/1, lp));
+ m_node.mempool->TrimToSize(0);
+ assert(m_node.mempool->GetMinFee() == target_feerate);
+}
/**
* @returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af)
* with 9 txs.
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 8874db7e75..b7429df02c 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -5,24 +5,25 @@
#ifndef BITCOIN_TEST_UTIL_SETUP_COMMON_H
#define BITCOIN_TEST_UTIL_SETUP_COMMON_H
-#include <chainparamsbase.h>
-#include <fs.h>
+#include <common/args.h>
#include <key.h>
#include <node/caches.h>
-#include <node/context.h>
+#include <node/context.h> // IWYU pragma: export
#include <primitives/transaction.h>
#include <pubkey.h>
#include <random.h>
#include <stdexcept>
+#include <util/chaintype.h>
#include <util/check.h>
+#include <util/fs.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/vector.h>
#include <functional>
#include <type_traits>
#include <vector>
+class CFeeRate;
class Chainstate;
/** This is connected to the logger. Can be used to redirect logs to any other log */
@@ -79,7 +80,7 @@ static constexpr CAmount CENT{1000000};
struct BasicTestingSetup {
node::NodeContext m_node; // keep as first member to be destructed last
- explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {});
+ explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, const std::vector<const char*>& extra_args = {});
~BasicTestingSetup();
const fs::path m_path_root;
@@ -92,21 +93,21 @@ struct BasicTestingSetup {
*/
struct ChainTestingSetup : public BasicTestingSetup {
node::CacheSizes m_cache_sizes{};
+ bool m_coins_db_in_memory{true};
+ bool m_block_tree_db_in_memory{true};
- explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {});
+ explicit ChainTestingSetup(const ChainType chainType = ChainType::MAIN, const std::vector<const char*>& extra_args = {});
~ChainTestingSetup();
+
+ // Supplies a chainstate, if one is needed
+ void LoadVerifyActivateChainstate();
};
/** Testing setup that configures a complete environment.
*/
struct TestingSetup : public ChainTestingSetup {
- bool m_coins_db_in_memory{true};
- bool m_block_tree_db_in_memory{true};
-
- void LoadVerifyActivateChainstate();
-
explicit TestingSetup(
- const std::string& chainName = CBaseChainParams::MAIN,
+ const ChainType chainType = ChainType::MAIN,
const std::vector<const char*>& extra_args = {},
const bool coins_db_in_memory = true,
const bool block_tree_db_in_memory = true);
@@ -115,7 +116,7 @@ struct TestingSetup : public ChainTestingSetup {
/** Identical to TestingSetup, but chain set to regtest */
struct RegTestingSetup : public TestingSetup {
RegTestingSetup()
- : TestingSetup{CBaseChainParams::REGTEST} {}
+ : TestingSetup{ChainType::REGTEST} {}
};
class CBlock;
@@ -127,7 +128,7 @@ class CScript;
*/
struct TestChain100Setup : public TestingSetup {
TestChain100Setup(
- const std::string& chain_name = CBaseChainParams::REGTEST,
+ const ChainType chain_type = ChainType::REGTEST,
const std::vector<const char*>& extra_args = {},
const bool coins_db_in_memory = true,
const bool block_tree_db_in_memory = true);
@@ -185,6 +186,17 @@ struct TestChain100Setup : public TestingSetup {
*/
std::vector<CTransactionRef> PopulateMempool(FastRandomContext& det_rand, size_t num_transactions, bool submit);
+ /** Mock the mempool minimum feerate by adding a transaction and calling TrimToSize(0),
+ * simulating the mempool "reaching capacity" and evicting by descendant feerate. Note that
+ * this clears the mempool, and the new minimum feerate will depend on the maximum feerate of
+ * transactions removed, so this must be called while the mempool is empty.
+ *
+ * @param target_feerate The new mempool minimum feerate after this function returns.
+ * Must be above max(incremental feerate, min relay feerate),
+ * or 1sat/vB with default settings.
+ */
+ void MockMempoolMinFee(const CFeeRate& target_feerate);
+
std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
};
@@ -194,7 +206,7 @@ struct TestChain100Setup : public TestingSetup {
* be used in "hot loops", for example fuzzing or benchmarking.
*/
template <class T = const BasicTestingSetup>
-std::unique_ptr<T> MakeNoLogFileContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {})
+std::unique_ptr<T> MakeNoLogFileContext(const ChainType chain_type = ChainType::REGTEST, const std::vector<const char*>& extra_args = {})
{
const std::vector<const char*> arguments = Cat(
{
@@ -203,7 +215,7 @@ std::unique_ptr<T> MakeNoLogFileContext(const std::string& chain_name = CBaseCha
},
extra_args);
- return std::make_unique<T>(chain_name, arguments);
+ return std::make_unique<T>(chain_type, arguments);
}
CBlock getBlock13b8a();
diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp
index 1873cf5ec8..4797d9c310 100644
--- a/src/test/util/txmempool.cpp
+++ b/src/test/util/txmempool.cpp
@@ -22,8 +22,8 @@ CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node)
// chainparams.DefaultConsistencyChecks for tests
.check_ratio = 1,
};
- const auto err{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)};
- Assert(!err);
+ const auto result{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)};
+ Assert(result);
return mempool_opts;
}
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index a13552653e..26677bfa55 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2,16 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util/system.h>
-
#include <clientversion.h>
-#include <fs.h>
#include <hash.h> // For Hash()
#include <key.h> // For CKey
#include <sync.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
#include <uint256.h>
+#include <util/bitdeque.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/getuniquepath.h>
#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC
#include <util/moneystr.h>
@@ -22,7 +22,6 @@
#include <util/string.h>
#include <util/time.h>
#include <util/vector.h>
-#include <util/bitdeque.h>
#include <array>
#include <cmath>
@@ -36,9 +35,11 @@
#include <univalue.h>
#include <utility>
#include <vector>
+
+#include <sys/types.h>
+
#ifndef WIN32
#include <signal.h>
-#include <sys/types.h>
#include <sys/wait.h>
#endif
@@ -1686,7 +1687,7 @@ BOOST_AUTO_TEST_CASE(message_hash)
BOOST_AUTO_TEST_CASE(remove_prefix)
{
- BOOST_CHECK_EQUAL(RemovePrefix("./util/system.h", "./"), "util/system.h");
+ BOOST_CHECK_EQUAL(RemovePrefix("./common/system.h", "./"), "common/system.h");
BOOST_CHECK_EQUAL(RemovePrefixView("foo", "foo"), "");
BOOST_CHECK_EQUAL(RemovePrefix("foo", "fo"), "o");
BOOST_CHECK_EQUAL(RemovePrefixView("foo", "f"), "oo");
diff --git a/src/test/util_threadnames_tests.cpp b/src/test/util_threadnames_tests.cpp
index dbb5423a77..ae913939e8 100644
--- a/src/test/util_threadnames_tests.cpp
+++ b/src/test/util_threadnames_tests.cpp
@@ -38,6 +38,7 @@ std::set<std::string> RenameEnMasse(int num_threads)
names.insert(util::ThreadGetInternalName());
};
+ threads.reserve(num_threads);
for (int i = 0; i < num_threads; ++i) {
threads.push_back(std::thread(RenameThisThread, i));
}
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 4c8687ce69..e08f2c98c2 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -174,6 +174,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
// this will create parallelism and randomness inside validation - the ValidationInterface
// will subscribe to events generated during block validation and assert on ordering invariance
std::vector<std::thread> threads;
+ threads.reserve(10);
for (int i = 0; i < 10; i++) {
threads.emplace_back([&]() {
bool ignored;
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 688aafdd46..b797de46af 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -4,6 +4,7 @@
//
#include <chainparams.h>
#include <consensus/validation.h>
+#include <node/kernel_notifications.h>
#include <node/utxo_snapshot.h>
#include <random.h>
#include <rpc/blockchain.h>
@@ -22,6 +23,8 @@
#include <boost/test/unit_test.hpp>
+using node::BlockManager;
+using node::KernelNotifications;
using node::SnapshotMetadata;
BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup)
@@ -181,7 +184,7 @@ struct SnapshotTestSetup : TestChain100Setup {
{
LOCK(::cs_main);
BOOST_CHECK(!chainman.IsSnapshotValidated());
- BOOST_CHECK(!node::FindSnapshotChainstateDir());
+ BOOST_CHECK(!node::FindSnapshotChainstateDir(chainman.m_options.datadir));
}
size_t initial_size;
@@ -231,7 +234,7 @@ struct SnapshotTestSetup : TestChain100Setup {
auto_infile >> coin;
}));
- BOOST_CHECK(!node::FindSnapshotChainstateDir());
+ BOOST_CHECK(!node::FindSnapshotChainstateDir(chainman.m_options.datadir));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
this, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
@@ -255,7 +258,7 @@ struct SnapshotTestSetup : TestChain100Setup {
}));
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(this));
- BOOST_CHECK(fs::exists(*node::FindSnapshotChainstateDir()));
+ BOOST_CHECK(fs::exists(*node::FindSnapshotChainstateDir(chainman.m_options.datadir)));
// Ensure our active chain is the snapshot chainstate.
BOOST_CHECK(!chainman.ActiveChainstate().m_from_snapshot_blockhash->IsNull());
@@ -268,7 +271,7 @@ struct SnapshotTestSetup : TestChain100Setup {
{
LOCK(::cs_main);
- fs::path found = *node::FindSnapshotChainstateDir();
+ fs::path found = *node::FindSnapshotChainstateDir(chainman.m_options.datadir);
// Note: WriteSnapshotBaseBlockhash() is implicitly tested above.
BOOST_CHECK_EQUAL(
@@ -367,21 +370,30 @@ struct SnapshotTestSetup : TestChain100Setup {
BOOST_TEST_MESSAGE("Simulating node restart");
{
- LOCK(::cs_main);
for (Chainstate* cs : chainman.GetAll()) {
+ LOCK(::cs_main);
cs->ForceFlushStateToDisk();
}
+ // Process all callbacks referring to the old manager before wiping it.
+ SyncWithValidationInterfaceQueue();
+ LOCK(::cs_main);
chainman.ResetChainstates();
BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
+ m_node.notifications = std::make_unique<KernelNotifications>();
const ChainstateManager::Options chainman_opts{
.chainparams = ::Params(),
- .datadir = m_args.GetDataDirNet(),
+ .datadir = chainman.m_options.datadir,
.adjusted_time_callback = GetAdjustedTime,
+ .notifications = *m_node.notifications,
+ };
+ const BlockManager::Options blockman_opts{
+ .chainparams = chainman_opts.chainparams,
+ .blocks_dir = m_args.GetBlocksDirPath(),
};
// For robustness, ensure the old manager is destroyed before creating a
// new one.
m_node.chainman.reset();
- m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, node::BlockManager::Options{});
+ m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
}
return *Assert(m_node.chainman);
}
@@ -479,7 +491,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup)
this->SetupSnapshot();
- fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
+ fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir(chainman.m_options.datadir);
BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");
@@ -553,7 +565,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion, SnapshotTestSetup
SnapshotCompletionResult res;
auto mock_shutdown = [](bilingual_str msg) {};
- fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir();
+ fs::path snapshot_chainstate_dir = *node::FindSnapshotChainstateDir(chainman.m_options.datadir);
BOOST_CHECK(fs::exists(snapshot_chainstate_dir));
BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");
diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp
index 26c48eb0e0..7398091215 100644
--- a/src/test/validation_flush_tests.cpp
+++ b/src/test/validation_flush_tests.cpp
@@ -36,12 +36,12 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
BOOST_TEST_MESSAGE("CCoinsViewCache memory usage: " << view.DynamicMemoryUsage());
};
- constexpr size_t MAX_COINS_CACHE_BYTES = 1024;
+ // PoolResource defaults to 256 KiB that will be allocated, so we'll take that and make it a bit larger.
+ constexpr size_t MAX_COINS_CACHE_BYTES = 262144 + 512;
// Without any coins in the cache, we shouldn't need to flush.
- BOOST_CHECK_EQUAL(
- chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
- CoinsCacheSizeState::OK);
+ BOOST_TEST(
+ chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 0) != CoinsCacheSizeState::CRITICAL);
// If the initial memory allocations of cacheCoins don't match these common
// cases, we can't really continue to make assertions about memory usage.
@@ -71,13 +71,21 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
// cacheCoins (unordered_map) preallocates.
constexpr int COINS_UNTIL_CRITICAL{3};
+ // no coin added, so we have plenty of space left.
+ BOOST_CHECK_EQUAL(
+ chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 0),
+ CoinsCacheSizeState::OK);
+
for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) {
const COutPoint res = AddTestCoin(view);
print_view_mem_usage(view);
BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE);
+
+ // adding first coin causes the MemoryResource to allocate one 256 KiB chunk of memory,
+ // pushing us immediately over to LARGE
BOOST_CHECK_EQUAL(
- chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
- CoinsCacheSizeState::OK);
+ chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 0),
+ CoinsCacheSizeState::LARGE);
}
// Adding some additional coins will push us over the edge to CRITICAL.
@@ -94,16 +102,16 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0),
CoinsCacheSizeState::CRITICAL);
- // Passing non-zero max mempool usage should allow us more headroom.
+ // Passing non-zero max mempool usage (512 KiB) should allow us more headroom.
BOOST_CHECK_EQUAL(
- chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10),
+ chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 1 << 19),
CoinsCacheSizeState::OK);
for (int i{0}; i < 3; ++i) {
AddTestCoin(view);
print_view_mem_usage(view);
BOOST_CHECK_EQUAL(
- chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/1 << 10),
+ chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 1 << 19),
CoinsCacheSizeState::OK);
}
@@ -119,7 +127,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
BOOST_CHECK(usage_percentage >= 0.9);
BOOST_CHECK(usage_percentage < 1);
BOOST_CHECK_EQUAL(
- chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 1 << 10),
+ chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes*/ 1 << 10), // 1024
CoinsCacheSizeState::LARGE);
}
@@ -131,8 +139,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
CoinsCacheSizeState::OK);
}
- // Flushing the view doesn't take us back to OK because cacheCoins has
- // preallocated memory that doesn't get reclaimed even after flush.
+ // Flushing the view does take us back to OK because ReallocateCache() is called
BOOST_CHECK_EQUAL(
chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0),
@@ -144,7 +151,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
BOOST_CHECK_EQUAL(
chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0),
- CoinsCacheSizeState::CRITICAL);
+ CoinsCacheSizeState::OK);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp
index 6ea49cb4ee..d00f2ff4d1 100644
--- a/src/test/validation_tests.cpp
+++ b/src/test/validation_tests.cpp
@@ -7,6 +7,7 @@
#include <net.h>
#include <signet.h>
#include <uint256.h>
+#include <util/chaintype.h>
#include <validation.h>
#include <test/util/setup_common.h>
@@ -41,7 +42,7 @@ static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
BOOST_AUTO_TEST_CASE(block_subsidy_test)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
TestBlockSubsidyHalvings(chainParams->GetConsensus()); // As in main
TestBlockSubsidyHalvings(150); // As in regtest
TestBlockSubsidyHalvings(1000); // Just another interval
@@ -49,7 +50,7 @@ BOOST_AUTO_TEST_CASE(block_subsidy_test)
BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
- const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN);
+ const auto chainParams = CreateChainParams(*m_node.args, ChainType::MAIN);
CAmount nSum = 0;
for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
CAmount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus());
@@ -64,7 +65,7 @@ BOOST_AUTO_TEST_CASE(signet_parse_tests)
{
ArgsManager signet_argsman;
signet_argsman.ForceSetArg("-signetchallenge", "51"); // set challenge to OP_TRUE
- const auto signet_params = CreateChainParams(signet_argsman, CBaseChainParams::SIGNET);
+ const auto signet_params = CreateChainParams(signet_argsman, ChainType::SIGNET);
CBlock block;
BOOST_CHECK(signet_params->GetConsensus().signet_challenge == std::vector<uint8_t>{OP_TRUE});
CScript challenge{OP_TRUE};
@@ -124,10 +125,10 @@ BOOST_AUTO_TEST_CASE(signet_parse_tests)
//! Test retrieval of valid assumeutxo values.
BOOST_AUTO_TEST_CASE(test_assumeutxo)
{
- const auto params = CreateChainParams(*m_node.args, CBaseChainParams::REGTEST);
+ const auto params = CreateChainParams(*m_node.args, ChainType::REGTEST);
// These heights don't have assumeutxo configurations associated, per the contents
- // of chainparams.cpp.
+ // of kernel/chainparams.cpp.
std::vector<int> bad_heights{0, 100, 111, 115, 209, 211};
for (auto empty : bad_heights) {
diff --git a/src/test/validationinterface_tests.cpp b/src/test/validationinterface_tests.cpp
index ceba689e52..576768a625 100644
--- a/src/test/validationinterface_tests.cpp
+++ b/src/test/validationinterface_tests.cpp
@@ -10,6 +10,8 @@
#include <util/check.h>
#include <validationinterface.h>
+#include <atomic>
+
BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup)
struct TestSubscriberNoop final : public CValidationInterface {
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 80c00036e7..9e69992752 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -7,6 +7,7 @@
#include <consensus/params.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
#include <versionbits.h>
#include <boost/test/unit_test.hpp>
@@ -418,8 +419,8 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// check that any deployment on any chain can conceivably reach both
// ACTIVE and FAILED states in roughly the way we expect
- for (const auto& chain_name : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST}) {
- const auto chainParams = CreateChainParams(*m_node.args, chain_name);
+ for (const auto& chain_type: {ChainType::MAIN, ChainType::TESTNET, ChainType::SIGNET, ChainType::REGTEST}) {
+ const auto chainParams = CreateChainParams(*m_node.args, chain_type);
uint32_t chain_all_vbits{0};
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
const auto dep = static_cast<Consensus::DeploymentPos>(i);
@@ -440,7 +441,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// deployment that's not always/never active
ArgsManager args;
args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999"); // January 1, 2008 - December 31, 2008
- const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST);
+ const auto chainParams = CreateChainParams(args, ChainType::REGTEST);
check_computeblockversion(vbcache, chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY);
}
@@ -450,7 +451,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// live deployment
ArgsManager args;
args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999:403200"); // January 1, 2008 - December 31, 2008, min act height 403200
- const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST);
+ const auto chainParams = CreateChainParams(args, ChainType::REGTEST);
check_computeblockversion(vbcache, chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY);
}
}
diff --git a/src/timedata.cpp b/src/timedata.cpp
index a0646b4707..15ca90ee6a 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -8,11 +8,12 @@
#include <timedata.h>
+#include <common/args.h>
+#include <logging.h>
#include <netaddress.h>
#include <node/interface_ui.h>
#include <sync.h>
#include <tinyformat.h>
-#include <util/system.h>
#include <util/translation.h>
#include <warnings.h>
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index d4daeacd3e..98d68f93e9 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -7,15 +7,16 @@
#include <chainparams.h>
#include <chainparamsbase.h>
+#include <common/args.h>
#include <compat/compat.h>
#include <crypto/hmac_sha256.h>
+#include <logging.h>
#include <net.h>
#include <netaddress.h>
#include <netbase.h>
#include <util/readwritefile.h>
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
-#include <util/system.h>
#include <util/thread.h>
#include <util/time.h>
@@ -132,15 +133,15 @@ bool TorControlConnection::Connect(const std::string& tor_control_center, const
Disconnect();
}
- CService control_service;
- if (!Lookup(tor_control_center, control_service, 9051, fNameLookup)) {
+ const std::optional<CService> control_service{Lookup(tor_control_center, 9051, fNameLookup)};
+ if (!control_service.has_value()) {
LogPrintf("tor: Failed to look up control center %s\n", tor_control_center);
return false;
}
struct sockaddr_storage control_address;
socklen_t control_address_len = sizeof(control_address);
- if (!control_service.GetSockAddr(reinterpret_cast<struct sockaddr*>(&control_address), &control_address_len)) {
+ if (!control_service.value().GetSockAddr(reinterpret_cast<struct sockaddr*>(&control_address), &control_address_len)) {
LogPrintf("tor: Error parsing socket address %s\n", tor_control_center);
return false;
}
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 6563a2ef42..afc5413db0 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -8,8 +8,8 @@
#ifndef BITCOIN_TORCONTROL_H
#define BITCOIN_TORCONTROL_H
-#include <fs.h>
#include <netaddress.h>
+#include <util/fs.h>
#include <boost/signals2/signal.hpp>
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 15351a4355..b2095bd4a3 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -31,22 +31,22 @@ static constexpr uint8_t DB_COINS{'c'};
static constexpr uint8_t DB_TXINDEX_BLOCK{'T'};
// uint8_t DB_TXINDEX{'t'}
-std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db)
+util::Result<void> CheckLegacyTxindex(CBlockTreeDB& block_tree_db)
{
CBlockLocator ignored{};
if (block_tree_db.Read(DB_TXINDEX_BLOCK, ignored)) {
- return _("The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.");
+ return util::Error{_("The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.")};
}
bool txindex_legacy_flag{false};
block_tree_db.ReadFlag("txindex", txindex_legacy_flag);
if (txindex_legacy_flag) {
// Disable legacy txindex and warn once about occupied disk space
if (!block_tree_db.WriteFlag("txindex", false)) {
- return Untranslated("Failed to write block index db flag 'txindex'='0'");
+ return util::Error{Untranslated("Failed to write block index db flag 'txindex'='0'")};
}
- return _("The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.");
+ return util::Error{_("The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.")};
}
- return std::nullopt;
+ return {};
}
bool CCoinsViewDB::NeedsUpgrade()
diff --git a/src/txdb.h b/src/txdb.h
index 8a876349fb..04d0ecb39f 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -10,8 +10,12 @@
#include <dbwrapper.h>
#include <kernel/cs_main.h>
#include <sync.h>
-#include <fs.h>
+#include <util/fs.h>
+#include <util/result.h>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
#include <memory>
#include <optional>
#include <string>
@@ -20,11 +24,11 @@
class CBlockFileInfo;
class CBlockIndex;
+class COutPoint;
class uint256;
namespace Consensus {
struct Params;
};
-struct bilingual_str;
//! -dbcache default (MiB)
static const int64_t nDefaultDbCache = 450;
@@ -98,6 +102,6 @@ public:
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
};
-std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db);
+[[nodiscard]] util::Result<void> CheckLegacyTxindex(CBlockTreeDB& block_tree_db);
#endif // BITCOIN_TXDB_H
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 032dfee3ea..845fbdb66e 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -7,9 +7,11 @@
#include <chain.h>
#include <coins.h>
+#include <common/system.h>
#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
+#include <logging.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/settings.h>
@@ -18,13 +20,13 @@
#include <util/moneystr.h>
#include <util/overflow.h>
#include <util/result.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/trace.h>
#include <util/translation.h>
#include <validationinterface.h>
#include <cmath>
+#include <numeric>
#include <optional>
#include <string_view>
#include <utility>
@@ -73,7 +75,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan
}
// descendants now contains all in-mempool descendants of updateIt.
// Update and add to cached descendant map
- int64_t modifySize = 0;
+ int32_t modifySize = 0;
CAmount modifyFee = 0;
int64_t modifyCount = 0;
for (const CTxMemPoolEntry& descendant : descendants) {
@@ -89,7 +91,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan
// Don't directly remove the transaction here -- doing so would
// invalidate iterators in cachedDescendants. Mark it for removal
// by inserting into descendants_to_remove.
- if (descendant.GetCountWithAncestors() > uint64_t(m_limits.ancestor_count) || descendant.GetSizeWithAncestors() > uint64_t(m_limits.ancestor_size_vbytes)) {
+ if (descendant.GetCountWithAncestors() > uint64_t(m_limits.ancestor_count) || descendant.GetSizeWithAncestors() > m_limits.ancestor_size_vbytes) {
descendants_to_remove.insert(descendant.GetTx().GetHash());
}
}
@@ -276,8 +278,8 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
for (const CTxMemPoolEntry& parent : parents) {
UpdateChild(mapTx.iterator_to(parent), it, add);
}
- const int64_t updateCount = (add ? 1 : -1);
- const int64_t updateSize = updateCount * it->GetTxSize();
+ const int32_t updateCount = (add ? 1 : -1);
+ const int32_t updateSize{updateCount * it->GetTxSize()};
const CAmount updateFee = updateCount * it->GetModifiedFee();
for (txiter ancestorIt : setAncestors) {
mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(updateSize, updateFee, updateCount); });
@@ -321,7 +323,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
setEntries setDescendants;
CalculateDescendants(removeIt, setDescendants);
setDescendants.erase(removeIt); // don't update state for self
- int64_t modifySize = -((int64_t)removeIt->GetTxSize());
+ int32_t modifySize = -removeIt->GetTxSize();
CAmount modifyFee = -removeIt->GetModifiedFee();
int modifySigOps = -removeIt->GetSigOpCost();
for (txiter dit : setDescendants) {
@@ -363,22 +365,22 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b
}
}
-void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
+void CTxMemPoolEntry::UpdateDescendantState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount)
{
nSizeWithDescendants += modifySize;
- assert(int64_t(nSizeWithDescendants) > 0);
+ assert(nSizeWithDescendants > 0);
nModFeesWithDescendants = SaturatingAdd(nModFeesWithDescendants, modifyFee);
- nCountWithDescendants += modifyCount;
- assert(int64_t(nCountWithDescendants) > 0);
+ m_count_with_descendants += modifyCount;
+ assert(m_count_with_descendants > 0);
}
-void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
+void CTxMemPoolEntry::UpdateAncestorState(int32_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
{
nSizeWithAncestors += modifySize;
- assert(int64_t(nSizeWithAncestors) > 0);
+ assert(nSizeWithAncestors > 0);
nModFeesWithAncestors = SaturatingAdd(nModFeesWithAncestors, modifyFee);
- nCountWithAncestors += modifyCount;
- assert(int64_t(nCountWithAncestors) > 0);
+ m_count_with_ancestors += modifyCount;
+ assert(m_count_with_ancestors > 0);
nSigOpCostWithAncestors += modifySigOps;
assert(int(nSigOpCostWithAncestors) >= 0);
}
@@ -697,7 +699,7 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
// Verify ancestor state is correct.
auto ancestors{AssumeCalculateMemPoolAncestors(__func__, *it, Limits::NoLimits())};
uint64_t nCountCheck = ancestors.size() + 1;
- uint64_t nSizeCheck = it->GetTxSize();
+ int32_t nSizeCheck = it->GetTxSize();
CAmount nFeesCheck = it->GetModifiedFee();
int64_t nSigOpCheck = it->GetSigOpCost();
@@ -718,7 +720,7 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
// Check children against mapNextTx
CTxMemPoolEntry::Children setChildrenCheck;
auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
- uint64_t child_sizes = 0;
+ int32_t child_sizes{0};
for (; iter != mapNextTx.end() && iter->first->hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
@@ -754,11 +756,16 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
bool CTxMemPool::CompareDepthAndScore(const uint256& hasha, const uint256& hashb, bool wtxid)
{
+ /* Return `true` if hasha should be considered sooner than hashb. Namely when:
+ * a is not in the mempool, but b is
+ * both are in the mempool and a has fewer ancestors than b
+ * both are in the mempool and a has a higher score than b
+ */
LOCK(cs);
- indexed_transaction_set::const_iterator i = wtxid ? get_iter_from_wtxid(hasha) : mapTx.find(hasha);
- if (i == mapTx.end()) return false;
indexed_transaction_set::const_iterator j = wtxid ? get_iter_from_wtxid(hashb) : mapTx.find(hashb);
- if (j == mapTx.end()) return true;
+ if (j == mapTx.end()) return false;
+ indexed_transaction_set::const_iterator i = wtxid ? get_iter_from_wtxid(hasha) : mapTx.find(hasha);
+ if (i == mapTx.end()) return true;
uint64_t counta = i->GetCountWithAncestors();
uint64_t countb = j->GetCountWithAncestors();
if (counta == countb) {
@@ -869,8 +876,17 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
}
++nTransactionsUpdated;
}
+ if (delta == 0) {
+ mapDeltas.erase(hash);
+ LogPrintf("PrioritiseTransaction: %s (%sin mempool) delta cleared\n", hash.ToString(), it == mapTx.end() ? "not " : "");
+ } else {
+ LogPrintf("PrioritiseTransaction: %s (%sin mempool) fee += %s, new delta=%s\n",
+ hash.ToString(),
+ it == mapTx.end() ? "not " : "",
+ FormatMoney(nFeeDelta),
+ FormatMoney(delta));
+ }
}
- LogPrintf("PrioritiseTransaction: %s fee += %s\n", hash.ToString(), FormatMoney(nFeeDelta));
}
void CTxMemPool::ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const
@@ -889,6 +905,22 @@ void CTxMemPool::ClearPrioritisation(const uint256& hash)
mapDeltas.erase(hash);
}
+std::vector<CTxMemPool::delta_info> CTxMemPool::GetPrioritisedTransactions() const
+{
+ AssertLockNotHeld(cs);
+ LOCK(cs);
+ std::vector<delta_info> result;
+ result.reserve(mapDeltas.size());
+ for (const auto& [txid, delta] : mapDeltas) {
+ const auto iter{mapTx.find(txid)};
+ const bool in_mempool{iter != mapTx.end()};
+ std::optional<CAmount> modified_fee;
+ if (in_mempool) modified_fee = iter->GetModifiedFee();
+ result.emplace_back(delta_info{in_mempool, delta, modified_fee, txid});
+ }
+ return result;
+}
+
const CTransaction* CTxMemPool::GetConflictTx(const COutPoint& prevout) const
{
const auto it = mapNextTx.find(prevout);
@@ -912,6 +944,19 @@ CTxMemPool::setEntries CTxMemPool::GetIterSet(const std::set<uint256>& hashes) c
return ret;
}
+std::vector<CTxMemPool::txiter> CTxMemPool::GetIterVec(const std::vector<uint256>& txids) const
+{
+ AssertLockHeld(cs);
+ std::vector<txiter> ret;
+ ret.reserve(txids.size());
+ for (const auto& txid : txids) {
+ const auto it{GetIter(txid)};
+ if (!it) return {};
+ ret.push_back(*it);
+ }
+ return ret;
+}
+
bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
{
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -1141,7 +1186,6 @@ void CTxMemPool::SetLoadTried(bool load_tried)
m_load_tried = load_tried;
}
-
std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
{
switch (r) {
@@ -1154,3 +1198,30 @@ std::string RemovalReasonToString(const MemPoolRemovalReason& r) noexcept
}
assert(false);
}
+
+std::vector<CTxMemPool::txiter> CTxMemPool::GatherClusters(const std::vector<uint256>& txids) const
+{
+ AssertLockHeld(cs);
+ std::vector<txiter> clustered_txs{GetIterVec(txids)};
+ // Use epoch: visiting an entry means we have added it to the clustered_txs vector. It does not
+ // necessarily mean the entry has been processed.
+ WITH_FRESH_EPOCH(m_epoch);
+ for (const auto& it : clustered_txs) {
+ visited(it);
+ }
+ // i = index of where the list of entries to process starts
+ for (size_t i{0}; i < clustered_txs.size(); ++i) {
+ // DoS protection: if there are 500 or more entries to process, just quit.
+ if (clustered_txs.size() > 500) return {};
+ const txiter& tx_iter = clustered_txs.at(i);
+ for (const auto& entries : {tx_iter->GetMemPoolParentsConst(), tx_iter->GetMemPoolChildrenConst()}) {
+ for (const CTxMemPoolEntry& entry : entries) {
+ const auto entry_it = mapTx.iterator_to(entry);
+ if (!visited(entry_it)) {
+ clustered_txs.push_back(entry_it);
+ }
+ }
+ }
+ }
+ return clustered_txs;
+}
diff --git a/src/txmempool.h b/src/txmempool.h
index 2c3cb7e9db..846def02cd 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -33,8 +33,11 @@
#include <util/result.h>
#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/tag.hpp>
#include <boost/multi_index_container.hpp>
class CBlockIndex;
@@ -219,7 +222,7 @@ struct TxMempoolInfo
CAmount fee;
/** Virtual size of the transaction. */
- size_t vsize;
+ int32_t vsize;
/** The fee delta. */
int64_t nFeeDelta;
@@ -516,15 +519,35 @@ public:
void ApplyDelta(const uint256& hash, CAmount &nFeeDelta) const EXCLUSIVE_LOCKS_REQUIRED(cs);
void ClearPrioritisation(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ struct delta_info {
+ /** Whether this transaction is in the mempool. */
+ const bool in_mempool;
+ /** The fee delta added using PrioritiseTransaction(). */
+ const CAmount delta;
+ /** The modified fee (base fee + delta) of this entry. Only present if in_mempool=true. */
+ std::optional<CAmount> modified_fee;
+ /** The prioritised transaction's txid. */
+ const uint256 txid;
+ };
+ /** Return a vector of all entries in mapDeltas with their corresponding delta_info. */
+ std::vector<delta_info> GetPrioritisedTransactions() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
+
/** Get the transaction in the pool that spends the same prevout */
const CTransaction* GetConflictTx(const COutPoint& prevout) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Returns an iterator to the given hash, if found */
std::optional<txiter> GetIter(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs);
- /** Translate a set of hashes into a set of pool iterators to avoid repeated lookups */
+ /** Translate a set of hashes into a set of pool iterators to avoid repeated lookups.
+ * Does not require that all of the hashes correspond to actual transactions in the mempool,
+ * only returns the ones that exist. */
setEntries GetIterSet(const std::set<uint256>& hashes) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ /** Translate a list of hashes into a list of mempool iterators to avoid repeated lookups.
+ * The nth element in txids becomes the nth element in the returned vector. If any of the txids
+ * don't actually exist in the mempool, returns an empty vector. */
+ std::vector<txiter> GetIterVec(const std::vector<uint256>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
/** Remove a set of transactions from the mempool.
* If a transaction is in this set, then all in-mempool descendants must
* also be in the set, unless this transaction is being removed for being
@@ -585,6 +608,12 @@ public:
const Limits& limits,
bool fSearchForParents = true) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ /** Collect the entire cluster of connected transactions for each transaction in txids.
+ * All txids must correspond to transaction entries in the mempool, otherwise this returns an
+ * empty vector. This call will also exit early and return an empty vector if it collects 500 or
+ * more transactions as a DoS protection. */
+ std::vector<txiter> GatherClusters(const std::vector<uint256>& txids) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+
/** Calculate all in-mempool ancestors of a set of transactions not already in the mempool and
* check ancestor and descendant limits. Heuristics are used to estimate the ancestor and
* descendant count of all entries if the package were to be added to the mempool. The limits
diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp
index 19f9fae998..af86baa8ac 100644
--- a/src/txorphanage.cpp
+++ b/src/txorphanage.cpp
@@ -55,10 +55,10 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
int TxOrphanage::EraseTx(const uint256& txid)
{
LOCK(m_mutex);
- return _EraseTx(txid);
+ return EraseTxNoLock(txid);
}
-int TxOrphanage::_EraseTx(const uint256& txid)
+int TxOrphanage::EraseTxNoLock(const uint256& txid)
{
AssertLockHeld(m_mutex);
std::map<uint256, OrphanTx>::iterator it = m_orphans.find(txid);
@@ -103,7 +103,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
std::map<uint256, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
if (maybeErase->second.fromPeer == peer)
{
- nErased += _EraseTx(maybeErase->second.tx->GetHash());
+ nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
}
}
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
@@ -125,7 +125,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
std::map<uint256, OrphanTx>::iterator maybeErase = iter++;
if (maybeErase->second.nTimeExpire <= nNow) {
- nErased += _EraseTx(maybeErase->second.tx->GetHash());
+ nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
} else {
nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime);
}
@@ -139,7 +139,7 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
// Evict a random orphan:
size_t randompos = rng.randrange(m_orphan_list.size());
- _EraseTx(m_orphan_list[randompos]->first);
+ EraseTxNoLock(m_orphan_list[randompos]->first);
++nEvicted;
}
if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
@@ -231,7 +231,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
if (vOrphanErase.size()) {
int nErased = 0;
for (const uint256& orphanHash : vOrphanErase) {
- nErased += _EraseTx(orphanHash);
+ nErased += EraseTxNoLock(orphanHash);
}
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
diff --git a/src/txorphanage.h b/src/txorphanage.h
index 45276c6c98..a4705bf382 100644
--- a/src/txorphanage.h
+++ b/src/txorphanage.h
@@ -99,7 +99,7 @@ protected:
std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(m_mutex);
/** Erase an orphan by txid */
- int _EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
+ int EraseTxNoLock(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
};
#endif // BITCOIN_TXORPHANAGE_H
diff --git a/src/txrequest.cpp b/src/txrequest.cpp
index 96a3d2eeeb..dd042103bd 100644
--- a/src/txrequest.cpp
+++ b/src/txrequest.cpp
@@ -10,8 +10,12 @@
#include <random.h>
#include <uint256.h>
-#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/tag.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/tuple/tuple.hpp>
#include <chrono>
#include <unordered_map>
@@ -69,7 +73,7 @@ struct Announcement {
const bool m_is_wtxid : 1;
/** What state this announcement is in.
- * This is a uint8_t instead of a State to silence a GCC warning in versions prior to 8.4 and 9.3.
+ * This is a uint8_t instead of a State to silence a GCC warning in versions prior to 9.3.
* See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414 */
uint8_t m_state : 3;
diff --git a/src/uint256.h b/src/uint256.h
index 1cc3721487..dc8887287a 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -22,6 +22,7 @@ class base_blob
{
protected:
static constexpr int WIDTH = BITS / 8;
+ static_assert(BITS % 8 == 0, "base_blob currently only supports whole bytes.");
std::array<uint8_t, WIDTH> m_data;
static_assert(WIDTH == sizeof(m_data), "Sanity check");
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index d501c3fb69..94f80f9c27 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -87,7 +87,7 @@ public:
template <class It>
void push_backV(It first, It last);
- void __pushKV(std::string key, UniValue val);
+ void pushKVEnd(std::string key, UniValue val);
void pushKV(std::string key, UniValue val);
void pushKVs(UniValue obj);
@@ -123,7 +123,7 @@ public:
const UniValue& get_array() const;
enum VType type() const { return getType(); }
- friend const UniValue& find_value( const UniValue& obj, const std::string& name);
+ const UniValue& find_value(std::string_view key) const;
};
template <class It>
@@ -201,6 +201,4 @@ static inline bool json_isspace(int ch)
extern const UniValue NullUniValue;
-const UniValue& find_value( const UniValue& obj, const std::string& name);
-
#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 5aa39edb75..656d2e8203 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -115,7 +115,7 @@ void UniValue::push_backV(const std::vector<UniValue>& vec)
values.insert(values.end(), vec.begin(), vec.end());
}
-void UniValue::__pushKV(std::string key, UniValue val)
+void UniValue::pushKVEnd(std::string key, UniValue val)
{
checkType(VOBJ);
@@ -131,7 +131,7 @@ void UniValue::pushKV(std::string key, UniValue val)
if (findKey(key, idx))
values[idx] = std::move(val);
else
- __pushKV(std::move(key), std::move(val));
+ pushKVEnd(std::move(key), std::move(val));
}
void UniValue::pushKVs(UniValue obj)
@@ -140,7 +140,7 @@ void UniValue::pushKVs(UniValue obj)
obj.checkType(VOBJ);
for (size_t i = 0; i < obj.keys.size(); i++)
- __pushKV(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
+ pushKVEnd(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
}
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
@@ -230,12 +230,13 @@ const char *uvTypeName(UniValue::VType t)
return nullptr;
}
-const UniValue& find_value(const UniValue& obj, const std::string& name)
+const UniValue& UniValue::find_value(std::string_view key) const
{
- for (unsigned int i = 0; i < obj.keys.size(); i++)
- if (obj.keys[i] == name)
- return obj.values.at(i);
-
+ for (unsigned int i = 0; i < keys.size(); ++i) {
+ if (keys[i] == key) {
+ return values.at(i);
+ }
+ }
return NullUniValue;
}
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index 5ddf300393..8b90448b36 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -86,7 +86,7 @@ void univalue_push_throw()
UniValue j;
BOOST_CHECK_THROW(j.push_back(1), std::runtime_error);
BOOST_CHECK_THROW(j.push_backV({1}), std::runtime_error);
- BOOST_CHECK_THROW(j.__pushKV("k", 1), std::runtime_error);
+ BOOST_CHECK_THROW(j.pushKVEnd("k", 1), std::runtime_error);
BOOST_CHECK_THROW(j.pushKV("k", 1), std::runtime_error);
BOOST_CHECK_THROW(j.pushKVs({}), std::runtime_error);
}
@@ -364,7 +364,7 @@ void univalue_object()
obj.setObject();
UniValue uv;
uv.setInt(42);
- obj.__pushKV("age", uv);
+ obj.pushKVEnd("age", uv);
BOOST_CHECK_EQUAL(obj.size(), 1);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42");
@@ -412,6 +412,33 @@ void univalue_readwrite()
BOOST_CHECK_EQUAL(strJson1, v.write());
+ // Valid
+ BOOST_CHECK(v.read("1.0") && (v.get_real() == 1.0));
+ BOOST_CHECK(v.read("true") && v.get_bool());
+ BOOST_CHECK(v.read("[false]") && !v[0].get_bool());
+ BOOST_CHECK(v.read("{\"a\": true}") && v["a"].get_bool());
+ BOOST_CHECK(v.read("{\"1\": \"true\"}") && (v["1"].get_str() == "true"));
+ // Valid, with leading or trailing whitespace
+ BOOST_CHECK(v.read(" 1.0") && (v.get_real() == 1.0));
+ BOOST_CHECK(v.read("1.0 ") && (v.get_real() == 1.0));
+ BOOST_CHECK(v.read("0.00000000000000000000000000000000000001e+30 ") && v.get_real() == 1e-8);
+
+ BOOST_CHECK(!v.read(".19e-6")); //should fail, missing leading 0, therefore invalid JSON
+ // Invalid, initial garbage
+ BOOST_CHECK(!v.read("[1.0"));
+ BOOST_CHECK(!v.read("a1.0"));
+ // Invalid, trailing garbage
+ BOOST_CHECK(!v.read("1.0sds"));
+ BOOST_CHECK(!v.read("1.0]"));
+ // Invalid, keys have to be names
+ BOOST_CHECK(!v.read("{1: \"true\"}"));
+ BOOST_CHECK(!v.read("{true: 1}"));
+ BOOST_CHECK(!v.read("{[1]: 1}"));
+ BOOST_CHECK(!v.read("{{\"a\": \"a\"}: 1}"));
+ // BTC addresses should fail parsing
+ BOOST_CHECK(!v.read("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
+ BOOST_CHECK(!v.read("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"));
+
/* Check for (correctly reporting) a parsing error if the initial
JSON construct is followed by more stuff. Note that whitespace
is, of course, exempt. */
diff --git a/src/util/any.h b/src/util/any.h
new file mode 100644
index 0000000000..4562c5bd8a
--- /dev/null
+++ b/src/util/any.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2023 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_ANY_H
+#define BITCOIN_UTIL_ANY_H
+
+#include <any>
+
+namespace util {
+
+/**
+ * Helper function to access the contained object of a std::any instance.
+ * Returns a pointer to the object if passed instance has a value and the type
+ * matches, nullptr otherwise.
+ */
+template<typename T>
+T* AnyPtr(const std::any& any) noexcept
+{
+ T* const* ptr = std::any_cast<T*>(&any);
+ return ptr ? *ptr : nullptr;
+}
+
+} // namespace util
+
+#endif // BITCOIN_UTIL_ANY_H
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index 4b548c5a4d..360573cbae 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -6,10 +6,10 @@
#include <clientversion.h>
#include <crypto/common.h>
-#include <fs.h>
#include <logging.h>
#include <serialize.h>
#include <streams.h>
+#include <util/fs.h>
#include <algorithm>
#include <cassert>
diff --git a/src/util/asmap.h b/src/util/asmap.h
index 844037f816..08a88f1b3c 100644
--- a/src/util/asmap.h
+++ b/src/util/asmap.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_ASMAP_H
#define BITCOIN_UTIL_ASMAP_H
-#include <fs.h>
+#include <util/fs.h>
#include <cstdint>
#include <vector>
diff --git a/src/util/batchpriority.cpp b/src/util/batchpriority.cpp
new file mode 100644
index 0000000000..c73aef1eb4
--- /dev/null
+++ b/src/util/batchpriority.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) 2023 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 <logging.h>
+#include <util/syserror.h>
+
+#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
+#include <pthread.h>
+#include <pthread_np.h>
+#endif
+
+#ifndef WIN32
+#include <sched.h>
+#endif
+
+void ScheduleBatchPriority()
+{
+#ifdef SCHED_BATCH
+ const static sched_param param{};
+ const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param);
+ if (rc != 0) {
+ LogPrintf("Failed to pthread_setschedparam: %s\n", SysErrorString(rc));
+ }
+#endif
+}
diff --git a/src/util/batchpriority.h b/src/util/batchpriority.h
new file mode 100644
index 0000000000..5ffc8dd684
--- /dev/null
+++ b/src/util/batchpriority.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2023 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_BATCHPRIORITY_H
+#define BITCOIN_UTIL_BATCHPRIORITY_H
+
+/**
+ * On platforms that support it, tell the kernel the calling thread is
+ * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
+ *
+ */
+void ScheduleBatchPriority();
+
+#endif // BITCOIN_UTIL_BATCHPRIORITY_H
diff --git a/src/util/bip32.cpp b/src/util/bip32.cpp
index c4b7120394..4ab14bd704 100644
--- a/src/util/bip32.cpp
+++ b/src/util/bip32.cpp
@@ -25,7 +25,7 @@ bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypa
}
// Finds whether it is hardened
uint32_t path = 0;
- size_t pos = item.find("'");
+ size_t pos = item.find('\'');
if (pos != std::string::npos) {
// The hardened tick can only be in the last index of the string
if (pos != item.size() - 1) {
@@ -51,17 +51,17 @@ bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypa
return true;
}
-std::string FormatHDKeypath(const std::vector<uint32_t>& path)
+std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe)
{
std::string ret;
for (auto i : path) {
ret += strprintf("/%i", (i << 1) >> 1);
- if (i >> 31) ret += '\'';
+ if (i >> 31) ret += apostrophe ? '\'' : 'h';
}
return ret;
}
-std::string WriteHDKeypath(const std::vector<uint32_t>& keypath)
+std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe)
{
- return "m" + FormatHDKeypath(keypath);
+ return "m" + FormatHDKeypath(keypath, apostrophe);
}
diff --git a/src/util/bip32.h b/src/util/bip32.h
index b720cb5638..ea5f192c07 100644
--- a/src/util/bip32.h
+++ b/src/util/bip32.h
@@ -13,7 +13,7 @@
[[nodiscard]] bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath);
/** Write HD keypaths as strings */
-std::string WriteHDKeypath(const std::vector<uint32_t>& keypath);
-std::string FormatHDKeypath(const std::vector<uint32_t>& path);
+std::string WriteHDKeypath(const std::vector<uint32_t>& keypath, bool apostrophe = false);
+std::string FormatHDKeypath(const std::vector<uint32_t>& path, bool apostrophe = false);
#endif // BITCOIN_UTIL_BIP32_H
diff --git a/src/util/chaintype.cpp b/src/util/chaintype.cpp
new file mode 100644
index 0000000000..8a199e352a
--- /dev/null
+++ b/src/util/chaintype.cpp
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 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 <util/chaintype.h>
+
+#include <cassert>
+#include <optional>
+#include <string>
+
+std::string ChainTypeToString(ChainType chain)
+{
+ switch (chain) {
+ case ChainType::MAIN:
+ return "main";
+ case ChainType::TESTNET:
+ return "test";
+ case ChainType::SIGNET:
+ return "signet";
+ case ChainType::REGTEST:
+ return "regtest";
+ }
+ assert(false);
+}
+
+std::optional<ChainType> ChainTypeFromString(std::string_view chain)
+{
+ if (chain == "main") {
+ return ChainType::MAIN;
+ } else if (chain == "test") {
+ return ChainType::TESTNET;
+ } else if (chain == "signet") {
+ return ChainType::SIGNET;
+ } else if (chain == "regtest") {
+ return ChainType::REGTEST;
+ } else {
+ return std::nullopt;
+ }
+}
diff --git a/src/util/chaintype.h b/src/util/chaintype.h
new file mode 100644
index 0000000000..c73985df57
--- /dev/null
+++ b/src/util/chaintype.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2023 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_CHAINTYPE_H
+#define BITCOIN_UTIL_CHAINTYPE_H
+
+#include <optional>
+#include <string>
+
+enum class ChainType {
+ MAIN,
+ TESTNET,
+ SIGNET,
+ REGTEST,
+};
+
+std::string ChainTypeToString(ChainType chain);
+
+std::optional<ChainType> ChainTypeFromString(std::string_view chain);
+
+#endif // BITCOIN_UTIL_CHAINTYPE_H
diff --git a/src/fs.cpp b/src/util/fs.cpp
index 64411fe41f..e8fb72670f 100644
--- a/src/fs.cpp
+++ b/src/util/fs.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 <fs.h>
+#include <util/fs.h>
#include <util/syserror.h>
#ifndef WIN32
diff --git a/src/fs.h b/src/util/fs.h
index 0ece256acb..8f79f6cba6 100644
--- a/src/fs.h
+++ b/src/util/fs.h
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_FS_H
-#define BITCOIN_FS_H
+#ifndef BITCOIN_UTIL_FS_H
+#define BITCOIN_UTIL_FS_H
#include <tinyformat.h>
#include <cstdio>
-#include <filesystem>
+#include <filesystem> // IWYU pragma: export
#include <functional>
#include <iomanip>
#include <ios>
@@ -248,4 +248,4 @@ template<> inline void formatValue(std::ostream&, const char*, const char*, int,
template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete;
} // namespace tinyformat
-#endif // BITCOIN_FS_H
+#endif // BITCOIN_UTIL_FS_H
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
new file mode 100644
index 0000000000..d05cb8a63d
--- /dev/null
+++ b/src/util/fs_helpers.cpp
@@ -0,0 +1,295 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2023 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 <util/fs_helpers.h>
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <logging.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <util/fs.h>
+#include <util/getuniquepath.h>
+
+#include <cerrno>
+#include <filesystem>
+#include <fstream>
+#include <map>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+#ifndef WIN32
+// for posix_fallocate, in configure.ac we check if it is present after this
+#ifdef __linux__
+
+#ifdef _POSIX_C_SOURCE
+#undef _POSIX_C_SOURCE
+#endif
+
+#define _POSIX_C_SOURCE 200112L
+
+#endif // __linux__
+
+#include <fcntl.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#else
+#include <io.h> /* For _get_osfhandle, _chsize */
+#include <shlobj.h> /* For SHGetSpecialFolderPathW */
+#endif // WIN32
+
+/** Mutex to protect dir_locks. */
+static GlobalMutex cs_dir_locks;
+/** A map that contains all the currently held directory locks. After
+ * successful locking, these will be held here until the global destructor
+ * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
+ * is called.
+ */
+static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks);
+
+bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only)
+{
+ LOCK(cs_dir_locks);
+ fs::path pathLockFile = directory / lockfile_name;
+
+ // If a lock for this directory already exists in the map, don't try to re-lock it
+ if (dir_locks.count(fs::PathToString(pathLockFile))) {
+ return true;
+ }
+
+ // Create empty lock file if it doesn't exist.
+ FILE* file = fsbridge::fopen(pathLockFile, "a");
+ if (file) fclose(file);
+ auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
+ if (!lock->TryLock()) {
+ return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
+ }
+ if (!probe_only) {
+ // Lock successful and we're not just probing, put it into the map
+ dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
+ }
+ return true;
+}
+
+void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name)
+{
+ LOCK(cs_dir_locks);
+ dir_locks.erase(fs::PathToString(directory / lockfile_name));
+}
+
+void ReleaseDirectoryLocks()
+{
+ LOCK(cs_dir_locks);
+ dir_locks.clear();
+}
+
+bool DirIsWritable(const fs::path& directory)
+{
+ fs::path tmpFile = GetUniquePath(directory);
+
+ FILE* file = fsbridge::fopen(tmpFile, "a");
+ if (!file) return false;
+
+ fclose(file);
+ remove(tmpFile);
+
+ return true;
+}
+
+bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)
+{
+ constexpr uint64_t min_disk_space = 52428800; // 50 MiB
+
+ uint64_t free_bytes_available = fs::space(dir).available;
+ return free_bytes_available >= min_disk_space + additional_bytes;
+}
+
+std::streampos GetFileSize(const char* path, std::streamsize max)
+{
+ std::ifstream file{path, std::ios::binary};
+ file.ignore(max);
+ return file.gcount();
+}
+
+bool FileCommit(FILE* file)
+{
+ if (fflush(file) != 0) { // harmless if redundantly called
+ LogPrintf("%s: fflush failed: %d\n", __func__, errno);
+ return false;
+ }
+#ifdef WIN32
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
+ if (FlushFileBuffers(hFile) == 0) {
+ LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
+ return false;
+ }
+#elif defined(MAC_OSX) && defined(F_FULLFSYNC)
+ if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
+ LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
+ return false;
+ }
+#elif HAVE_FDATASYNC
+ if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
+ LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
+ return false;
+ }
+#else
+ if (fsync(fileno(file)) != 0 && errno != EINVAL) {
+ LogPrintf("%s: fsync failed: %d\n", __func__, errno);
+ return false;
+ }
+#endif
+ return true;
+}
+
+void DirectoryCommit(const fs::path& dirname)
+{
+#ifndef WIN32
+ FILE* file = fsbridge::fopen(dirname, "r");
+ if (file) {
+ fsync(fileno(file));
+ fclose(file);
+ }
+#endif
+}
+
+bool TruncateFile(FILE* file, unsigned int length)
+{
+#if defined(WIN32)
+ return _chsize(_fileno(file), length) == 0;
+#else
+ return ftruncate(fileno(file), length) == 0;
+#endif
+}
+
+/**
+ * this function tries to raise the file descriptor limit to the requested number.
+ * It returns the actual file descriptor limit (which may be more or less than nMinFD)
+ */
+int RaiseFileDescriptorLimit(int nMinFD)
+{
+#if defined(WIN32)
+ return 2048;
+#else
+ struct rlimit limitFD;
+ if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
+ if (limitFD.rlim_cur < (rlim_t)nMinFD) {
+ limitFD.rlim_cur = nMinFD;
+ if (limitFD.rlim_cur > limitFD.rlim_max)
+ limitFD.rlim_cur = limitFD.rlim_max;
+ setrlimit(RLIMIT_NOFILE, &limitFD);
+ getrlimit(RLIMIT_NOFILE, &limitFD);
+ }
+ return limitFD.rlim_cur;
+ }
+ return nMinFD; // getrlimit failed, assume it's fine
+#endif
+}
+
+/**
+ * this function tries to make a particular range of a file allocated (corresponding to disk space)
+ * it is advisory, and the range specified in the arguments will never contain live data
+ */
+void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
+{
+#if defined(WIN32)
+ // Windows-specific version
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
+ LARGE_INTEGER nFileSize;
+ int64_t nEndPos = (int64_t)offset + length;
+ nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
+ nFileSize.u.HighPart = nEndPos >> 32;
+ SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
+ SetEndOfFile(hFile);
+#elif defined(MAC_OSX)
+ // OSX specific version
+ // NOTE: Contrary to other OS versions, the OSX version assumes that
+ // NOTE: offset is the size of the file.
+ fstore_t fst;
+ fst.fst_flags = F_ALLOCATECONTIG;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = length; // mac os fst_length takes the # of free bytes to allocate, not desired file size
+ fst.fst_bytesalloc = 0;
+ if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
+ fst.fst_flags = F_ALLOCATEALL;
+ fcntl(fileno(file), F_PREALLOCATE, &fst);
+ }
+ ftruncate(fileno(file), static_cast<off_t>(offset) + length);
+#else
+#if defined(HAVE_POSIX_FALLOCATE)
+ // Version using posix_fallocate
+ off_t nEndPos = (off_t)offset + length;
+ if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
+#endif
+ // Fallback version
+ // TODO: just write one byte per block
+ static const char buf[65536] = {};
+ if (fseek(file, offset, SEEK_SET)) {
+ return;
+ }
+ while (length > 0) {
+ unsigned int now = 65536;
+ if (length < now)
+ now = length;
+ fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
+ length -= now;
+ }
+#endif
+}
+
+#ifdef WIN32
+fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
+{
+ WCHAR pszPath[MAX_PATH] = L"";
+
+ if (SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) {
+ return fs::path(pszPath);
+ }
+
+ LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
+ return fs::path("");
+}
+#endif
+
+bool RenameOver(fs::path src, fs::path dest)
+{
+#ifdef __MINGW64__
+ // This is a workaround for a bug in libstdc++ which
+ // implements std::filesystem::rename with _wrename function.
+ // This bug has been fixed in upstream:
+ // - GCC 10.3: 8dd1c1085587c9f8a21bb5e588dfe1e8cdbba79e
+ // - GCC 11.1: 1dfd95f0a0ca1d9e6cbc00e6cbfd1fa20a98f312
+ // For more details see the commits mentioned above.
+ return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
+ MOVEFILE_REPLACE_EXISTING) != 0;
+#else
+ std::error_code error;
+ fs::rename(src, dest, error);
+ return !error;
+#endif
+}
+
+/**
+ * Ignores exceptions thrown by create_directories if the requested directory exists.
+ * Specifically handles case where path p exists, but it wasn't possible for the user to
+ * write to the parent directory.
+ */
+bool TryCreateDirectories(const fs::path& p)
+{
+ try {
+ return fs::create_directories(p);
+ } catch (const fs::filesystem_error&) {
+ if (!fs::exists(p) || !fs::is_directory(p))
+ throw;
+ }
+
+ // create_directories didn't create the directory, it had to have existed already
+ return false;
+}
diff --git a/src/util/fs_helpers.h b/src/util/fs_helpers.h
new file mode 100644
index 0000000000..e7db01a89b
--- /dev/null
+++ b/src/util/fs_helpers.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2023 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_FS_HELPERS_H
+#define BITCOIN_UTIL_FS_HELPERS_H
+
+#include <util/fs.h>
+
+#include <cstdint>
+#include <cstdio>
+#include <iosfwd>
+#include <limits>
+
+/**
+ * Ensure file contents are fully committed to disk, using a platform-specific
+ * feature analogous to fsync().
+ */
+bool FileCommit(FILE* file);
+
+/**
+ * Sync directory contents. This is required on some environments to ensure that
+ * newly created files are committed to disk.
+ */
+void DirectoryCommit(const fs::path& dirname);
+
+bool TruncateFile(FILE* file, unsigned int length);
+int RaiseFileDescriptorLimit(int nMinFD);
+void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length);
+
+/**
+ * Rename src to dest.
+ * @return true if the rename was successful.
+ */
+[[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
+
+bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only = false);
+void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name);
+bool DirIsWritable(const fs::path& directory);
+bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
+
+/** Get the size of a file by scanning it.
+ *
+ * @param[in] path The file path
+ * @param[in] max Stop seeking beyond this limit
+ * @return The file size or max
+ */
+std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max());
+
+/** Release all directory locks. This is used for unit testing only, at runtime
+ * the global destructor will take care of the locks.
+ */
+void ReleaseDirectoryLocks();
+
+bool TryCreateDirectories(const fs::path& p);
+fs::path GetDefaultDataDir();
+
+#ifdef WIN32
+fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
+#endif
+
+#endif // BITCOIN_UTIL_FS_HELPERS_H
diff --git a/src/util/getuniquepath.cpp b/src/util/getuniquepath.cpp
index 42c5dee0ed..105b4d52d2 100644
--- a/src/util/getuniquepath.cpp
+++ b/src/util/getuniquepath.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <random.h>
-#include <fs.h>
+#include <util/fs.h>
#include <util/strencodings.h>
fs::path GetUniquePath(const fs::path& base)
diff --git a/src/util/getuniquepath.h b/src/util/getuniquepath.h
index e0c6147876..1563652300 100644
--- a/src/util/getuniquepath.h
+++ b/src/util/getuniquepath.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_GETUNIQUEPATH_H
#define BITCOIN_UTIL_GETUNIQUEPATH_H
-#include <fs.h>
+#include <util/fs.h>
/**
* Helper function for getting a unique path
diff --git a/src/util/insert.h b/src/util/insert.h
new file mode 100644
index 0000000000..5332eca60a
--- /dev/null
+++ b/src/util/insert.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2023 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_INSERT_H
+#define BITCOIN_UTIL_INSERT_H
+
+#include <set>
+
+namespace util {
+
+//! Simplification of std insertion
+template <typename Tdst, typename Tsrc>
+inline void insert(Tdst& dst, const Tsrc& src) {
+ dst.insert(dst.begin(), src.begin(), src.end());
+}
+template <typename TsetT, typename Tsrc>
+inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
+ dst.insert(src.begin(), src.end());
+}
+
+} // namespace util
+
+#endif // BITCOIN_UTIL_INSERT_H
diff --git a/src/util/readwritefile.cpp b/src/util/readwritefile.cpp
index cc555adf45..773d7ad1cc 100644
--- a/src/util/readwritefile.cpp
+++ b/src/util/readwritefile.cpp
@@ -5,7 +5,7 @@
#include <util/readwritefile.h>
-#include <fs.h>
+#include <util/fs.h>
#include <algorithm>
#include <cstdio>
diff --git a/src/util/readwritefile.h b/src/util/readwritefile.h
index 73437baf1b..6ddfcb4f35 100644
--- a/src/util/readwritefile.h
+++ b/src/util/readwritefile.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_READWRITEFILE_H
#define BITCOIN_UTIL_READWRITEFILE_H
-#include <fs.h>
+#include <util/fs.h>
#include <limits>
#include <string>
diff --git a/src/util/result.h b/src/util/result.h
index 972b1aada0..b99995c7e5 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -31,16 +31,19 @@ struct Error {
//! `std::optional<T>` can be updated to return `util::Result<T>` and return
//! error strings usually just replacing `return std::nullopt;` with `return
//! util::Error{error_string};`.
-template <class T>
+template <class M>
class Result
{
private:
+ using T = std::conditional_t<std::is_same_v<M, void>, std::monostate, M>;
+
std::variant<bilingual_str, T> m_variant;
template <typename FT>
friend bilingual_str ErrorString(const Result<FT>& result);
public:
+ Result() : m_variant{std::in_place_index_t<1>{}, std::monostate{}} {} // constructor for void
Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index 53d20bdf19..c83869bc77 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <compat/compat.h>
#include <logging.h>
#include <tinyformat.h>
#include <util/sock.h>
#include <util/syserror.h>
-#include <util/system.h>
#include <util/threadinterrupt.h>
#include <util/time.h>
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 05e7b957c4..d792562735 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -17,8 +17,8 @@
#include <cstdint>
#include <limits>
#include <optional>
-#include <string>
-#include <string_view>
+#include <string> // IWYU pragma: export
+#include <string_view> // IWYU pragma: export
#include <system_error>
#include <type_traits>
#include <vector>
diff --git a/src/util/string.h b/src/util/string.h
index fb93d2a80e..8b69d6ccae 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -12,8 +12,8 @@
#include <cstring>
#include <locale>
#include <sstream>
-#include <string>
-#include <string_view>
+#include <string> // IWYU pragma: export
+#include <string_view> // IWYU pragma: export
#include <vector>
void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
diff --git a/src/util/time.cpp b/src/util/time.cpp
index fb9bc34931..5ca9d21f8d 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -78,14 +78,6 @@ NodeClock::time_point NodeClock::now() noexcept
return time_point{ret};
};
-template <typename T>
-static T GetSystemTime()
-{
- const auto now = std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch());
- assert(now.count() > 0);
- return now;
-}
-
void SetMockTime(int64_t nMockTimeIn)
{
Assert(nMockTimeIn >= 0);
@@ -102,11 +94,6 @@ std::chrono::seconds GetMockTime()
return std::chrono::seconds(nMockTime.load(std::memory_order_relaxed));
}
-int64_t GetTimeMillis()
-{
- return int64_t{GetSystemTime<std::chrono::milliseconds>().count()};
-}
-
int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); }
std::string FormatISO8601DateTime(int64_t nTime) {
diff --git a/src/util/time.h b/src/util/time.h
index 8c6baeb12a..b6aab615ba 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -71,9 +71,6 @@ using MillisecondsDouble = std::chrono::duration<double, std::chrono::millisecon
*/
int64_t GetTime();
-/** Returns the system time (not mockable) */
-int64_t GetTimeMillis();
-
/**
* DEPRECATED
* Use SetMockTime with chrono type
diff --git a/src/util/translation.h b/src/util/translation.h
index d2b49d00b0..d33fd2d0a0 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -49,22 +49,18 @@ inline bilingual_str Untranslated(std::string original) { return {original, orig
// Provide an overload of tinyformat::format which can take bilingual_str arguments.
namespace tinyformat {
-inline std::string TranslateArg(const bilingual_str& arg, bool translated)
-{
- return translated ? arg.translated : arg.original;
-}
-
-template <typename T>
-inline T const& TranslateArg(const T& arg, bool translated)
-{
- return arg;
-}
-
template <typename... Args>
bilingual_str format(const bilingual_str& fmt, const Args&... args)
{
- return bilingual_str{format(fmt.original, TranslateArg(args, false)...),
- format(fmt.translated, TranslateArg(args, true)...)};
+ const auto translate_arg{[](const auto& arg, bool translated) -> const auto& {
+ if constexpr (std::is_same_v<decltype(arg), const bilingual_str&>) {
+ return translated ? arg.translated : arg.original;
+ } else {
+ return arg;
+ }
+ }};
+ return bilingual_str{tfm::format(fmt.original, translate_arg(args, false)...),
+ tfm::format(fmt.translated, translate_arg(args, true)...)};
}
} // namespace tinyformat
diff --git a/src/validation.cpp b/src/validation.cpp
index e82fead89e..6836498a64 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -19,14 +19,13 @@
#include <consensus/validation.h>
#include <cuckoocache.h>
#include <flatfile.h>
-#include <fs.h>
#include <hash.h>
#include <kernel/chainparams.h>
#include <kernel/mempool_entry.h>
+#include <kernel/notifications_interface.h>
#include <logging.h>
#include <logging/timer.h>
#include <node/blockstorage.h>
-#include <node/interface_ui.h>
#include <node/utxo_snapshot.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@@ -46,11 +45,12 @@
#include <uint256.h>
#include <undo.h>
#include <util/check.h> // For NDEBUG compile time check
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/hasher.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/time.h>
#include <util/trace.h>
#include <util/translation.h>
@@ -70,6 +70,7 @@ using kernel::CCoinsStats;
using kernel::CoinStatsHashType;
using kernel::ComputeUTXOStats;
using kernel::LoadMempool;
+using kernel::Notifications;
using fsbridge::FopenFn;
using node::BlockManager;
@@ -77,10 +78,7 @@ using node::BlockMap;
using node::CBlockIndexHeightOnlyComparator;
using node::CBlockIndexWorkComparator;
using node::fReindex;
-using node::ReadBlockFromDisk;
using node::SnapshotMetadata;
-using node::UndoReadFromDisk;
-using node::UnlinkPrunedFiles;
/** Maximum kilobytes for transactions to store for processing during reorg */
static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000;
@@ -844,9 +842,18 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
strprintf("%d", nSigOpsCost));
- // No individual transactions are allowed below the min relay feerate and mempool min feerate except from
- // disconnected blocks and transactions in a package. Package transactions will be checked using
- // package feerate later.
+ // No individual transactions are allowed below the min relay feerate except from disconnected blocks.
+ // This requirement, unlike CheckFeeRate, cannot be bypassed using m_package_feerates because,
+ // while a tx could be package CPFP'd when entering the mempool, we do not have a DoS-resistant
+ // method of ensuring the tx remains bumped. For example, the fee-bumping child could disappear
+ // due to a replacement.
+ if (!bypass_limits && ws.m_modified_fees < m_pool.m_min_relay_feerate.GetFee(ws.m_vsize)) {
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met",
+ strprintf("%d < %d", ws.m_modified_fees, m_pool.m_min_relay_feerate.GetFee(ws.m_vsize)));
+ }
+ // No individual transactions are allowed below the mempool min feerate except from disconnected
+ // blocks and transactions in a package. Package transactions will be checked using package
+ // feerate later.
if (!bypass_limits && !args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
@@ -1190,6 +1197,7 @@ bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>&
} else {
all_submitted = false;
ws.m_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");
+ package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
}
}
@@ -1630,26 +1638,6 @@ bool Chainstate::IsInitialBlockDownload() const
return false;
}
-static void AlertNotify(const std::string& strMessage)
-{
- uiInterface.NotifyAlertChanged();
-#if HAVE_SYSTEM
- std::string strCmd = gArgs.GetArg("-alertnotify", "");
- if (strCmd.empty()) return;
-
- // Alert text should be plain ascii coming from a trusted source, but to
- // be safe we first strip anything not in safeChars, then add single quotes around
- // the whole string before passing it to the shell:
- std::string singleQuote("'");
- std::string safeStatus = SanitizeString(strMessage);
- safeStatus = singleQuote+safeStatus+singleQuote;
- ReplaceAll(strCmd, "%s", safeStatus);
-
- std::thread t(runCommand, strCmd);
- t.detach(); // thread runs free
-#endif
-}
-
void Chainstate::CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
@@ -1902,7 +1890,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
bool fClean = true;
CBlockUndo blockUndo;
- if (!UndoReadFromDisk(blockUndo, pindex)) {
+ if (!m_blockman.UndoReadFromDisk(blockUndo, *pindex)) {
error("DisconnectBlock(): failure reading undo data");
return DISCONNECT_FAILED;
}
@@ -2005,8 +1993,6 @@ public:
}
};
-static std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> warningcache GUARDED_BY(cs_main);
-
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
{
const Consensus::Params& consensusparams = chainman.GetConsensus();
@@ -2362,7 +2348,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
if (fJustCheck)
return true;
- if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, params)) {
+ if (!m_blockman.WriteUndoDataForBlock(blockundo, state, *pindex)) {
return false;
}
@@ -2511,7 +2497,7 @@ bool Chainstate::FlushStateToDisk(
// Write blocks and block index to disk.
if (fDoFullFlush || fPeriodicWrite) {
// Ensure we can write block index
- if (!CheckDiskSpace(gArgs.GetBlocksDirPath())) {
+ if (!CheckDiskSpace(m_blockman.m_opts.blocks_dir)) {
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
}
{
@@ -2533,7 +2519,7 @@ bool Chainstate::FlushStateToDisk(
if (fFlushForPrune) {
LOG_TIME_MILLIS_WITH_CATEGORY("unlink pruned files", BCLog::BENCH);
- UnlinkPrunedFiles(setFilesToPrune);
+ m_blockman.UnlinkPrunedFiles(setFilesToPrune);
}
m_last_write = nNow;
}
@@ -2547,7 +2533,7 @@ bool Chainstate::FlushStateToDisk(
// twice (once in the log, and once in the tables). This is already
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
- if (!CheckDiskSpace(gArgs.GetDataDirNet(), 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
+ if (!CheckDiskSpace(m_chainman.m_options.datadir, 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
}
// Flush the chainstate (which may refer to block index entries).
@@ -2590,16 +2576,6 @@ void Chainstate::PruneAndFlush()
}
}
-static void DoWarning(const bilingual_str& warning)
-{
- static bool fWarned = false;
- SetMiscWarning(warning);
- if (!fWarned) {
- AlertNotify(warning.original);
- fWarned = true;
- }
-}
-
/** Private helper function that concatenates warning messages. */
static void AppendWarning(bilingual_str& res, const bilingual_str& warn)
{
@@ -2662,11 +2638,11 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(m_chainman, bit);
- ThresholdState state = checker.GetStateFor(pindex, params.GetConsensus(), warningcache.at(bit));
+ ThresholdState state = checker.GetStateFor(pindex, params.GetConsensus(), m_chainman.m_warningcache.at(bit));
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
if (state == ThresholdState::ACTIVE) {
- DoWarning(warning);
+ m_chainman.GetNotifications().warning(warning);
} else {
AppendWarning(warning_messages, warning);
}
@@ -2697,7 +2673,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
// Read block from disk.
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
CBlock& block = *pblock;
- if (!ReadBlockFromDisk(block, pindexDelete, m_chainman.GetConsensus())) {
+ if (!m_blockman.ReadBlockFromDisk(block, *pindexDelete)) {
return error("DisconnectTip(): Failed to read block");
}
// Apply the block atomically to the chain state.
@@ -2751,7 +2727,6 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
return true;
}
-static SteadyClock::duration time_read_from_disk_total{};
static SteadyClock::duration time_connect_total{};
static SteadyClock::duration time_flush{};
static SteadyClock::duration time_chainstate{};
@@ -2814,7 +2789,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
std::shared_ptr<const CBlock> pthisBlock;
if (!pblock) {
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
- if (!ReadBlockFromDisk(*pblockNew, pindexNew, m_chainman.GetConsensus())) {
+ if (!m_blockman.ReadBlockFromDisk(*pblockNew, *pindexNew)) {
return AbortNode(state, "Failed to read block");
}
pthisBlock = pblockNew;
@@ -2825,12 +2800,11 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
const CBlock& blockConnecting = *pthisBlock;
// Apply the block atomically to the chain state.
const auto time_2{SteadyClock::now()};
- time_read_from_disk_total += time_2 - time_1;
SteadyClock::time_point time_3;
- LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs (%.2fms/blk)]\n",
- Ticks<MillisecondsDouble>(time_2 - time_1),
- Ticks<SecondsDouble>(time_read_from_disk_total),
- Ticks<MillisecondsDouble>(time_read_from_disk_total) / num_blocks_total);
+ // When adding aggregate statistics in the future, keep in mind that
+ // num_blocks_total may be zero until the ConnectBlock() call below.
+ LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms\n",
+ Ticks<MillisecondsDouble>(time_2 - time_1));
{
CCoinsViewCache view(&CoinsTip());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view);
@@ -2940,6 +2914,7 @@ CBlockIndex* Chainstate::FindMostWorkChain()
while (pindexTest != pindexFailed) {
if (fFailedChain) {
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
+ m_blockman.m_dirty_blockindex.insert(pindexFailed);
} else if (fMissingData) {
// If we're missing data, then add back to m_blocks_unlinked,
// so that if the block arrives in the future we can try adding
@@ -3088,7 +3063,7 @@ static bool NotifyHeaderTip(Chainstate& chainstate) LOCKS_EXCLUDED(cs_main) {
}
// Send block tip changed notifications without cs_main
if (fNotify) {
- uiInterface.NotifyHeaderTip(GetSynchronizationState(fInitialBlockDownload), pindexHeader->nHeight, pindexHeader->nTime, false);
+ chainstate.m_chainman.GetNotifications().headerTip(GetSynchronizationState(fInitialBlockDownload), pindexHeader->nHeight, pindexHeader->nTime, false);
}
return fNotify;
}
@@ -3127,7 +3102,6 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
CBlockIndex *pindexMostWork = nullptr;
CBlockIndex *pindexNewTip = nullptr;
- int nStopAtHeight = gArgs.GetIntArg("-stopatheight", DEFAULT_STOPATHEIGHT);
do {
// Block until the validation queue drains. This should largely
// never happen in normal operation, however may happen during
@@ -3197,12 +3171,12 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
// Always notify the UI if a new block tip was connected
- uiInterface.NotifyBlockTip(GetSynchronizationState(fInitialDownload), pindexNewTip);
+ m_chainman.GetNotifications().blockTip(GetSynchronizationState(fInitialDownload), *pindexNewTip);
}
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
- if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
+ if (m_chainman.StopAtHeight() && pindexNewTip && pindexNewTip->nHeight >= m_chainman.StopAtHeight()) StartShutdown();
if (WITH_LOCK(::cs_main, return m_disabled)) {
// Background chainstate has reached the snapshot base block, so exit.
@@ -3394,7 +3368,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
// Only notify about a new block tip if the active chain was modified.
if (pindex_was_in_chain) {
- uiInterface.NotifyBlockTip(GetSynchronizationState(IsInitialBlockDownload()), to_mark_failed->pprev);
+ m_chainman.GetNotifications().blockTip(GetSynchronizationState(IsInitialBlockDownload()), *to_mark_failed->pprev);
}
return true;
}
@@ -3911,7 +3885,7 @@ void ChainstateManager::ReportHeadersPresync(const arith_uint256& work, int64_t
m_last_presync_update = now;
}
bool initial_download = chainstate.IsInitialBlockDownload();
- uiInterface.NotifyHeaderTip(GetSynchronizationState(initial_download), height, timestamp, /*presync=*/true);
+ GetNotifications().headerTip(GetSynchronizationState(initial_download), height, timestamp, /*presync=*/true);
if (initial_download) {
const int64_t blocks_left{(GetTime() - timestamp) / GetConsensus().nPowTargetSpacing};
const double progress{100.0 * height / (height + blocks_left)};
@@ -3988,7 +3962,7 @@ bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockV
// Write block to history file
if (fNewBlock) *fNewBlock = true;
try {
- FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, params, dbp)};
+ FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, dbp)};
if (blockPos.IsNull()) {
state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
return false;
@@ -4136,14 +4110,15 @@ bool Chainstate::LoadChainTip()
return true;
}
-CVerifyDB::CVerifyDB()
+CVerifyDB::CVerifyDB(Notifications& notifications)
+ : m_notifications{notifications}
{
- uiInterface.ShowProgress(_("Verifying blocks…").translated, 0, false);
+ m_notifications.progress(_("Verifying blocks…"), 0, false);
}
CVerifyDB::~CVerifyDB()
{
- uiInterface.ShowProgress("", 100, false);
+ m_notifications.progress(bilingual_str{}, 100, false);
}
VerifyDBResult CVerifyDB::VerifyDB(
@@ -4183,7 +4158,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
LogPrintf("Verification progress: %d%%\n", percentageDone);
reportDone = percentageDone / 10;
}
- uiInterface.ShowProgress(_("Verifying blocks…").translated, percentageDone, false);
+ m_notifications.progress(_("Verifying blocks…"), percentageDone, false);
if (pindex->nHeight <= chainstate.m_chain.Height() - nCheckDepth) {
break;
}
@@ -4196,7 +4171,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
}
CBlock block;
// check level 0: read from disk
- if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
+ if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) {
LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
@@ -4210,7 +4185,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo;
if (!pindex->GetUndoPos().IsNull()) {
- if (!UndoReadFromDisk(undo, pindex)) {
+ if (!chainstate.m_blockman.UndoReadFromDisk(undo, *pindex)) {
LogPrintf("Verification error: found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
@@ -4259,10 +4234,10 @@ VerifyDBResult CVerifyDB::VerifyDB(
LogPrintf("Verification progress: %d%%\n", percentageDone);
reportDone = percentageDone / 10;
}
- uiInterface.ShowProgress(_("Verifying blocks…").translated, percentageDone, false);
+ m_notifications.progress(_("Verifying blocks…"), percentageDone, false);
pindex = chainstate.m_chain.Next(pindex);
CBlock block;
- if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
+ if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) {
LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
@@ -4291,7 +4266,7 @@ bool Chainstate::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& in
AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock
CBlock block;
- if (!ReadBlockFromDisk(block, pindex, m_chainman.GetConsensus())) {
+ if (!m_blockman.ReadBlockFromDisk(block, *pindex)) {
return error("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
@@ -4318,7 +4293,7 @@ bool Chainstate::ReplayBlocks()
if (hashHeads.empty()) return true; // We're already in a consistent state.
if (hashHeads.size() != 2) return error("ReplayBlocks(): unknown inconsistent state");
- uiInterface.ShowProgress(_("Replaying blocks…").translated, 0, false);
+ m_chainman.GetNotifications().progress(_("Replaying blocks…"), 0, false);
LogPrintf("Replaying blocks\n");
const CBlockIndex* pindexOld = nullptr; // Old tip during the interrupted flush.
@@ -4343,7 +4318,7 @@ bool Chainstate::ReplayBlocks()
while (pindexOld != pindexFork) {
if (pindexOld->nHeight > 0) { // Never disconnect the genesis block.
CBlock block;
- if (!ReadBlockFromDisk(block, pindexOld, m_chainman.GetConsensus())) {
+ if (!m_blockman.ReadBlockFromDisk(block, *pindexOld)) {
return error("RollbackBlock(): ReadBlockFromDisk() failed at %d, hash=%s", pindexOld->nHeight, pindexOld->GetBlockHash().ToString());
}
LogPrintf("Rolling back %s (%i)\n", pindexOld->GetBlockHash().ToString(), pindexOld->nHeight);
@@ -4365,13 +4340,13 @@ bool Chainstate::ReplayBlocks()
const CBlockIndex& pindex{*Assert(pindexNew->GetAncestor(nHeight))};
LogPrintf("Rolling forward %s (%i)\n", pindex.GetBlockHash().ToString(), nHeight);
- uiInterface.ShowProgress(_("Replaying blocks…").translated, (int) ((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)) , false);
+ m_chainman.GetNotifications().progress(_("Replaying blocks…"), (int)((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)), false);
if (!RollforwardBlock(&pindex, cache)) return false;
}
cache.SetBestBlock(pindexNew->GetBlockHash());
cache.Flush();
- uiInterface.ShowProgress("", 100, false);
+ m_chainman.GetNotifications().progress(bilingual_str{}, 100, false);
return true;
}
@@ -4406,7 +4381,7 @@ bool ChainstateManager::LoadBlockIndex()
// Load block index from databases
bool needs_init = fReindex;
if (!fReindex) {
- bool ret = m_blockman.LoadBlockIndexDB(GetConsensus());
+ bool ret{m_blockman.LoadBlockIndexDB()};
if (!ret) return false;
m_blockman.ScanAndUnlinkAlreadyPrunedFiles();
@@ -4510,7 +4485,7 @@ bool Chainstate::LoadGenesisBlock()
try {
const CBlock& block = params.GenesisBlock();
- FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, params, nullptr)};
+ FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, nullptr)};
if (blockPos.IsNull()) {
return error("%s: writing genesis block to disk failed", __func__);
}
@@ -4553,7 +4528,7 @@ void Chainstate::LoadExternalBlockFile(
try {
// locate a header
unsigned char buf[CMessageHeader::MESSAGE_START_SIZE];
- blkdat.FindByte(params.MessageStart()[0]);
+ blkdat.FindByte(std::byte(params.MessageStart()[0]));
nRewind = blkdat.GetPos() + 1;
blkdat >> buf;
if (memcmp(buf, params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE)) {
@@ -4581,6 +4556,9 @@ void Chainstate::LoadExternalBlockFile(
// next block, but it's still possible to rewind to the start of the current block (without a disk read).
nRewind = nBlockPos + nSize;
blkdat.SkipTo(nRewind);
+
+ std::shared_ptr<CBlock> pblock{}; // needs to remain available after the cs_main lock is released to avoid duplicate reads from disk
+
{
LOCK(cs_main);
// detect out of order blocks, and store them for later
@@ -4598,7 +4576,7 @@ void Chainstate::LoadExternalBlockFile(
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
// This block can be processed immediately; rewind to its start, read and deserialize it.
blkdat.SetPos(nBlockPos);
- std::shared_ptr<CBlock> pblock{std::make_shared<CBlock>()};
+ pblock = std::make_shared<CBlock>();
blkdat >> *pblock;
nRewind = blkdat.GetPos();
@@ -4622,6 +4600,21 @@ void Chainstate::LoadExternalBlockFile(
}
}
+ if (m_blockman.IsPruneMode() && !fReindex && pblock) {
+ // must update the tip for pruning to work while importing with -loadblock.
+ // this is a tradeoff to conserve disk space at the expense of time
+ // spent updating the tip to be able to prune.
+ // otherwise, ActivateBestChain won't be called by the import process
+ // until after all of the block files are loaded. ActivateBestChain can be
+ // called by concurrent network message processing. but, that is not
+ // reliable for the purpose of pruning while importing.
+ BlockValidationState state;
+ if (!ActivateBestChain(state, pblock)) {
+ LogPrint(BCLog::REINDEX, "failed to activate chain (%s)\n", state.ToString());
+ break;
+ }
+ }
+
NotifyHeaderTip(*this);
if (!blocks_with_unknown_parent) continue;
@@ -4636,7 +4629,7 @@ void Chainstate::LoadExternalBlockFile(
while (range.first != range.second) {
std::multimap<uint256, FlatFilePos>::iterator it = range.first;
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
- if (ReadBlockFromDisk(*pblockrecursive, it->second, params.GetConsensus())) {
+ if (m_blockman.ReadBlockFromDisk(*pblockrecursive, it->second)) {
LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
head.ToString());
LOCK(cs_main);
@@ -4930,7 +4923,6 @@ bool Chainstate::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
} else {
// Otherwise, flush state to disk and deallocate the in-memory coins map.
ret = FlushStateToDisk(state, FlushStateMode::ALWAYS);
- CoinsTip().ReallocateCache();
}
return ret;
}
@@ -5007,15 +4999,15 @@ static bool DeleteCoinsDBFromDisk(const fs::path db_path, bool is_snapshot)
if (is_snapshot) {
fs::path base_blockhash_path = db_path / node::SNAPSHOT_BLOCKHASH_FILENAME;
- if (fs::exists(base_blockhash_path)) {
- bool removed = fs::remove(base_blockhash_path);
- if (!removed) {
- LogPrintf("[snapshot] failed to remove file %s\n",
- fs::PathToString(base_blockhash_path));
+ try {
+ bool existed = fs::remove(base_blockhash_path);
+ if (!existed) {
+ LogPrintf("[snapshot] snapshot chainstate dir being removed lacks %s file\n",
+ fs::PathToString(node::SNAPSHOT_BLOCKHASH_FILENAME));
}
- } else {
- LogPrintf("[snapshot] snapshot chainstate dir being removed lacks %s file\n",
- fs::PathToString(node::SNAPSHOT_BLOCKHASH_FILENAME));
+ } catch (const fs::filesystem_error& e) {
+ LogPrintf("[snapshot] failed to remove file %s: %s\n",
+ fs::PathToString(base_blockhash_path), fsbridge::get_filesystem_error_message(e));
}
}
@@ -5113,7 +5105,7 @@ bool ChainstateManager::ActivateSnapshot(
// PopulateAndValidateSnapshot can return (in error) before the leveldb datadir
// has been created, so only attempt removal if we got that far.
- if (auto snapshot_datadir = node::FindSnapshotChainstateDir()) {
+ if (auto snapshot_datadir = node::FindSnapshotChainstateDir(m_options.datadir)) {
// We have to destruct leveldb::DB in order to release the db lock, otherwise
// DestroyDB() (in DeleteCoinsDBFromDisk()) will fail. See `leveldb::~DBImpl()`.
// Destructing the chainstate (and so resetting the coinsviews object) does this.
@@ -5420,7 +5412,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
"restart, the node will resume syncing from %d "
"without using any snapshot data. "
"Please report this incident to %s, including how you obtained the snapshot. "
- "The invalid snapshot chainstate has been left on disk in case it is "
+ "The invalid snapshot chainstate will be left on disk in case it is "
"helpful in diagnosing the issue that caused this error."),
PACKAGE_NAME, snapshot_tip_height, snapshot_base_height, snapshot_base_height, PACKAGE_BUGREPORT
);
@@ -5433,7 +5425,10 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
assert(!this->IsUsable(m_snapshot_chainstate.get()));
assert(this->IsUsable(m_ibd_chainstate.get()));
- m_snapshot_chainstate->InvalidateCoinsDBOnDisk();
+ auto rename_result = m_snapshot_chainstate->InvalidateCoinsDBOnDisk();
+ if (!rename_result) {
+ user_error = strprintf(Untranslated("%s\n%s"), user_error, util::ErrorString(rename_result));
+ }
shutdown_fnc(user_error);
};
@@ -5593,17 +5588,12 @@ ChainstateManager::~ChainstateManager()
LOCK(::cs_main);
m_versionbitscache.Clear();
-
- // TODO: The warning cache should probably become non-global
- for (auto& i : warningcache) {
- i.clear();
- }
}
bool ChainstateManager::DetectSnapshotChainstate(CTxMemPool* mempool)
{
assert(!m_snapshot_chainstate);
- std::optional<fs::path> path = node::FindSnapshotChainstateDir();
+ std::optional<fs::path> path = node::FindSnapshotChainstateDir(m_options.datadir);
if (!path) {
return false;
}
@@ -5640,7 +5630,7 @@ bool IsBIP30Unspendable(const CBlockIndex& block_index)
(block_index.nHeight==91812 && block_index.GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"));
}
-void Chainstate::InvalidateCoinsDBOnDisk()
+util::Result<void> Chainstate::InvalidateCoinsDBOnDisk()
{
AssertLockHeld(::cs_main);
// Should never be called on a non-snapshot chainstate.
@@ -5669,13 +5659,14 @@ void Chainstate::InvalidateCoinsDBOnDisk()
LogPrintf("%s: error renaming file '%s' -> '%s': %s\n",
__func__, src_str, dest_str, e.what());
- AbortNode(strprintf(
+ return util::Error{strprintf(_(
"Rename of '%s' -> '%s' failed. "
"You should resolve this by manually moving or deleting the invalid "
"snapshot directory %s, otherwise you will encounter the same error again "
- "on the next startup.",
- src_str, dest_str, src_str));
+ "on the next startup."),
+ src_str, dest_str, src_str)};
}
+ return {};
}
const CBlockIndex* ChainstateManager::GetSnapshotBaseBlock() const
diff --git a/src/validation.h b/src/validation.h
index b6d1995c5b..8bc8842c54 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -15,7 +15,6 @@
#include <chain.h>
#include <consensus/amount.h>
#include <deploymentstatus.h>
-#include <fs.h>
#include <kernel/chainparams.h>
#include <kernel/chainstatemanager_opts.h>
#include <kernel/cs_main.h> // IWYU pragma: export
@@ -30,7 +29,9 @@
#include <txmempool.h> // For CTxMemPool::cs
#include <uint256.h>
#include <util/check.h>
+#include <util/fs.h>
#include <util/hasher.h>
+#include <util/result.h>
#include <util/translation.h>
#include <versionbits.h>
@@ -66,8 +67,6 @@ struct Params;
static const int MAX_SCRIPTCHECK_THREADS = 15;
/** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
-/** Default for -stopatheight */
-static const int DEFAULT_STOPATHEIGHT = 0;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
@@ -370,9 +369,13 @@ enum class VerifyDBResult {
};
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
-class CVerifyDB {
+class CVerifyDB
+{
+private:
+ kernel::Notifications& m_notifications;
+
public:
- CVerifyDB();
+ explicit CVerifyDB(kernel::Notifications& notifications);
~CVerifyDB();
[[nodiscard]] VerifyDBResult VerifyDB(
Chainstate& chainstate,
@@ -814,7 +817,7 @@ private:
* In case of an invalid snapshot, rename the coins leveldb directory so
* that it can be examined for issue diagnosis.
*/
- void InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ [[nodiscard]] util::Result<void> InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
friend ChainstateManager;
};
@@ -942,6 +945,8 @@ private:
//! nullopt.
std::optional<int> GetSnapshotBaseHeight() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> m_warningcache GUARDED_BY(::cs_main);
+
//! Return true if a chainstate is considered usable.
//!
//! This is false when a background validation chainstate has completed its
@@ -961,6 +966,8 @@ public:
bool ShouldCheckBlockIndex() const { return *Assert(m_options.check_block_index); }
const arith_uint256& MinimumChainWork() const { return *Assert(m_options.minimum_chain_work); }
const uint256& AssumedValidBlock() const { return *Assert(m_options.assumed_valid_block); }
+ kernel::Notifications& GetNotifications() const { return m_options.notifications; };
+ int StopAtHeight() const { return m_options.stop_at_height; };
/**
* Alias for ::cs_main.
@@ -1003,7 +1010,7 @@ public:
std::set<CBlockIndex*> m_failed_blocks;
/** Best header we've seen so far (used for getheaders queries' starting points). */
- CBlockIndex* m_best_header = nullptr;
+ CBlockIndex* m_best_header GUARDED_BY(::cs_main){nullptr};
//! The total number of bytes available for us to use across all in-memory
//! coins caches. This will be split somehow across chainstates.
diff --git a/src/version.h b/src/version.h
index ee646eefc3..611a670314 100644
--- a/src/version.h
+++ b/src/version.h
@@ -20,9 +20,6 @@ static const int MIN_PEER_PROTO_VERSION = 31800;
//! BIP 0031, pong message, is enabled for all versions AFTER this one
static const int BIP0031_VERSION = 60000;
-//! "filter*" commands are disabled without NODE_BLOOM after and including this version
-static const int NO_BLOOM_VERSION = 70011;
-
//! "sendheaders" command and announcing blocks with headers starts with this version
static const int SENDHEADERS_VERSION = 70012;
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 653115aa81..68abdcd81e 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -4,18 +4,29 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <compat/compat.h>
-#include <fs.h>
+#include <logging.h>
+#include <util/fs.h>
+#include <util/time.h>
#include <wallet/bdb.h>
#include <wallet/db.h>
+#include <sync.h>
#include <util/check.h>
+#include <util/fs_helpers.h>
#include <util/strencodings.h>
#include <util/translation.h>
#include <stdint.h>
-#ifndef WIN32
#include <sys/stat.h>
+
+// Windows may not define S_IRUSR or S_IWUSR. We define both
+// here, with the same values as glibc (see stat.h).
+#ifdef WIN32
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#endif
#endif
namespace wallet {
@@ -432,6 +443,7 @@ void BerkeleyEnvironment::ReloadDbEnv()
});
std::vector<fs::path> filenames;
+ filenames.reserve(m_databases.size());
for (const auto& it : m_databases) {
filenames.push_back(it.first);
}
@@ -656,12 +668,15 @@ void BerkeleyDatabase::ReloadDbEnv()
env->ReloadDbEnv();
}
-BerkeleyCursor::BerkeleyCursor(BerkeleyDatabase& database)
+BerkeleyCursor::BerkeleyCursor(BerkeleyDatabase& database, const BerkeleyBatch& batch, Span<const std::byte> prefix)
+ : m_key_prefix(prefix.begin(), prefix.end())
{
if (!database.m_db.get()) {
throw std::runtime_error(STR_INTERNAL_BUG("BerkeleyDatabase does not exist"));
}
- int ret = database.m_db->cursor(nullptr, &m_cursor, 0);
+ // Transaction argument to cursor is only needed when using the cursor to
+ // write to the database. Read-only cursors do not need a txn pointer.
+ int ret = database.m_db->cursor(batch.txn(), &m_cursor, 0);
if (ret != 0) {
throw std::runtime_error(STR_INTERNAL_BUG(strprintf("BDB Cursor could not be created. Returned %d", ret)));
}
@@ -671,19 +686,30 @@ DatabaseCursor::Status BerkeleyCursor::Next(DataStream& ssKey, DataStream& ssVal
{
if (m_cursor == nullptr) return Status::FAIL;
// Read at cursor
- SafeDbt datKey;
+ SafeDbt datKey(m_key_prefix.data(), m_key_prefix.size());
SafeDbt datValue;
- int ret = m_cursor->get(datKey, datValue, DB_NEXT);
+ int ret = -1;
+ if (m_first && !m_key_prefix.empty()) {
+ ret = m_cursor->get(datKey, datValue, DB_SET_RANGE);
+ } else {
+ ret = m_cursor->get(datKey, datValue, DB_NEXT);
+ }
+ m_first = false;
if (ret == DB_NOTFOUND) {
return Status::DONE;
}
- if (ret != 0 || datKey.get_data() == nullptr || datValue.get_data() == nullptr) {
+ if (ret != 0) {
return Status::FAIL;
}
+ Span<const std::byte> raw_key = {AsBytePtr(datKey.get_data()), datKey.get_size()};
+ if (!m_key_prefix.empty() && std::mismatch(raw_key.begin(), raw_key.end(), m_key_prefix.begin(), m_key_prefix.end()).second != m_key_prefix.end()) {
+ return Status::DONE;
+ }
+
// Convert to streams
ssKey.clear();
- ssKey.write({AsBytePtr(datKey.get_data()), datKey.get_size()});
+ ssKey.write(raw_key);
ssValue.clear();
ssValue.write({AsBytePtr(datValue.get_data()), datValue.get_size()});
return Status::MORE;
@@ -699,7 +725,13 @@ BerkeleyCursor::~BerkeleyCursor()
std::unique_ptr<DatabaseCursor> BerkeleyBatch::GetNewCursor()
{
if (!pdb) return nullptr;
- return std::make_unique<BerkeleyCursor>(m_database);
+ return std::make_unique<BerkeleyCursor>(m_database, *this);
+}
+
+std::unique_ptr<DatabaseCursor> BerkeleyBatch::GetNewPrefixCursor(Span<const std::byte> prefix)
+{
+ if (!pdb) return nullptr;
+ return std::make_unique<BerkeleyCursor>(m_database, *this, prefix);
}
bool BerkeleyBatch::TxnBegin()
@@ -763,6 +795,7 @@ bool BerkeleyBatch::ReadKey(DataStream&& key, DataStream& value)
SafeDbt datValue;
int ret = pdb->get(activeTxn, datKey, datValue, 0);
if (ret == 0 && datValue.get_data() != nullptr) {
+ value.clear();
value.write({AsBytePtr(datValue.get_data()), datValue.get_size()});
return true;
}
@@ -808,6 +841,25 @@ bool BerkeleyBatch::HasKey(DataStream&& key)
return ret == 0;
}
+bool BerkeleyBatch::ErasePrefix(Span<const std::byte> prefix)
+{
+ if (!TxnBegin()) return false;
+ auto cursor{std::make_unique<BerkeleyCursor>(m_database, *this)};
+ // const_cast is safe below even though prefix_key is an in/out parameter,
+ // because we are not using the DB_DBT_USERMEM flag, so BDB will allocate
+ // and return a different output data pointer
+ Dbt prefix_key{const_cast<std::byte*>(prefix.data()), static_cast<uint32_t>(prefix.size())}, prefix_value{};
+ int ret{cursor->dbc()->get(&prefix_key, &prefix_value, DB_SET_RANGE)};
+ for (int flag{DB_CURRENT}; ret == 0; flag = DB_NEXT) {
+ SafeDbt key, value;
+ ret = cursor->dbc()->get(key, value, flag);
+ if (ret != 0 || key.get_size() < prefix.size() || memcmp(key.get_data(), prefix.data(), prefix.size()) != 0) break;
+ ret = cursor->dbc()->del(0);
+ }
+ cursor.reset();
+ return TxnCommit() && (ret == 0 || ret == DB_NOTFOUND);
+}
+
void BerkeleyDatabase::AddRef()
{
LOCK(cs_db);
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index 06c98972b0..8cc03692d6 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -7,13 +7,14 @@
#define BITCOIN_WALLET_BDB_H
#include <clientversion.h>
-#include <fs.h>
+#include <common/system.h>
#include <serialize.h>
#include <streams.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <wallet/db.h>
#include <atomic>
+#include <condition_variable>
#include <map>
#include <memory>
#include <string>
@@ -189,12 +190,17 @@ class BerkeleyCursor : public DatabaseCursor
{
private:
Dbc* m_cursor;
+ std::vector<std::byte> m_key_prefix;
+ bool m_first{true};
public:
- explicit BerkeleyCursor(BerkeleyDatabase& database);
+ // Constructor for cursor for records matching the prefix
+ // To match all records, an empty prefix may be provided.
+ explicit BerkeleyCursor(BerkeleyDatabase& database, const BerkeleyBatch& batch, Span<const std::byte> prefix = {});
~BerkeleyCursor() override;
Status Next(DataStream& key, DataStream& value) override;
+ Dbc* dbc() const { return m_cursor; }
};
/** RAII class that provides access to a Berkeley database */
@@ -205,6 +211,7 @@ private:
bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
bool EraseKey(DataStream&& key) override;
bool HasKey(DataStream&& key) override;
+ bool ErasePrefix(Span<const std::byte> prefix) override;
protected:
Db* pdb{nullptr};
@@ -226,9 +233,11 @@ public:
void Close() override;
std::unique_ptr<DatabaseCursor> GetNewCursor() override;
+ std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override;
bool TxnBegin() override;
bool TxnCommit() override;
bool TxnAbort() override;
+ DbTxn* txn() const { return activeTxn; }
};
std::string BerkeleyDatabaseVersion();
diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp
index 3b3c1f8da4..2087119db9 100644
--- a/src/wallet/coincontrol.cpp
+++ b/src/wallet/coincontrol.cpp
@@ -4,11 +4,79 @@
#include <wallet/coincontrol.h>
-#include <util/system.h>
+#include <common/args.h>
namespace wallet {
CCoinControl::CCoinControl()
{
m_avoid_partial_spends = gArgs.GetBoolArg("-avoidpartialspends", DEFAULT_AVOIDPARTIALSPENDS);
}
+
+bool CCoinControl::HasSelected() const
+{
+ return !m_selected_inputs.empty();
+}
+
+bool CCoinControl::IsSelected(const COutPoint& output) const
+{
+ return m_selected_inputs.count(output) > 0;
+}
+
+bool CCoinControl::IsExternalSelected(const COutPoint& output) const
+{
+ return m_external_txouts.count(output) > 0;
+}
+
+std::optional<CTxOut> CCoinControl::GetExternalOutput(const COutPoint& outpoint) const
+{
+ const auto ext_it = m_external_txouts.find(outpoint);
+ if (ext_it == m_external_txouts.end()) {
+ return std::nullopt;
+ }
+
+ return std::make_optional(ext_it->second);
+}
+
+void CCoinControl::Select(const COutPoint& output)
+{
+ m_selected_inputs.insert(output);
+}
+
+void CCoinControl::SelectExternal(const COutPoint& outpoint, const CTxOut& txout)
+{
+ m_selected_inputs.insert(outpoint);
+ m_external_txouts.emplace(outpoint, txout);
+}
+
+void CCoinControl::UnSelect(const COutPoint& output)
+{
+ m_selected_inputs.erase(output);
+}
+
+void CCoinControl::UnSelectAll()
+{
+ m_selected_inputs.clear();
+}
+
+std::vector<COutPoint> CCoinControl::ListSelected() const
+{
+ return {m_selected_inputs.begin(), m_selected_inputs.end()};
+}
+
+void CCoinControl::SetInputWeight(const COutPoint& outpoint, int64_t weight)
+{
+ m_input_weights[outpoint] = weight;
+}
+
+bool CCoinControl::HasInputWeight(const COutPoint& outpoint) const
+{
+ return m_input_weights.count(outpoint) > 0;
+}
+
+int64_t CCoinControl::GetInputWeight(const COutPoint& outpoint) const
+{
+ auto it = m_input_weights.find(outpoint);
+ assert(it != m_input_weights.end());
+ return it->second;
+}
} // namespace wallet
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index cb6f0a1635..7ff8fee5bc 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -13,9 +13,9 @@
#include <script/signingprovider.h>
#include <script/standard.h>
-#include <optional>
#include <algorithm>
#include <map>
+#include <optional>
#include <set>
namespace wallet {
@@ -63,76 +63,62 @@ public:
CCoinControl();
- bool HasSelected() const
- {
- return (setSelected.size() > 0);
- }
-
- bool IsSelected(const COutPoint& output) const
- {
- return (setSelected.count(output) > 0);
- }
-
- bool IsExternalSelected(const COutPoint& output) const
- {
- return (m_external_txouts.count(output) > 0);
- }
-
- bool GetExternalOutput(const COutPoint& outpoint, CTxOut& txout) const
- {
- const auto ext_it = m_external_txouts.find(outpoint);
- if (ext_it == m_external_txouts.end()) {
- return false;
- }
- txout = ext_it->second;
- return true;
- }
-
- void Select(const COutPoint& output)
- {
- setSelected.insert(output);
- }
-
- void SelectExternal(const COutPoint& outpoint, const CTxOut& txout)
- {
- setSelected.insert(outpoint);
- m_external_txouts.emplace(outpoint, txout);
- }
-
- void UnSelect(const COutPoint& output)
- {
- setSelected.erase(output);
- }
-
- void UnSelectAll()
- {
- setSelected.clear();
- }
-
- void ListSelected(std::vector<COutPoint>& vOutpoints) const
- {
- vOutpoints.assign(setSelected.begin(), setSelected.end());
- }
-
- void SetInputWeight(const COutPoint& outpoint, int64_t weight)
- {
- m_input_weights[outpoint] = weight;
- }
-
- bool HasInputWeight(const COutPoint& outpoint) const
- {
- return m_input_weights.count(outpoint) > 0;
- }
-
- int64_t GetInputWeight(const COutPoint& outpoint) const
- {
- auto it = m_input_weights.find(outpoint);
- assert(it != m_input_weights.end());
- return it->second;
- }
+ /**
+ * Returns true if there are pre-selected inputs.
+ */
+ bool HasSelected() const;
+ /**
+ * Returns true if the given output is pre-selected.
+ */
+ bool IsSelected(const COutPoint& output) const;
+ /**
+ * Returns true if the given output is selected as an external input.
+ */
+ bool IsExternalSelected(const COutPoint& output) const;
+ /**
+ * Returns the external output for the given outpoint if it exists.
+ */
+ std::optional<CTxOut> GetExternalOutput(const COutPoint& outpoint) const;
+ /**
+ * Lock-in the given output for spending.
+ * The output will be included in the transaction even if it's not the most optimal choice.
+ */
+ void Select(const COutPoint& output);
+ /**
+ * Lock-in the given output as an external input for spending because it is not in the wallet.
+ * The output will be included in the transaction even if it's not the most optimal choice.
+ */
+ void SelectExternal(const COutPoint& outpoint, const CTxOut& txout);
+ /**
+ * Unselects the given output.
+ */
+ void UnSelect(const COutPoint& output);
+ /**
+ * Unselects all outputs.
+ */
+ void UnSelectAll();
+ /**
+ * List the selected inputs.
+ */
+ std::vector<COutPoint> ListSelected() const;
+ /**
+ * Set an input's weight.
+ */
+ void SetInputWeight(const COutPoint& outpoint, int64_t weight);
+ /**
+ * Returns true if the input weight is set.
+ */
+ bool HasInputWeight(const COutPoint& outpoint) const;
+ /**
+ * Returns the input weight.
+ */
+ int64_t GetInputWeight(const COutPoint& outpoint) const;
private:
- std::set<COutPoint> setSelected;
+ //! Selected inputs (inputs that will be used, regardless of whether they're optimal or not)
+ std::set<COutPoint> m_selected_inputs;
+ //! Map of external inputs to include in the transaction
+ //! These are not in the wallet, so we need to track them separately
std::map<COutPoint, CTxOut> m_external_txouts;
//! Map of COutPoints to the maximum weight for that input
std::map<COutPoint, int64_t> m_input_weights;
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 9cf61dbe51..d6b9b68e1f 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -4,17 +4,26 @@
#include <wallet/coinselection.h>
+#include <common/system.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
+#include <logging.h>
#include <policy/feerate.h>
#include <util/check.h>
-#include <util/system.h>
#include <util/moneystr.h>
#include <numeric>
#include <optional>
+#include <queue>
namespace wallet {
+// Common selection error across the algorithms
+static util::Result<SelectionResult> ErrorMaxWeightExceeded()
+{
+ return util::Error{_("The inputs size exceeds the maximum weight. "
+ "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")};
+}
+
// Descending order comparator
struct {
bool operator()(const OutputGroup& a, const OutputGroup& b) const
@@ -63,11 +72,13 @@ struct {
static const size_t TOTAL_TRIES = 100000;
-std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change)
+util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change,
+ int max_weight)
{
SelectionResult result(selection_target, SelectionAlgorithm::BNB);
CAmount curr_value = 0;
std::vector<size_t> curr_selection; // selected utxo indexes
+ int curr_selection_weight = 0; // sum of selected utxo weight
// Calculate curr_available_value
CAmount curr_available_value = 0;
@@ -78,7 +89,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
curr_available_value += utxo.GetSelectionAmount();
}
if (curr_available_value < selection_target) {
- return std::nullopt;
+ return util::Error();
}
// Sort the utxo_pool
@@ -89,6 +100,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
CAmount best_waste = MAX_MONEY;
bool is_feerate_high = utxo_pool.at(0).fee > utxo_pool.at(0).long_term_fee;
+ bool max_tx_weight_exceeded = false;
// Depth First search loop for choosing the UTXOs
for (size_t curr_try = 0, utxo_pool_index = 0; curr_try < TOTAL_TRIES; ++curr_try, ++utxo_pool_index) {
@@ -98,6 +110,9 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
curr_value > selection_target + cost_of_change || // Selected value is out of range, go back and try other branch
(curr_waste > best_waste && is_feerate_high)) { // Don't select things which we know will be more wasteful if the waste is increasing
backtrack = true;
+ } else if (curr_selection_weight > max_weight) { // Exceeding weight for standard tx, cannot find more solutions by adding more inputs
+ max_tx_weight_exceeded = true; // at least one selection attempt exceeded the max weight
+ backtrack = true;
} else if (curr_value >= selection_target) { // Selected value is within range
curr_waste += (curr_value - selection_target); // This is the excess value which is added to the waste for the below comparison
// Adding another UTXO after this check could bring the waste down if the long term fee is higher than the current fee.
@@ -127,6 +142,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
OutputGroup& utxo = utxo_pool.at(utxo_pool_index);
curr_value -= utxo.GetSelectionAmount();
curr_waste -= utxo.fee - utxo.long_term_fee;
+ curr_selection_weight -= utxo.m_weight;
curr_selection.pop_back();
} else { // Moving forwards, continuing down this branch
OutputGroup& utxo = utxo_pool.at(utxo_pool_index);
@@ -146,13 +162,14 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
curr_selection.push_back(utxo_pool_index);
curr_value += utxo.GetSelectionAmount();
curr_waste += utxo.fee - utxo.long_term_fee;
+ curr_selection_weight += utxo.m_weight;
}
}
}
// Check for solution
if (best_selection.empty()) {
- return std::nullopt;
+ return max_tx_weight_exceeded ? ErrorMaxWeightExceeded() : util::Error();
}
// Set output set
@@ -165,15 +182,26 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
return result;
}
-std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng)
+class MinOutputGroupComparator
+{
+public:
+ int operator() (const OutputGroup& group1, const OutputGroup& group2) const
+ {
+ return group1.GetSelectionAmount() > group2.GetSelectionAmount();
+ }
+};
+
+util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,
+ int max_weight)
{
SelectionResult result(target_value, SelectionAlgorithm::SRD);
+ std::priority_queue<OutputGroup, std::vector<OutputGroup>, MinOutputGroupComparator> heap;
// Include change for SRD as we want to avoid making really small change if the selection just
// barely meets the target. Just use the lower bound change target instead of the randomly
// generated one, since SRD will result in a random change amount anyway; avoid making the
// target needlessly large.
- target_value += CHANGE_LOWER;
+ target_value += CHANGE_LOWER + change_fee;
std::vector<size_t> indexes;
indexes.resize(utxo_pool.size());
@@ -181,16 +209,40 @@ std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& ut
Shuffle(indexes.begin(), indexes.end(), rng);
CAmount selected_eff_value = 0;
+ int weight = 0;
+ bool max_tx_weight_exceeded = false;
for (const size_t i : indexes) {
const OutputGroup& group = utxo_pool.at(i);
Assume(group.GetSelectionAmount() > 0);
+
+ // Add group to selection
+ heap.push(group);
selected_eff_value += group.GetSelectionAmount();
- result.AddInput(group);
+ weight += group.m_weight;
+
+ // If the selection weight exceeds the maximum allowed size, remove the least valuable inputs until we
+ // are below max weight.
+ if (weight > max_weight) {
+ max_tx_weight_exceeded = true; // mark it in case we don't find any useful result.
+ do {
+ const OutputGroup& to_remove_group = heap.top();
+ selected_eff_value -= to_remove_group.GetSelectionAmount();
+ weight -= to_remove_group.m_weight;
+ heap.pop();
+ } while (!heap.empty() && weight > max_weight);
+ }
+
+ // Now check if we are above the target
if (selected_eff_value >= target_value) {
+ // Result found, add it.
+ while (!heap.empty()) {
+ result.AddInput(heap.top());
+ heap.pop();
+ }
return result;
}
}
- return std::nullopt;
+ return max_tx_weight_exceeded ? ErrorMaxWeightExceeded() : util::Error();
}
/** Find a subset of the OutputGroups that is at least as large as, but as close as possible to, the
@@ -252,8 +304,8 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
}
}
-std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
- CAmount change_target, FastRandomContext& rng)
+util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
+ CAmount change_target, FastRandomContext& rng, int max_weight)
{
SelectionResult result(nTargetValue, SelectionAlgorithm::KNAPSACK);
@@ -286,7 +338,7 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
}
if (nTotalLower < nTargetValue) {
- if (!lowest_larger) return std::nullopt;
+ if (!lowest_larger) return util::Error();
result.AddInput(*lowest_larger);
return result;
}
@@ -313,6 +365,16 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
}
}
+ // If the result exceeds the maximum allowed size, return closest UTXO above the target
+ if (result.GetWeight() > max_weight) {
+ // No coin above target, nothing to do.
+ if (!lowest_larger) return ErrorMaxWeightExceeded();
+
+ // Return closest UTXO above target
+ result.Clear();
+ result.AddInput(*lowest_larger);
+ }
+
if (LogAcceptCategory(BCLog::SELECTCOINS, BCLog::Level::Debug)) {
std::string log_message{"Coin selection best subset: "};
for (unsigned int i = 0; i < applicable_groups.size(); i++) {
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 5a7b748be1..afd868fc89 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -11,8 +11,9 @@
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <random.h>
-#include <util/system.h>
#include <util/check.h>
+#include <util/insert.h>
+#include <util/result.h>
#include <optional>
@@ -408,20 +409,24 @@ public:
int GetWeight() const { return m_weight; }
};
-std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change);
+util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change,
+ int max_weight);
/** Select coins by Single Random Draw. OutputGroups are selected randomly from the eligible
* outputs until the target is satisfied
*
* @param[in] utxo_pool The positive effective value OutputGroups eligible for selection
* @param[in] target_value The target value to select for
- * @returns If successful, a SelectionResult, otherwise, std::nullopt
+ * @param[in] rng The randomness source to shuffle coins
+ * @param[in] max_weight The maximum allowed weight for a selection result to be valid
+ * @returns If successful, a valid SelectionResult, otherwise, util::Error
*/
-std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng);
+util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext& rng,
+ int max_weight);
// Original coin selection algorithm as a fallback
-std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
- CAmount change_target, FastRandomContext& rng);
+util::Result<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
+ CAmount change_target, FastRandomContext& rng, int max_weight);
} // namespace wallet
#endif // BITCOIN_WALLET_COINSELECTION_H
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index cd414b3d44..e2799c2d05 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -4,9 +4,9 @@
#include <wallet/crypter.h>
+#include <common/system.h>
#include <crypto/aes.h>
#include <crypto/sha512.h>
-#include <util/system.h>
#include <vector>
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 8e79ee678e..0c24920516 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -4,9 +4,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <fs.h>
+#include <common/args.h>
#include <logging.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <wallet/db.h>
#include <exception>
diff --git a/src/wallet/db.h b/src/wallet/db.h
index d4c590fac7..9d684225c3 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -7,9 +7,9 @@
#define BITCOIN_WALLET_DB_H
#include <clientversion.h>
-#include <fs.h>
#include <streams.h>
#include <support/allocators/secure.h>
+#include <util/fs.h>
#include <atomic>
#include <memory>
@@ -110,8 +110,10 @@ public:
return HasKey(std::move(ssKey));
}
+ virtual bool ErasePrefix(Span<const std::byte> prefix) = 0;
virtual std::unique_ptr<DatabaseCursor> GetNewCursor() = 0;
+ virtual std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) = 0;
virtual bool TxnBegin() = 0;
virtual bool TxnCommit() = 0;
virtual bool TxnAbort() = 0;
@@ -173,50 +175,6 @@ public:
virtual std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) = 0;
};
-class DummyCursor : public DatabaseCursor
-{
- Status Next(DataStream& key, DataStream& value) override { return Status::FAIL; }
-};
-
-/** RAII class that provides access to a DummyDatabase. Never fails. */
-class DummyBatch : public DatabaseBatch
-{
-private:
- bool ReadKey(DataStream&& key, DataStream& value) override { return true; }
- bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override { return true; }
- bool EraseKey(DataStream&& key) override { return true; }
- bool HasKey(DataStream&& key) override { return true; }
-
-public:
- void Flush() override {}
- void Close() override {}
-
- std::unique_ptr<DatabaseCursor> GetNewCursor() override { return std::make_unique<DummyCursor>(); }
- bool TxnBegin() override { return true; }
- bool TxnCommit() override { return true; }
- bool TxnAbort() override { return true; }
-};
-
-/** A dummy WalletDatabase that does nothing and never fails. Only used by unit tests.
- **/
-class DummyDatabase : public WalletDatabase
-{
-public:
- void Open() override {};
- void AddRef() override {}
- void RemoveRef() override {}
- bool Rewrite(const char* pszSkip=nullptr) override { return true; }
- bool Backup(const std::string& strDest) const override { return true; }
- void Close() override {}
- void Flush() override {}
- bool PeriodicFlush() override { return true; }
- void IncrementUpdateCounter() override { ++nUpdateCounter; }
- void ReloadDbEnv() override {}
- std::string Filename() override { return "dummy"; }
- std::string Format() override { return "dummy"; }
- std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<DummyBatch>(); }
-};
-
enum class DatabaseFormat {
BERKELEY,
SQLITE,
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index 69208c19dc..44c93eed7c 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -4,8 +4,8 @@
#include <wallet/dump.h>
-#include <fs.h>
-#include <util/system.h>
+#include <common/args.h>
+#include <util/fs.h>
#include <util/translation.h>
#include <wallet/wallet.h>
@@ -255,11 +255,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
std::vector<unsigned char> k = ParseHex(key);
std::vector<unsigned char> v = ParseHex(value);
-
- DataStream ss_key{k};
- DataStream ss_value{v};
-
- if (!batch->Write(ss_key, ss_value)) {
+ if (!batch->Write(Span{k}, Span{v})) {
error = strprintf(_("Error: Unable to write record to new wallet"));
ret = false;
break;
diff --git a/src/wallet/dump.h b/src/wallet/dump.h
index ff0d94e4b2..5034f95479 100644
--- a/src/wallet/dump.h
+++ b/src/wallet/dump.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_WALLET_DUMP_H
#define BITCOIN_WALLET_DUMP_H
-#include <fs.h>
+#include <util/fs.h>
#include <string>
#include <vector>
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index cb861d835e..6d026d02c1 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
+#include <common/args.h>
+#include <common/system.h>
#include <external_signer.h>
#include <wallet/external_signer_scriptpubkeyman.h>
@@ -43,7 +45,7 @@ ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
const std::string command = gArgs.GetArg("-signer", "");
if (command == "") throw std::runtime_error(std::string(__func__) + ": restart bitcoind with -signer=<cmd>");
std::vector<ExternalSigner> signers;
- ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
+ ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString());
if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found");
// TODO: add fingerprint argument instead of failing in case of multiple signers.
if (signers.size() > 1) throw std::runtime_error(std::string(__func__) + ": More than one external signer found. Please connect only one at a time.");
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 37a704bfa4..0e1f1f9847 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/system.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <util/moneystr.h>
#include <util/rbf.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/feebumper.h>
@@ -63,7 +63,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
}
//! Check if the user provided a valid feeRate
-static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
+static feebumper::Result CheckFeeRate(const CWallet& wallet, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
{
// check that fee rate is higher than mempool's minimum fee
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
@@ -84,15 +84,12 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
- // Given old total fee and transaction size, calculate the old feeRate
- const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
- CFeeRate nOldFeeRate(old_fee, txSize);
// Min total fee is old fee + relay fee
- CAmount minTotalFee = nOldFeeRate.GetFee(maxTxSize) + incrementalRelayFee.GetFee(maxTxSize);
+ CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize);
if (new_total_fee < minTotalFee) {
errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
- FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
+ FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(old_fee), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
return feebumper::Result::INVALID_PARAMETER;
}
@@ -234,7 +231,9 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
// is one). If outputs vector is non-empty, replace original
// outputs with its contents, otherwise use original outputs.
std::vector<CRecipient> recipients;
- for (const auto& output : outputs.empty() ? wtx.tx->vout : outputs) {
+ CAmount new_outputs_value = 0;
+ const auto& txouts = outputs.empty() ? wtx.tx->vout : outputs;
+ for (const auto& output : txouts) {
if (!OutputIsChange(wallet, output)) {
CRecipient recipient = {output.scriptPubKey, output.nValue, false};
recipients.push_back(recipient);
@@ -243,19 +242,35 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
ExtractDestination(output.scriptPubKey, change_dest);
new_coin_control.destChange = change_dest;
}
+ new_outputs_value += output.nValue;
+ }
+
+ // If no recipients, means that we are sending coins to a change address
+ if (recipients.empty()) {
+ // Just as a sanity check, ensure that the change address exist
+ if (std::get_if<CNoDestination>(&new_coin_control.destChange)) {
+ errors.emplace_back(Untranslated("Unable to create transaction. Transaction must have at least one recipient"));
+ return Result::INVALID_PARAMETER;
+ }
+
+ // Add change as recipient with SFFO flag enabled, so fees are deduced from it.
+ // If the output differs from the original tx output (because the user customized it) a new change output will be created.
+ recipients.emplace_back(CRecipient{GetScriptForDestination(new_coin_control.destChange), new_outputs_value, /*fSubtractFeeFromAmount=*/true});
+ new_coin_control.destChange = CNoDestination();
}
if (coin_control.m_feerate) {
// The user provided a feeRate argument.
// We calculate this here to avoid compiler warning on the cs_wallet lock
// We need to make a temporary transaction with no input witnesses as the dummy signer expects them to be empty for external inputs
- CMutableTransaction mtx{*wtx.tx};
- for (auto& txin : mtx.vin) {
+ CMutableTransaction temp_mtx{*wtx.tx};
+ for (auto& txin : temp_mtx.vin) {
txin.scriptSig.clear();
txin.scriptWitness.SetNull();
}
- const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(mtx), &wallet, &new_coin_control).vsize};
- Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
+ temp_mtx.vout = txouts;
+ const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(temp_mtx), &wallet, &new_coin_control).vsize};
+ Result res = CheckFeeRate(wallet, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
if (res != Result::OK) {
return res;
}
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 5403e38950..0d0a8650ac 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <common/args.h>
#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/init.h>
@@ -14,7 +15,6 @@
#include <univalue.h>
#include <util/check.h>
#include <util/moneystr.h>
-#include <util/system.h>
#include <util/translation.h>
#ifdef USE_BDB
#include <wallet/bdb.h>
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 1a76e46c54..cd438cfe2f 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -4,6 +4,7 @@
#include <interfaces/wallet.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
@@ -15,13 +16,13 @@
#include <sync.h>
#include <uint256.h>
#include <util/check.h>
-#include <util/system.h>
#include <util/translation.h>
#include <util/ui_change_type.h>
+#include <wallet/coincontrol.h>
#include <wallet/context.h>
#include <wallet/feebumper.h>
#include <wallet/fees.h>
-#include <wallet/ismine.h>
+#include <wallet/types.h>
#include <wallet/load.h>
#include <wallet/receive.h>
#include <wallet/rpc/wallet.h>
@@ -178,7 +179,7 @@ public:
}
return false;
};
- bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
+ bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override
{
return m_wallet->SetAddressBook(dest, name, purpose);
}
@@ -189,7 +190,7 @@ public:
bool getAddress(const CTxDestination& dest,
std::string* name,
isminetype* is_mine,
- std::string* purpose) override
+ AddressPurpose* purpose) override
{
LOCK(m_wallet->cs_wallet);
const auto& entry = m_wallet->FindAddressBookEntry(dest, /*allow_change=*/false);
@@ -197,11 +198,16 @@ public:
if (name) {
*name = entry->GetLabel();
}
+ std::optional<isminetype> dest_is_mine;
+ if (is_mine || purpose) {
+ dest_is_mine = m_wallet->IsMine(dest);
+ }
if (is_mine) {
- *is_mine = m_wallet->IsMine(dest);
+ *is_mine = *dest_is_mine;
}
if (purpose) {
- *purpose = entry->purpose;
+ // In very old wallets, address purpose may not be recorded so we derive it from IsMine
+ *purpose = entry->purpose.value_or(*dest_is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND);
}
return true;
}
@@ -209,9 +215,11 @@ public:
{
LOCK(m_wallet->cs_wallet);
std::vector<WalletAddress> result;
- m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, const std::string& purpose, bool is_change) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {
+ m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {
if (is_change) return;
- result.emplace_back(dest, m_wallet->IsMine(dest), label, purpose);
+ isminetype is_mine = m_wallet->IsMine(dest);
+ // In very old wallets, address purpose may not be recorded so we derive it from IsMine
+ result.emplace_back(dest, is_mine, purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND), label);
});
return result;
}
@@ -220,9 +228,22 @@ public:
return m_wallet->GetAddressReceiveRequests();
}
bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) override {
+ // Note: The setAddressReceiveRequest interface used by the GUI to store
+ // receive requests is a little awkward and could be improved in the
+ // future:
+ //
+ // - The same method is used to save requests and erase them, but
+ // having separate methods could be clearer and prevent bugs.
+ //
+ // - Request ids are passed as strings even though they are generated as
+ // integers.
+ //
+ // - Multiple requests can be stored for the same address, but it might
+ // be better to only allow one request or only keep the current one.
LOCK(m_wallet->cs_wallet);
WalletBatch batch{m_wallet->GetDatabase()};
- return m_wallet->SetAddressReceiveRequest(batch, dest, id, value);
+ return value.empty() ? m_wallet->EraseAddressReceiveRequest(batch, dest, id)
+ : m_wallet->SetAddressReceiveRequest(batch, dest, id, value);
}
bool displayAddress(const CTxDestination& dest) override
{
@@ -403,7 +424,24 @@ public:
CAmount getBalance() override { return GetBalance(*m_wallet).m_mine_trusted; }
CAmount getAvailableBalance(const CCoinControl& coin_control) override
{
- return GetAvailableBalance(*m_wallet, &coin_control);
+ LOCK(m_wallet->cs_wallet);
+ CAmount total_amount = 0;
+ // Fetch selected coins total amount
+ if (coin_control.HasSelected()) {
+ FastRandomContext rng{};
+ CoinSelectionParams params(rng);
+ // Note: for now, swallow any error.
+ if (auto res = FetchSelectedInputs(*m_wallet, coin_control, params)) {
+ total_amount += res->total_amount;
+ }
+ }
+
+ // And fetch the wallet available coins
+ if (coin_control.m_allow_other_inputs) {
+ total_amount += AvailableCoins(*m_wallet, &coin_control).GetTotalAmount();
+ }
+
+ return total_amount;
}
isminetype txinIsMine(const CTxIn& txin) override
{
@@ -501,7 +539,7 @@ public:
{
return MakeSignalHandler(m_wallet->NotifyAddressBookChanged.connect(
[fn](const CTxDestination& address, const std::string& label, bool is_mine,
- const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
+ AddressPurpose purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
}
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
{
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 8c60a2da72..4cdfadbee2 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -5,12 +5,12 @@
#include <wallet/load.h>
-#include <fs.h>
+#include <common/args.h>
#include <interfaces/chain.h>
#include <scheduler.h>
#include <util/check.h>
+#include <util/fs.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/context.h>
#include <wallet/spend.h>
@@ -62,7 +62,7 @@ bool VerifyWallets(WalletContext& context)
options.require_existing = true;
options.verify = false;
if (MakeWalletDatabase("", options, status, error_string)) {
- util::SettingsValue wallets(util::SettingsValue::VARR);
+ common::SettingsValue wallets(common::SettingsValue::VARR);
wallets.push_back(""); // Default wallet name is ""
// Pass write=false because no need to write file and probably
// better not to. If unnamed wallet needs to be added next startup
diff --git a/src/wallet/receive.h b/src/wallet/receive.h
index 87be0fc2ae..d50644b4cf 100644
--- a/src/wallet/receive.h
+++ b/src/wallet/receive.h
@@ -6,8 +6,8 @@
#define BITCOIN_WALLET_RECEIVE_H
#include <consensus/amount.h>
-#include <wallet/ismine.h>
#include <wallet/transaction.h>
+#include <wallet/types.h>
#include <wallet/wallet.h>
namespace wallet {
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index da63d45d11..a8ef0a5731 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -141,9 +141,9 @@ RPCHelpMan setlabel()
const std::string label{LabelFromValue(request.params[1])};
if (pwallet->IsMine(dest)) {
- pwallet->SetAddressBook(dest, label, "receive");
+ pwallet->SetAddressBook(dest, label, AddressPurpose::RECEIVE);
} else {
- pwallet->SetAddressBook(dest, label, "send");
+ pwallet->SetAddressBook(dest, label, AddressPurpose::SEND);
}
return UniValue::VNULL;
@@ -218,7 +218,8 @@ RPCHelpMan addmultisigaddress()
"Each key is a Bitcoin address or hex-encoded public key.\n"
"This functionality is only intended for use with non-watchonly addresses.\n"
"See `importaddress` for watchonly p2sh address support.\n"
- "If 'label' is specified, assign address to that label.\n",
+ "If 'label' is specified, assign address to that label.\n"
+ "Note: This command is only compatible with legacy wallets.\n",
{
{"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
{"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The bitcoin addresses or hex-encoded public keys",
@@ -285,7 +286,7 @@ RPCHelpMan addmultisigaddress()
// Construct using pay-to-script-hash:
CScript inner;
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
- pwallet->SetAddressBook(dest, label, "send");
+ pwallet->SetAddressBook(dest, label, AddressPurpose::SEND);
// Make the descriptor
std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man);
@@ -300,7 +301,7 @@ RPCHelpMan addmultisigaddress()
// Only warns if the user has explicitly chosen an address type we cannot generate
warnings.push_back("Unable to make chosen address type, please ensure no uncompressed public keys are present.");
}
- if (!warnings.empty()) result.pushKV("warnings", warnings);
+ PushWarnings(warnings, result);
return result;
},
@@ -607,7 +608,9 @@ RPCHelpMan getaddressinfo()
if (const std::unique_ptr<CKeyMetadata> meta = spk_man->GetMetadata(dest)) {
ret.pushKV("timestamp", meta->nCreateTime);
if (meta->has_key_origin) {
- ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
+ // In legacy wallets hdkeypath has always used an apostrophe for
+ // hardened derivation. Perhaps some external tool depends on that.
+ ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path, /*apostrophe=*/!desc_spk_man));
ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));
}
@@ -663,7 +666,7 @@ RPCHelpMan getaddressesbylabel()
// Find all addresses that have the given label
UniValue ret(UniValue::VOBJ);
std::set<std::string> addresses;
- pwallet->ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label, const std::string& _purpose, bool _is_change) {
+ pwallet->ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label, bool _is_change, const std::optional<AddressPurpose>& _purpose) {
if (_is_change) return;
if (_label == label) {
std::string address = EncodeDestination(_dest);
@@ -674,11 +677,11 @@ RPCHelpMan getaddressesbylabel()
CHECK_NONFATAL(unique);
// UniValue::pushKV checks if the key exists in O(N)
// and since duplicate addresses are unexpected (checked with
- // std::set in O(log(N))), UniValue::__pushKV is used instead,
+ // std::set in O(log(N))), UniValue::pushKVEnd is used instead,
// which currently is O(1).
UniValue value(UniValue::VOBJ);
- value.pushKV("purpose", _purpose);
- ret.__pushKV(address, value);
+ value.pushKV("purpose", _purpose ? PurposeToString(*_purpose) : "unknown");
+ ret.pushKVEnd(address, value);
}
});
@@ -721,9 +724,15 @@ RPCHelpMan listlabels()
LOCK(pwallet->cs_wallet);
- std::string purpose;
+ std::optional<AddressPurpose> purpose;
if (!request.params[0].isNull()) {
- purpose = request.params[0].get_str();
+ std::string purpose_str = request.params[0].get_str();
+ if (!purpose_str.empty()) {
+ purpose = PurposeFromString(purpose_str);
+ if (!purpose) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid 'purpose' argument, must be a known purpose string, typically 'send', or 'receive'.");
+ }
+ }
}
// Add to a set to sort by label name, then insert into Univalue array
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 09cfc07bc2..af8043f158 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -5,7 +5,6 @@
#include <chain.h>
#include <clientversion.h>
#include <core_io.h>
-#include <fs.h>
#include <hash.h>
#include <interfaces/chain.h>
#include <key_io.h>
@@ -17,6 +16,7 @@
#include <sync.h>
#include <uint256.h>
#include <util/bip32.h>
+#include <util/fs.h>
#include <util/time.h>
#include <util/translation.h>
#include <wallet/rpc/util.h>
@@ -119,7 +119,8 @@ RPCHelpMan importprivkey()
"may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
"but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
- "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
+ "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" with \"combo(X)\" for descriptor wallets.\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
{"label", RPCArg::Type::STR, RPCArg::DefaultHint{"current label if address exists, otherwise \"\""}, "An optional label"},
@@ -188,7 +189,7 @@ RPCHelpMan importprivkey()
// label was passed.
for (const auto& dest : GetAllDestinationsForKey(pubkey)) {
if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
- pwallet->SetAddressBook(dest, strLabel, "receive");
+ pwallet->SetAddressBook(dest, strLabel, AddressPurpose::RECEIVE);
}
}
@@ -225,7 +226,7 @@ RPCHelpMan importaddress()
"\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
"as change, and not show up in many RPCs.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n"
- "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" with \"addr(X)\" for descriptor wallets.\n",
+ "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" for descriptor wallets.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
{"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"},
@@ -417,7 +418,8 @@ RPCHelpMan importpubkey()
"may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
"but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
- "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
+ "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" with \"combo(X)\" for descriptor wallets.\n",
{
{"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
{"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"},
@@ -495,7 +497,8 @@ RPCHelpMan importwallet()
{
return RPCHelpMan{"importwallet",
"\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
- "Note: Blockchain and Mempool will be rescanned after a successful import. Use \"getwalletinfo\" to query the scanning progress.\n",
+ "Note: Blockchain and Mempool will be rescanned after a successful import. Use \"getwalletinfo\" to query the scanning progress.\n"
+ "Note: This command is only compatible with legacy wallets.\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"},
},
@@ -608,7 +611,7 @@ RPCHelpMan importwallet()
}
if (has_label)
- pwallet->SetAddressBook(PKHash(keyid), label, "receive");
+ pwallet->SetAddressBook(PKHash(keyid), label, AddressPurpose::RECEIVE);
progress++;
}
for (const auto& script_pair : scripts) {
@@ -642,7 +645,8 @@ RPCHelpMan dumpprivkey()
{
return RPCHelpMan{"dumpprivkey",
"\nReveals the private key corresponding to 'address'.\n"
- "Then the importprivkey can be used with this output\n",
+ "Then the importprivkey can be used with this output\n"
+ "Note: This command is only compatible with legacy wallets.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for the private key"},
},
@@ -690,7 +694,8 @@ RPCHelpMan dumpwallet()
"\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
"Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
"Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n"
- "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
+ "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n"
+ "Note: This command is only compatible with legacy wallets.\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The filename with path (absolute path recommended)"},
},
@@ -752,6 +757,7 @@ RPCHelpMan dumpwallet()
// sort time/key pairs
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
+ vKeyBirth.reserve(mapKeyBirth.size());
for (const auto& entry : mapKeyBirth) {
vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
}
@@ -799,7 +805,7 @@ RPCHelpMan dumpwallet()
} else {
file << "change=1";
}
- file << strprintf(" # addr=%s%s\n", strAddr, (metadata.has_key_origin ? " hdkeypath="+WriteHDKeypath(metadata.key_origin.path) : ""));
+ file << strprintf(" # addr=%s%s\n", strAddr, (metadata.has_key_origin ? " hdkeypath="+WriteHDKeypath(metadata.key_origin.path, /*apostrophe=*/true) : ""));
}
}
file << "\n";
@@ -1224,7 +1230,7 @@ static UniValue ProcessImport(CWallet& wallet, const UniValue& data, const int64
result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
}
- if (warnings.size()) result.pushKV("warnings", warnings);
+ PushWarnings(warnings, result);
return result;
}
@@ -1252,7 +1258,8 @@ RPCHelpMan importmulti()
"may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
"The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
"but the key was used to create transactions, rescanblockchain needs to be called with the appropriate block range.\n"
- "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
+ "Note: This command is only compatible with legacy wallets. Use \"importdescriptors\" for descriptor wallets.\n",
{
{"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
{
@@ -1291,7 +1298,7 @@ RPCHelpMan importmulti()
},
},
RPCArgOptions{.oneline_description="\"requests\""}},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
{
{"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions after all imports."},
},
@@ -1578,7 +1585,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
result.pushKV("success", UniValue(false));
result.pushKV("error", e);
}
- if (warnings.size()) result.pushKV("warnings", warnings);
+ PushWarnings(warnings, result);
return result;
}
@@ -1855,7 +1862,7 @@ RPCHelpMan listdescriptors()
RPCHelpMan backupwallet()
{
return RPCHelpMan{"backupwallet",
- "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
+ "\nSafely copies the current wallet file to the specified destination, which can either be a directory or a path with a filename.\n",
{
{"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
},
@@ -1890,7 +1897,7 @@ RPCHelpMan restorewallet()
{
return RPCHelpMan{
"restorewallet",
- "\nRestore and loads a wallet from backup.\n"
+ "\nRestores and loads a wallet from backup.\n"
"\nThe rescan is significantly faster if a descriptor wallet is restored"
"\nand block filters are available (using startup option \"-blockfilterindex=1\").\n",
{
@@ -1902,7 +1909,10 @@ RPCHelpMan restorewallet()
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "name", "The wallet name if restored successfully."},
- {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
+ {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to restoring and loading the wallet.",
+ {
+ {RPCResult::Type::STR, "", ""},
+ }},
}
},
RPCExamples{
@@ -1932,7 +1942,7 @@ RPCHelpMan restorewallet()
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
- obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
+ PushWarnings(warnings, obj);
return obj;
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index 4c386789f1..22f0f0b83c 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -320,7 +320,7 @@ RPCHelpMan lockunspent()
});
const uint256 txid(ParseHashO(o, "txid"));
- const int nOutput = find_value(o, "vout").getInt<int>();
+ const int nOutput = o.find_value("vout").getInt<int>();
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
}
@@ -448,6 +448,7 @@ RPCHelpMan getbalances()
{RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
{RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
}},
+ RESULT_LAST_PROCESSED_BLOCK,
}
},
RPCExamples{
@@ -488,6 +489,8 @@ RPCHelpMan getbalances()
balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
balances.pushKV("watchonly", balances_watchonly);
}
+
+ AppendLastProcessedBlock(balances, wallet);
return balances;
},
};
@@ -510,7 +513,7 @@ RPCHelpMan listunspent()
},
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n"
"See description of \"safe\" attribute below."},
- {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "JSON with query options",
+ {"query_options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
{
{"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
{"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index 88ee6e96b0..feee643f26 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -453,9 +453,9 @@ RPCHelpMan settxfee()
static std::vector<RPCArg> FundTxDoc(bool solving_data = true)
{
std::vector<RPCArg> args = {
- {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
+ {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks", RPCArgOptions{.also_positional = true}},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
- "\"" + FeeModes("\"\n\"") + "\""},
+ "\"" + FeeModes("\"\n\"") + "\"", RPCArgOptions{.also_positional = true}},
{
"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125-replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees"
@@ -673,7 +673,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
for (const UniValue& input : options["input_weights"].get_array().getValues()) {
uint256 txid = ParseHashO(input, "txid");
- const UniValue& vout_v = find_value(input, "vout");
+ const UniValue& vout_v = input.find_value("vout");
if (!vout_v.isNum()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
}
@@ -682,7 +682,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
}
- const UniValue& weight_v = find_value(input, "weight");
+ const UniValue& weight_v = input.find_value("weight");
if (!weight_v.isNum()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing weight key");
}
@@ -758,7 +758,7 @@ RPCHelpMan fundrawtransaction()
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "For backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
@@ -997,7 +997,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
"* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
{
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
@@ -1187,7 +1187,7 @@ RPCHelpMan send()
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
"\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"},"Automatically include coins from the wallet to cover the target amount.\n"},
@@ -1200,7 +1200,7 @@ RPCHelpMan send()
{"change_address", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", \"bech32\" and \"bech32m\"."},
- {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
@@ -1302,11 +1302,11 @@ RPCHelpMan sendall()
"\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{
- "options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ "options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
Cat<std::vector<RPCArg>>(
{
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns the serialized transaction without broadcasting or adding it to the wallet"},
- {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
+ {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB.", RPCArgOptions{.also_positional = true}},
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch-only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
"e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
@@ -1635,7 +1635,7 @@ RPCHelpMan walletcreatefundedpsbt()
OutputsDoc(),
RPCArgOptions{.skip_type_check = true}},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
Cat<std::vector<RPCArg>>(
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"}, "Automatically include coins from the wallet to cover the target amount.\n"},
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index 3bfe296d90..c34391e6e8 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -134,7 +134,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
UniValue ret(UniValue::VARR);
std::map<std::string, tallyitem> label_tally;
- const auto& func = [&](const CTxDestination& address, const std::string& label, const std::string& purpose, bool is_change) {
+ const auto& func = [&](const CTxDestination& address, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) {
if (is_change) return; // no change addresses
auto it = mapTally.find(address);
@@ -175,7 +175,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
if (filtered_address) {
const auto& entry = wallet.FindAddressBookEntry(*filtered_address, /*allow_change=*/false);
- if (entry) func(*filtered_address, entry->GetLabel(), entry->purpose, /*is_change=*/false);
+ if (entry) func(*filtered_address, entry->GetLabel(), entry->IsChange(), entry->purpose);
} else {
// No filtered addr, walk-through the addressbook entry
wallet.ForEachAddrBookEntry(func);
@@ -389,6 +389,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
entry.pushKV("label", label);
}
entry.pushKV("vout", r.vout);
+ entry.pushKV("abandoned", wtx.isAbandoned());
if (fLong)
WalletTxToJSON(wallet, wtx, entry);
ret.push_back(entry);
@@ -462,8 +463,7 @@ RPCHelpMan listtransactions()
},
TransactionDescriptionString()),
{
- {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
- "'send' category of transactions."},
+ {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
})},
}
},
@@ -576,8 +576,7 @@ RPCHelpMan listsinceblock()
},
TransactionDescriptionString()),
{
- {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
- "'send' category of transactions."},
+ {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
{RPCResult::Type::STR, "label", /*optional=*/true, "A comment for the address/transaction, if any"},
})},
}},
@@ -721,8 +720,7 @@ RPCHelpMan gettransaction()
{RPCResult::Type::NUM, "vout", "the vout value"},
{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
"'send' category of transactions."},
- {RPCResult::Type::BOOL, "abandoned", /*optional=*/true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
- "'send' category of transactions."},
+ {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable)."},
{RPCResult::Type::ARR, "parent_descs", /*optional=*/true, "Only if 'category' is 'received'. List of parent descriptors for the scriptPubKey of this coin.", {
{RPCResult::Type::STR, "desc", "The descriptor string."},
}},
@@ -733,6 +731,7 @@ RPCHelpMan gettransaction()
{
{RPCResult::Type::ELISION, "", "Equivalent to the RPC decoderawtransaction method, or the RPC getrawtransaction method when `verbose` is passed."},
}},
+ RESULT_LAST_PROCESSED_BLOCK,
})
},
RPCExamples{
@@ -793,6 +792,7 @@ RPCHelpMan gettransaction()
entry.pushKV("decoded", decoded);
}
+ AppendLastProcessedBlock(entry, *pwallet);
return entry;
},
};
diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp
index 4d82e0a41f..06ec7db1bc 100644
--- a/src/wallet/rpc/util.cpp
+++ b/src/wallet/rpc/util.cpp
@@ -6,7 +6,7 @@
#include <common/url.h>
#include <rpc/util.h>
-#include <util/system.h>
+#include <util/any.h>
#include <util/translation.h>
#include <wallet/context.h>
#include <wallet/wallet.h>
@@ -177,4 +177,14 @@ void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& st
throw JSONRPCError(code, error.original);
}
}
+
+void AppendLastProcessedBlock(UniValue& entry, const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
+{
+ AssertLockHeld(wallet.cs_wallet);
+ UniValue lastprocessedblock{UniValue::VOBJ};
+ lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());
+ lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());
+ entry.pushKV("lastprocessedblock", lastprocessedblock);
+}
+
} // namespace wallet
diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h
index d5d6ac0dfa..2fdba04352 100644
--- a/src/wallet/rpc/util.h
+++ b/src/wallet/rpc/util.h
@@ -5,7 +5,9 @@
#ifndef BITCOIN_WALLET_RPC_UTIL_H
#define BITCOIN_WALLET_RPC_UTIL_H
+#include <rpc/util.h>
#include <script/script.h>
+#include <wallet/wallet.h>
#include <any>
#include <memory>
@@ -17,13 +19,17 @@ class UniValue;
struct bilingual_str;
namespace wallet {
-class CWallet;
class LegacyScriptPubKeyMan;
enum class DatabaseStatus;
struct WalletContext;
extern const std::string HELP_REQUIRING_PASSPHRASE;
+static const RPCResult RESULT_LAST_PROCESSED_BLOCK { RPCResult::Type::OBJ, "lastprocessedblock", "hash and height of the block this information was generated on",{
+ {RPCResult::Type::STR_HEX, "hash", "hash of the block this information was generated on"},
+ {RPCResult::Type::NUM, "height", "height of the block this information was generated on"}}
+};
+
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
@@ -45,8 +51,8 @@ std::string LabelFromValue(const UniValue& value);
void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry);
void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error);
-
int64_t ParseISO8601DateTime(const std::string& str);
+void AppendLastProcessedBlock(UniValue& entry, const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
} // namespace wallet
#endif // BITCOIN_WALLET_RPC_UTIL_H
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 16595267b4..fb4b642bba 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -13,6 +13,7 @@
#include <wallet/rpc/wallet.h>
#include <wallet/rpc/util.h>
#include <wallet/wallet.h>
+#include <wallet/walletutil.h>
#include <optional>
@@ -20,6 +21,14 @@
namespace wallet {
+
+static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{
+ {WALLET_FLAG_AVOID_REUSE,
+ "You need to rescan the blockchain in order to correctly mark used "
+ "destinations in the past. Until this is done, some destinations may "
+ "be considered unused, even if the opposite is the case."},
+};
+
/** Checks if a CKey is in the given CWallet compressed or otherwise*/
bool HaveKey(const SigningProvider& wallet, const CKey& key)
{
@@ -59,6 +68,8 @@ static RPCHelpMan getwalletinfo()
}, /*skip_type_check=*/true},
{RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
+ {RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
+ RESULT_LAST_PROCESSED_BLOCK,
}},
},
RPCExamples{
@@ -112,7 +123,7 @@ static RPCHelpMan getwalletinfo()
obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
if (pwallet->IsScanning()) {
UniValue scanning(UniValue::VOBJ);
- scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
+ scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
scanning.pushKV("progress", pwallet->ScanningProgress());
obj.pushKV("scanning", scanning);
} else {
@@ -120,6 +131,9 @@ static RPCHelpMan getwalletinfo()
}
obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));
+ obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
+
+ AppendLastProcessedBlock(obj, *pwallet);
return obj;
},
};
@@ -207,7 +221,10 @@ static RPCHelpMan loadwallet()
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
- {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
+ {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",
+ {
+ {RPCResult::Type::STR, "", ""},
+ }},
}
},
RPCExamples{
@@ -240,7 +257,7 @@ static RPCHelpMan loadwallet()
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
- obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
+ PushWarnings(warnings, obj);
return obj;
},
@@ -335,7 +352,10 @@ static RPCHelpMan createwallet()
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "name", "The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
- {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
+ {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to creating and loading the wallet.",
+ {
+ {RPCResult::Type::STR, "", ""},
+ }},
}
},
RPCExamples{
@@ -405,7 +425,7 @@ static RPCHelpMan createwallet()
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
- obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
+ PushWarnings(warnings, obj);
return obj;
},
@@ -415,14 +435,17 @@ static RPCHelpMan createwallet()
static RPCHelpMan unloadwallet()
{
return RPCHelpMan{"unloadwallet",
- "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
+ "Unloads the wallet referenced by the request endpoint, otherwise unloads the wallet specified in the argument.\n"
"Specifying the wallet name on a wallet endpoint is invalid.",
{
{"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
{"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
},
RPCResult{RPCResult::Type::OBJ, "", "", {
- {RPCResult::Type::STR, "warning", "Warning message if wallet was not unloaded cleanly."},
+ {RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to unloading the wallet.",
+ {
+ {RPCResult::Type::STR, "", ""},
+ }},
}},
RPCExamples{
HelpExampleCli("unloadwallet", "wallet_name")
@@ -464,7 +487,8 @@ static RPCHelpMan unloadwallet()
UnloadWallet(std::move(wallet));
UniValue result(UniValue::VOBJ);
- result.pushKV("warning", Join(warnings, Untranslated("\n")).original);
+ PushWarnings(warnings, result);
+
return result;
},
};
@@ -475,8 +499,8 @@ static RPCHelpMan sethdseed()
return RPCHelpMan{"sethdseed",
"\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
"HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
- "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." +
- HELP_REQUIRING_PASSPHRASE,
+ "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." + HELP_REQUIRING_PASSPHRASE +
+ "Note: This command is only compatible with legacy wallets.\n",
{
{"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
"If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
@@ -613,7 +637,7 @@ RPCHelpMan simulaterawtransaction()
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
},
},
- {"options", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "Options",
+ {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
{
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
},
diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp
index e2b4dbf4c2..e303310273 100644
--- a/src/wallet/salvage.cpp
+++ b/src/wallet/salvage.cpp
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <fs.h>
#include <streams.h>
+#include <util/fs.h>
#include <util/translation.h>
#include <wallet/bdb.h>
#include <wallet/salvage.h>
@@ -23,6 +23,52 @@ static bool KeyFilter(const std::string& type)
return WalletBatch::IsKeyType(type) || type == DBKeys::HDCHAIN;
}
+class DummyCursor : public DatabaseCursor
+{
+ Status Next(DataStream& key, DataStream& value) override { return Status::FAIL; }
+};
+
+/** RAII class that provides access to a DummyDatabase. Never fails. */
+class DummyBatch : public DatabaseBatch
+{
+private:
+ bool ReadKey(DataStream&& key, DataStream& value) override { return true; }
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite=true) override { return true; }
+ bool EraseKey(DataStream&& key) override { return true; }
+ bool HasKey(DataStream&& key) override { return true; }
+ bool ErasePrefix(Span<const std::byte> prefix) override { return true; }
+
+public:
+ void Flush() override {}
+ void Close() override {}
+
+ std::unique_ptr<DatabaseCursor> GetNewCursor() override { return std::make_unique<DummyCursor>(); }
+ std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override { return GetNewCursor(); }
+ bool TxnBegin() override { return true; }
+ bool TxnCommit() override { return true; }
+ bool TxnAbort() override { return true; }
+};
+
+/** A dummy WalletDatabase that does nothing and never fails. Only used by salvage.
+ **/
+class DummyDatabase : public WalletDatabase
+{
+public:
+ void Open() override {};
+ void AddRef() override {}
+ void RemoveRef() override {}
+ bool Rewrite(const char* pszSkip=nullptr) override { return true; }
+ bool Backup(const std::string& strDest) const override { return true; }
+ void Close() override {}
+ void Flush() override {}
+ bool PeriodicFlush() override { return true; }
+ void IncrementUpdateCounter() override { ++nUpdateCounter; }
+ void ReloadDbEnv() override {}
+ std::string Filename() override { return "dummy"; }
+ std::string Format() override { return "dummy"; }
+ std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<DummyBatch>(); }
+};
+
bool RecoverDatabaseFile(const ArgsManager& args, const fs::path& file_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
DatabaseOptions options;
@@ -135,7 +181,7 @@ bool RecoverDatabaseFile(const ArgsManager& args, const fs::path& file_path, bil
}
DbTxn* ptxn = env->TxnBegin();
- CWallet dummyWallet(nullptr, "", CreateDummyWalletDatabase());
+ CWallet dummyWallet(nullptr, "", std::make_unique<DummyDatabase>());
for (KeyValPair& row : salvagedData)
{
/* Filter for only private key type KV pairs to be added to the salvaged wallet */
diff --git a/src/wallet/salvage.h b/src/wallet/salvage.h
index ce918aec2d..fbf152ec79 100644
--- a/src/wallet/salvage.h
+++ b/src/wallet/salvage.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_WALLET_SALVAGE_H
#define BITCOIN_WALLET_SALVAGE_H
-#include <fs.h>
#include <streams.h>
+#include <util/fs.h>
class ArgsManager;
struct bilingual_str;
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 1589e52deb..796b7f11c5 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -710,6 +710,8 @@ void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime)
} else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) {
nTimeFirstKey = nCreateTime;
}
+
+ NotifyFirstKeyTimeChanged(this, nTimeFirstKey);
}
bool LegacyScriptPubKeyMan::LoadKey(const CKey& key, const CPubKey &pubkey)
@@ -755,12 +757,12 @@ bool LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& s
RemoveWatchOnly(script);
}
+ m_storage.UnsetBlankWalletFlag(batch);
if (!m_storage.HasEncryptionKeys()) {
return batch.WriteKey(pubkey,
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
- m_storage.UnsetBlankWalletFlag(batch);
return true;
}
@@ -1385,10 +1387,10 @@ void LegacyScriptPubKeyMan::ReturnDestination(int64_t nIndex, bool fInternal, co
WalletLogPrintf("keypool return %d\n", nIndex);
}
-bool LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const OutputType type, bool internal)
+bool LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const OutputType type)
{
assert(type != OutputType::BECH32M);
- if (!CanGetAddresses(internal)) {
+ if (!CanGetAddresses(/*internal=*/ false)) {
return false;
}
@@ -1396,10 +1398,10 @@ bool LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const OutputType typ
{
LOCK(cs_KeyStore);
int64_t nIndex;
- if (!ReserveKeyFromKeyPool(nIndex, keypool, internal) && !m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ if (!ReserveKeyFromKeyPool(nIndex, keypool, /*fRequestedInternal=*/ false) && !m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (m_storage.IsLocked()) return false;
WalletBatch batch(m_storage.GetDatabase());
- result = GenerateNewKey(batch, m_hd_chain, internal);
+ result = GenerateNewKey(batch, m_hd_chain, /*internal=*/ false);
return true;
}
KeepDestination(nIndex, type);
@@ -1507,6 +1509,7 @@ std::vector<CKeyID> GetAffectedKeys(const CScript& spk, const SigningProvider& p
FlatSigningProvider out;
InferDescriptor(spk, provider)->Expand(0, DUMMY_SIGNING_PROVIDER, dummy, out);
std::vector<CKeyID> ret;
+ ret.reserve(out.pubkeys.size());
for (const auto& entry : out.pubkeys) {
ret.push_back(entry.first);
}
@@ -1554,7 +1557,7 @@ bool LegacyScriptPubKeyMan::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey
std::copy(info.fingerprint, info.fingerprint + 4, mapKeyMetadata[pubkey.GetID()].key_origin.fingerprint);
mapKeyMetadata[pubkey.GetID()].key_origin.path = info.path;
mapKeyMetadata[pubkey.GetID()].has_key_origin = true;
- mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path);
+ mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path, /*apostrophe=*/true);
return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
}
@@ -1820,7 +1823,7 @@ std::optional<MigrationData> LegacyScriptPubKeyMan::MigrateToDescriptor()
// Make the combo descriptor
std::string xpub = EncodeExtPubKey(master_key.Neuter());
- std::string desc_str = "combo(" + xpub + "/0'/" + ToString(i) + "'/*')";
+ std::string desc_str = "combo(" + xpub + "/0h/" + ToString(i) + "h/*h)";
FlatSigningProvider keys;
std::string error;
std::unique_ptr<Descriptor> desc = Parse(desc_str, keys, error, false);
@@ -2263,20 +2266,20 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
std::string desc_suffix = "/*)";
switch (addr_type) {
case OutputType::LEGACY: {
- desc_prefix = "pkh(" + xpub + "/44'";
+ desc_prefix = "pkh(" + xpub + "/44h";
break;
}
case OutputType::P2SH_SEGWIT: {
- desc_prefix = "sh(wpkh(" + xpub + "/49'";
+ desc_prefix = "sh(wpkh(" + xpub + "/49h";
desc_suffix += ")";
break;
}
case OutputType::BECH32: {
- desc_prefix = "wpkh(" + xpub + "/84'";
+ desc_prefix = "wpkh(" + xpub + "/84h";
break;
}
case OutputType::BECH32M: {
- desc_prefix = "tr(" + xpub + "/86'";
+ desc_prefix = "tr(" + xpub + "/86h";
break;
}
case OutputType::UNKNOWN: {
@@ -2289,13 +2292,13 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
// Mainnet derives at 0', testnet and regtest derive at 1'
if (Params().IsTestChain()) {
- desc_prefix += "/1'";
+ desc_prefix += "/1h";
} else {
- desc_prefix += "/0'";
+ desc_prefix += "/0h";
}
std::string internal_path = internal ? "/1" : "/0";
- std::string desc_str = desc_prefix + "/0'" + internal_path + desc_suffix;
+ std::string desc_str = desc_prefix + "/0h" + internal_path + desc_suffix;
// Make the descriptor
FlatSigningProvider keys;
@@ -2501,6 +2504,7 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
} else {
// Maybe there are pubkeys listed that we can sign for
std::vector<CPubKey> pubkeys;
+ pubkeys.reserve(input.hd_keypaths.size() + 2);
// ECDSA Pubkeys
for (const auto& [pk, _] : input.hd_keypaths) {
@@ -2734,6 +2738,8 @@ void DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescriptor& descrip
m_map_script_pub_keys.clear();
m_max_cached_index = -1;
m_wallet_descriptor = descriptor;
+
+ NotifyFirstKeyTimeChanged(this, m_wallet_descriptor.creation_time);
}
bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error)
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index 4d14325241..bf35c776ae 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
#define BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
+#include <logging.h>
#include <psbt.h>
#include <script/descriptor.h>
#include <script/signingprovider.h>
@@ -14,7 +15,7 @@
#include <util/result.h>
#include <util/time.h>
#include <wallet/crypter.h>
-#include <wallet/ismine.h>
+#include <wallet/types.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
@@ -27,6 +28,8 @@ enum class OutputType;
struct bilingual_str;
namespace wallet {
+struct MigrationData;
+
// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
// It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as
// wallet flags, wallet version, encryption keys, encryption status, and the database itself. This allows a
@@ -256,6 +259,9 @@ public:
/** Keypool has new keys */
boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
+
+ /** Birth time changed */
+ boost::signals2::signal<void (const ScriptPubKeyMan* spkm, int64_t new_birth_time)> NotifyFirstKeyTimeChanged;
};
/** OutputTypes supported by the LegacyScriptPubKeyMan */
@@ -334,7 +340,7 @@ private:
std::map<int64_t, CKeyID> m_index_to_reserved_key;
//! Fetches a key from the keypool
- bool GetKeyFromPool(CPubKey &key, const OutputType type, bool internal = false);
+ bool GetKeyFromPool(CPubKey &key, const OutputType type);
/**
* Reserves a key from the keypool and sets nIndex to its index
@@ -658,6 +664,18 @@ public:
void UpgradeDescriptorCache();
};
+
+/** struct containing information needed for migrating legacy wallets to descriptor wallets */
+struct MigrationData
+{
+ CExtKey master_key;
+ std::vector<std::pair<std::string, int64_t>> watch_descs;
+ std::vector<std::pair<std::string, int64_t>> solvable_descs;
+ std::vector<std::unique_ptr<DescriptorScriptPubKeyMan>> desc_spkms;
+ std::shared_ptr<CWallet> watchonly_wallet{nullptr};
+ std::shared_ptr<CWallet> solvable_wallet{nullptr};
+};
+
} // namespace wallet
#endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 4548d5f813..a3728223fb 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <algorithm>
+#include <common/args.h>
+#include <common/system.h>
#include <consensus/amount.h>
#include <consensus/validation.h>
#include <interfaces/chain.h>
@@ -50,9 +52,7 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet,
TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control)
{
CMutableTransaction txNew(tx);
- if (!wallet->DummySignTx(txNew, txouts, coin_control)) {
- return TxSize{-1, -1};
- }
+ if (!wallet->DummySignTx(txNew, txouts, coin_control)) return TxSize{-1, -1};
CTransaction ctx(txNew);
int64_t vsize = GetVirtualTransactionSize(ctx);
int64_t weight = GetTransactionWeight(ctx);
@@ -70,11 +70,9 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
assert(input.prevout.n < mi->second.tx->vout.size());
txouts.emplace_back(mi->second.tx->vout.at(input.prevout.n));
} else if (coin_control) {
- CTxOut txout;
- if (!coin_control->GetExternalOutput(input.prevout, txout)) {
- return TxSize{-1, -1};
- }
- txouts.emplace_back(txout);
+ const auto& txout{coin_control->GetExternalOutput(input.prevout)};
+ if (!txout) return TxSize{-1, -1};
+ txouts.emplace_back(*txout);
} else {
return TxSize{-1, -1};
}
@@ -161,10 +159,8 @@ util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
PreSelectedInputs result;
- std::vector<COutPoint> vPresetInputs;
- coin_control.ListSelected(vPresetInputs);
const bool can_grind_r = wallet.CanGrindR();
- for (const COutPoint& outpoint : vPresetInputs) {
+ for (const COutPoint& outpoint : coin_control.ListSelected()) {
int input_bytes = -1;
CTxOut txout;
if (auto ptr_wtx = wallet.GetWalletTx(outpoint.hash)) {
@@ -176,9 +172,12 @@ util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const
input_bytes = CalculateMaximumSignedInputSize(txout, &wallet, &coin_control);
} else {
// The input is external. We did not find the tx in mapWallet.
- if (!coin_control.GetExternalOutput(outpoint, txout)) {
+ const auto out{coin_control.GetExternalOutput(outpoint)};
+ if (!out) {
return util::Error{strprintf(_("Not found pre-selected input %s"), outpoint.ToString())};
}
+
+ txout = *out;
}
if (input_bytes == -1) {
@@ -356,12 +355,6 @@ CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl*
return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, params);
}
-CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl)
-{
- LOCK(wallet.cs_wallet);
- return AvailableCoins(wallet, coinControl).GetTotalAmount();
-}
-
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
{
AssertLockHeld(wallet.cs_wallet);
@@ -565,42 +558,45 @@ util::Result<SelectionResult> ChooseSelectionResult(const CAmount& nTargetValue,
{
// Vector of results. We will choose the best one based on waste.
std::vector<SelectionResult> results;
+ std::vector<util::Result<SelectionResult>> errors;
+ auto append_error = [&] (const util::Result<SelectionResult>& result) {
+ // If any specific error message appears here, then something different from a simple "no selection found" happened.
+ // Let's save it, so it can be retrieved to the user if no other selection algorithm succeeded.
+ if (HasErrorMsg(result)) {
+ errors.emplace_back(result);
+ }
+ };
- if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change)}) {
+ // Maximum allowed weight
+ int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR);
+
+ if (auto bnb_result{SelectCoinsBnB(groups.positive_group, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) {
results.push_back(*bnb_result);
- }
+ } else append_error(bnb_result);
+
+ // As Knapsack and SRD can create change, also deduce change weight.
+ max_inputs_weight -= (coin_selection_params.change_output_size * WITNESS_SCALE_FACTOR);
// The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
- if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast)}) {
+ if (auto knapsack_result{KnapsackSolver(groups.mixed_group, nTargetValue, coin_selection_params.m_min_change_target, coin_selection_params.rng_fast, max_inputs_weight)}) {
knapsack_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
results.push_back(*knapsack_result);
- }
+ } else append_error(knapsack_result);
- if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.rng_fast)}) {
+ if (auto srd_result{SelectCoinsSRD(groups.positive_group, nTargetValue, coin_selection_params.m_change_fee, coin_selection_params.rng_fast, max_inputs_weight)}) {
srd_result->ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee);
results.push_back(*srd_result);
- }
+ } else append_error(srd_result);
if (results.empty()) {
- // No solution found
- return util::Error();
- }
-
- std::vector<SelectionResult> eligible_results;
- std::copy_if(results.begin(), results.end(), std::back_inserter(eligible_results), [coin_selection_params](const SelectionResult& result) {
- const auto initWeight{coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR};
- return initWeight + result.GetWeight() <= static_cast<int>(MAX_STANDARD_TX_WEIGHT);
- });
-
- if (eligible_results.empty()) {
- return util::Error{_("The inputs size exceeds the maximum weight. "
- "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")};
+ // No solution found, retrieve the first explicit error (if any).
+ // future: add 'severity level' to errors so the worst one can be retrieved instead of the first one.
+ return errors.empty() ? util::Error() : errors.front();
}
// Choose the result with the least waste
// If the waste is the same, choose the one which spends more inputs.
- auto& best_result = *std::min_element(eligible_results.begin(), eligible_results.end());
- return best_result;
+ return *std::min_element(results.begin(), results.end());
}
util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const PreSelectedInputs& pre_set_inputs,
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index 78c2c5f22b..cc9ccf3011 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -94,8 +94,6 @@ CoinsResult AvailableCoins(const CWallet& wallet,
*/
CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, CoinFilterParams params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
-CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl = nullptr);
-
/**
* Find non-change parent output.
*/
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 8d8a7ab2a2..8d7fe97bb1 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -8,8 +8,9 @@
#include <crypto/common.h>
#include <logging.h>
#include <sync.h>
+#include <util/fs_helpers.h>
+#include <util/check.h>
#include <util/strencodings.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/db.h>
@@ -34,12 +35,31 @@ static void ErrorLogCallback(void* arg, int code, const char* msg)
LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg);
}
+static int TraceSqlCallback(unsigned code, void* context, void* param1, void* param2)
+{
+ auto* db = static_cast<SQLiteDatabase*>(context);
+ if (code == SQLITE_TRACE_STMT) {
+ auto* stmt = static_cast<sqlite3_stmt*>(param1);
+ // To be conservative and avoid leaking potentially secret information
+ // in the log file, only expand statements that query the database, not
+ // statements that update the database.
+ char* expanded{sqlite3_stmt_readonly(stmt) ? sqlite3_expanded_sql(stmt) : nullptr};
+ LogPrintf("[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt));
+ if (expanded) sqlite3_free(expanded);
+ }
+ return SQLITE_OK;
+}
+
static bool BindBlobToStatement(sqlite3_stmt* stmt,
int index,
Span<const std::byte> blob,
const std::string& description)
{
- int res = sqlite3_bind_blob(stmt, index, blob.data(), blob.size(), SQLITE_STATIC);
+ // Pass a pointer to the empty string "" below instead of passing the
+ // blob.data() pointer if the blob.data() pointer is null. Passing a null
+ // data pointer to bind_blob would cause sqlite to bind the SQL NULL value
+ // instead of the empty blob value X'', which would mess up SQL comparisons.
+ int res = sqlite3_bind_blob(stmt, index, blob.data() ? static_cast<const void*>(blob.data()) : "", blob.size(), SQLITE_STATIC);
if (res != SQLITE_OK) {
LogPrintf("Unable to bind %s to statement: %s\n", description, sqlite3_errstr(res));
sqlite3_clear_bindings(stmt);
@@ -125,6 +145,7 @@ void SQLiteBatch::SetupSQLStatements()
{&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
{&m_overwrite_stmt, "INSERT or REPLACE into main values(?, ?)"},
{&m_delete_stmt, "DELETE FROM main WHERE key = ?"},
+ {&m_delete_prefix_stmt, "DELETE FROM main WHERE instr(key, ?) = 1"},
};
for (const auto& [stmt_prepared, stmt_text] : statements) {
@@ -234,6 +255,13 @@ void SQLiteDatabase::Open()
if (ret != SQLITE_OK) {
throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable extended result codes: %s\n", sqlite3_errstr(ret)));
}
+ // Trace SQL statements if tracing is enabled with -debug=walletdb -loglevel=walletdb:trace
+ if (LogAcceptCategory(BCLog::WALLETDB, BCLog::Level::Trace)) {
+ ret = sqlite3_trace_v2(m_db, SQLITE_TRACE_STMT, TraceSqlCallback, this);
+ if (ret != SQLITE_OK) {
+ LogPrintf("Failed to enable SQL tracing for %s\n", Filename());
+ }
+ }
}
if (sqlite3_db_readonly(m_db, "main") != 0) {
@@ -375,6 +403,7 @@ void SQLiteBatch::Close()
{&m_insert_stmt, "insert"},
{&m_overwrite_stmt, "overwrite"},
{&m_delete_stmt, "delete"},
+ {&m_delete_prefix_stmt, "delete prefix"},
};
for (const auto& [stmt_prepared, stmt_description] : statements) {
@@ -407,6 +436,7 @@ bool SQLiteBatch::ReadKey(DataStream&& key, DataStream& value)
// Leftmost column in result is index 0
const std::byte* data{AsBytePtr(sqlite3_column_blob(m_read_stmt, 0))};
size_t data_size(sqlite3_column_bytes(m_read_stmt, 0));
+ value.clear();
value.write({data, data_size});
sqlite3_clear_bindings(m_read_stmt);
@@ -441,24 +471,34 @@ bool SQLiteBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
return res == SQLITE_DONE;
}
-bool SQLiteBatch::EraseKey(DataStream&& key)
+bool SQLiteBatch::ExecStatement(sqlite3_stmt* stmt, Span<const std::byte> blob)
{
if (!m_database.m_db) return false;
- assert(m_delete_stmt);
+ assert(stmt);
// Bind: leftmost parameter in statement is index 1
- if (!BindBlobToStatement(m_delete_stmt, 1, key, "key")) return false;
+ if (!BindBlobToStatement(stmt, 1, blob, "key")) return false;
// Execute
- int res = sqlite3_step(m_delete_stmt);
- sqlite3_clear_bindings(m_delete_stmt);
- sqlite3_reset(m_delete_stmt);
+ int res = sqlite3_step(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_reset(stmt);
if (res != SQLITE_DONE) {
LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res));
}
return res == SQLITE_DONE;
}
+bool SQLiteBatch::EraseKey(DataStream&& key)
+{
+ return ExecStatement(m_delete_stmt, key);
+}
+
+bool SQLiteBatch::ErasePrefix(Span<const std::byte> prefix)
+{
+ return ExecStatement(m_delete_prefix_stmt, prefix);
+}
+
bool SQLiteBatch::HasKey(DataStream&& key)
{
if (!m_database.m_db) return false;
@@ -483,6 +523,9 @@ DatabaseCursor::Status SQLiteCursor::Next(DataStream& key, DataStream& value)
return Status::FAIL;
}
+ key.clear();
+ value.clear();
+
// Leftmost column in result is index 0
const std::byte* key_data{AsBytePtr(sqlite3_column_blob(m_cursor_stmt, 0))};
size_t key_data_size(sqlite3_column_bytes(m_cursor_stmt, 0));
@@ -495,6 +538,7 @@ DatabaseCursor::Status SQLiteCursor::Next(DataStream& key, DataStream& value)
SQLiteCursor::~SQLiteCursor()
{
+ sqlite3_clear_bindings(m_cursor_stmt);
sqlite3_reset(m_cursor_stmt);
int res = sqlite3_finalize(m_cursor_stmt);
if (res != SQLITE_OK) {
@@ -518,6 +562,48 @@ std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewCursor()
return cursor;
}
+std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewPrefixCursor(Span<const std::byte> prefix)
+{
+ if (!m_database.m_db) return nullptr;
+
+ // To get just the records we want, the SQL statement does a comparison of the binary data
+ // where the data must be greater than or equal to the prefix, and less than
+ // the prefix incremented by one (when interpreted as an integer)
+ std::vector<std::byte> start_range(prefix.begin(), prefix.end());
+ std::vector<std::byte> end_range(prefix.begin(), prefix.end());
+ auto it = end_range.rbegin();
+ for (; it != end_range.rend(); ++it) {
+ if (*it == std::byte(std::numeric_limits<unsigned char>::max())) {
+ *it = std::byte(0);
+ continue;
+ }
+ *it = std::byte(std::to_integer<unsigned char>(*it) + 1);
+ break;
+ }
+ if (it == end_range.rend()) {
+ // If the prefix is all 0xff bytes, clear end_range as we won't need it
+ end_range.clear();
+ }
+
+ auto cursor = std::make_unique<SQLiteCursor>(start_range, end_range);
+ if (!cursor) return nullptr;
+
+ const char* stmt_text = end_range.empty() ? "SELECT key, value FROM main WHERE key >= ?" :
+ "SELECT key, value FROM main WHERE key >= ? AND key < ?";
+ int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
+ if (res != SQLITE_OK) {
+ throw std::runtime_error(strprintf(
+ "SQLiteDatabase: Failed to setup cursor SQL statement: %s\n", sqlite3_errstr(res)));
+ }
+
+ if (!BindBlobToStatement(cursor->m_cursor_stmt, 1, cursor->m_prefix_range_start, "prefix_start")) return nullptr;
+ if (!end_range.empty()) {
+ if (!BindBlobToStatement(cursor->m_cursor_stmt, 2, cursor->m_prefix_range_end, "prefix_end")) return nullptr;
+ }
+
+ return cursor;
+}
+
bool SQLiteBatch::TxnBegin()
{
if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) == 0) return false;
diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h
index 5745a1d4cf..0378bbb8d6 100644
--- a/src/wallet/sqlite.h
+++ b/src/wallet/sqlite.h
@@ -15,12 +15,21 @@ struct bilingual_str;
namespace wallet {
class SQLiteDatabase;
+/** RAII class that provides a database cursor */
class SQLiteCursor : public DatabaseCursor
{
public:
sqlite3_stmt* m_cursor_stmt{nullptr};
+ // Copies of the prefix things for the prefix cursor.
+ // Prevents SQLite from accessing temp variables for the prefix things.
+ std::vector<std::byte> m_prefix_range_start;
+ std::vector<std::byte> m_prefix_range_end;
explicit SQLiteCursor() {}
+ explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range)
+ : m_prefix_range_start(std::move(start_range)),
+ m_prefix_range_end(std::move(end_range))
+ {}
~SQLiteCursor() override;
Status Next(DataStream& key, DataStream& value) override;
@@ -36,13 +45,16 @@ private:
sqlite3_stmt* m_insert_stmt{nullptr};
sqlite3_stmt* m_overwrite_stmt{nullptr};
sqlite3_stmt* m_delete_stmt{nullptr};
+ sqlite3_stmt* m_delete_prefix_stmt{nullptr};
void SetupSQLStatements();
+ bool ExecStatement(sqlite3_stmt* stmt, Span<const std::byte> blob);
bool ReadKey(DataStream&& key, DataStream& value) override;
bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
bool EraseKey(DataStream&& key) override;
bool HasKey(DataStream&& key) override;
+ bool ErasePrefix(Span<const std::byte> prefix) override;
public:
explicit SQLiteBatch(SQLiteDatabase& database);
@@ -54,6 +66,7 @@ public:
void Close() override;
std::unique_ptr<DatabaseCursor> GetNewCursor() override;
+ std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override;
bool TxnBegin() override;
bool TxnCommit() override;
bool TxnAbort() override;
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 8f626addde..c8283f453a 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -12,6 +12,7 @@
#include <wallet/coincontrol.h>
#include <wallet/coinselection.h>
#include <wallet/spend.h>
+#include <wallet/test/util.h>
#include <wallet/test/wallet_test_fixture.h>
#include <wallet/wallet.h>
@@ -68,7 +69,7 @@ static void add_coin(const CAmount& nValue, int nInput, CoinSet& set, CAmount fe
set.insert(std::make_shared<COutput>(coin));
}
-static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmount& nValue, CFeeRate feerate = CFeeRate(0), int nAge = 6*24, bool fIsFromMe = false, int nInput =0, bool spendable = false)
+static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmount& nValue, CFeeRate feerate = CFeeRate(0), int nAge = 6*24, bool fIsFromMe = false, int nInput =0, bool spendable = false, int custom_size = 0)
{
CMutableTransaction tx;
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
@@ -84,7 +85,21 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
assert(ret.second);
CWalletTx& wtx = (*ret.first).second;
const auto& txout = wtx.tx->vout.at(nInput);
- available_coins.Add(OutputType::BECH32, {COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate});
+ available_coins.Add(OutputType::BECH32, {COutPoint(wtx.GetHash(), nInput), txout, nAge, custom_size == 0 ? CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr) : custom_size, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate});
+}
+
+// Helpers
+std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
+ CAmount change_target, FastRandomContext& rng)
+{
+ auto res{KnapsackSolver(groups, nTargetValue, change_target, rng, MAX_STANDARD_TX_WEIGHT)};
+ return res ? std::optional<SelectionResult>(*res) : std::nullopt;
+}
+
+std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change)
+{
+ auto res{SelectCoinsBnB(utxo_pool, selection_target, cost_of_change, MAX_STANDARD_TX_WEIGHT)};
+ return res ? std::optional<SelectionResult>(*res) : std::nullopt;
}
/** Check if SelectionResult a is equivalent to SelectionResult b.
@@ -128,13 +143,15 @@ static CAmount make_hard_case(int utxos, std::vector<COutput>& utxo_pool)
return target;
}
-inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& available_coins)
+inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& available_coins, bool subtract_fee_outputs = false)
{
static std::vector<OutputGroup> static_groups;
static_groups.clear();
for (auto& coin : available_coins) {
static_groups.emplace_back();
- static_groups.back().Insert(std::make_shared<COutput>(coin), /*ancestors=*/ 0, /*descendants=*/ 0);
+ OutputGroup& group = static_groups.back();
+ group.Insert(std::make_shared<COutput>(coin), /*ancestors=*/ 0, /*descendants=*/ 0);
+ group.m_subtract_fee_outputs = subtract_fee_outputs;
}
return static_groups;
}
@@ -158,6 +175,16 @@ inline std::vector<OutputGroup>& KnapsackGroupOutputs(const CoinsResult& availab
return static_groups.all_groups.mixed_group;
}
+static std::unique_ptr<CWallet> NewWallet(const node::NodeContext& m_node, const std::string& wallet_name = "")
+{
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), wallet_name, CreateMockableWalletDatabase());
+ BOOST_CHECK(wallet->LoadWallet() == DBErrors::LOAD_OK);
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+ return wallet;
+}
+
// Branch and bound coin selection tests
BOOST_AUTO_TEST_CASE(bnb_search_test)
{
@@ -294,11 +321,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_subtract_fee_outputs = true;
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
CoinsResult available_coins;
@@ -316,11 +339,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
}
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
CoinsResult available_coins;
@@ -335,15 +354,13 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
+ LOCK(wallet->cs_wallet);
const auto result10 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(result10);
}
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+ LOCK(wallet->cs_wallet); // Every 'SelectCoins' call requires it
CoinsResult available_coins;
@@ -397,6 +414,37 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
const auto result13 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result13));
}
+
+ {
+ // Test bnb max weight exceeded
+ // Inputs set [10, 9, 8, 5, 3, 1], Selection Target = 16 and coin 5 exceeding the max weight.
+
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+
+ CoinsResult available_coins;
+ add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 8 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true, /*custom_size=*/MAX_STANDARD_TX_WEIGHT);
+ add_coin(available_coins, *wallet, 3 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+
+ CAmount selection_target = 16 * CENT;
+ const auto& no_res = SelectCoinsBnB(GroupCoins(available_coins.All(), /*subtract_fee_outputs*/true),
+ selection_target, /*cost_of_change=*/0, MAX_STANDARD_TX_WEIGHT);
+ BOOST_REQUIRE(!no_res);
+ BOOST_CHECK(util::ErrorString(no_res).original.find("The inputs size exceeds the maximum weight") != std::string::npos);
+
+ // Now add same coin value with a good size and check that it gets selected
+ add_coin(available_coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ const auto& res = SelectCoinsBnB(GroupCoins(available_coins.All(), /*subtract_fee_outputs*/true), selection_target, /*cost_of_change=*/0);
+
+ expected_result.Clear();
+ add_coin(8 * CENT, 2, expected_result);
+ add_coin(5 * CENT, 2, expected_result);
+ add_coin(3 * CENT, 2, expected_result);
+ BOOST_CHECK(EquivalentResult(expected_result, *res));
+ }
}
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
@@ -404,11 +452,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
FastRandomContext rand{};
const auto temp1{[&rand](std::vector<OutputGroup>& g, const CAmount& v, CAmount c) { return KnapsackSolver(g, v, c, rand); }};
const auto KnapsackSolver{temp1};
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
CoinsResult available_coins;
@@ -714,11 +758,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
{
FastRandomContext rand{};
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
CoinsResult available_coins;
@@ -736,11 +776,8 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
// Tests that with the ideal conditions, the coin selector will always be able to find a solution that can pay the target value
BOOST_AUTO_TEST_CASE(SelectCoins_test)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+ LOCK(wallet->cs_wallet); // Every 'SelectCoins' call requires it
// Random generator stuff
std::default_random_engine generator;
@@ -921,16 +958,101 @@ BOOST_AUTO_TEST_CASE(effective_value_test)
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
}
-static util::Result<SelectionResult> select_coins(const CAmount& target, const CoinSelectionParams& cs_params, const CCoinControl& cc, std::function<CoinsResult(CWallet&)> coin_setup, interfaces::Chain* chain)
+
+static util::Result<SelectionResult> SelectCoinsSRD(const CAmount& target,
+ const CoinSelectionParams& cs_params,
+ const node::NodeContext& m_node,
+ int max_weight,
+ std::function<CoinsResult(CWallet&)> coin_setup)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(chain, "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+ CoinEligibilityFilter filter(0, 0, 0); // accept all coins without ancestors
+ Groups group = GroupOutputs(*wallet, coin_setup(*wallet), cs_params, {{filter}})[filter].all_groups;
+ return SelectCoinsSRD(group.positive_group, target, cs_params.m_change_fee, cs_params.rng_fast, max_weight);
+}
+
+BOOST_AUTO_TEST_CASE(srd_tests)
+{
+ // Test SRD:
+ // 1) Insufficient funds, select all provided coins and fail.
+ // 2) Exceeded max weight, coin selection always surpasses the max allowed weight.
+ // 3) Select coins without surpassing the max weight (some coins surpasses the max allowed weight, some others not)
+
+ FastRandomContext rand;
+ CoinSelectionParams dummy_params{ // Only used to provide the 'avoid_partial' flag.
+ rand,
+ /*change_output_size=*/34,
+ /*change_spend_size=*/68,
+ /*min_change_target=*/CENT,
+ /*effective_feerate=*/CFeeRate(0),
+ /*long_term_feerate=*/CFeeRate(0),
+ /*discard_feerate=*/CFeeRate(0),
+ /*tx_noinputs_size=*/10 + 34, // static header size + output size
+ /*avoid_partial=*/false,
+ };
+
+ {
+ // #########################################################
+ // 1) Insufficient funds, select all provided coins and fail
+ // #########################################################
+ CAmount target = 49.5L * COIN;
+ int max_weight = 10000; // high enough to not fail for this reason.
+ const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 10; ++j) {
+ add_coin(available_coins, wallet, CAmount(1 * COIN));
+ add_coin(available_coins, wallet, CAmount(2 * COIN));
+ }
+ return available_coins;
+ });
+ BOOST_CHECK(!res);
+ BOOST_CHECK(util::ErrorString(res).empty()); // empty means "insufficient funds"
+ }
+
+ {
+ // ###########################
+ // 2) Test max weight exceeded
+ // ###########################
+ CAmount target = 49.5L * COIN;
+ int max_weight = 3000;
+ const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 10; ++j) {
+ add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(0), 144, false, 0, true);
+ add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ return available_coins;
+ });
+ BOOST_CHECK(!res);
+ BOOST_CHECK(util::ErrorString(res).original.find("The inputs size exceeds the maximum weight") != std::string::npos);
+ }
+ {
+ // ################################################################################################################
+ // 3) Test selection when some coins surpass the max allowed weight while others not. --> must find a good solution
+ // ################################################################################################################
+ CAmount target = 25.33L * COIN;
+ int max_weight = 10000; // WU
+ const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 60; ++j) { // 60 UTXO --> 19,8 BTC total --> 60 × 272 WU = 16320 WU
+ add_coin(available_coins, wallet, CAmount(0.33 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ for (int i = 0; i < 10; i++) { // 10 UTXO --> 20 BTC total --> 10 × 272 WU = 2720 WU
+ add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ return available_coins;
+ });
+ BOOST_CHECK(res);
+ }
+}
+
+static util::Result<SelectionResult> select_coins(const CAmount& target, const CoinSelectionParams& cs_params, const CCoinControl& cc, std::function<CoinsResult(CWallet&)> coin_setup, const node::NodeContext& m_node)
+{
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
auto available_coins = coin_setup(*wallet);
+ LOCK(wallet->cs_wallet);
auto result = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/ {}, target, cc, cs_params);
if (result) {
const auto signedTxSize = 10 + 34 + 68 * result->GetInputSet().size(); // static header size + output size + inputs size (P2WPKH)
@@ -964,8 +1086,6 @@ BOOST_AUTO_TEST_CASE(check_max_weight)
/*avoid_partial=*/false,
};
- auto chain{m_node.chain.get()};
-
{
// Scenario 1:
// The actor starts with 1x 50.0 BTC and 1515x 0.033 BTC (~100.0 BTC total) unspent outputs
@@ -984,10 +1104,13 @@ BOOST_AUTO_TEST_CASE(check_max_weight)
add_coin(available_coins, wallet, CAmount(50 * COIN), CFeeRate(0), 144, false, 0, true);
return available_coins;
},
- chain);
+ m_node);
BOOST_CHECK(result);
- BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(50 * COIN)));
+ // Verify that only the 50 BTC UTXO was selected
+ const auto& selection_res = result->GetInputSet();
+ BOOST_CHECK(selection_res.size() == 1);
+ BOOST_CHECK((*selection_res.begin())->GetEffectiveValue() == 50 * COIN);
}
{
@@ -1009,7 +1132,7 @@ BOOST_AUTO_TEST_CASE(check_max_weight)
}
return available_coins;
},
- chain);
+ m_node);
BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(0.0625 * COIN)));
BOOST_CHECK(has_coin(result->GetInputSet(), CAmount(0.025 * COIN)));
@@ -1030,7 +1153,7 @@ BOOST_AUTO_TEST_CASE(check_max_weight)
}
return available_coins;
},
- chain);
+ m_node);
// No results
// 1515 inputs * 68 bytes = 103,020 bytes
@@ -1045,20 +1168,11 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
// This test creates a coin whose value is higher than the target but whose effective value is lower than the target.
// The coin is selected using coin control, with m_allow_other_inputs = false. SelectCoins should fail due to insufficient funds.
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
- wallet->LoadWallet();
- LOCK(wallet->cs_wallet);
- wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- wallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
CoinsResult available_coins;
{
- std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", CreateMockWalletDatabase());
- dummyWallet->LoadWallet();
- LOCK(dummyWallet->cs_wallet);
- dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- dummyWallet->SetupDescriptorScriptPubKeyMans();
-
+ std::unique_ptr<CWallet> dummyWallet = NewWallet(m_node, /*wallet_name=*/"dummy");
add_coin(available_coins, *dummyWallet, 100000); // 0.001 BTC
}
@@ -1082,6 +1196,7 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
cc.SetInputWeight(output.outpoint, 148);
cc.SelectExternal(output.outpoint, output.txout);
+ LOCK(wallet->cs_wallet);
const auto preset_inputs = *Assert(FetchSelectedInputs(*wallet, cc, cs_params));
available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
@@ -1094,11 +1209,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
// Test case to verify CoinsResult object sanity.
CoinsResult available_coins;
{
- std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", CreateMockWalletDatabase());
- BOOST_CHECK_EQUAL(dummyWallet->LoadWallet(), DBErrors::LOAD_OK);
- LOCK(dummyWallet->cs_wallet);
- dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
- dummyWallet->SetupDescriptorScriptPubKeyMans();
+ std::unique_ptr<CWallet> dummyWallet = NewWallet(m_node, /*wallet_name=*/"dummy");
// Add some coins to 'available_coins'
for (int i=0; i<10; i++) {
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 7e26656b86..e0b4a1e74c 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -4,15 +4,59 @@
#include <boost/test/unit_test.hpp>
-#include <fs.h>
#include <test/util/setup_common.h>
+#include <util/check.h>
+#include <util/fs.h>
+#include <util/translation.h>
+#ifdef USE_BDB
#include <wallet/bdb.h>
+#endif
+#ifdef USE_SQLITE
+#include <wallet/sqlite.h>
+#endif
+#include <wallet/test/util.h>
+#include <wallet/walletutil.h> // for WALLET_FLAG_DESCRIPTORS
#include <fstream>
#include <memory>
#include <string>
+inline std::ostream& operator<<(std::ostream& os, const std::pair<const SerializeData, SerializeData>& kv)
+{
+ Span key{kv.first}, value{kv.second};
+ os << "(\"" << std::string_view{reinterpret_cast<const char*>(key.data()), key.size()} << "\", \""
+ << std::string_view{reinterpret_cast<const char*>(key.data()), key.size()} << "\")";
+ return os;
+}
+
namespace wallet {
+
+static Span<const std::byte> StringBytes(std::string_view str)
+{
+ return AsBytes<const char>({str.data(), str.size()});
+}
+
+static SerializeData StringData(std::string_view str)
+{
+ auto bytes = StringBytes(str);
+ return SerializeData{bytes.begin(), bytes.end()};
+}
+
+static void CheckPrefix(DatabaseBatch& batch, Span<const std::byte> prefix, MockableData expected)
+{
+ std::unique_ptr<DatabaseCursor> cursor = batch.GetNewPrefixCursor(prefix);
+ MockableData actual;
+ while (true) {
+ DataStream key, value;
+ DatabaseCursor::Status status = cursor->Next(key, value);
+ if (status == DatabaseCursor::Status::DONE) break;
+ BOOST_CHECK(status == DatabaseCursor::Status::MORE);
+ BOOST_CHECK(
+ actual.emplace(SerializeData(key.begin(), key.end()), SerializeData(value.begin(), value.end())).second);
+ }
+ BOOST_CHECK_EQUAL_COLLECTIONS(actual.begin(), actual.end(), expected.begin(), expected.end());
+}
+
BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, fs::path& database_filename)
@@ -78,5 +122,88 @@ BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance)
BOOST_CHECK(env_2_a == env_2_b);
}
+static std::vector<std::unique_ptr<WalletDatabase>> TestDatabases(const fs::path& path_root)
+{
+ std::vector<std::unique_ptr<WalletDatabase>> dbs;
+ DatabaseOptions options;
+ DatabaseStatus status;
+ bilingual_str error;
+#ifdef USE_BDB
+ dbs.emplace_back(MakeBerkeleyDatabase(path_root / "bdb", options, status, error));
+#endif
+#ifdef USE_SQLITE
+ dbs.emplace_back(MakeSQLiteDatabase(path_root / "sqlite", options, status, error));
+#endif
+ dbs.emplace_back(CreateMockableWalletDatabase());
+ return dbs;
+}
+
+BOOST_AUTO_TEST_CASE(db_cursor_prefix_range_test)
+{
+ // Test each supported db
+ for (const auto& database : TestDatabases(m_path_root)) {
+ std::vector<std::string> prefixes = {"", "FIRST", "SECOND", "P\xfe\xff", "P\xff\x01", "\xff\xff"};
+
+ // Write elements to it
+ std::unique_ptr<DatabaseBatch> handler = Assert(database)->MakeBatch();
+ for (unsigned int i = 0; i < 10; i++) {
+ for (const auto& prefix : prefixes) {
+ BOOST_CHECK(handler->Write(std::make_pair(prefix, i), i));
+ }
+ }
+
+ // Now read all the items by prefix and verify that each element gets parsed correctly
+ for (const auto& prefix : prefixes) {
+ DataStream s_prefix;
+ s_prefix << prefix;
+ std::unique_ptr<DatabaseCursor> cursor = handler->GetNewPrefixCursor(s_prefix);
+ DataStream key;
+ DataStream value;
+ for (int i = 0; i < 10; i++) {
+ DatabaseCursor::Status status = cursor->Next(key, value);
+ BOOST_CHECK_EQUAL(status, DatabaseCursor::Status::MORE);
+
+ std::string key_back;
+ unsigned int i_back;
+ key >> key_back >> i_back;
+ BOOST_CHECK_EQUAL(key_back, prefix);
+
+ unsigned int value_back;
+ value >> value_back;
+ BOOST_CHECK_EQUAL(value_back, i_back);
+ }
+
+ // Let's now read it once more, it should return DONE
+ BOOST_CHECK(cursor->Next(key, value) == DatabaseCursor::Status::DONE);
+ }
+ }
+}
+
+// Lower level DatabaseBase::GetNewPrefixCursor test, to cover cases that aren't
+// covered in the higher level test above. The higher level test uses
+// serialized strings which are prefixed with string length, so it doesn't test
+// truly empty prefixes or prefixes that begin with \xff
+BOOST_AUTO_TEST_CASE(db_cursor_prefix_byte_test)
+{
+ const MockableData::value_type
+ e{StringData(""), StringData("e")},
+ p{StringData("prefix"), StringData("p")},
+ ps{StringData("prefixsuffix"), StringData("ps")},
+ f{StringData("\xff"), StringData("f")},
+ fs{StringData("\xffsuffix"), StringData("fs")},
+ ff{StringData("\xff\xff"), StringData("ff")},
+ ffs{StringData("\xff\xffsuffix"), StringData("ffs")};
+ for (const auto& database : TestDatabases(m_path_root)) {
+ std::unique_ptr<DatabaseBatch> batch = database->MakeBatch();
+ for (const auto& [k, v] : {e, p, ps, f, fs, ff, ffs}) {
+ batch->Write(MakeUCharSpan(k), MakeUCharSpan(v));
+ }
+ CheckPrefix(*batch, StringBytes(""), {e, p, ps, f, fs, ff, ffs});
+ CheckPrefix(*batch, StringBytes("prefix"), {p, ps});
+ CheckPrefix(*batch, StringBytes("\xff"), {f, fs, ff, ffs});
+ CheckPrefix(*batch, StringBytes("\xff\xff"), {ff, ffs});
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/test/fuzz/coincontrol.cpp b/src/wallet/test/fuzz/coincontrol.cpp
new file mode 100644
index 0000000000..7dabdfb472
--- /dev/null
+++ b/src/wallet/test/fuzz/coincontrol.cpp
@@ -0,0 +1,87 @@
+// Copyright (c) 2022 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 <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <wallet/coincontrol.h>
+#include <wallet/test/util.h>
+
+namespace wallet {
+namespace {
+
+const TestingSetup* g_setup;
+
+void initialize_coincontrol()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+}
+
+FUZZ_TARGET_INIT(coincontrol, initialize_coincontrol)
+{
+ FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+ const auto& node = g_setup->m_node;
+ ArgsManager& args = *node.args;
+
+ // for GetBoolArg to return true sometimes
+ args.ForceSetArg("-avoidpartialspends", fuzzed_data_provider.ConsumeBool()?"1":"0");
+
+ CCoinControl coin_control;
+ COutPoint out_point;
+
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
+ {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ std::optional<COutPoint> optional_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (!optional_out_point) {
+ return;
+ }
+ out_point = *optional_out_point;
+ },
+ [&] {
+ (void)coin_control.HasSelected();
+ },
+ [&] {
+ (void)coin_control.IsSelected(out_point);
+ },
+ [&] {
+ (void)coin_control.IsExternalSelected(out_point);
+ },
+ [&] {
+ (void)coin_control.GetExternalOutput(out_point);
+ },
+ [&] {
+ (void)coin_control.Select(out_point);
+ },
+ [&] {
+ const CTxOut tx_out{ConsumeMoney(fuzzed_data_provider), ConsumeScript(fuzzed_data_provider)};
+ (void)coin_control.SelectExternal(out_point, tx_out);
+ },
+ [&] {
+ (void)coin_control.UnSelect(out_point);
+ },
+ [&] {
+ (void)coin_control.UnSelectAll();
+ },
+ [&] {
+ (void)coin_control.ListSelected();
+ },
+ [&] {
+ int64_t weight{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
+ (void)coin_control.SetInputWeight(out_point, weight);
+ },
+ [&] {
+ // Condition to avoid the assertion in GetInputWeight
+ if (coin_control.HasInputWeight(out_point)) {
+ (void)coin_control.GetInputWeight(out_point);
+ }
+ });
+ }
+}
+} // namespace
+} // namespace wallet
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 304190eec1..bc935157b1 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/feerate.h>
+#include <policy/policy.h>
#include <primitives/transaction.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -44,6 +45,9 @@ static void GroupCoins(FuzzedDataProvider& fuzzed_data_provider, const std::vect
if (valid_outputgroup) output_groups.push_back(output_group);
}
+// Returns true if the result contains an error and the message is not empty
+static bool HasErrorMsg(const util::Result<SelectionResult>& res) { return !util::ErrorString(res).empty(); }
+
FUZZ_TARGET(coinselection)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
@@ -84,18 +88,21 @@ FUZZ_TARGET(coinselection)
GroupCoins(fuzzed_data_provider, utxo_pool, coin_params, /*positive_only=*/false, group_all);
// Run coinselection algorithms
- const auto result_bnb = SelectCoinsBnB(group_pos, target, cost_of_change);
+ const auto result_bnb = SelectCoinsBnB(group_pos, target, cost_of_change, MAX_STANDARD_TX_WEIGHT);
- auto result_srd = SelectCoinsSRD(group_pos, target, fast_random_context);
- if (result_srd) result_srd->ComputeAndSetWaste(cost_of_change, cost_of_change, 0);
+ auto result_srd = SelectCoinsSRD(group_pos, target, coin_params.m_change_fee, fast_random_context, MAX_STANDARD_TX_WEIGHT);
+ if (result_srd) {
+ assert(result_srd->GetChange(CHANGE_LOWER, coin_params.m_change_fee) > 0); // Demonstrate that SRD creates change of at least CHANGE_LOWER
+ result_srd->ComputeAndSetWaste(cost_of_change, cost_of_change, 0);
+ }
CAmount change_target{GenerateChangeTarget(target, coin_params.m_change_fee, fast_random_context)};
- auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context);
+ auto result_knapsack = KnapsackSolver(group_all, target, change_target, fast_random_context, MAX_STANDARD_TX_WEIGHT);
if (result_knapsack) result_knapsack->ComputeAndSetWaste(cost_of_change, cost_of_change, 0);
// If the total balance is sufficient for the target and we are not using
- // effective values, Knapsack should always find a solution.
- if (total_balance >= target && subtract_fee_outputs) {
+ // effective values, Knapsack should always find a solution (unless the selection exceeded the max tx weight).
+ if (total_balance >= target && subtract_fee_outputs && !HasErrorMsg(result_knapsack)) {
assert(result_knapsack);
}
}
diff --git a/src/wallet/test/fuzz/fees.cpp b/src/wallet/test/fuzz/fees.cpp
new file mode 100644
index 0000000000..24e1098941
--- /dev/null
+++ b/src/wallet/test/fuzz/fees.cpp
@@ -0,0 +1,68 @@
+// Copyright (c) 2022 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 <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <wallet/coincontrol.h>
+#include <wallet/fees.h>
+#include <wallet/wallet.h>
+#include <wallet/test/util.h>
+#include <validation.h>
+
+namespace wallet {
+namespace {
+const TestingSetup* g_setup;
+static std::unique_ptr<CWallet> g_wallet_ptr;
+
+void initialize_setup()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+ const auto& node{g_setup->m_node};
+ g_wallet_ptr = std::make_unique<CWallet>(node.chain.get(), "", CreateMockableWalletDatabase());
+}
+
+FUZZ_TARGET_INIT(wallet_fees, initialize_setup)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const auto& node{g_setup->m_node};
+ Chainstate* chainstate = &node.chainman->ActiveChainstate();
+ CWallet& wallet = *g_wallet_ptr;
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetLastBlockProcessed(chainstate->m_chain.Height(), chainstate->m_chain.Tip()->GetBlockHash());
+ }
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ wallet.m_discard_rate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
+ }
+ (void)GetDiscardRate(wallet);
+
+ const auto tx_bytes{fuzzed_data_provider.ConsumeIntegral<unsigned int>()};
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ wallet.m_pay_tx_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
+ wallet.m_min_fee = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
+ }
+
+ (void)GetRequiredFee(wallet, tx_bytes);
+ (void)GetRequiredFeeRate(wallet);
+
+ CCoinControl coin_control;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ coin_control.m_feerate = CFeeRate{ConsumeMoney(fuzzed_data_provider, /*max=*/COIN)};
+ }
+ if (fuzzed_data_provider.ConsumeBool()) {
+ coin_control.m_confirm_target = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 999'000);
+ }
+
+ FeeCalculation fee_calculation;
+ FeeCalculation* maybe_fee_calculation{fuzzed_data_provider.ConsumeBool() ? nullptr : &fee_calculation};
+ (void)GetMinimumFeeRate(wallet, coin_control, maybe_fee_calculation);
+ (void)GetMinimumFee(wallet, tx_bytes, coin_control, maybe_fee_calculation);
+}
+} // namespace
+} // namespace wallet
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index de381a5ec9..f4b69f7403 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -141,6 +141,10 @@ FUZZ_TARGET_INIT(wallet_notifications, initialize_setup)
info.prev_hash = &block.hashPrevBlock;
info.height = chain.size();
info.data = &block;
+ // Ensure that no blocks are skipped by the wallet by setting the chain's accumulated
+ // time to the maximum value. This ensures that the wallet's birth time is always
+ // earlier than this maximum time.
+ info.chain_time_max = std::numeric_limits<unsigned int>::max();
a.wallet->blockConnected(info);
b.wallet->blockConnected(info);
// Store the coins for the next block
diff --git a/src/wallet/test/group_outputs_tests.cpp b/src/wallet/test/group_outputs_tests.cpp
index 283e87989c..e6b25cc216 100644
--- a/src/wallet/test/group_outputs_tests.cpp
+++ b/src/wallet/test/group_outputs_tests.cpp
@@ -6,6 +6,7 @@
#include <wallet/coinselection.h>
#include <wallet/spend.h>
+#include <wallet/test/util.h>
#include <wallet/wallet.h>
#include <boost/test/unit_test.hpp>
@@ -17,7 +18,7 @@ static int nextLockTime = 0;
static std::shared_ptr<CWallet> NewWallet(const node::NodeContext& m_node)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockableWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 60b1bab8ac..5bdf36ec19 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -2,10 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <fs.h>
+#include <common/args.h>
#include <univalue.h>
+#include <util/chaintype.h>
#include <util/check.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <fstream>
#include <string>
@@ -13,7 +14,7 @@
#include <wallet/test/init_test_fixture.h>
namespace wallet {
-InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
+InitWalletDirTestingSetup::InitWalletDirTestingSetup(const ChainType chainType) : BasicTestingSetup(chainType)
{
m_wallet_loader = MakeWalletLoader(*m_node.chain, m_args);
diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h
index df5819fd1d..ac7bb8997c 100644
--- a/src/wallet/test/init_test_fixture.h
+++ b/src/wallet/test/init_test_fixture.h
@@ -9,11 +9,12 @@
#include <interfaces/wallet.h>
#include <node/context.h>
#include <test/util/setup_common.h>
+#include <util/chaintype.h>
namespace wallet {
struct InitWalletDirTestingSetup: public BasicTestingSetup {
- explicit InitWalletDirTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit InitWalletDirTestingSetup(const ChainType chain_type = ChainType::MAIN);
~InitWalletDirTestingSetup();
void SetWalletDir(const fs::path& walletdir_path);
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 3dbc91fc68..10aeed49cb 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -4,10 +4,10 @@
#include <boost/test/unit_test.hpp>
+#include <common/args.h>
#include <noui.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
-#include <util/system.h>
#include <wallet/test/init_test_fixture.h>
namespace wallet {
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index 90f369b22a..fd0718fbb9 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -8,8 +8,9 @@
#include <script/script.h>
#include <script/standard.h>
#include <test/util/setup_common.h>
-#include <wallet/ismine.h>
+#include <wallet/types.h>
#include <wallet/wallet.h>
+#include <wallet/test/util.h>
#include <boost/test/unit_test.hpp>
@@ -55,7 +56,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK compressed - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
@@ -74,7 +75,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK compressed - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "pk(" + EncodeSecret(keys[0]) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -86,7 +87,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK uncompressed - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
@@ -105,7 +106,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK uncompressed - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "pk(" + EncodeSecret(uncompressedKey) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -117,7 +118,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH compressed - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
@@ -136,7 +137,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH compressed - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "pkh(" + EncodeSecret(keys[0]) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -148,7 +149,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH uncompressed - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
@@ -167,7 +168,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH uncompressed - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "pkh(" + EncodeSecret(uncompressedKey) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -179,7 +180,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -206,7 +207,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "sh(pkh(" + EncodeSecret(keys[0]) + "))";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -219,7 +220,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2SH (invalid) - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -238,7 +239,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "sh(sh(" + EncodeSecret(keys[0]) + "))";
auto spk_manager = CreateDescriptor(keystore, desc_str, false);
@@ -247,7 +248,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2WSH (invalid) - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -266,7 +267,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2WSH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wsh(sh(" + EncodeSecret(keys[0]) + "))";
auto spk_manager = CreateDescriptor(keystore, desc_str, false);
@@ -275,7 +276,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH inside P2WSH (invalid) - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -292,7 +293,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH inside P2WSH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wsh(wpkh(" + EncodeSecret(keys[0]) + "))";
auto spk_manager = CreateDescriptor(keystore, desc_str, false);
@@ -301,7 +302,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2WSH inside P2WSH (invalid) - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -320,7 +321,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2WSH inside P2WSH (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wsh(wsh(" + EncodeSecret(keys[0]) + "))";
auto spk_manager = CreateDescriptor(keystore, desc_str, false);
@@ -329,7 +330,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH compressed - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -345,7 +346,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH compressed - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wpkh(" + EncodeSecret(keys[0]) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -357,7 +358,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH uncompressed - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -378,7 +379,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH uncompressed (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wpkh(" + EncodeSecret(uncompressedKey) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, false);
@@ -387,7 +388,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// scriptPubKey multisig - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -422,7 +423,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// scriptPubKey multisig - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + ")";
auto spk_manager = CreateDescriptor(keystore, desc_str, true);
@@ -434,7 +435,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH multisig - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -457,7 +458,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH multisig - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "sh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
@@ -471,7 +472,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with compressed keys - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -500,7 +501,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with compressed keys - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + "))";
@@ -514,7 +515,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with uncompressed key - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -543,7 +544,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with uncompressed key (invalid) - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "wsh(multi(2, " + EncodeSecret(uncompressedKey) + ", " + EncodeSecret(keys[1]) + "))";
@@ -553,7 +554,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig wrapped in P2SH - Legacy
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -583,7 +584,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig wrapped in P2SH - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "sh(wsh(multi(2, " + EncodeSecret(keys[0]) + ", " + EncodeSecret(keys[1]) + ")))";
@@ -598,7 +599,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Combo - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "combo(" + EncodeSecret(keys[0]) + ")";
@@ -642,7 +643,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Taproot - Descriptor
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
std::string desc_str = "tr(" + EncodeSecret(keys[0]) + ")";
@@ -660,7 +661,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// OP_RETURN
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -675,7 +676,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unspendable
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -690,7 +691,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unknown
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -705,7 +706,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Nonstandard
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", CreateMockableWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp
index 90042f5252..d4997c418a 100644
--- a/src/wallet/test/scriptpubkeyman_tests.cpp
+++ b/src/wallet/test/scriptpubkeyman_tests.cpp
@@ -7,6 +7,7 @@
#include <test/util/setup_common.h>
#include <wallet/scriptpubkeyman.h>
#include <wallet/wallet.h>
+#include <wallet/test/util.h>
#include <boost/test/unit_test.hpp>
@@ -18,7 +19,7 @@ BOOST_FIXTURE_TEST_SUITE(scriptpubkeyman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(CanProvide)
{
// Set up wallet and keyman variables.
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
// Make a 1 of 2 multisig script
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index b7bf312edf..069ab25f26 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -7,7 +7,9 @@
#include <chain.h>
#include <key.h>
#include <key_io.h>
+#include <streams.h>
#include <test/util/setup_common.h>
+#include <wallet/context.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
@@ -16,7 +18,7 @@
namespace wallet {
std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
{
- auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockWalletDatabase());
+ auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockableWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
@@ -44,28 +46,39 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
return wallet;
}
-std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options)
+std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags)
{
- auto new_database = CreateMockWalletDatabase(options);
-
- // Get a cursor to the original database
- auto batch = database.MakeBatch();
- std::unique_ptr<wallet::DatabaseCursor> cursor = batch->GetNewCursor();
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ auto wallet = CWallet::Create(context, "", std::move(database), create_flags, error, warnings);
+ NotifyWalletLoaded(context, wallet);
+ if (context.chain) {
+ wallet->postInitProcess();
+ }
+ return wallet;
+}
- // Get a batch for the new database
- auto new_batch = new_database->MakeBatch();
+std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
+{
+ DatabaseOptions options;
+ options.create_flags = WALLET_FLAG_DESCRIPTORS;
+ DatabaseStatus status;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ auto database = MakeWalletDatabase("", options, status, error);
+ return TestLoadWallet(std::move(database), context, options.create_flags);
+}
- // Read all records from the original database and write them to the new one
- while (true) {
- DataStream key{};
- DataStream value{};
- DatabaseCursor::Status status = cursor->Next(key, value);
- assert(status != DatabaseCursor::Status::FAIL);
- if (status == DatabaseCursor::Status::DONE) break;
- new_batch->Write(key, value);
- }
+void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
+{
+ SyncWithValidationInterfaceQueue();
+ wallet->m_chain_notifications_handler.reset();
+ UnloadWallet(std::move(wallet));
+}
- return new_database;
+std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database)
+{
+ return std::make_unique<MockableDatabase>(dynamic_cast<MockableDatabase&>(database).m_records);
}
std::string getnewaddress(CWallet& w)
@@ -79,4 +92,107 @@ CTxDestination getNewDestination(CWallet& w, OutputType output_type)
return *Assert(w.GetNewDestination(output_type, ""));
}
+// BytePrefix compares equality with other byte spans that begin with the same prefix.
+struct BytePrefix { Span<const std::byte> prefix; };
+bool operator<(BytePrefix a, Span<const std::byte> b) { return a.prefix < b.subspan(0, std::min(a.prefix.size(), b.size())); }
+bool operator<(Span<const std::byte> a, BytePrefix b) { return a.subspan(0, std::min(a.size(), b.prefix.size())) < b.prefix; }
+
+MockableCursor::MockableCursor(const MockableData& records, bool pass, Span<const std::byte> prefix)
+{
+ m_pass = pass;
+ std::tie(m_cursor, m_cursor_end) = records.equal_range(BytePrefix{prefix});
+}
+
+DatabaseCursor::Status MockableCursor::Next(DataStream& key, DataStream& value)
+{
+ if (!m_pass) {
+ return Status::FAIL;
+ }
+ if (m_cursor == m_cursor_end) {
+ return Status::DONE;
+ }
+ key.clear();
+ value.clear();
+ const auto& [key_data, value_data] = *m_cursor;
+ key.write(key_data);
+ value.write(value_data);
+ m_cursor++;
+ return Status::MORE;
+}
+
+bool MockableBatch::ReadKey(DataStream&& key, DataStream& value)
+{
+ if (!m_pass) {
+ return false;
+ }
+ SerializeData key_data{key.begin(), key.end()};
+ const auto& it = m_records.find(key_data);
+ if (it == m_records.end()) {
+ return false;
+ }
+ value.clear();
+ value.write(it->second);
+ return true;
+}
+
+bool MockableBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
+{
+ if (!m_pass) {
+ return false;
+ }
+ SerializeData key_data{key.begin(), key.end()};
+ SerializeData value_data{value.begin(), value.end()};
+ auto [it, inserted] = m_records.emplace(key_data, value_data);
+ if (!inserted && overwrite) { // Overwrite if requested
+ it->second = value_data;
+ inserted = true;
+ }
+ return inserted;
+}
+
+bool MockableBatch::EraseKey(DataStream&& key)
+{
+ if (!m_pass) {
+ return false;
+ }
+ SerializeData key_data{key.begin(), key.end()};
+ m_records.erase(key_data);
+ return true;
+}
+
+bool MockableBatch::HasKey(DataStream&& key)
+{
+ if (!m_pass) {
+ return false;
+ }
+ SerializeData key_data{key.begin(), key.end()};
+ return m_records.count(key_data) > 0;
+}
+
+bool MockableBatch::ErasePrefix(Span<const std::byte> prefix)
+{
+ if (!m_pass) {
+ return false;
+ }
+ auto it = m_records.begin();
+ while (it != m_records.end()) {
+ auto& key = it->first;
+ if (key.size() < prefix.size() || std::search(key.begin(), key.end(), prefix.begin(), prefix.end()) != key.begin()) {
+ it++;
+ continue;
+ }
+ it = m_records.erase(it);
+ }
+ return true;
+}
+
+std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records)
+{
+ return std::make_unique<MockableDatabase>(records);
+}
+
+MockableDatabase& GetMockableDatabase(CWallet& wallet)
+{
+ return dynamic_cast<MockableDatabase&>(wallet.GetDatabase());
+}
} // namespace wallet
diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h
index d726517e21..2a1fe639de 100644
--- a/src/wallet/test/util.h
+++ b/src/wallet/test/util.h
@@ -6,6 +6,8 @@
#define BITCOIN_WALLET_TEST_UTIL_H
#include <script/standard.h>
+#include <wallet/db.h>
+
#include <memory>
class ArgsManager;
@@ -18,19 +20,112 @@ class Chain;
namespace wallet {
class CWallet;
-struct DatabaseOptions;
class WalletDatabase;
+struct WalletContext;
+
+static const DatabaseFormat DATABASE_FORMATS[] = {
+#ifdef USE_SQLITE
+ DatabaseFormat::SQLITE,
+#endif
+#ifdef USE_BDB
+ DatabaseFormat::BERKELEY,
+#endif
+};
+
+const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";
std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key);
+std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context);
+std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags);
+void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet);
+
// Creates a copy of the provided database
-std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options);
+std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database);
/** Returns a new encoded destination from the wallet (hardcoded to BECH32) */
std::string getnewaddress(CWallet& w);
/** Returns a new destination, of an specific type, from the wallet */
CTxDestination getNewDestination(CWallet& w, OutputType output_type);
+using MockableData = std::map<SerializeData, SerializeData, std::less<>>;
+
+class MockableCursor: public DatabaseCursor
+{
+public:
+ MockableData::const_iterator m_cursor;
+ MockableData::const_iterator m_cursor_end;
+ bool m_pass;
+
+ explicit MockableCursor(const MockableData& records, bool pass) : m_cursor(records.begin()), m_cursor_end(records.end()), m_pass(pass) {}
+ MockableCursor(const MockableData& records, bool pass, Span<const std::byte> prefix);
+ ~MockableCursor() {}
+
+ Status Next(DataStream& key, DataStream& value) override;
+};
+
+class MockableBatch : public DatabaseBatch
+{
+private:
+ MockableData& m_records;
+ bool m_pass;
+
+ bool ReadKey(DataStream&& key, DataStream& value) override;
+ bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite=true) override;
+ bool EraseKey(DataStream&& key) override;
+ bool HasKey(DataStream&& key) override;
+ bool ErasePrefix(Span<const std::byte> prefix) override;
+
+public:
+ explicit MockableBatch(MockableData& records, bool pass) : m_records(records), m_pass(pass) {}
+ ~MockableBatch() {}
+
+ void Flush() override {}
+ void Close() override {}
+
+ std::unique_ptr<DatabaseCursor> GetNewCursor() override
+ {
+ return std::make_unique<MockableCursor>(m_records, m_pass);
+ }
+ std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override {
+ return std::make_unique<MockableCursor>(m_records, m_pass, prefix);
+ }
+ bool TxnBegin() override { return m_pass; }
+ bool TxnCommit() override { return m_pass; }
+ bool TxnAbort() override { return m_pass; }
+};
+
+/** A WalletDatabase whose contents and return values can be modified as needed for testing
+ **/
+class MockableDatabase : public WalletDatabase
+{
+public:
+ MockableData m_records;
+ bool m_pass{true};
+
+ MockableDatabase(MockableData records = {}) : WalletDatabase(), m_records(records) {}
+ ~MockableDatabase() {};
+
+ void Open() override {}
+ void AddRef() override {}
+ void RemoveRef() override {}
+
+ bool Rewrite(const char* pszSkip=nullptr) override { return m_pass; }
+ bool Backup(const std::string& strDest) const override { return m_pass; }
+ void Flush() override {}
+ void Close() override {}
+ bool PeriodicFlush() override { return m_pass; }
+ void IncrementUpdateCounter() override {}
+ void ReloadDbEnv() override {}
+
+ std::string Filename() override { return "mockable"; }
+ std::string Format() override { return "mock"; }
+ std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<MockableBatch>(m_records, m_pass); }
+};
+
+std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records = {});
+
+MockableDatabase& GetMockableDatabase(CWallet& wallet);
} // namespace wallet
#endif // BITCOIN_WALLET_TEST_UTIL_H
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 2dd8f9ad33..57c538e4ef 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -2,15 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <wallet/test/util.h>
#include <wallet/test/wallet_test_fixture.h>
#include <scheduler.h>
+#include <util/chaintype.h>
namespace wallet {
-WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
- : TestingSetup(chainName),
+WalletTestingSetup::WalletTestingSetup(const ChainType chainType)
+ : TestingSetup(chainType),
m_wallet_loader{interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args))},
- m_wallet(m_node.chain.get(), "", CreateMockWalletDatabase())
+ m_wallet(m_node.chain.get(), "", CreateMockableWalletDatabase())
{
m_wallet.LoadWallet();
m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} });
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index f1ef15a282..4aae02e075 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -10,6 +10,7 @@
#include <interfaces/chain.h>
#include <interfaces/wallet.h>
#include <node/context.h>
+#include <util/chaintype.h>
#include <util/check.h>
#include <wallet/wallet.h>
@@ -19,7 +20,7 @@ namespace wallet {
/** Testing setup and teardown for wallet.
*/
struct WalletTestingSetup : public TestingSetup {
- explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit WalletTestingSetup(const ChainType chainType = ChainType::MAIN);
~WalletTestingSetup();
std::unique_ptr<interfaces::WalletLoader> m_wallet_loader;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 2e95a14807..65b02c267d 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -29,7 +29,6 @@
#include <univalue.h>
using node::MAX_BLOCKFILE_SIZE;
-using node::UnlinkPrunedFiles;
namespace wallet {
RPCHelpMan importmulti();
@@ -43,26 +42,6 @@ static_assert(WALLET_INCREMENTAL_RELAY_FEE >= DEFAULT_INCREMENTAL_RELAY_FEE, "wa
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
-static std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
-{
- DatabaseOptions options;
- options.create_flags = WALLET_FLAG_DESCRIPTORS;
- DatabaseStatus status;
- bilingual_str error;
- std::vector<bilingual_str> warnings;
- auto database = MakeWalletDatabase("", options, status, error);
- auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings);
- NotifyWalletLoaded(context, wallet);
- return wallet;
-}
-
-static void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
-{
- SyncWithValidationInterfaceQueue();
- wallet->m_chain_notifications_handler.reset();
- UnloadWallet(std::move(wallet));
-}
-
static CMutableTransaction TestSimpleSpend(const CTransaction& from, uint32_t index, const CKey& key, const CScript& pubkey)
{
CMutableTransaction mtx;
@@ -98,7 +77,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions fails to read an unknown start block.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -119,7 +98,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet(m_node.chain.get(), "", CreateMockWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -159,12 +138,12 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
file_number = oldTip->GetBlockPos().nFile;
Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(file_number);
}
- UnlinkPrunedFiles({file_number});
+ m_node.chainman->m_blockman.UnlinkPrunedFiles({file_number});
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -188,11 +167,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
file_number = newTip->GetBlockPos().nFile;
Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(file_number);
}
- UnlinkPrunedFiles({file_number});
+ m_node.chainman->m_blockman.UnlinkPrunedFiles({file_number});
// Verify ScanForWalletTransactions scans no blocks.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
{
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -226,13 +205,13 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
file_number = oldTip->GetBlockPos().nFile;
Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(file_number);
}
- UnlinkPrunedFiles({file_number});
+ m_node.chainman->m_blockman.UnlinkPrunedFiles({file_number});
// Verify importmulti RPC returns failure for a key whose creation time is
// before the missing block, and success for a key whose creation time is
// after.
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateMockableWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash()));
WalletContext context;
@@ -298,7 +277,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
{
WalletContext context;
context.args = &m_args;
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateMockableWalletDatabase());
{
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
@@ -321,7 +300,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateMockableWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetupLegacyScriptPubKeyMan();
@@ -355,7 +334,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// debit functions.
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
LOCK(wallet.cs_wallet);
LOCK(Assert(m_node.chainman)->GetMutex());
@@ -427,19 +406,54 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
BOOST_CHECK_EQUAL(AddTx(*m_node.chainman, m_wallet, 5, 50, 600), 300);
}
-BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
+void TestLoadWallet(const std::string& name, DatabaseFormat format, std::function<void(std::shared_ptr<CWallet>)> f)
+{
+ node::NodeContext node;
+ auto chain{interfaces::MakeChain(node)};
+ DatabaseOptions options;
+ options.require_format = format;
+ DatabaseStatus status;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ auto database{MakeWalletDatabase(name, options, status, error)};
+ auto wallet{std::make_shared<CWallet>(chain.get(), "", std::move(database))};
+ BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK);
+ WITH_LOCK(wallet->cs_wallet, f(wallet));
+}
+
+BOOST_FIXTURE_TEST_CASE(LoadReceiveRequests, TestingSetup)
{
- CTxDestination dest = PKHash();
- LOCK(m_wallet.cs_wallet);
- WalletBatch batch{m_wallet.GetDatabase()};
- m_wallet.SetAddressUsed(batch, dest, true);
- m_wallet.SetAddressReceiveRequest(batch, dest, "0", "val_rr0");
- m_wallet.SetAddressReceiveRequest(batch, dest, "1", "val_rr1");
-
- auto values = m_wallet.GetAddressReceiveRequests();
- BOOST_CHECK_EQUAL(values.size(), 2U);
- BOOST_CHECK_EQUAL(values[0], "val_rr0");
- BOOST_CHECK_EQUAL(values[1], "val_rr1");
+ for (DatabaseFormat format : DATABASE_FORMATS) {
+ const std::string name{strprintf("receive-requests-%i", format)};
+ TestLoadWallet(name, format, [](std::shared_ptr<CWallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet) {
+ BOOST_CHECK(!wallet->IsAddressPreviouslySpent(PKHash()));
+ WalletBatch batch{wallet->GetDatabase()};
+ BOOST_CHECK(batch.WriteAddressPreviouslySpent(PKHash(), true));
+ BOOST_CHECK(batch.WriteAddressPreviouslySpent(ScriptHash(), true));
+ BOOST_CHECK(wallet->SetAddressReceiveRequest(batch, PKHash(), "0", "val_rr00"));
+ BOOST_CHECK(wallet->EraseAddressReceiveRequest(batch, PKHash(), "0"));
+ BOOST_CHECK(wallet->SetAddressReceiveRequest(batch, PKHash(), "1", "val_rr10"));
+ BOOST_CHECK(wallet->SetAddressReceiveRequest(batch, PKHash(), "1", "val_rr11"));
+ BOOST_CHECK(wallet->SetAddressReceiveRequest(batch, ScriptHash(), "2", "val_rr20"));
+ });
+ TestLoadWallet(name, format, [](std::shared_ptr<CWallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet) {
+ BOOST_CHECK(wallet->IsAddressPreviouslySpent(PKHash()));
+ BOOST_CHECK(wallet->IsAddressPreviouslySpent(ScriptHash()));
+ auto requests = wallet->GetAddressReceiveRequests();
+ auto erequests = {"val_rr11", "val_rr20"};
+ BOOST_CHECK_EQUAL_COLLECTIONS(requests.begin(), requests.end(), std::begin(erequests), std::end(erequests));
+ WalletBatch batch{wallet->GetDatabase()};
+ BOOST_CHECK(batch.WriteAddressPreviouslySpent(PKHash(), false));
+ BOOST_CHECK(batch.EraseAddressData(ScriptHash()));
+ });
+ TestLoadWallet(name, format, [](std::shared_ptr<CWallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet) {
+ BOOST_CHECK(!wallet->IsAddressPreviouslySpent(PKHash()));
+ BOOST_CHECK(!wallet->IsAddressPreviouslySpent(ScriptHash()));
+ auto requests = wallet->GetAddressReceiveRequests();
+ auto erequests = {"val_rr11"};
+ BOOST_CHECK_EQUAL_COLLECTIONS(requests.begin(), requests.end(), std::begin(erequests), std::end(erequests));
+ });
+ }
}
// Test some watch-only LegacyScriptPubKeyMan methods by the procedure of loading (LoadWatchOnly),
@@ -581,7 +595,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
// Check initial balance from one mature coinbase transaction.
- BOOST_CHECK_EQUAL(50 * COIN, GetAvailableBalance(*wallet));
+ BOOST_CHECK_EQUAL(50 * COIN, WITH_LOCK(wallet->cs_wallet, return AvailableCoins(*wallet).GetTotalAmount()));
// Add a transaction creating a change address, and confirm ListCoins still
// returns the coin associated with the change address underneath the
@@ -665,7 +679,7 @@ BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, ListCoinsTest)
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateMockableWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
@@ -673,7 +687,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, ""));
}
{
- const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateMockableWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetMinVersion(FEATURE_LATEST);
@@ -811,10 +825,11 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
// Reload wallet and make sure new transactions are detected despite events
// being blocked
+ // Loading will also ask for current mempool transactions
wallet = TestLoadWallet(context);
BOOST_CHECK(rescan_completed);
- // AddToWallet events for block_tx and mempool_tx
- BOOST_CHECK_EQUAL(addtx_count, 2);
+ // AddToWallet events for block_tx and mempool_tx (x2)
+ BOOST_CHECK_EQUAL(addtx_count, 3);
{
LOCK(wallet->cs_wallet);
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_tx.GetHash()), 1U);
@@ -828,7 +843,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
SyncWithValidationInterfaceQueue();
// AddToWallet events for block_tx and mempool_tx events are counted a
// second time as the notification queue is processed
- BOOST_CHECK_EQUAL(addtx_count, 4);
+ BOOST_CHECK_EQUAL(addtx_count, 5);
TestUnloadWallet(std::move(wallet));
@@ -851,7 +866,9 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
SyncWithValidationInterfaceQueue();
});
wallet = TestLoadWallet(context);
- BOOST_CHECK_EQUAL(addtx_count, 2);
+ // Since mempool transactions are requested at the end of loading, there will
+ // be 2 additional AddToWallet calls, one from the previous test, and a duplicate for mempool_tx
+ BOOST_CHECK_EQUAL(addtx_count, 2 + 2);
{
LOCK(wallet->cs_wallet);
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_tx.GetHash()), 1U);
@@ -907,61 +924,13 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
TestUnloadWallet(std::move(wallet));
}
-class FailCursor : public DatabaseCursor
-{
-public:
- Status Next(DataStream& key, DataStream& value) override { return Status::FAIL; }
-};
-
-/** RAII class that provides access to a FailDatabase. Which fails if needed. */
-class FailBatch : public DatabaseBatch
-{
-private:
- bool m_pass{true};
- bool ReadKey(DataStream&& key, DataStream& value) override { return m_pass; }
- bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override { return m_pass; }
- bool EraseKey(DataStream&& key) override { return m_pass; }
- bool HasKey(DataStream&& key) override { return m_pass; }
-
-public:
- explicit FailBatch(bool pass) : m_pass(pass) {}
- void Flush() override {}
- void Close() override {}
-
- std::unique_ptr<DatabaseCursor> GetNewCursor() override { return std::make_unique<FailCursor>(); }
- bool TxnBegin() override { return false; }
- bool TxnCommit() override { return false; }
- bool TxnAbort() override { return false; }
-};
-
-/** A dummy WalletDatabase that does nothing, only fails if needed.**/
-class FailDatabase : public WalletDatabase
-{
-public:
- bool m_pass{true}; // false when this db should fail
-
- void Open() override {};
- void AddRef() override {}
- void RemoveRef() override {}
- bool Rewrite(const char* pszSkip=nullptr) override { return true; }
- bool Backup(const std::string& strDest) const override { return true; }
- void Close() override {}
- void Flush() override {}
- bool PeriodicFlush() override { return true; }
- void IncrementUpdateCounter() override { ++nUpdateCounter; }
- void ReloadDbEnv() override {}
- std::string Filename() override { return "faildb"; }
- std::string Format() override { return "faildb"; }
- std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<FailBatch>(m_pass); }
-};
-
/**
* Checks a wallet invalid state where the inputs (prev-txs) of a new arriving transaction are not marked dirty,
* while the transaction that spends them exist inside the in-memory wallet tx map (not stored on db due a db write failure).
*/
BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
{
- CWallet wallet(m_node.chain.get(), "", std::make_unique<FailDatabase>());
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -969,11 +938,10 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
}
// Add tx to wallet
- const auto& op_dest = wallet.GetNewDestination(OutputType::BECH32M, "");
- BOOST_ASSERT(op_dest);
+ const auto op_dest{*Assert(wallet.GetNewDestination(OutputType::BECH32M, ""))};
CMutableTransaction mtx;
- mtx.vout.push_back({COIN, GetScriptForDestination(*op_dest)});
+ mtx.vout.push_back({COIN, GetScriptForDestination(op_dest)});
mtx.vin.push_back(CTxIn(g_insecure_rand_ctx.rand256(), 0));
const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash();
@@ -1008,7 +976,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
// 1) Make db always fail
// 2) Try to add a transaction that spends the previously created transaction and
// verify that we are not moving forward if the wallet cannot store it
- static_cast<FailDatabase&>(wallet.GetDatabase()).m_pass = false;
+ GetMockableDatabase(wallet).m_pass = false;
mtx.vin.clear();
mtx.vin.push_back(CTxIn(good_tx_id, 0));
BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx)),
diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp
index 21842fe780..17b6c4f7ed 100644
--- a/src/wallet/test/walletdb_tests.cpp
+++ b/src/wallet/test/walletdb_tests.cpp
@@ -6,6 +6,8 @@
#include <clientversion.h>
#include <streams.h>
#include <uint256.h>
+#include <wallet/test/util.h>
+#include <wallet/wallet.h>
#include <boost/test/unit_test.hpp>
@@ -27,5 +29,31 @@ BOOST_AUTO_TEST_CASE(walletdb_readkeyvalue)
BOOST_CHECK_THROW(ssValue >> dummy, std::ios_base::failure);
}
+BOOST_AUTO_TEST_CASE(walletdb_read_write_deadlock)
+{
+ // Exercises a db read write operation that shouldn't deadlock.
+ for (const DatabaseFormat& db_format : DATABASE_FORMATS) {
+ // Context setup
+ DatabaseOptions options;
+ options.require_format = db_format;
+ DatabaseStatus status;
+ bilingual_str error_string;
+ std::unique_ptr<WalletDatabase> db = MakeDatabase(m_path_root / strprintf("wallet_%d_.dat", db_format).c_str(), options, status, error_string);
+ BOOST_CHECK_EQUAL(status, DatabaseStatus::SUCCESS);
+
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+ wallet->m_keypool_size = 4;
+
+ // Create legacy spkm
+ LOCK(wallet->cs_wallet);
+ auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
+ BOOST_CHECK(legacy_spkm->SetupGeneration(true));
+ wallet->Flush();
+
+ // Now delete all records, which performs a read write operation.
+ BOOST_CHECK(wallet->GetLegacyScriptPubKeyMan()->DeleteRecords());
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp
index 9f5a4b14d3..73a4b77188 100644
--- a/src/wallet/test/walletload_tests.cpp
+++ b/src/wallet/test/walletload_tests.cpp
@@ -34,7 +34,7 @@ public:
BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup)
{
- std::unique_ptr<WalletDatabase> database = CreateMockWalletDatabase();
+ std::unique_ptr<WalletDatabase> database = CreateMockableWalletDatabase();
{
// Write unknown active descriptor
WalletBatch batch(*database, false);
@@ -70,38 +70,45 @@ bool HasAnyRecordOfType(WalletDatabase& db, const std::string& key)
return false;
}
-BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_key_checksum, TestingSetup)
+template<typename... Args>
+SerializeData MakeSerializeData(const Args&... args)
{
- // The test duplicates the db so each case has its own db instance.
- int NUMBER_OF_TESTS = 4;
- std::vector<std::unique_ptr<WalletDatabase>> dbs;
- CKey first_key;
- auto get_db = [](std::vector<std::unique_ptr<WalletDatabase>>& dbs) {
- std::unique_ptr<WalletDatabase> db = std::move(dbs.back());
- dbs.pop_back();
- return db;
- };
-
- { // Context setup.
+ CDataStream s(0, 0);
+ SerializeMany(s, args...);
+ return {s.begin(), s.end()};
+}
+
+
+BOOST_FIXTURE_TEST_CASE(wallet_load_ckey, TestingSetup)
+{
+ SerializeData ckey_record_key;
+ SerializeData ckey_record_value;
+ MockableData records;
+
+ {
+ // Context setup.
// Create and encrypt legacy wallet
- std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockWalletDatabase()));
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockableWalletDatabase()));
LOCK(wallet->cs_wallet);
auto legacy_spkm = wallet->GetOrCreateLegacyScriptPubKeyMan();
BOOST_CHECK(legacy_spkm->SetupGeneration(true));
- // Get the first key in the wallet
+ // Retrieve a key
CTxDestination dest = *Assert(legacy_spkm->GetNewDestination(OutputType::LEGACY));
CKeyID key_id = GetKeyForDestination(*legacy_spkm, dest);
+ CKey first_key;
BOOST_CHECK(legacy_spkm->GetKey(key_id, first_key));
- // Encrypt the wallet and duplicate database
+ // Encrypt the wallet
BOOST_CHECK(wallet->EncryptWallet("encrypt"));
wallet->Flush();
- DatabaseOptions options;
- for (int i=0; i < NUMBER_OF_TESTS; i++) {
- dbs.emplace_back(DuplicateMockDatabase(wallet->GetDatabase(), options));
- }
+ // Store a copy of all the records
+ records = GetMockableDatabase(*wallet).m_records;
+
+ // Get the record for the retrieved key
+ ckey_record_key = MakeSerializeData(DBKeys::CRYPTED_KEY, first_key.GetPubKey());
+ ckey_record_value = records.at(ckey_record_key);
}
{
@@ -112,7 +119,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_key_checksum, TestingSetup)
// the records every time that 'CWallet::Unlock' gets called, which is not good.
// Load the wallet and check that is encrypted
- std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", get_db(dbs)));
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockableWalletDatabase(records)));
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK);
BOOST_CHECK(wallet->IsCrypted());
BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
@@ -127,18 +134,12 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_key_checksum, TestingSetup)
{
// Second test case:
// Verify that loading up a 'ckey' with no checksum triggers a complete re-write of the crypted keys.
- std::unique_ptr<WalletDatabase> db = get_db(dbs);
- {
- std::unique_ptr<DatabaseBatch> batch = db->MakeBatch(false);
- std::pair<std::vector<unsigned char>, uint256> value;
- BOOST_CHECK(batch->Read(std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()), value));
- const auto key = std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey());
- BOOST_CHECK(batch->Write(key, value.first, /*fOverwrite=*/true));
- }
+ // Cut off the 32 byte checksum from a ckey record
+ records[ckey_record_key].resize(ckey_record_value.size() - 32);
// Load the wallet and check that is encrypted
- std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockableWalletDatabase(records)));
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::LOAD_OK);
BOOST_CHECK(wallet->IsCrypted());
BOOST_CHECK(HasAnyRecordOfType(wallet->GetDatabase(), DBKeys::CRYPTED_KEY));
@@ -154,35 +155,25 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_verif_crypted_key_checksum, TestingSetup)
{
// Third test case:
// Verify that loading up a 'ckey' with an invalid checksum throws an error.
- std::unique_ptr<WalletDatabase> db = get_db(dbs);
- {
- std::unique_ptr<DatabaseBatch> batch = db->MakeBatch(false);
- std::vector<unsigned char> crypted_data;
- BOOST_CHECK(batch->Read(std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey()), crypted_data));
-
- // Write an invalid checksum
- std::pair<std::vector<unsigned char>, uint256> value = std::make_pair(crypted_data, uint256::ONE);
- const auto key = std::make_pair(DBKeys::CRYPTED_KEY, first_key.GetPubKey());
- BOOST_CHECK(batch->Write(key, value, /*fOverwrite=*/true));
- }
-
- std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+
+ // Cut off the 32 byte checksum from a ckey record
+ records[ckey_record_key].resize(ckey_record_value.size() - 32);
+ // Fill in the checksum space with 0s
+ records[ckey_record_key].resize(ckey_record_value.size());
+
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockableWalletDatabase(records)));
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT);
}
{
// Fourth test case:
// Verify that loading up a 'ckey' with an invalid pubkey throws an error
- std::unique_ptr<WalletDatabase> db = get_db(dbs);
- {
- CPubKey invalid_key;
- BOOST_ASSERT(!invalid_key.IsValid());
- const auto key = std::make_pair(DBKeys::CRYPTED_KEY, invalid_key);
- std::pair<std::vector<unsigned char>, uint256> value;
- BOOST_CHECK(db->MakeBatch(false)->Write(key, value, /*fOverwrite=*/true));
- }
-
- std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(db)));
+ CPubKey invalid_key;
+ BOOST_CHECK(!invalid_key.IsValid());
+ SerializeData key = MakeSerializeData(DBKeys::CRYPTED_KEY, invalid_key);
+ records[key] = ckey_record_value;
+
+ std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", CreateMockableWalletDatabase(records)));
BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::CORRUPT);
}
}
diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h
index 290ef4eaa9..1a79d7db4e 100644
--- a/src/wallet/transaction.h
+++ b/src/wallet/transaction.h
@@ -5,10 +5,12 @@
#ifndef BITCOIN_WALLET_TRANSACTION_H
#define BITCOIN_WALLET_TRANSACTION_H
+#include <bitset>
+#include <cstdint>
#include <consensus/amount.h>
#include <primitives/transaction.h>
#include <serialize.h>
-#include <wallet/ismine.h>
+#include <wallet/types.h>
#include <threadsafety.h>
#include <tinyformat.h>
#include <util/overloaded.h>
@@ -108,8 +110,29 @@ static inline int TxStateSerializedIndex(const TxState& state)
}
+/**
+ * Cachable amount subdivided into watchonly and spendable parts.
+ */
+struct CachableAmount
+{
+ // NO and ALL are never (supposed to be) cached
+ std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
+ CAmount m_value[ISMINE_ENUM_ELEMENTS];
+ inline void Reset()
+ {
+ m_cached.reset();
+ }
+ void Set(isminefilter filter, CAmount value)
+ {
+ m_cached.set(filter);
+ m_value[filter] = value;
+ }
+};
+
+
typedef std::map<std::string, std::string> mapValue_t;
+
/** Legacy class used for deserializing vtxPrev for backwards compatibility.
* vtxPrev was removed in commit 93a18a3650292afbb441a47d1fa1b94aeb0164e3,
* but old wallet.dat files may still contain vtxPrev vectors of CMerkleTxs.
diff --git a/src/wallet/ismine.h b/src/wallet/types.h
index 4ef4ef98ac..6198f1ae33 100644
--- a/src/wallet/ismine.h
+++ b/src/wallet/types.h
@@ -3,20 +3,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_WALLET_ISMINE_H
-#define BITCOIN_WALLET_ISMINE_H
+//! @file Public type definitions that are used inside and outside of the wallet
+//! (e.g. by src/wallet and src/interfaces and src/qt code).
+//!
+//! File is home for simple enum and struct definitions that don't deserve
+//! separate header files. More complicated wallet public types like
+//! CCoinControl that are used externally can have separate headers.
-#include <script/standard.h>
+#ifndef BITCOIN_WALLET_TYPES_H
+#define BITCOIN_WALLET_TYPES_H
-#include <bitset>
-#include <cstdint>
#include <type_traits>
-class CScript;
-
namespace wallet {
-class CWallet;
-
/**
* IsMine() return codes, which depend on ScriptPubKeyMan implementation.
* Not every ScriptPubKeyMan covers all types, please refer to
@@ -51,23 +50,18 @@ enum isminetype : unsigned int {
using isminefilter = std::underlying_type<isminetype>::type;
/**
- * Cachable amount subdivided into watchonly and spendable parts.
+ * Address purpose field that has been been stored with wallet sending and
+ * receiving addresses since BIP70 payment protocol support was added in
+ * https://github.com/bitcoin/bitcoin/pull/2539. This field is not currently
+ * used for any logic inside the wallet, but it is still shown in RPC and GUI
+ * interfaces and saved for new addresses. It is basically redundant with an
+ * address's IsMine() result.
*/
-struct CachableAmount
-{
- // NO and ALL are never (supposed to be) cached
- std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
- CAmount m_value[ISMINE_ENUM_ELEMENTS];
- inline void Reset()
- {
- m_cached.reset();
- }
- void Set(isminefilter filter, CAmount value)
- {
- m_cached.set(filter);
- m_value[filter] = value;
- }
+enum class AddressPurpose {
+ RECEIVE,
+ SEND,
+ REFUND, //!< Never set in current code may be present in older wallet databases
};
} // namespace wallet
-#endif // BITCOIN_WALLET_ISMINE_H
+#endif // BITCOIN_WALLET_TYPES_H
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ef8fb29e64..ba11933b91 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -7,11 +7,11 @@
#include <blockfilter.h>
#include <chain.h>
+#include <common/args.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <external_signer.h>
-#include <fs.h>
#include <interfaces/chain.h>
#include <interfaces/wallet.h>
#include <key.h>
@@ -32,15 +32,17 @@
#include <util/check.h>
#include <util/error.h>
#include <util/fees.h>
+#include <util/fs.h>
+#include <util/fs_helpers.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/context.h>
-#include <wallet/fees.h>
#include <wallet/external_signer_scriptpubkeyman.h>
+#include <wallet/fees.h>
+#include <wallet/scriptpubkeyman.h>
#include <univalue.h>
@@ -51,19 +53,12 @@
using interfaces::FoundBlock;
namespace wallet {
-const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{
- {WALLET_FLAG_AVOID_REUSE,
- "You need to rescan the blockchain in order to correctly mark used "
- "destinations in the past. Until this is done, some destinations may "
- "be considered unused, even if the opposite is the case."
- },
-};
bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
{
- util::SettingsValue setting_value = chain.getRwSetting("wallet");
+ common::SettingsValue setting_value = chain.getRwSetting("wallet");
if (!setting_value.isArray()) setting_value.setArray();
- for (const util::SettingsValue& value : setting_value.getValues()) {
+ for (const common::SettingsValue& value : setting_value.getValues()) {
if (value.isStr() && value.get_str() == wallet_name) return true;
}
setting_value.push_back(wallet_name);
@@ -72,10 +67,10 @@ bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)
{
- util::SettingsValue setting_value = chain.getRwSetting("wallet");
+ common::SettingsValue setting_value = chain.getRwSetting("wallet");
if (!setting_value.isArray()) return true;
- util::SettingsValue new_value(util::SettingsValue::VARR);
- for (const util::SettingsValue& value : setting_value.getValues()) {
+ common::SettingsValue new_value(common::SettingsValue::VARR);
+ for (const common::SettingsValue& value : setting_value.getValues()) {
if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);
}
if (new_value.size() == setting_value.size()) return true;
@@ -565,13 +560,14 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false;
if (Unlock(_vMasterKey))
{
- int64_t nStartTime = GetTimeMillis();
+ constexpr MillisecondsDouble target{100};
+ auto start{SteadyClock::now()};
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
- pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))));
+ pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
- nStartTime = GetTimeMillis();
+ start = SteadyClock::now();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
- pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
+ pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000;
@@ -768,13 +764,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
GetStrongRandBytes(kMasterKey.vchSalt);
CCrypter crypter;
- int64_t nStartTime = GetTimeMillis();
+ constexpr MillisecondsDouble target{100};
+ auto start{SteadyClock::now()};
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
- kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(GetTimeMillis() - nStartTime)));
+ kMasterKey.nDeriveIterations = static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
- nStartTime = GetTimeMillis();
+ start = SteadyClock::now();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
- kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2;
+ kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000;
@@ -973,11 +970,11 @@ void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned
CTxDestination dst;
if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) {
if (IsMine(dst)) {
- if (used != IsAddressUsed(dst)) {
+ if (used != IsAddressPreviouslySpent(dst)) {
if (used) {
tx_destinations.insert(dst);
}
- SetAddressUsed(batch, dst, used);
+ SetAddressPreviouslySpent(batch, dst, used);
}
}
}
@@ -990,7 +987,7 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const
if (!ExtractDestination(scriptPubKey, dest)) {
return false;
}
- if (IsAddressUsed(dest)) {
+ if (IsAddressPreviouslySpent(dest)) {
return true;
}
if (IsLegacy()) {
@@ -998,15 +995,15 @@ bool CWallet::IsSpentKey(const CScript& scriptPubKey) const
assert(spk_man != nullptr);
for (const auto& keyid : GetAffectedKeys(scriptPubKey, *spk_man)) {
WitnessV0KeyHash wpkh_dest(keyid);
- if (IsAddressUsed(wpkh_dest)) {
+ if (IsAddressPreviouslySpent(wpkh_dest)) {
return true;
}
ScriptHash sh_wpkh_dest(GetScriptForDestination(wpkh_dest));
- if (IsAddressUsed(sh_wpkh_dest)) {
+ if (IsAddressPreviouslySpent(sh_wpkh_dest)) {
return true;
}
PKHash pkh_dest(keyid);
- if (IsAddressUsed(pkh_dest)) {
+ if (IsAddressPreviouslySpent(pkh_dest)) {
return true;
}
}
@@ -1228,7 +1225,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS
// (e.g. it wasn't generated on this node or we're restoring from backup)
// add it to the address book for proper transaction accounting
if (!*dest.internal && !FindAddressBookEntry(dest.dest, /* allow_change= */ false)) {
- SetAddressBook(dest.dest, "", "receive");
+ SetAddressBook(dest.dest, "", AddressPurpose::RECEIVE);
}
}
}
@@ -1270,11 +1267,6 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
{
LOCK(cs_wallet);
- WalletBatch batch(GetDatabase());
-
- std::set<uint256> todo;
- std::set<uint256> done;
-
// Can't mark abandoned if confirmed or in mempool
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
@@ -1283,44 +1275,25 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
return false;
}
- todo.insert(hashTx);
-
- while (!todo.empty()) {
- uint256 now = *todo.begin();
- todo.erase(now);
- done.insert(now);
- auto it = mapWallet.find(now);
- assert(it != mapWallet.end());
- CWalletTx& wtx = it->second;
- int currentconfirm = GetTxDepthInMainChain(wtx);
- // If the orig tx was not in block, none of its spends can be
- assert(currentconfirm <= 0);
- // if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
- 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());
+ auto try_updating_state = [](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
+ // If the orig tx was not in block/mempool, none of its spends can be.
+ assert(!wtx.isConfirmed());
+ assert(!wtx.InMempool());
+ // If already conflicted or abandoned, no need to set abandoned
+ if (!wtx.isConflicted() && !wtx.isAbandoned()) {
wtx.m_state = TxStateInactive{/*abandoned=*/true};
- wtx.MarkDirty();
- batch.WriteTx(wtx);
- NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
- // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
- // States are not permanent, so these transactions can become unabandoned if they are re-added to the
- // mempool, or confirmed in a block, or conflicted.
- // Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
- // states change will remain abandoned and will require manual broadcast if the user wants them.
- for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
- std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
- for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
- if (!done.count(iter->second)) {
- todo.insert(iter->second);
- }
- }
- }
- // If a transaction changes 'conflicted' state, that changes the balance
- // available of the outputs it spends. So force those to be recomputed
- MarkInputsDirty(wtx.tx);
+ return TxUpdate::NOTIFY_CHANGED;
}
- }
+ return TxUpdate::UNCHANGED;
+ };
+
+ // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too.
+ // States are not permanent, so these transactions can become unabandoned if they are re-added to the
+ // mempool, or confirmed in a block, or conflicted.
+ // Note: If the reorged coinbase is re-added to the main chain, the descendants that have not had their
+ // states change will remain abandoned and will require manual broadcast if the user wants them.
+
+ RecursiveUpdateTxState(hashTx, try_updating_state);
return true;
}
@@ -1337,13 +1310,29 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
if (conflictconfirms >= 0)
return;
+ auto try_updating_state = [&](CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
+ if (conflictconfirms < GetTxDepthInMainChain(wtx)) {
+ // Block is 'more conflicted' than current confirm; update.
+ // Mark transaction as conflicted with this block.
+ wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
+ return TxUpdate::CHANGED;
+ }
+ return TxUpdate::UNCHANGED;
+ };
+
+ // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too.
+ RecursiveUpdateTxState(hashTx, try_updating_state);
+
+}
+
+void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
// Do not flush the wallet here for performance reasons
WalletBatch batch(GetDatabase(), false);
std::set<uint256> todo;
std::set<uint256> done;
- todo.insert(hashTx);
+ todo.insert(tx_hash);
while (!todo.empty()) {
uint256 now = *todo.begin();
@@ -1352,14 +1341,12 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
auto it = mapWallet.find(now);
assert(it != mapWallet.end());
CWalletTx& wtx = it->second;
- int currentconfirm = GetTxDepthInMainChain(wtx);
- if (conflictconfirms < currentconfirm) {
- // Block is 'more conflicted' than current confirm; update.
- // Mark transaction as conflicted with this block.
- wtx.m_state = TxStateConflicted{hashBlock, conflicting_height};
+
+ TxUpdate update_state = try_updating_state(wtx);
+ if (update_state != TxUpdate::UNCHANGED) {
wtx.MarkDirty();
batch.WriteTx(wtx);
- // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
+ // Iterate over all its outputs, and update those tx states as well (if applicable)
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
@@ -1368,7 +1355,12 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
}
}
}
- // If a transaction changes 'conflicted' state, that changes the balance
+
+ if (update_state == TxUpdate::NOTIFY_CHANGED) {
+ NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
+ }
+
+ // If a transaction changes its tx state, that usually changes the balance
// available of the outputs it spends. So force those to be recomputed
MarkInputsDirty(wtx.tx);
}
@@ -1440,6 +1432,12 @@ void CWallet::blockConnected(const interfaces::BlockInfo& block)
m_last_block_processed_height = block.height;
m_last_block_processed = block.hash;
+
+ // No need to scan block if it was created before the wallet birthday.
+ // Uses chain max time and twice the grace period to adjust time for block time variability.
+ if (block.chain_time_max < m_birth_time.load() - (TIMESTAMP_WINDOW * 2)) return;
+
+ // Scan block
for (size_t index = 0; index < block.data->vtx.size(); index++) {
SyncTransaction(block.data->vtx[index], TxStateConfirmed{block.hash, block.height, static_cast<int>(index)});
transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK);
@@ -1457,8 +1455,36 @@ void CWallet::blockDisconnected(const interfaces::BlockInfo& block)
// future with a stickier abandoned state or even removing abandontransaction call.
m_last_block_processed_height = block.height - 1;
m_last_block_processed = *Assert(block.prev_hash);
+
+ int disconnect_height = block.height;
+
for (const CTransactionRef& ptx : Assert(block.data)->vtx) {
SyncTransaction(ptx, TxStateInactive{});
+
+ for (const CTxIn& tx_in : ptx->vin) {
+ // No other wallet transactions conflicted with this transaction
+ if (mapTxSpends.count(tx_in.prevout) < 1) continue;
+
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(tx_in.prevout);
+
+ // For all of the spends that conflict with this transaction
+ for (TxSpends::const_iterator _it = range.first; _it != range.second; ++_it) {
+ CWalletTx& wtx = mapWallet.find(_it->second)->second;
+
+ if (!wtx.isConflicted()) continue;
+
+ auto try_updating_state = [&](CWalletTx& tx) {
+ if (!tx.isConflicted()) return TxUpdate::UNCHANGED;
+ if (tx.state<TxStateConflicted>()->conflicting_block_height >= disconnect_height) {
+ tx.m_state = TxStateInactive{};
+ return TxUpdate::CHANGED;
+ }
+ return TxUpdate::UNCHANGED;
+ };
+
+ RecursiveUpdateTxState(wtx.tx->GetHash(), try_updating_state);
+ }
+ }
}
}
@@ -1776,13 +1802,21 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
CTxDestination dest;
ExtractDestination(script, dest);
if (IsValidDestination(dest)) {
- SetAddressBookWithDB(batch, dest, label, "receive");
+ SetAddressBookWithDB(batch, dest, label, AddressPurpose::RECEIVE);
}
}
}
return true;
}
+void CWallet::FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time)
+{
+ int64_t birthtime = m_birth_time.load();
+ if (new_birth_time < birthtime) {
+ m_birth_time = new_birth_time;
+ }
+}
+
/**
* Scan active chain for relevant transactions after importing keys. This should
* be called whenever new keys are added to the wallet, with the oldest key
@@ -2190,34 +2224,7 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
}
}
- // Only drop non_witness_utxos if sighash_type != SIGHASH_ANYONECANPAY
- if ((sighash_type & 0x80) != SIGHASH_ANYONECANPAY) {
- // Figure out if any non_witness_utxos should be dropped
- std::vector<unsigned int> to_drop;
- for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
- const auto& input = psbtx.inputs.at(i);
- int wit_ver;
- std::vector<unsigned char> wit_prog;
- if (input.witness_utxo.IsNull() || !input.witness_utxo.scriptPubKey.IsWitnessProgram(wit_ver, wit_prog)) {
- // There's a non-segwit input or Segwit v0, so we cannot drop any witness_utxos
- to_drop.clear();
- break;
- }
- if (wit_ver == 0) {
- // Segwit v0, so we cannot drop any non_witness_utxos
- to_drop.clear();
- break;
- }
- if (input.non_witness_utxo) {
- to_drop.push_back(i);
- }
- }
-
- // Drop the non_witness_utxos that we can drop
- for (unsigned int i : to_drop) {
- psbtx.inputs.at(i).non_witness_utxo = nullptr;
- }
- }
+ RemoveUnnecessaryTransactions(psbtx, sighash_type);
// Complete if every input is now signed
complete = true;
@@ -2399,56 +2406,56 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
return DBErrors::LOAD_OK;
}
-bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
+bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& new_purpose)
{
bool fUpdated = false;
bool is_mine;
+ std::optional<AddressPurpose> purpose;
{
LOCK(cs_wallet);
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
m_address_book[address].SetLabel(strName);
- if (!strPurpose.empty()) /* update purpose only if requested */
- m_address_book[address].purpose = strPurpose;
is_mine = IsMine(address) != ISMINE_NO;
+ if (new_purpose) { /* update purpose only if requested */
+ purpose = m_address_book[address].purpose = new_purpose;
+ } else {
+ purpose = m_address_book[address].purpose;
+ }
}
+ // In very old wallets, address purpose may not be recorded so we derive it from IsMine
NotifyAddressBookChanged(address, strName, is_mine,
- strPurpose, (fUpdated ? CT_UPDATED : CT_NEW));
- if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
+ purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND),
+ (fUpdated ? CT_UPDATED : CT_NEW));
+ if (new_purpose && !batch.WritePurpose(EncodeDestination(address), PurposeToString(*new_purpose)))
return false;
return batch.WriteName(EncodeDestination(address), strName);
}
-bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
+bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& purpose)
{
WalletBatch batch(GetDatabase());
- return SetAddressBookWithDB(batch, address, strName, strPurpose);
+ return SetAddressBookWithDB(batch, address, strName, purpose);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
{
- bool is_mine;
WalletBatch batch(GetDatabase());
{
LOCK(cs_wallet);
- // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
- // NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
- // When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
+ // If we want to delete receiving addresses, we should avoid calling EraseAddressData because it will delete the previously_spent value. Could instead just erase the label so it becomes a change address, and keep the data.
+ // NOTE: This isn't a problem for sending addresses because they don't have any data that needs to be kept.
+ // When adding new address data, it should be considered here whether to retain or delete it.
if (IsMine(address)) {
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
return false;
}
- // Delete destdata tuples associated with address
- std::string strAddress = EncodeDestination(address);
- for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
- {
- batch.EraseDestData(strAddress, item.first);
- }
+ // Delete data rows associated with this address
+ batch.EraseAddressData(address);
m_address_book.erase(address);
- is_mine = IsMine(address) != ISMINE_NO;
}
- NotifyAddressBookChanged(address, "", is_mine, "", CT_DELETED);
+ NotifyAddressBookChanged(address, "", /*is_mine=*/false, AddressPurpose::SEND, CT_DELETED);
batch.ErasePurpose(EncodeDestination(address));
return batch.EraseName(EncodeDestination(address));
@@ -2502,7 +2509,7 @@ util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, c
auto op_dest = spk_man->GetNewDestination(type);
if (op_dest) {
- SetAddressBook(*op_dest, label, "receive");
+ SetAddressBook(*op_dest, label, AddressPurpose::RECEIVE);
}
return op_dest;
@@ -2552,7 +2559,7 @@ void CWallet::ForEachAddrBookEntry(const ListAddrBookFunc& func) const
AssertLockHeld(cs_wallet);
for (const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book) {
const auto& entry = item.second;
- func(item.first, entry.GetLabel(), entry.purpose, entry.IsChange());
+ func(item.first, entry.GetLabel(), entry.IsChange(), entry.purpose);
}
}
@@ -2561,7 +2568,7 @@ std::vector<CTxDestination> CWallet::ListAddrBookAddresses(const std::optional<A
AssertLockHeld(cs_wallet);
std::vector<CTxDestination> result;
AddrBookFilter filter = _filter ? *_filter : AddrBookFilter();
- ForEachAddrBookEntry([&result, &filter](const CTxDestination& dest, const std::string& label, const std::string& purpose, bool is_change) {
+ ForEachAddrBookEntry([&result, &filter](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) {
// Filter by change
if (filter.ignore_change && is_change) return;
// Filter by label
@@ -2572,14 +2579,14 @@ std::vector<CTxDestination> CWallet::ListAddrBookAddresses(const std::optional<A
return result;
}
-std::set<std::string> CWallet::ListAddrBookLabels(const std::string& purpose) const
+std::set<std::string> CWallet::ListAddrBookLabels(const std::optional<AddressPurpose> purpose) const
{
AssertLockHeld(cs_wallet);
std::set<std::string> label_set;
ForEachAddrBookEntry([&](const CTxDestination& _dest, const std::string& _label,
- const std::string& _purpose, bool _is_change) {
+ bool _is_change, const std::optional<AddressPurpose>& _purpose) {
if (_is_change) return;
- if (purpose.empty() || _purpose == purpose) {
+ if (!purpose || purpose == _purpose) {
label_set.insert(_label);
}
});
@@ -2819,51 +2826,42 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old
return nTimeSmart;
}
-bool CWallet::SetAddressUsed(WalletBatch& batch, const CTxDestination& dest, bool used)
+bool CWallet::SetAddressPreviouslySpent(WalletBatch& batch, const CTxDestination& dest, bool used)
{
- const std::string key{"used"};
if (std::get_if<CNoDestination>(&dest))
return false;
if (!used) {
- if (auto* data = util::FindKey(m_address_book, dest)) data->destdata.erase(key);
- return batch.EraseDestData(EncodeDestination(dest), key);
+ if (auto* data{common::FindKey(m_address_book, dest)}) data->previously_spent = false;
+ return batch.WriteAddressPreviouslySpent(dest, false);
}
- const std::string value{"1"};
- m_address_book[dest].destdata.insert(std::make_pair(key, value));
- return batch.WriteDestData(EncodeDestination(dest), key, value);
+ LoadAddressPreviouslySpent(dest);
+ return batch.WriteAddressPreviouslySpent(dest, true);
}
-void CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
+void CWallet::LoadAddressPreviouslySpent(const CTxDestination& dest)
{
- m_address_book[dest].destdata.insert(std::make_pair(key, value));
+ m_address_book[dest].previously_spent = true;
}
-bool CWallet::IsAddressUsed(const CTxDestination& dest) const
+void CWallet::LoadAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& request)
{
- const std::string key{"used"};
- std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dest);
- if(i != m_address_book.end())
- {
- CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
- if(j != i->second.destdata.end())
- {
- return true;
- }
- }
+ m_address_book[dest].receive_requests[id] = request;
+}
+
+bool CWallet::IsAddressPreviouslySpent(const CTxDestination& dest) const
+{
+ if (auto* data{common::FindKey(m_address_book, dest)}) return data->previously_spent;
return false;
}
std::vector<std::string> CWallet::GetAddressReceiveRequests() const
{
- const std::string prefix{"rr"};
std::vector<std::string> values;
- for (const auto& address : m_address_book) {
- for (const auto& data : address.second.destdata) {
- if (!data.first.compare(0, prefix.size(), prefix)) {
- values.emplace_back(data.second);
- }
+ for (const auto& [dest, entry] : m_address_book) {
+ for (const auto& [id, request] : entry.receive_requests) {
+ values.emplace_back(request);
}
}
return values;
@@ -2871,15 +2869,15 @@ std::vector<std::string> CWallet::GetAddressReceiveRequests() const
bool CWallet::SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value)
{
- const std::string key{"rr" + id}; // "rr" prefix = "receive request" in destdata
- CAddressBookData& data = m_address_book.at(dest);
- if (value.empty()) {
- if (!batch.EraseDestData(EncodeDestination(dest), key)) return false;
- data.destdata.erase(key);
- } else {
- if (!batch.WriteDestData(EncodeDestination(dest), key, value)) return false;
- data.destdata[key] = value;
- }
+ if (!batch.WriteAddressReceiveRequest(dest, id, value)) return false;
+ m_address_book[dest].receive_requests[id] = value;
+ return true;
+}
+
+bool CWallet::EraseAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id)
+{
+ if (!batch.EraseAddressReceiveRequest(dest, id)) return false;
+ m_address_book[dest].receive_requests.erase(id);
return true;
}
@@ -3147,6 +3145,14 @@ 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();
+ // Cache the first key time
+ std::optional<int64_t> time_first_key;
+ for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
+ int64_t time = spk_man->GetTimeFirstKey();
+ if (!time_first_key || time < *time_first_key) time_first_key = time;
+ }
+ if (time_first_key) walletInstance->m_birth_time = *time_first_key;
+
if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
return nullptr;
}
@@ -3222,11 +3228,7 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
{
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
- std::optional<int64_t> time_first_key;
- for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
- int64_t time = spk_man->GetTimeFirstKey();
- if (!time_first_key || time < *time_first_key) time_first_key = time;
- }
+ std::optional<int64_t> time_first_key = walletInstance->m_birth_time.load();
if (time_first_key) {
FoundBlock found = FoundBlock().height(rescan_height);
chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, found);
@@ -3538,6 +3540,14 @@ LegacyScriptPubKeyMan* CWallet::GetOrCreateLegacyScriptPubKeyMan()
return GetLegacyScriptPubKeyMan();
}
+void CWallet::AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man)
+{
+ const auto& spkm = m_spk_managers[id] = std::move(spkm_man);
+
+ // Update birth time if needed
+ FirstKeyTimeChanged(spkm.get(), spkm->GetTimeFirstKey());
+}
+
void CWallet::SetupLegacyScriptPubKeyMan()
{
if (!m_internal_spk_managers.empty() || !m_external_spk_managers.empty() || !m_spk_managers.empty() || IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
@@ -3549,7 +3559,8 @@ void CWallet::SetupLegacyScriptPubKeyMan()
m_internal_spk_managers[type] = spk_manager.get();
m_external_spk_managers[type] = spk_manager.get();
}
- m_spk_managers[spk_manager->GetID()] = std::move(spk_manager);
+ uint256 id = spk_manager->GetID();
+ AddScriptPubKeyMan(id, std::move(spk_manager));
}
const CKeyingMaterial& CWallet::GetEncryptionKey() const
@@ -3567,6 +3578,7 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
for (const auto& spk_man : GetActiveScriptPubKeyMans()) {
spk_man->NotifyWatchonlyChanged.connect(NotifyWatchonlyChanged);
spk_man->NotifyCanGetAddressesChanged.connect(NotifyCanGetAddressesChanged);
+ spk_man->NotifyFirstKeyTimeChanged.connect(std::bind(&CWallet::FirstKeyTimeChanged, this, std::placeholders::_1, std::placeholders::_2));
}
}
@@ -3574,10 +3586,10 @@ void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
{
if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc, m_keypool_size));
- m_spk_managers[id] = std::move(spk_manager);
+ AddScriptPubKeyMan(id, std::move(spk_manager));
} else {
auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc, m_keypool_size));
- m_spk_managers[id] = std::move(spk_manager);
+ AddScriptPubKeyMan(id, std::move(spk_manager));
}
}
@@ -3598,7 +3610,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const CExtKey& master_key)
}
spk_manager->SetupDescriptorGeneration(master_key, t, internal);
uint256 id = spk_manager->GetID();
- m_spk_managers[id] = std::move(spk_manager);
+ AddScriptPubKeyMan(id, std::move(spk_manager));
AddActiveScriptPubKeyMan(id, t, internal);
}
}
@@ -3629,7 +3641,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
if (!signer_res.isObject()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
for (bool internal : {false, true}) {
- const UniValue& descriptor_vals = find_value(signer_res, internal ? "internal" : "receive");
+ const UniValue& descriptor_vals = signer_res.find_value(internal ? "internal" : "receive");
if (!descriptor_vals.isArray()) throw std::runtime_error(std::string(__func__) + ": Unexpected result");
for (const UniValue& desc_val : descriptor_vals.get_array().getValues()) {
const std::string& desc_str = desc_val.getValStr();
@@ -3646,7 +3658,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, m_keypool_size));
spk_manager->SetupDescriptor(std::move(desc));
uint256 id = spk_manager->GetID();
- m_spk_managers[id] = std::move(spk_manager);
+ AddScriptPubKeyMan(id, std::move(spk_manager));
AddActiveScriptPubKeyMan(id, t, internal);
}
}
@@ -3763,7 +3775,8 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
spk_man = new_spk_man.get();
// Save the descriptor to memory
- m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
+ uint256 id = new_spk_man->GetID();
+ AddScriptPubKeyMan(id, std::move(new_spk_man));
}
// Add the private keys to the descriptor
@@ -3791,7 +3804,7 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
for (const auto& script : script_pub_keys) {
CTxDestination dest;
if (ExtractDestination(script, dest)) {
- SetAddressBook(dest, label, "receive");
+ SetAddressBook(dest, label, AddressPurpose::RECEIVE);
}
}
}
@@ -3843,16 +3856,19 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
// Close this database and delete the file
fs::path db_path = fs::PathFromString(m_database->Filename());
- fs::path db_dir = db_path.parent_path();
m_database->Close();
fs::remove(db_path);
+ // Generate the path for the location of the migrated wallet
+ // Wallets that are plain files rather than wallet directories will be migrated to be wallet directories.
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(m_name));
+
// Make new DB
DatabaseOptions opts;
opts.require_create = true;
opts.require_format = DatabaseFormat::SQLITE;
DatabaseStatus db_status;
- std::unique_ptr<WalletDatabase> new_db = MakeDatabase(db_dir, opts, db_status, error);
+ std::unique_ptr<WalletDatabase> new_db = MakeDatabase(wallet_path, opts, db_status, error);
assert(new_db); // This is to prevent doing anything further with this wallet. The original file was deleted, but a backup exists.
m_database.reset();
m_database = std::move(new_db);
@@ -3862,9 +3878,7 @@ bool CWallet::MigrateToSQLite(bilingual_str& error)
bool began = batch->TxnBegin();
assert(began); // This is a critical error, the new db could not be written to. The original db exists as a backup, but we should not continue execution.
for (const auto& [key, value] : records) {
- DataStream ss_key{key};
- DataStream ss_value{value};
- if (!batch->Write(ss_key, ss_value)) {
+ if (!batch->Write(MakeUCharSpan(key), MakeUCharSpan(value))) {
batch->TxnAbort();
m_database->Close();
fs::remove(m_database->Filename());
@@ -3906,7 +3920,8 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
error = _("Error: Duplicate descriptors created during migration. Your wallet may be corrupted.");
return false;
}
- m_spk_managers[desc_spkm->GetID()] = std::move(desc_spkm);
+ uint256 id = desc_spkm->GetID();
+ AddScriptPubKeyMan(id, std::move(desc_spkm));
}
// Remove the LegacyScriptPubKeyMan from disk
@@ -3977,7 +3992,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
std::vector<CTxDestination> dests_to_delete;
for (const auto& addr_pair : m_address_book) {
// Labels applied to receiving addresses should go based on IsMine
- if (addr_pair.second.purpose == "receive") {
+ if (addr_pair.second.purpose == AddressPurpose::RECEIVE) {
if (!IsMine(addr_pair.first)) {
// Check the address book data is the watchonly wallet's
if (data.watchonly_wallet) {
@@ -3985,10 +4000,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
if (data.watchonly_wallet->IsMine(addr_pair.first)) {
// Add to the watchonly. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
- std::string purpose = addr_pair.second.purpose;
- if (!purpose.empty()) {
- data.watchonly_wallet->m_address_book[addr_pair.first].purpose = purpose;
- }
+ data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
@@ -4001,10 +4013,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
if (data.solvable_wallet->IsMine(addr_pair.first)) {
// Add to the solvable. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
- std::string purpose = addr_pair.second.purpose;
- if (!purpose.empty()) {
- data.solvable_wallet->m_address_book[addr_pair.first].purpose = purpose;
- }
+ data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
@@ -4022,10 +4031,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
LOCK(data.watchonly_wallet->cs_wallet);
// Add to the watchonly. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
- std::string purpose = addr_pair.second.purpose;
- if (!purpose.empty()) {
- data.watchonly_wallet->m_address_book[addr_pair.first].purpose = purpose;
- }
+ data.watchonly_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.watchonly_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
@@ -4035,10 +4041,7 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
LOCK(data.solvable_wallet->cs_wallet);
// Add to the solvable. Preserve the labels, purpose, and change-ness
std::string label = addr_pair.second.GetLabel();
- std::string purpose = addr_pair.second.purpose;
- if (!purpose.empty()) {
- data.solvable_wallet->m_address_book[addr_pair.first].purpose = purpose;
- }
+ data.solvable_wallet->m_address_book[addr_pair.first].purpose = addr_pair.second.purpose;
if (!addr_pair.second.IsChange()) {
data.solvable_wallet->m_address_book[addr_pair.first].SetLabel(label);
}
@@ -4053,10 +4056,9 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
WalletBatch batch{wallet.GetDatabase()};
for (const auto& [destination, addr_book_data] : wallet.m_address_book) {
auto address{EncodeDestination(destination)};
- auto purpose{addr_book_data.purpose};
auto label{addr_book_data.GetLabel()};
// don't bother writing default values (unknown purpose, empty label)
- if (purpose != "unknown") batch.WritePurpose(address, purpose);
+ if (addr_book_data.purpose) batch.WritePurpose(address, PurposeToString(*addr_book_data.purpose));
if (!label.empty()) batch.WriteName(address, label);
}
};
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e8c18dbb67..cbd5008366 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,14 +7,15 @@
#define BITCOIN_WALLET_WALLET_H
#include <consensus/amount.h>
-#include <fs.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
+#include <interfaces/wallet.h>
#include <logging.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <psbt.h>
#include <tinyformat.h>
+#include <util/fs.h>
#include <util/hasher.h>
#include <util/message.h>
#include <util/result.h>
@@ -145,8 +146,6 @@ static const std::map<std::string,WalletFlags> WALLET_FLAG_MAP{
{"external_signer", WALLET_FLAG_EXTERNAL_SIGNER}
};
-extern const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS;
-
/** A wrapper to reserve an address from a wallet
*
* ReserveDestination is used to reserve an address.
@@ -200,28 +199,69 @@ public:
void KeepDestination();
};
-/** Address book data */
-class CAddressBookData
+/**
+ * Address book data.
+ */
+struct CAddressBookData
{
-private:
- bool m_change{true};
- std::string m_label;
-public:
- std::string purpose;
+ /**
+ * Address label which is always nullopt for change addresses. For sending
+ * and receiving addresses, it will be set to an arbitrary label string
+ * provided by the user, or to "", which is the default label. The presence
+ * or absence of a label is used to distinguish change addresses from
+ * non-change addresses by wallet transaction listing and fee bumping code.
+ */
+ std::optional<std::string> label;
- CAddressBookData() : purpose("unknown") {}
+ /**
+ * Address purpose which was originally recorded for payment protocol
+ * support but now serves as a cached IsMine value. Wallet code should
+ * not rely on this field being set.
+ */
+ std::optional<AddressPurpose> purpose;
- typedef std::map<std::string, std::string> StringMap;
- StringMap destdata;
+ /**
+ * Whether coins with this address have previously been spent. Set when the
+ * the wallet avoid_reuse option is enabled and this is an IsMine address
+ * that has already received funds and spent them. This is used during coin
+ * selection to increase privacy by not creating different transactions
+ * that spend from the same addresses.
+ */
+ bool previously_spent{false};
- bool IsChange() const { return m_change; }
- const std::string& GetLabel() const { return m_label; }
- void SetLabel(const std::string& label) {
- m_change = false;
- m_label = label;
- }
+ /**
+ * Map containing data about previously generated receive requests
+ * requesting funds to be sent to this address. Only present for IsMine
+ * addresses. Map keys are decimal numbers uniquely identifying each
+ * request, and map values are serialized RecentRequestEntry objects
+ * containing BIP21 URI information including message and amount.
+ */
+ std::map<std::string, std::string> receive_requests{};
+
+ /** Accessor methods. */
+ bool IsChange() const { return !label.has_value(); }
+ std::string GetLabel() const { return label ? *label : std::string{}; }
+ void SetLabel(std::string name) { label = std::move(name); }
};
+inline std::string PurposeToString(AddressPurpose p)
+{
+ switch(p) {
+ case AddressPurpose::RECEIVE: return "receive";
+ case AddressPurpose::SEND: return "send";
+ case AddressPurpose::REFUND: return "refund";
+ } // no default case so the compiler will warn when a new enum as added
+ assert(false);
+}
+
+inline std::optional<AddressPurpose> PurposeFromString(std::string_view s)
+{
+ if (s == "receive") return AddressPurpose::RECEIVE;
+ else if (s == "send") return AddressPurpose::SEND;
+ else if (s == "refund") return AddressPurpose::REFUND;
+ return {};
+}
+
struct CRecipient
{
CScript scriptPubKey;
@@ -244,7 +284,7 @@ private:
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<bool> m_attaching_chain{false};
std::atomic<bool> m_scanning_with_passphrase{false};
- std::atomic<int64_t> m_scanning_start{0};
+ std::atomic<SteadyClock::time_point> m_scanning_start{SteadyClock::time_point{}};
std::atomic<double> m_scanning_progress{0};
friend class WalletRescanReserver;
@@ -259,6 +299,10 @@ private:
// Local time that the tip block was received. Used to schedule wallet rebroadcasts.
std::atomic<int64_t> m_best_block_time {0};
+ // First created key time. Used to skip blocks prior to this time.
+ // 'std::numeric_limits<int64_t>::max()' if wallet is blank.
+ std::atomic<int64_t> m_birth_time{std::numeric_limits<int64_t>::max()};
+
/**
* Used to keep track of spent outpoints, and
* detect and report conflicts (double-spends or
@@ -290,6 +334,13 @@ private:
/** 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);
+ enum class TxUpdate { UNCHANGED, CHANGED, NOTIFY_CHANGED };
+
+ using TryUpdatingStateFn = std::function<TxUpdate(CWalletTx& wtx)>;
+
+ /** Mark a transaction (and its in-wallet descendants) as a particular tx state. */
+ void RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingStateFn& try_updating_state) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
/** Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -300,7 +351,7 @@ private:
/** WalletFlags set on this wallet. */
std::atomic<uint64_t> m_wallet_flags{0};
- bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose);
+ bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& strPurpose);
//! Unsets a wallet flag and saves it to disk
void UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag);
@@ -340,6 +391,10 @@ private:
// ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure
std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers;
+ // Appends spk managers into the main 'm_spk_managers'.
+ // Must be the only method adding data to it.
+ void AddScriptPubKeyMan(const uint256& id, std::unique_ptr<ScriptPubKeyMan> spkm_man);
+
/**
* Catch wallet up to current chain, scanning new blocks, updating the best
* block locator and m_last_block_processed, and registering for
@@ -465,7 +520,7 @@ public:
bool IsAbortingRescan() const { return fAbortRescan; }
bool IsScanning() const { return fScanningWallet; }
bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; }
- int64_t ScanningDuration() const { return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0; }
+ SteadyClock::duration ScanningDuration() const { return fScanningWallet ? SteadyClock::now() - m_scanning_start.load() : SteadyClock::duration{}; }
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
@@ -476,8 +531,10 @@ public:
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; return true; }
- //! Adds a destination data tuple to the store, without saving it to disk
- void LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ //! Marks destination as previously spent.
+ void LoadAddressPreviouslySpent(const CTxDestination& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ //! Appends payment request to destination.
+ void LoadAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& request) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
int64_t nRelockTime GUARDED_BY(cs_wallet){0};
@@ -599,6 +656,9 @@ public:
bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ /** Updates wallet birth time if 'new_birth_time' is below it */
+ void FirstKeyTimeChanged(const ScriptPubKeyMan* spkm, int64_t new_birth_time);
+
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
/** Allow Coin Selection to pick unconfirmed UTXOs that were sent from our own wallet if it
@@ -664,13 +724,13 @@ public:
/**
* Retrieve all the known labels in the address book
*/
- std::set<std::string> ListAddrBookLabels(const std::string& purpose) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ std::set<std::string> ListAddrBookLabels(const std::optional<AddressPurpose> purpose) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Walk-through the address book entries.
* Stops when the provided 'ListAddrBookFunc' returns false.
*/
- using ListAddrBookFunc = std::function<void(const CTxDestination& dest, const std::string& label, const std::string& purpose, bool is_change)>;
+ using ListAddrBookFunc = std::function<void(const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose> purpose)>;
void ForEachAddrBookEntry(const ListAddrBookFunc& func) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
@@ -700,15 +760,16 @@ public:
DBErrors LoadWallet();
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
+ bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::optional<AddressPurpose>& purpose);
bool DelAddressBook(const CTxDestination& address);
- bool IsAddressUsed(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool SetAddressUsed(WalletBatch& batch, const CTxDestination& dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool IsAddressPreviouslySpent(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool SetAddressPreviouslySpent(WalletBatch& batch, const CTxDestination& dest, bool used) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::vector<std::string> GetAddressReceiveRequests() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool SetAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool EraseAddressReceiveRequest(WalletBatch& batch, const CTxDestination& dest, const std::string& id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -739,7 +800,7 @@ public:
*/
boost::signals2::signal<void(const CTxDestination& address,
const std::string& label, bool isMine,
- const std::string& purpose, ChangeType status)>
+ AddressPurpose purpose, ChangeType status)>
NotifyAddressBookChanged;
/**
@@ -971,7 +1032,7 @@ public:
return false;
}
m_wallet.m_scanning_with_passphrase.exchange(with_passphrase);
- m_wallet.m_scanning_start = GetTimeMillis();
+ m_wallet.m_scanning_start = SteadyClock::now();
m_wallet.m_scanning_progress = 0;
m_could_reserve = true;
return true;
@@ -1013,7 +1074,7 @@ struct MigrationResult {
};
//! Do all steps to migrate a legacy wallet to a descriptor wallet
-util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context);
+[[nodiscard]] util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& wallet_name, const SecureString& passphrase, WalletContext& context);
} // namespace wallet
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 2cd35ae40e..34fe8ab17f 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -5,13 +5,13 @@
#include <wallet/walletdb.h>
-#include <fs.h>
+#include <common/system.h>
#include <key_io.h>
#include <protocol.h>
#include <serialize.h>
#include <sync.h>
#include <util/bip32.h>
-#include <util/system.h>
+#include <util/fs.h>
#include <util/time.h>
#include <util/translation.h>
#ifdef USE_BDB
@@ -347,7 +347,13 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::PURPOSE) {
std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
+ std::string purpose_str;
+ ssValue >> purpose_str;
+ std::optional<AddressPurpose> purpose{PurposeFromString(purpose_str)};
+ if (!purpose) {
+ pwallet->WalletLogPrintf("Warning: nonstandard purpose string '%s' for address '%s'\n", purpose_str, strAddress);
+ }
+ pwallet->m_address_book[DecodeDestination(strAddress)].purpose = purpose;
} else if (strType == DBKeys::TX) {
uint256 hash;
ssKey >> hash;
@@ -609,7 +615,20 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
ssKey >> strAddress;
ssKey >> strKey;
ssValue >> strValue;
- pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue);
+ const CTxDestination& dest{DecodeDestination(strAddress)};
+ if (strKey.compare("used") == 0) {
+ // Load "used" key indicating if an IsMine address has
+ // previously been spent from with avoid_reuse option enabled.
+ // The strValue is not used for anything currently, but could
+ // hold more information in the future. Current values are just
+ // "1" or "p" for present (which was written prior to
+ // f5ba424cd44619d9b9be88b8593d69a7ba96db26).
+ pwallet->LoadAddressPreviouslySpent(dest);
+ } else if (strKey.compare(0, 2, "rr") == 0) {
+ // Load "rr##" keys where ## is a decimal number, and strValue
+ // is a serialized RecentRequestEntry object.
+ pwallet->LoadAddressReceiveRequest(dest, strKey.substr(2), strValue);
+ }
} else if (strType == DBKeys::HDCHAIN) {
CHDChain chain;
ssValue >> chain;
@@ -1082,16 +1101,28 @@ void MaybeCompactWalletDB(WalletContext& context)
fOneThread = false;
}
-bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
+bool WalletBatch::WriteAddressPreviouslySpent(const CTxDestination& dest, bool previously_spent)
+{
+ auto key{std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), std::string("used")))};
+ return previously_spent ? WriteIC(key, std::string("1")) : EraseIC(key);
+}
+
+bool WalletBatch::WriteAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& receive_request)
{
- return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value);
+ return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), "rr" + id)), receive_request);
}
-bool WalletBatch::EraseDestData(const std::string &address, const std::string &key)
+bool WalletBatch::EraseAddressReceiveRequest(const CTxDestination& dest, const std::string& id)
{
- return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)));
+ return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), "rr" + id)));
}
+bool WalletBatch::EraseAddressData(const CTxDestination& dest)
+{
+ DataStream prefix;
+ prefix << DBKeys::DESTDATA << EncodeDestination(dest);
+ return m_batch->ErasePrefix(prefix);
+}
bool WalletBatch::WriteHDChain(const CHDChain& chain)
{
@@ -1105,6 +1136,9 @@ bool WalletBatch::WriteWalletFlags(const uint64_t flags)
bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
{
+ // Begin db txn
+ if (!m_batch->TxnBegin()) return false;
+
// Get cursor
std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor();
if (!cursor)
@@ -1113,8 +1147,7 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
}
// Iterate the DB and look for any records that have the type prefixes
- while (true)
- {
+ while (true) {
// Read next record
DataStream key{};
DataStream value{};
@@ -1122,6 +1155,8 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
if (status == DatabaseCursor::Status::DONE) {
break;
} else if (status == DatabaseCursor::Status::FAIL) {
+ cursor.reset(nullptr);
+ m_batch->TxnAbort(); // abort db txn
return false;
}
@@ -1132,10 +1167,16 @@ bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
key >> type;
if (types.count(type) > 0) {
- m_batch->Erase(key_data);
+ if (!m_batch->Erase(key_data)) {
+ cursor.reset(nullptr);
+ m_batch->TxnAbort();
+ return false; // erase failed
+ }
}
}
- return true;
+ // Finish db txn
+ cursor.reset(nullptr);
+ return m_batch->TxnCommit();
}
bool WalletBatch::TxnBegin()
@@ -1231,44 +1272,4 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas
status = DatabaseStatus::FAILED_BAD_FORMAT;
return nullptr;
}
-
-/** Return object for accessing dummy database with no read/write capabilities. */
-std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
-{
- return std::make_unique<DummyDatabase>();
-}
-
-/** Return object for accessing temporary in-memory database. */
-std::unique_ptr<WalletDatabase> CreateMockWalletDatabase(DatabaseOptions& options)
-{
-
- std::optional<DatabaseFormat> format;
- if (options.require_format) format = options.require_format;
- if (!format) {
-#ifdef USE_BDB
- format = DatabaseFormat::BERKELEY;
-#endif
-#ifdef USE_SQLITE
- format = DatabaseFormat::SQLITE;
-#endif
- }
-
- if (format == DatabaseFormat::SQLITE) {
-#ifdef USE_SQLITE
- return std::make_unique<SQLiteDatabase>(":memory:", "", options, true);
-#endif
- assert(false);
- }
-
-#ifdef USE_BDB
- return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "", options);
-#endif
- assert(false);
-}
-
-std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
-{
- DatabaseOptions options;
- return CreateMockWalletDatabase(options);
-}
} // namespace wallet
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index c97356a71f..f84a89b23f 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -7,6 +7,7 @@
#define BITCOIN_WALLET_WALLETDB_H
#include <script/sign.h>
+#include <script/standard.h>
#include <wallet/db.h>
#include <wallet/walletutil.h>
#include <key.h>
@@ -264,10 +265,10 @@ public:
bool WriteLockedUTXO(const COutPoint& output);
bool EraseLockedUTXO(const COutPoint& output);
- /// Write destination data key,value tuple to database
- bool WriteDestData(const std::string &address, const std::string &key, const std::string &value);
- /// Erase destination data tuple from wallet database
- bool EraseDestData(const std::string &address, const std::string &key);
+ bool WriteAddressPreviouslySpent(const CTxDestination& dest, bool previously_spent);
+ bool WriteAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& receive_request);
+ bool EraseAddressReceiveRequest(const CTxDestination& dest, const std::string& id);
+ bool EraseAddressData(const CTxDestination& dest);
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal);
bool EraseActiveScriptPubKeyMan(uint8_t type, bool internal);
@@ -304,13 +305,6 @@ using KeyFilterFn = std::function<bool(const std::string&)>;
//! Unserialize a given Key-Value pair and load it into the wallet
bool ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
-
-/** Return object for accessing dummy database with no read/write capabilities. */
-std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase();
-
-/** Return object for accessing temporary in-memory database. */
-std::unique_ptr<WalletDatabase> CreateMockWalletDatabase(DatabaseOptions& options);
-std::unique_ptr<WalletDatabase> CreateMockWalletDatabase();
} // namespace wallet
#endif // BITCOIN_WALLET_WALLETDB_H
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index f389676204..2f3f8ef77d 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -8,8 +8,8 @@
#include <wallet/wallettool.h>
-#include <fs.h>
-#include <util/system.h>
+#include <common/args.h>
+#include <util/fs.h>
#include <util/translation.h>
#include <wallet/dump.h>
#include <wallet/salvage.h>
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 299c74d01c..fdd5bc36d8 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -4,8 +4,8 @@
#include <wallet/walletutil.h>
+#include <common/args.h>
#include <logging.h>
-#include <util/system.h>
namespace wallet {
fs::path GetWalletDir()
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index 8434d64fb5..c5975144c1 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_WALLET_WALLETUTIL_H
#define BITCOIN_WALLET_WALLETUTIL_H
-#include <fs.h>
#include <script/descriptor.h>
+#include <util/fs.h>
#include <vector>
@@ -53,10 +53,18 @@ enum WalletFlags : uint64_t {
//! Flag set when a wallet contains no HD seed and no private keys, scripts,
//! addresses, and other watch only things, and is therefore "blank."
//!
- //! The only function this flag serves is to distinguish a blank wallet from
+ //! The main function this flag serves is to distinguish a blank wallet from
//! a newly created wallet when the wallet database is loaded, to avoid
//! initialization that should only happen on first run.
//!
+ //! A secondary function of this flag, which applies to descriptor wallets
+ //! only, is to serve as an ongoing indication that descriptors in the
+ //! wallet should be created manually, and that the wallet should not
+ //! generate automatically generate new descriptors if it is later
+ //! encrypted. To support this behavior, descriptor wallets unlike legacy
+ //! wallets do not automatically unset the BLANK flag when things are
+ //! imported.
+ //!
//! This flag is also a mandatory flag to prevent previous versions of
//! bitcoin from opening the wallet, thinking it was newly created, and
//! then improperly reinitializing it.
@@ -104,20 +112,6 @@ public:
WalletDescriptor() {}
WalletDescriptor(std::shared_ptr<Descriptor> descriptor, uint64_t creation_time, int32_t range_start, int32_t range_end, int32_t next_index) : descriptor(descriptor), creation_time(creation_time), range_start(range_start), range_end(range_end), next_index(next_index) {}
};
-
-class CWallet;
-class DescriptorScriptPubKeyMan;
-
-/** struct containing information needed for migrating legacy wallets to descriptor wallets */
-struct MigrationData
-{
- CExtKey master_key;
- std::vector<std::pair<std::string, int64_t>> watch_descs;
- std::vector<std::pair<std::string, int64_t>> solvable_descs;
- std::vector<std::unique_ptr<DescriptorScriptPubKeyMan>> desc_spkms;
- std::shared_ptr<CWallet> watchonly_wallet{nullptr};
- std::shared_ptr<CWallet> solvable_wallet{nullptr};
-};
} // namespace wallet
#endif // BITCOIN_WALLET_WALLETUTIL_H
diff --git a/src/warnings.cpp b/src/warnings.cpp
index d0de706953..cb73c7aea2 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -5,9 +5,9 @@
#include <warnings.h>
+#include <common/system.h>
#include <sync.h>
#include <util/string.h>
-#include <util/system.h>
#include <util/translation.h>
#include <vector>
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index cf0ee48f47..17fa7bbaa9 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -6,6 +6,7 @@
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#include <cstdint>
+#include <functional>
#include <memory>
#include <string>
@@ -13,7 +14,7 @@ class CBlockIndex;
class CTransaction;
class CZMQAbstractNotifier;
-using CZMQNotifierFactory = std::unique_ptr<CZMQAbstractNotifier> (*)();
+using CZMQNotifierFactory = std::function<std::unique_ptr<CZMQAbstractNotifier>()>;
class CZMQAbstractNotifier
{
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index df129c0830..6755368249 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -4,10 +4,10 @@
#include <zmq/zmqnotificationinterface.h>
+#include <common/args.h>
#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
-#include <util/system.h>
#include <validationinterface.h>
#include <zmq/zmqabstractnotifier.h>
#include <zmq/zmqpublishnotifier.h>
@@ -39,12 +39,14 @@ std::list<const CZMQAbstractNotifier*> CZMQNotificationInterface::GetActiveNotif
return result;
}
-CZMQNotificationInterface* CZMQNotificationInterface::Create()
+std::unique_ptr<CZMQNotificationInterface> CZMQNotificationInterface::Create(std::function<bool(CBlock&, const CBlockIndex&)> get_block_by_index)
{
std::map<std::string, CZMQNotifierFactory> factories;
factories["pubhashblock"] = CZMQAbstractNotifier::Create<CZMQPublishHashBlockNotifier>;
factories["pubhashtx"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;
- factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
+ factories["pubrawblock"] = [&get_block_by_index]() -> std::unique_ptr<CZMQAbstractNotifier> {
+ return std::make_unique<CZMQPublishRawBlockNotifier>(get_block_by_index);
+ };
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
factories["pubsequence"] = CZMQAbstractNotifier::Create<CZMQPublishSequenceNotifier>;
@@ -68,7 +70,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
notificationInterface->notifiers = std::move(notifiers);
if (notificationInterface->Initialize()) {
- return notificationInterface.release();
+ return notificationInterface;
}
}
@@ -198,4 +200,4 @@ void CZMQNotificationInterface::BlockDisconnected(const std::shared_ptr<const CB
});
}
-CZMQNotificationInterface* g_zmq_notification_interface = nullptr;
+std::unique_ptr<CZMQNotificationInterface> g_zmq_notification_interface;
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index a43f9bfef3..ce67633b30 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -9,6 +9,7 @@
#include <validationinterface.h>
#include <cstdint>
+#include <functional>
#include <list>
#include <memory>
@@ -23,7 +24,7 @@ public:
std::list<const CZMQAbstractNotifier*> GetActiveNotifiers() const;
- static CZMQNotificationInterface* Create();
+ static std::unique_ptr<CZMQNotificationInterface> Create(std::function<bool(CBlock&, const CBlockIndex&)> get_block_by_index);
protected:
bool Initialize();
@@ -43,6 +44,6 @@ private:
std::list<std::unique_ptr<CZMQAbstractNotifier>> notifiers;
};
-extern CZMQNotificationInterface* g_zmq_notification_interface;
+extern std::unique_ptr<CZMQNotificationInterface> g_zmq_notification_interface;
#endif // BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 6418455d19..1241431523 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -39,8 +39,6 @@ namespace Consensus {
struct Params;
}
-using node::ReadBlockFromDisk;
-
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
static const char *MSG_HASHBLOCK = "hashblock";
@@ -96,12 +94,11 @@ static bool IsZMQAddressIPV6(const std::string &zmq_address)
{
const std::string tcp_prefix = "tcp://";
const size_t tcp_index = zmq_address.rfind(tcp_prefix);
- const size_t colon_index = zmq_address.rfind(":");
+ const size_t colon_index = zmq_address.rfind(':');
if (tcp_index == 0 && colon_index != std::string::npos) {
const std::string ip = zmq_address.substr(tcp_prefix.length(), colon_index - tcp_prefix.length());
- CNetAddr addr;
- LookupHost(ip, addr, false);
- if (addr.IsIPv6()) return true;
+ const std::optional<CNetAddr> addr{LookupHost(ip, false)};
+ if (addr.has_value() && addr.value().IsIPv6()) return true;
}
return false;
}
@@ -247,10 +244,9 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
{
LogPrint(BCLog::ZMQ, "Publish rawblock %s to %s\n", pindex->GetBlockHash().GetHex(), this->address);
- const Consensus::Params& consensusParams = Params().GetConsensus();
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
CBlock block;
- if (!ReadBlockFromDisk(block, pindex, consensusParams)) {
+ if (!m_get_block_by_index(block, *pindex)) {
zmqError("Can't read block from disk");
return false;
}
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 18336a5eb0..a5cd433761 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -9,7 +9,9 @@
#include <cstddef>
#include <cstdint>
+#include <functional>
+class CBlock;
class CBlockIndex;
class CTransaction;
@@ -46,7 +48,12 @@ public:
class CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier
{
+private:
+ const std::function<bool(CBlock&, const CBlockIndex&)> m_get_block_by_index;
+
public:
+ CZMQPublishRawBlockNotifier(std::function<bool(CBlock&, const CBlockIndex&)> get_block_by_index)
+ : m_get_block_by_index{std::move(get_block_by_index)} {}
bool NotifyBlock(const CBlockIndex *pindex) override;
};
diff --git a/test/README.md b/test/README.md
index 0eddb72e1f..fee8828d34 100644
--- a/test/README.md
+++ b/test/README.md
@@ -331,6 +331,7 @@ Use the `-v` option for verbose output.
| Lint test | Dependency |
|-----------|:----------:|
| [`lint-python.py`](lint/lint-python.py) | [flake8](https://gitlab.com/pycqa/flake8)
+| [`lint-python.py`](lint/lint-python.py) | [lief](https://github.com/lief-project/LIEF)
| [`lint-python.py`](lint/lint-python.py) | [mypy](https://github.com/python/mypy)
| [`lint-python.py`](lint/lint-python.py) | [pyzmq](https://github.com/zeromq/pyzmq)
| [`lint-python-dead-code.py`](lint/lint-python-dead-code.py) | [vulture](https://github.com/jendrikseipp/vulture)
diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py
index fa1bb6506a..586722aa65 100755
--- a/test/functional/feature_abortnode.py
+++ b/test/functional/feature_abortnode.py
@@ -40,7 +40,7 @@ class AbortNodeTest(BitcoinTestFramework):
# Check that node0 aborted
self.log.info("Waiting for crash")
- self.nodes[0].wait_until_stopped(timeout=5)
+ self.nodes[0].wait_until_stopped(timeout=5, expect_error=True)
self.log.info("Node crashed - now verifying restart fails")
self.nodes[0].assert_start_raises_init_error()
diff --git a/test/functional/feature_anchors.py b/test/functional/feature_anchors.py
index 713c0826d3..468ad1eafa 100755
--- a/test/functional/feature_anchors.py
+++ b/test/functional/feature_anchors.py
@@ -63,17 +63,25 @@ class AnchorsTest(BitcoinTestFramework):
self.log.info("Check the addresses in anchors.dat")
with open(node_anchors_path, "rb") as file_handler:
- anchors = file_handler.read().hex()
+ anchors = file_handler.read()
+ anchors_hex = anchors.hex()
for port in block_relay_nodes_port:
ip_port = ip + port
- assert ip_port in anchors
+ assert ip_port in anchors_hex
for port in inbound_nodes_port:
ip_port = ip + port
- assert ip_port not in anchors
+ assert ip_port not in anchors_hex
- self.log.info("Start node")
- self.start_node(0)
+ self.log.info("Perturb anchors.dat to test it doesn't throw an error during initialization")
+ with self.nodes[0].assert_debug_log(["0 block-relay-only anchors will be tried for connections."]):
+ with open(node_anchors_path, "wb") as out_file_handler:
+ tweaked_contents = bytearray(anchors)
+ tweaked_contents[20:20] = b'1'
+ out_file_handler.write(bytes(tweaked_contents))
+
+ self.log.info("Start node")
+ self.start_node(0)
self.log.info("When node starts, check if anchors.dat doesn't exist anymore")
assert not os.path.exists(node_anchors_path)
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 36ee79dab9..613d2eab14 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -35,7 +35,6 @@ from test_framework.blocktools import (
create_block,
create_coinbase,
)
-from test_framework.key import ECKey
from test_framework.messages import (
CBlockHeader,
COutPoint,
@@ -46,9 +45,13 @@ from test_framework.messages import (
msg_headers,
)
from test_framework.p2p import P2PInterface
-from test_framework.script import (CScript, OP_TRUE)
+from test_framework.script import (
+ CScript,
+ OP_TRUE,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+from test_framework.wallet_util import generate_keypair
class BaseNode(P2PInterface):
@@ -90,9 +93,7 @@ class AssumeValidTest(BitcoinTestFramework):
self.blocks = []
# Get a pubkey for the coinbase TXO
- coinbase_key = ECKey()
- coinbase_key.generate()
- coinbase_pubkey = coinbase_key.get_pubkey().get_bytes()
+ _, coinbase_pubkey = generate_keypair()
# Create the first block with a coinbase output to our key
height = 1
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 1080e77c40..765db97445 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -14,7 +14,6 @@ from test_framework.blocktools import (
get_legacy_sigopcount_block,
MAX_BLOCK_SIGOPS,
)
-from test_framework.key import ECKey
from test_framework.messages import (
CBlock,
COIN,
@@ -55,6 +54,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
)
+from test_framework.wallet_util import generate_keypair
from data import invalid_txs
@@ -98,9 +98,7 @@ class FullBlockTest(BitcoinTestFramework):
self.bootstrap_p2p() # Add one p2p connection to the node
self.block_heights = {}
- self.coinbase_key = ECKey()
- self.coinbase_key.generate()
- self.coinbase_pubkey = self.coinbase_key.get_pubkey().get_bytes()
+ self.coinbase_key, self.coinbase_pubkey = generate_keypair()
self.tip = None
self.blocks = {}
self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 4f8541a5d7..2ffb182946 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -52,6 +52,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
self._test_use_index_option()
self._test_reorg_index()
self._test_index_rejects_hash_serialized()
+ self._test_init_index_after_reorg()
def block_sanity_check(self, block_info):
block_subsidy = 50
@@ -60,6 +61,9 @@ class CoinStatsIndexTest(BitcoinTestFramework):
block_info['new_outputs_ex_coinbase'] + block_info['coinbase'] + block_info['unspendable']
)
+ def sync_index_node(self):
+ self.wait_until(lambda: self.nodes[1].getindexinfo()['coinstatsindex']['synced'] is True)
+
def _test_coin_stats_index(self):
node = self.nodes[0]
index_node = self.nodes[1]
@@ -145,14 +149,14 @@ class CoinStatsIndexTest(BitcoinTestFramework):
self.block_sanity_check(res5['block_info'])
# Generate and send a normal tx with two outputs
- tx1_txid, tx1_vout = self.wallet.send_to(
+ tx1 = self.wallet.send_to(
from_node=node,
scriptPubKey=self.wallet.get_scriptPubKey(),
amount=21 * COIN,
)
# Find the right position of the 21 BTC output
- tx1_out_21 = self.wallet.get_utxo(txid=tx1_txid, vout=tx1_vout)
+ tx1_out_21 = self.wallet.get_utxo(txid=tx1["txid"], vout=tx1["sent_vout"])
# Generate and send another tx with an OP_RETURN output (which is unspendable)
tx2 = self.wallet.create_self_transfer(utxo_to_spend=tx1_out_21)['tx']
@@ -227,18 +231,16 @@ class CoinStatsIndexTest(BitcoinTestFramework):
self.log.info("Test that the index works with -reindex")
self.restart_node(1, extra_args=["-coinstatsindex", "-reindex"])
+ self.sync_index_node()
res11 = index_node.gettxoutsetinfo('muhash')
assert_equal(res11, res10)
- self.log.info("Test that -reindex-chainstate is disallowed with coinstatsindex")
+ self.log.info("Test that the index works with -reindex-chainstate")
- self.stop_node(1)
- self.nodes[1].assert_start_raises_init_error(
- expected_msg='Error: -reindex-chainstate option is not compatible with -coinstatsindex. '
- 'Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.',
- extra_args=['-coinstatsindex', '-reindex-chainstate'],
- )
- self.restart_node(1, extra_args=["-coinstatsindex"])
+ self.restart_node(1, extra_args=["-coinstatsindex", "-reindex-chainstate"])
+ self.sync_index_node()
+ res12 = index_node.gettxoutsetinfo('muhash')
+ assert_equal(res12, res10)
def _test_use_index_option(self):
self.log.info("Test use_index option for nodes running the index")
@@ -257,6 +259,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
index_node = self.nodes[1]
reorg_blocks = self.generatetoaddress(index_node, 2, getnewdestination()[2])
reorg_block = reorg_blocks[1]
+ self.sync_index_node()
res_invalid = index_node.gettxoutsetinfo('muhash')
index_node.invalidateblock(reorg_blocks[0])
assert_equal(index_node.gettxoutsetinfo('muhash')['height'], 110)
@@ -296,6 +299,26 @@ class CoinStatsIndexTest(BitcoinTestFramework):
for use_index in {True, False, None}:
assert_raises_rpc_error(-8, msg, self.nodes[1].gettxoutsetinfo, hash_type='hash_serialized_2', hash_or_height=111, use_index=use_index)
+ def _test_init_index_after_reorg(self):
+ self.log.info("Test a reorg while the index is deactivated")
+ index_node = self.nodes[1]
+ block = self.nodes[0].getbestblockhash()
+ self.generate(index_node, 2, sync_fun=self.no_op)
+ self.sync_index_node()
+
+ # Restart without index
+ self.restart_node(1, extra_args=[])
+ self.connect_nodes(0, 1)
+ index_node.invalidateblock(block)
+ self.generatetoaddress(index_node, 5, getnewdestination()[2])
+ res = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=None, use_index=False)
+
+ # Restart with index that still has its best block on the old chain
+ self.restart_node(1, extra_args=self.extra_args[1])
+ self.sync_index_node()
+ res1 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=None, use_index=True)
+ assert_equal(res["muhash"], res1["muhash"])
+
if __name__ == '__main__':
CoinStatsIndexTest().main()
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index f9730b48c5..b898488924 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -5,9 +5,14 @@
"""Test various command line arguments and configuration file parameters."""
import os
+import pathlib
+import re
+import sys
+import tempfile
import time
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.test_node import ErrorMatch
from test_framework import util
@@ -74,7 +79,7 @@ class ConfArgsTest(BitcoinTestFramework):
util.write_config(main_conf_file_path, n=0, chain='', extra_config=f'includeconf={inc_conf_file_path}\n')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('acceptnonstdtxn=1\n')
- self.nodes[0].assert_start_raises_init_error(extra_args=[f"-conf={main_conf_file_path}"], expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
+ self.nodes[0].assert_start_raises_init_error(extra_args=[f"-conf={main_conf_file_path}", "-allowignoredconf"], expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('nono\n')
@@ -108,6 +113,41 @@ class ConfArgsTest(BitcoinTestFramework):
with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf:
conf.write('') # clear
+ def test_config_file_log(self):
+ # Disable this test for windows currently because trying to override
+ # the default datadir through the environment does not seem to work.
+ if sys.platform == "win32":
+ return
+
+ self.log.info('Test that correct configuration path is changed when configuration file changes the datadir')
+
+ # Create a temporary directory that will be treated as the default data
+ # directory by bitcoind.
+ env, default_datadir = util.get_temp_default_datadir(pathlib.Path(self.options.tmpdir, "test_config_file_log"))
+ default_datadir.mkdir(parents=True)
+
+ # Write a bitcoin.conf file in the default data directory containing a
+ # datadir= line pointing at the node datadir.
+ node = self.nodes[0]
+ conf_text = pathlib.Path(node.bitcoinconf).read_text()
+ conf_path = default_datadir / "bitcoin.conf"
+ conf_path.write_text(f"datadir={node.datadir}\n{conf_text}")
+
+ # Drop the node -datadir= argument during this test, because if it is
+ # specified it would take precedence over the datadir setting in the
+ # config file.
+ node_args = node.args
+ node.args = [arg for arg in node.args if not arg.startswith("-datadir=")]
+
+ # Check that correct configuration file path is actually logged
+ # (conf_path, not node.bitcoinconf)
+ with self.nodes[0].assert_debug_log(expected_msgs=[f"Config file: {conf_path}"]):
+ self.start_node(0, ["-allowignoredconf"], env=env)
+ self.stop_node(0)
+
+ # Restore node arguments after the test
+ node.args = node_args
+
def test_invalid_command_line_options(self):
self.nodes[0].assert_start_raises_init_error(
expected_msg='Error: Error parsing command line arguments: Can not set -proxy with no value. Please specify value with -proxy=value.',
@@ -213,7 +253,7 @@ class ConfArgsTest(BitcoinTestFramework):
with self.nodes[0].assert_debug_log(expected_msgs=[
"Loaded 0 addresses from peers.dat",
"DNS seeding disabled",
- "Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n",
+ "Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n",
]):
self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1'])
assert time.time() - start < 60
@@ -282,6 +322,55 @@ class ConfArgsTest(BitcoinTestFramework):
unexpected_msgs=seednode_ignored):
self.restart_node(0, extra_args=[connect_arg, '-seednode=fakeaddress2'])
+ def test_ignored_conf(self):
+ self.log.info('Test error is triggered when the datadir in use contains a bitcoin.conf file that would be ignored '
+ 'because a conflicting -conf file argument is passed.')
+ node = self.nodes[0]
+ with tempfile.NamedTemporaryFile(dir=self.options.tmpdir, mode="wt", delete=False) as temp_conf:
+ temp_conf.write(f"datadir={node.datadir}\n")
+ node.assert_start_raises_init_error([f"-conf={temp_conf.name}"], re.escape(
+ f'Error: Data directory "{node.datadir}" contains a "bitcoin.conf" file which is ignored, because a '
+ f'different configuration file "{temp_conf.name}" from command line argument "-conf={temp_conf.name}" '
+ f'is being used instead.') + r"[\s\S]*", match=ErrorMatch.FULL_REGEX)
+
+ # Test that passing a redundant -conf command line argument pointing to
+ # the same bitcoin.conf that would be loaded anyway does not trigger an
+ # error.
+ self.start_node(0, [f'-conf={node.datadir}/bitcoin.conf'])
+ self.stop_node(0)
+
+ def test_ignored_default_conf(self):
+ # Disable this test for windows currently because trying to override
+ # the default datadir through the environment does not seem to work.
+ if sys.platform == "win32":
+ return
+
+ self.log.info('Test error is triggered when bitcoin.conf in the default data directory sets another datadir '
+ 'and it contains a different bitcoin.conf file that would be ignored')
+
+ # Create a temporary directory that will be treated as the default data
+ # directory by bitcoind.
+ env, default_datadir = util.get_temp_default_datadir(pathlib.Path(self.options.tmpdir, "home"))
+ default_datadir.mkdir(parents=True)
+
+ # Write a bitcoin.conf file in the default data directory containing a
+ # datadir= line pointing at the node datadir. This will trigger a
+ # startup error because the node datadir contains a different
+ # bitcoin.conf that would be ignored.
+ node = self.nodes[0]
+ (default_datadir / "bitcoin.conf").write_text(f"datadir={node.datadir}\n")
+
+ # Drop the node -datadir= argument during this test, because if it is
+ # specified it would take precedence over the datadir setting in the
+ # config file.
+ node_args = node.args
+ node.args = [arg for arg in node.args if not arg.startswith("-datadir=")]
+ node.assert_start_raises_init_error([], re.escape(
+ f'Error: Data directory "{node.datadir}" contains a "bitcoin.conf" file which is ignored, because a '
+ f'different configuration file "{default_datadir}/bitcoin.conf" from data directory "{default_datadir}" '
+ f'is being used instead.') + r"[\s\S]*", env=env, match=ErrorMatch.FULL_REGEX)
+ node.args = node_args
+
def run_test(self):
self.test_log_buffer()
self.test_args_log()
@@ -290,7 +379,10 @@ class ConfArgsTest(BitcoinTestFramework):
self.test_connect_with_seednode()
self.test_config_file_parser()
+ self.test_config_file_log()
self.test_invalid_command_line_options()
+ self.test_ignored_conf()
+ self.test_ignored_default_conf()
# Remove the -datadir argument so it doesn't override the config file
self.nodes[0].args = [arg for arg in self.nodes[0].args if not arg.startswith("-datadir")]
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 1f2e0936ed..3f94bbc9d1 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -51,9 +51,11 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.supports_cli = False
# Set -maxmempool=0 to turn off mempool memory sharing with dbcache
- # Set -rpcservertimeout=900 to reduce socket disconnects in this
- # long-running test
- self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000"]
+ self.base_args = [
+ "-limitdescendantsize=0",
+ "-maxmempool=0",
+ "-dbbatchsize=200000",
+ ]
# Set different crash ratios and cache sizes. Note that not all of
# -dbcache goes to the in-memory coins cache.
diff --git a/test/functional/feature_fastprune.py b/test/functional/feature_fastprune.py
new file mode 100755
index 0000000000..c913c4f93a
--- /dev/null
+++ b/test/functional/feature_fastprune.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 fastprune mode."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal
+)
+from test_framework.wallet import MiniWallet
+
+
+class FeatureFastpruneTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.extra_args = [["-fastprune"]]
+
+ def run_test(self):
+ self.log.info("ensure that large blocks don't crash or freeze in -fastprune")
+ wallet = MiniWallet(self.nodes[0])
+ tx = wallet.create_self_transfer()['tx']
+ annex = b"\x50" + b"\xff" * 0x10000
+ tx.wit.vtxinwit[0].scriptWitness.stack.append(annex)
+ self.generateblock(self.nodes[0], output="raw(55)", transactions=[tx.serialize().hex()])
+ assert_equal(self.nodes[0].getblockcount(), 201)
+
+
+if __name__ == '__main__':
+ FeatureFastpruneTest().main()
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py
index 05ee556ece..03970415ac 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -7,6 +7,7 @@ from copy import deepcopy
from decimal import Decimal
import os
import random
+import time
from test_framework.messages import (
COIN,
@@ -21,6 +22,8 @@ from test_framework.util import (
)
from test_framework.wallet import MiniWallet
+MAX_FILE_AGE = 60
+SECONDS_PER_HOUR = 60 * 60
def small_txpuzzle_randfee(
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs
@@ -290,6 +293,95 @@ class EstimateFeeTest(BitcoinTestFramework):
est_feerate = node.estimatesmartfee(2)["feerate"]
assert_equal(est_feerate, high_feerate_kvb)
+ def test_old_fee_estimate_file(self):
+ # Get the initial fee rate while node is running
+ fee_rate = self.nodes[0].estimatesmartfee(1)["feerate"]
+
+ # Restart node to ensure fee_estimate.dat file is read
+ self.restart_node(0)
+ assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)
+
+ fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
+
+ # Stop the node and backdate the fee_estimates.dat file more than MAX_FILE_AGE
+ self.stop_node(0)
+ last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
+ os.utime(fee_dat, (last_modified_time, last_modified_time))
+
+ # Start node and ensure the fee_estimates.dat file was not read
+ self.start_node(0)
+ assert_equal(self.nodes[0].estimatesmartfee(1)["errors"], ["Insufficient data or no feerate found"])
+
+
+ def test_estimate_dat_is_flushed_periodically(self):
+ fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
+ os.remove(fee_dat) if os.path.exists(fee_dat) else None
+
+ # Verify that fee_estimates.dat does not exist
+ assert_equal(os.path.isfile(fee_dat), False)
+
+ # Verify if the string "Flushed fee estimates to fee_estimates.dat." is present in the debug log file.
+ # If present, it indicates that fee estimates have been successfully flushed to disk.
+ with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
+ # Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
+ self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
+
+ # Verify that fee estimates were flushed and fee_estimates.dat file is created
+ assert_equal(os.path.isfile(fee_dat), True)
+
+ # Verify that the estimates remain the same if there are no blocks in the flush interval
+ block_hash_before = self.nodes[0].getbestblockhash()
+ fee_dat_initial_content = open(fee_dat, "rb").read()
+ with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
+ # Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
+ self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
+
+ # Verify that there were no blocks in between the flush interval
+ assert_equal(block_hash_before, self.nodes[0].getbestblockhash())
+
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert_equal(fee_dat_current_content, fee_dat_initial_content)
+
+ # Verify that the estimates remain the same after shutdown with no blocks before shutdown
+ self.restart_node(0)
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert_equal(fee_dat_current_content, fee_dat_initial_content)
+
+ # Verify that the estimates are not the same if new blocks were produced in the flush interval
+ with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
+ # Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
+ self.generate(self.nodes[0], 5, sync_fun=self.no_op)
+ self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
+
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert fee_dat_current_content != fee_dat_initial_content
+
+ fee_dat_initial_content = fee_dat_current_content
+
+ # Generate blocks before shutdown and verify that the fee estimates are not the same
+ self.generate(self.nodes[0], 5, sync_fun=self.no_op)
+ self.restart_node(0)
+ fee_dat_current_content = open(fee_dat, "rb").read()
+ assert fee_dat_current_content != fee_dat_initial_content
+
+
+ def test_acceptstalefeeestimates_option(self):
+ # Get the initial fee rate while node is running
+ fee_rate = self.nodes[0].estimatesmartfee(1)["feerate"]
+
+ self.stop_node(0)
+
+ fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
+
+ # Stop the node and backdate the fee_estimates.dat file more than MAX_FILE_AGE
+ last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
+ os.utime(fee_dat, (last_modified_time, last_modified_time))
+
+ # Restart node with -acceptstalefeeestimates option to ensure fee_estimate.dat file is read
+ self.start_node(0,extra_args=["-acceptstalefeeestimates"])
+ assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)
+
+
def run_test(self):
self.log.info("This test is time consuming, please be patient")
self.log.info("Splitting inputs so we can generate tx's")
@@ -312,12 +404,21 @@ class EstimateFeeTest(BitcoinTestFramework):
self.log.info("Testing estimates with single transactions.")
self.sanity_check_estimates_range()
+ self.log.info("Test fee_estimates.dat is flushed periodically")
+ self.test_estimate_dat_is_flushed_periodically()
+
# check that the effective feerate is greater than or equal to the mempoolminfee even for high mempoolminfee
self.log.info(
"Test fee rate estimation after restarting node with high MempoolMinFee"
)
self.test_feerate_mempoolminfee()
+ self.log.info("Test acceptstalefeeestimates option")
+ self.test_acceptstalefeeestimates_option()
+
+ self.log.info("Test reading old fee_estimates.dat")
+ self.test_old_fee_estimate_file()
+
self.log.info("Restarting node with fresh estimation")
self.stop_node(0)
fee_dat = os.path.join(self.nodes[0].datadir, self.chain, "fee_estimates.dat")
diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py
index 70a802dc58..7af67730bd 100755
--- a/test/functional/feature_init.py
+++ b/test/functional/feature_init.py
@@ -45,6 +45,13 @@ class InitStressTest(BitcoinTestFramework):
node.process.terminate()
node.process.wait()
+ def start_expecting_error(err_fragment):
+ node.assert_start_raises_init_error(
+ extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'],
+ expected_msg=err_fragment,
+ match=ErrorMatch.PARTIAL_REGEX,
+ )
+
def check_clean_start():
"""Ensure that node restarts successfully after various interrupts."""
node.start()
@@ -87,36 +94,27 @@ class InitStressTest(BitcoinTestFramework):
self.log.info("Test startup errors after removing certain essential files")
- files_to_disturb = {
+ files_to_delete = {
'blocks/index/*.ldb': 'Error opening block database.',
'chainstate/*.ldb': 'Error opening block database.',
'blocks/blk*.dat': 'Error loading block database.',
}
- for file_patt, err_fragment in files_to_disturb.items():
+ files_to_perturb = {
+ 'blocks/index/*.ldb': 'Error opening block database.',
+ 'chainstate/*.ldb': 'Error opening block database.',
+ 'blocks/blk*.dat': 'Error opening block database.',
+ }
+
+ for file_patt, err_fragment in files_to_delete.items():
target_files = list(node.chain_path.glob(file_patt))
for target_file in target_files:
- self.log.info(f"Tweaking file to ensure failure {target_file}")
+ self.log.info(f"Deleting file to ensure failure {target_file}")
bak_path = str(target_file) + ".bak"
target_file.rename(bak_path)
- # TODO: at some point, we should test perturbing the files instead of removing
- # them, e.g.
- #
- # contents = target_file.read_bytes()
- # tweaked_contents = bytearray(contents)
- # tweaked_contents[50:250] = b'1' * 200
- # target_file.write_bytes(bytes(tweaked_contents))
- #
- # At the moment I can't get this to work (bitcoind loads successfully?) so
- # investigate doing this later.
-
- node.assert_start_raises_init_error(
- extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'],
- expected_msg=err_fragment,
- match=ErrorMatch.PARTIAL_REGEX,
- )
+ start_expecting_error(err_fragment)
for target_file in target_files:
bak_path = str(target_file) + ".bak"
@@ -126,6 +124,18 @@ class InitStressTest(BitcoinTestFramework):
check_clean_start()
self.stop_node(0)
+ for file_patt, err_fragment in files_to_perturb.items():
+ target_files = list(node.chain_path.glob(file_patt))
+
+ for target_file in target_files:
+ self.log.info(f"Perturbing file to ensure failure {target_file}")
+ with open(target_file, "rb") as tf_read, open(target_file, "wb") as tf_write:
+ contents = tf_read.read()
+ tweaked_contents = bytearray(contents)
+ tweaked_contents[50:250] = b'1' * 200
+ tf_write.write(bytes(tweaked_contents))
+
+ start_expecting_error(err_fragment)
if __name__ == '__main__':
InitStressTest().main()
diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py
index fe4f02dfe6..b0788e2a2d 100755
--- a/test/functional/feature_logging.py
+++ b/test/functional/feature_logging.py
@@ -69,6 +69,36 @@ class LoggingTest(BitcoinTestFramework):
# just sanity check no crash here
self.restart_node(0, [f"-debuglogfile={os.devnull}"])
+ self.log.info("Test -debug and -debugexclude raise when invalid values are passed")
+ self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-debug=abc"],
+ expected_msg="Error: Unsupported logging category -debug=abc.",
+ match=ErrorMatch.FULL_REGEX,
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-debugexclude=abc"],
+ expected_msg="Error: Unsupported logging category -debugexclude=abc.",
+ match=ErrorMatch.FULL_REGEX,
+ )
+
+ self.log.info("Test -loglevel raises when invalid values are passed")
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-loglevel=abc"],
+ expected_msg="Error: Unsupported global logging level -loglevel=abc. Valid values: info, debug, trace.",
+ match=ErrorMatch.FULL_REGEX,
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-loglevel=net:abc"],
+ expected_msg="Error: Unsupported category-specific logging level -loglevel=net:abc.",
+ match=ErrorMatch.PARTIAL_REGEX,
+ )
+ self.nodes[0].assert_start_raises_init_error(
+ extra_args=["-loglevel=net:info:abc"],
+ expected_msg="Error: Unsupported category-specific logging level -loglevel=net:info:abc.",
+ match=ErrorMatch.PARTIAL_REGEX,
+ )
+
if __name__ == '__main__':
LoggingTest().main()
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index d7558c830e..7b2a29bdb4 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -14,6 +14,7 @@ Generate COINBASE_MATURITY (CB) more blocks to ensure the coinbases are mature.
"""
import time
+from test_framework.address import address_to_scriptpubkey
from test_framework.blocktools import (
COINBASE_MATURITY,
NORMAL_GBT_REQUEST_PARAMS,
@@ -34,8 +35,7 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import getnewdestination
-from test_framework.key import ECKey
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
@@ -70,14 +70,11 @@ class NULLDUMMYTest(BitcoinTestFramework):
return tx_from_hex(signedtx["hex"])
def run_test(self):
- eckey = ECKey()
- eckey.generate()
- self.privkey = bytes_to_wif(eckey.get_bytes())
- self.pubkey = eckey.get_pubkey().get_bytes().hex()
- cms = self.nodes[0].createmultisig(1, [self.pubkey])
- wms = self.nodes[0].createmultisig(1, [self.pubkey], 'p2sh-segwit')
+ self.privkey, self.pubkey = generate_keypair(wif=True)
+ cms = self.nodes[0].createmultisig(1, [self.pubkey.hex()])
+ wms = self.nodes[0].createmultisig(1, [self.pubkey.hex()], 'p2sh-segwit')
self.ms_address = cms["address"]
- ms_unlock_details = {"scriptPubKey": self.nodes[0].validateaddress(self.ms_address)["scriptPubKey"],
+ ms_unlock_details = {"scriptPubKey": address_to_scriptpubkey(self.ms_address).hex(),
"redeemScript": cms["redeemScript"]}
self.wit_ms_address = wms['address']
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 519877ac5b..b0c6138bcf 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -135,6 +135,10 @@ class PruneTest(BitcoinTestFramework):
extra_args=['-prune=550', '-reindex-chainstate'],
)
+ def test_rescan_blockchain(self):
+ self.restart_node(0, ["-prune=550"])
+ assert_raises_rpc_error(-1, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.", self.nodes[0].rescanblockchain)
+
def test_height_min(self):
assert os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")), "blk00000.dat is missing, pruning too early"
self.log.info("Success")
@@ -469,6 +473,9 @@ class PruneTest(BitcoinTestFramework):
self.log.info("Test wallet re-scan")
self.wallet_test()
+ self.log.info("Test it's not possible to rescan beyond pruned data")
+ self.test_rescan_blockchain()
+
self.log.info("Test invalid pruning command line options")
self.test_invalid_command_line_options()
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 947d2e8273..c5eeaf66e0 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -93,7 +93,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
confirmed - txout created will be confirmed in the blockchain;
unconfirmed otherwise.
"""
- txid, n = self.wallet.send_to(from_node=node, scriptPubKey=scriptPubKey or self.wallet.get_scriptPubKey(), amount=amount)
+ tx = self.wallet.send_to(from_node=node, scriptPubKey=scriptPubKey or self.wallet.get_scriptPubKey(), amount=amount)
if confirmed:
mempool_size = len(node.getrawmempool())
@@ -105,7 +105,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert new_size < mempool_size
mempool_size = new_size
- return self.wallet.get_utxo(txid=txid, vout=n)
+ return self.wallet.get_utxo(txid=tx["txid"], vout=tx["sent_vout"])
def test_simple_doublespend(self):
"""Simple doublespend"""
diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py
index b41fe378af..a90a2a8e5e 100755
--- a/test/functional/feature_signet.py
+++ b/test/functional/feature_signet.py
@@ -76,6 +76,9 @@ class SignetBasicTest(BitcoinTestFramework):
self.log.info("test that signet logs the network magic on node start")
with self.nodes[0].assert_debug_log(["Signet derived magic (message start)"]):
self.restart_node(0)
+ self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(extra_args=["-signetchallenge=abc"], expected_msg="Error: -signetchallenge must be hex, not 'abc'.")
+ self.nodes[0].assert_start_raises_init_error(extra_args=["-signetchallenge=abc"] * 2, expected_msg="Error: -signetchallenge cannot be multiple values.")
if __name__ == '__main__':
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 8ac06f570d..ec1e580369 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -19,6 +19,7 @@ from test_framework.messages import (
CTxInWitness,
CTxOut,
SEQUENCE_FINAL,
+ tx_from_hex,
)
from test_framework.script import (
ANNEX_TAG,
@@ -96,6 +97,7 @@ from test_framework.util import (
assert_equal,
random_bytes,
)
+from test_framework.wallet_util import generate_keypair
from test_framework.key import (
generate_privkey,
compute_xonly_pubkey,
@@ -109,7 +111,6 @@ from test_framework.address import (
program_to_witness,
)
from collections import OrderedDict, namedtuple
-from io import BytesIO
import json
import hashlib
import os
@@ -738,7 +739,11 @@ def spenders_taproot_active():
scripts = [
("pk_codesep", CScript(random_checksig_style(pubs[1]) + bytes([OP_CODESEPARATOR]))), # codesep after checksig
("codesep_pk", CScript(bytes([OP_CODESEPARATOR]) + random_checksig_style(pubs[1]))), # codesep before checksig
- ("branched_codesep", CScript([random_bytes(random.randrange(511)), OP_DROP, OP_IF, OP_CODESEPARATOR, pubs[0], OP_ELSE, OP_CODESEPARATOR, pubs[1], OP_ENDIF, OP_CHECKSIG])), # branch dependent codesep
+ ("branched_codesep", CScript([random_bytes(random.randrange(2, 511)), OP_DROP, OP_IF, OP_CODESEPARATOR, pubs[0], OP_ELSE, OP_CODESEPARATOR, pubs[1], OP_ENDIF, OP_CHECKSIG])), # branch dependent codesep
+ # Note that the first data push in the "branched_codesep" script has the purpose of
+ # randomizing the sighash, both by varying script size and content. In order to
+ # avoid MINIMALDATA script verification errors caused by not-minimal-encoded data
+ # pushes (e.g. `OP_PUSH1 1` instead of `OP_1`), we set a minimum data size of 2 bytes.
]
random.shuffle(scripts)
tap = taproot_construct(pubs[0], scripts)
@@ -1186,11 +1191,8 @@ def spenders_taproot_active():
# Also add a few legacy spends into the mix, so that transactions which combine taproot and pre-taproot spends get tested too.
for compressed in [False, True]:
- eckey1 = ECKey()
- eckey1.set(generate_privkey(), compressed)
- pubkey1 = eckey1.get_pubkey().get_bytes()
- eckey2 = ECKey()
- eckey2.set(generate_privkey(), compressed)
+ eckey1, pubkey1 = generate_keypair(compressed=compressed)
+ eckey2, _ = generate_keypair(compressed=compressed)
for p2sh in [False, True]:
for witv0 in [False, True]:
for hashtype in VALID_SIGHASHES_ECDSA + [random.randrange(0x04, 0x80), random.randrange(0x84, 0x100)]:
@@ -1386,8 +1388,7 @@ class TaprootTest(BitcoinTestFramework):
# Add change
fund_tx.vout.append(CTxOut(balance - 10000, random.choice(host_spks)))
# Ask the wallet to sign
- ss = BytesIO(bytes.fromhex(node.signrawtransactionwithwallet(fund_tx.serialize().hex())["hex"]))
- fund_tx.deserialize(ss)
+ fund_tx = tx_from_hex(node.signrawtransactionwithwallet(fund_tx.serialize().hex())["hex"])
# Construct UTXOData entries
fund_tx.rehash()
for i in range(count_this_tx):
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index aafee7e87c..1ba8f60d99 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -7,9 +7,7 @@
from decimal import Decimal
from enum import Enum
import http.client
-from io import BytesIO
import json
-from struct import pack, unpack
import typing
import urllib.parse
@@ -98,7 +96,7 @@ class RESTTest (BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
self.log.info("Broadcast test transaction and sync nodes")
- txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN))
+ txid = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN))["txid"]
self.sync_all()
self.log.info("Test the /tx URI")
@@ -160,12 +158,11 @@ class RESTTest (BitcoinTestFramework):
bin_request = b'\x01\x02'
for txid, n in [spending, spent]:
bin_request += bytes.fromhex(txid)
- bin_request += pack("i", n)
+ bin_request += n.to_bytes(4, 'little')
bin_response = self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.BIN, body=bin_request, ret_type=RetType.BYTES)
- output = BytesIO(bin_response)
- chain_height, = unpack("<i", output.read(4))
- response_hash = output.read(32)[::-1].hex()
+ chain_height = int.from_bytes(bin_response[0:4], 'little')
+ response_hash = bin_response[4:36][::-1].hex()
assert_equal(bb_hash, response_hash) # check if getutxo's chaintip during calculation was fine
assert_equal(chain_height, 201) # chain height must be 201 (pre-mined chain [200] + generated block [1])
@@ -176,7 +173,7 @@ class RESTTest (BitcoinTestFramework):
# found with or without /checkmempool.
# do a tx and don't sync
- txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN))
+ txid = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN))["txid"]
json_obj = self.test_rest_request(f"/tx/{txid}")
# get the spent output to later check for utxo (should be spent by then)
spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout'])
@@ -280,6 +277,11 @@ class RESTTest (BitcoinTestFramework):
assert_equal(len(json_obj), 1) # ensure that there is one header in the json response
assert_equal(json_obj[0]['hash'], bb_hash) # request/response hash should be the same
+ # Check invalid uri (% symbol at the end of the request)
+ for invalid_uri in [f"/headers/{bb_hash}%", f"/blockfilterheaders/basic/{bb_hash}%", "/mempool/contents.json?%"]:
+ resp = self.test_rest_request(invalid_uri, ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), "URI parsing failed, it likely contained RFC 3986 invalid characters")
+
# Compare with normal RPC block response
rpc_block_json = self.nodes[0].getblock(bb_hash)
for key in ['hash', 'confirmations', 'height', 'version', 'merkleroot', 'time', 'nonce', 'bits', 'difficulty', 'chainwork', 'previousblockhash']:
@@ -419,6 +421,10 @@ class RESTTest (BitcoinTestFramework):
deployment_info = self.nodes[0].getdeploymentinfo()
assert_equal(deployment_info, self.test_rest_request('/deploymentinfo'))
+ previous_bb_hash = self.nodes[0].getblockhash(self.nodes[0].getblockcount() - 1)
+ deployment_info = self.nodes[0].getdeploymentinfo(previous_bb_hash)
+ assert_equal(deployment_info, self.test_rest_request(f"/deploymentinfo/{previous_bb_hash}"))
+
non_existing_blockhash = '42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4'
resp = self.test_rest_request(f'/deploymentinfo/{non_existing_blockhash}', ret_type=RetType.OBJ, status=400)
assert_equal(resp.read().decode('utf-8').rstrip(), "Block not found")
diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py
index ec2f9e4e77..f138fa44cc 100755
--- a/test/functional/interface_usdt_mempool.py
+++ b/test/functional/interface_usdt_mempool.py
@@ -35,7 +35,7 @@ MEMPOOL_TRACEPOINTS_PROGRAM = """
struct added_event
{
u8 hash[HASH_LENGTH];
- u64 vsize;
+ s32 vsize;
s64 fee;
};
@@ -43,7 +43,7 @@ struct removed_event
{
u8 hash[HASH_LENGTH];
char reason[MAX_REMOVAL_REASON_LENGTH];
- u64 vsize;
+ s32 vsize;
s64 fee;
u64 entry_time;
};
@@ -57,11 +57,11 @@ struct rejected_event
struct replaced_event
{
u8 replaced_hash[HASH_LENGTH];
- u64 replaced_vsize;
+ s32 replaced_vsize;
s64 replaced_fee;
u64 replaced_entry_time;
u8 replacement_hash[HASH_LENGTH];
- u64 replacement_vsize;
+ s32 replacement_vsize;
s64 replacement_fee;
};
@@ -139,6 +139,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_ADDED_EVENTS = 1
handled_added_events = 0
+ event = None
self.log.info("Hooking into mempool:added tracepoint...")
node = self.nodes[0]
@@ -147,11 +148,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_added_event(_, data, __):
- nonlocal handled_added_events
+ nonlocal event, handled_added_events
event = bpf["added_events"].event(data)
- assert_equal(txid, bytes(event.hash)[::-1].hex())
- assert_equal(vsize, event.vsize)
- assert_equal(fee, event.fee)
handled_added_events += 1
bpf["added_events"].open_perf_buffer(handle_added_event)
@@ -159,9 +157,6 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Sending transaction...")
fee = Decimal(31200)
tx = self.wallet.send_self_transfer(from_node=node, fee=fee / COIN)
- # expected data
- txid = tx["txid"]
- vsize = tx["tx"].get_vsize()
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
@@ -169,10 +164,14 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Cleaning up mempool...")
self.generate(node, 1)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:added event was handled successfully...")
assert_equal(EXPECTED_ADDED_EVENTS, handled_added_events)
+ assert_equal(bytes(event.hash)[::-1].hex(), tx["txid"])
+ assert_equal(event.vsize, tx["tx"].get_vsize())
+ assert_equal(event.fee, fee)
+
+ bpf.cleanup()
+ self.generate(self.wallet, 1)
def removed_test(self):
"""Expire a transaction from the mempool and make sure the tracepoint returns
@@ -180,6 +179,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_REMOVED_EVENTS = 1
handled_removed_events = 0
+ event = None
self.log.info("Hooking into mempool:removed tracepoint...")
node = self.nodes[0]
@@ -188,13 +188,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_removed_event(_, data, __):
- nonlocal handled_removed_events
+ nonlocal event, handled_removed_events
event = bpf["removed_events"].event(data)
- assert_equal(txid, bytes(event.hash)[::-1].hex())
- assert_equal(reason, event.reason.decode("UTF-8"))
- assert_equal(vsize, event.vsize)
- assert_equal(fee, event.fee)
- assert_equal(entry_time, event.entry_time)
handled_removed_events += 1
bpf["removed_events"].open_perf_buffer(handle_removed_event)
@@ -202,10 +197,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Sending transaction...")
fee = Decimal(31200)
tx = self.wallet.send_self_transfer(from_node=node, fee=fee / COIN)
- # expected data
txid = tx["txid"]
- reason = "expiry"
- vsize = tx["tx"].get_vsize()
self.log.info("Fast-forwarding time to mempool expiry...")
entry_time = node.getmempoolentry(txid)["time"]
@@ -219,10 +211,16 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:removed event was handled successfully...")
assert_equal(EXPECTED_REMOVED_EVENTS, handled_removed_events)
+ assert_equal(bytes(event.hash)[::-1].hex(), txid)
+ assert_equal(event.reason.decode("UTF-8"), "expiry")
+ assert_equal(event.vsize, tx["tx"].get_vsize())
+ assert_equal(event.fee, fee)
+ assert_equal(event.entry_time, entry_time)
+
+ bpf.cleanup()
+ self.generate(self.wallet, 1)
def replaced_test(self):
"""Replace one and two transactions in the mempool and make sure the tracepoint
@@ -230,6 +228,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_REPLACED_EVENTS = 1
handled_replaced_events = 0
+ event = None
self.log.info("Hooking into mempool:replaced tracepoint...")
node = self.nodes[0]
@@ -238,15 +237,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_replaced_event(_, data, __):
- nonlocal handled_replaced_events
+ nonlocal event, handled_replaced_events
event = bpf["replaced_events"].event(data)
- assert_equal(replaced_txid, bytes(event.replaced_hash)[::-1].hex())
- assert_equal(replaced_vsize, event.replaced_vsize)
- assert_equal(replaced_fee, event.replaced_fee)
- assert_equal(replaced_entry_time, event.replaced_entry_time)
- assert_equal(replacement_txid, bytes(event.replacement_hash)[::-1].hex())
- assert_equal(replacement_vsize, event.replacement_vsize)
- assert_equal(replacement_fee, event.replacement_fee)
handled_replaced_events += 1
bpf["replaced_events"].open_perf_buffer(handle_replaced_event)
@@ -265,21 +257,21 @@ class MempoolTracepointTest(BitcoinTestFramework):
from_node=node, utxo_to_spend=utxo, fee=replacement_fee / COIN
)
- # expected data
- replaced_txid = original_tx["txid"]
- replaced_vsize = original_tx["tx"].get_vsize()
- replaced_fee = original_fee
- replaced_entry_time = entry_time
- replacement_txid = replacement_tx["txid"]
- replacement_vsize = replacement_tx["tx"].get_vsize()
-
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:replaced event was handled successfully...")
assert_equal(EXPECTED_REPLACED_EVENTS, handled_replaced_events)
+ assert_equal(bytes(event.replaced_hash)[::-1].hex(), original_tx["txid"])
+ assert_equal(event.replaced_vsize, original_tx["tx"].get_vsize())
+ assert_equal(event.replaced_fee, original_fee)
+ assert_equal(event.replaced_entry_time, entry_time)
+ assert_equal(bytes(event.replacement_hash)[::-1].hex(), replacement_tx["txid"])
+ assert_equal(event.replacement_vsize, replacement_tx["tx"].get_vsize())
+ assert_equal(event.replacement_fee, replacement_fee)
+
+ bpf.cleanup()
+ self.generate(self.wallet, 1)
def rejected_test(self):
"""Create an invalid transaction and make sure the tracepoint returns
@@ -287,6 +279,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
EXPECTED_REJECTED_EVENTS = 1
handled_rejected_events = 0
+ event = None
self.log.info("Adding P2P connection...")
node = self.nodes[0]
@@ -298,10 +291,8 @@ class MempoolTracepointTest(BitcoinTestFramework):
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0)
def handle_rejected_event(_, data, __):
- nonlocal handled_rejected_events
+ nonlocal event, handled_rejected_events
event = bpf["rejected_events"].event(data)
- assert_equal(txid, bytes(event.hash)[::-1].hex())
- assert_equal(reason, event.reason.decode("UTF-8"))
handled_rejected_events += 1
bpf["rejected_events"].open_perf_buffer(handle_rejected_event)
@@ -310,17 +301,16 @@ class MempoolTracepointTest(BitcoinTestFramework):
tx = self.wallet.create_self_transfer(fee_rate=Decimal(0))
node.p2ps[0].send_txs_and_test([tx["tx"]], node, success=False)
- # expected data
- txid = tx["tx"].hash
- reason = "min relay fee not met"
-
self.log.info("Polling buffer...")
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
-
self.log.info("Ensuring mempool:rejected event was handled successfully...")
assert_equal(EXPECTED_REJECTED_EVENTS, handled_rejected_events)
+ assert_equal(bytes(event.hash)[::-1].hex(), tx["tx"].hash)
+ assert_equal(event.reason.decode("UTF-8"), "min relay fee not met")
+
+ bpf.cleanup()
+ self.generate(self.wallet, 1)
def run_test(self):
"""Tests the mempool:added, mempool:removed, mempool:replaced,
diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py
index 2235da702b..d1f94637c9 100755
--- a/test/functional/interface_usdt_net.py
+++ b/test/functional/interface_usdt_net.py
@@ -116,13 +116,10 @@ class NetTracepointTest(BitcoinTestFramework):
fn_name="trace_outbound_message")
bpf = BPF(text=net_tracepoints_program, usdt_contexts=[ctx], debug=0)
- # The handle_* function is a ctypes callback function called from C. When
- # we assert in the handle_* function, the AssertError doesn't propagate
- # back to Python. The exception is ignored. We manually count and assert
- # that the handle_* functions succeeded.
EXPECTED_INOUTBOUND_VERSION_MSG = 1
checked_inbound_version_msg = 0
checked_outbound_version_msg = 0
+ events = []
def check_p2p_message(event, inbound):
nonlocal checked_inbound_version_msg, checked_outbound_version_msg
@@ -142,12 +139,13 @@ class NetTracepointTest(BitcoinTestFramework):
checked_outbound_version_msg += 1
def handle_inbound(_, data, __):
+ nonlocal events
event = ctypes.cast(data, ctypes.POINTER(P2PMessage)).contents
- check_p2p_message(event, True)
+ events.append((event, True))
def handle_outbound(_, data, __):
event = ctypes.cast(data, ctypes.POINTER(P2PMessage)).contents
- check_p2p_message(event, False)
+ events.append((event, False))
bpf["inbound_messages"].open_perf_buffer(handle_inbound)
bpf["outbound_messages"].open_perf_buffer(handle_outbound)
@@ -158,12 +156,15 @@ class NetTracepointTest(BitcoinTestFramework):
bpf.perf_buffer_poll(timeout=200)
self.log.info(
- "check that we got both an inbound and outbound version message")
+ "check receipt and content of in- and outbound version messages")
+ for event, inbound in events:
+ check_p2p_message(event, inbound)
assert_equal(EXPECTED_INOUTBOUND_VERSION_MSG,
checked_inbound_version_msg)
assert_equal(EXPECTED_INOUTBOUND_VERSION_MSG,
checked_outbound_version_msg)
+
bpf.cleanup()
diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py
index 23785b1e8a..5f2ba49026 100755
--- a/test/functional/interface_usdt_utxocache.py
+++ b/test/functional/interface_usdt_utxocache.py
@@ -188,13 +188,16 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
nonlocal handle_uncache_succeeds
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
self.log.info(f"handle_utxocache_uncache(): {event}")
- assert_equal(block_1_coinbase_txid, bytes(event.txid[::-1]).hex())
- assert_equal(0, event.index) # prevout index
- assert_equal(EARLY_BLOCK_HEIGHT, event.height)
- assert_equal(50 * COIN, event.value)
- assert_equal(True, event.is_coinbase)
-
- handle_uncache_succeeds += 1
+ try:
+ assert_equal(block_1_coinbase_txid, bytes(event.txid[::-1]).hex())
+ assert_equal(0, event.index) # prevout index
+ assert_equal(EARLY_BLOCK_HEIGHT, event.height)
+ assert_equal(50 * COIN, event.value)
+ assert_equal(True, event.is_coinbase)
+ except AssertionError:
+ self.log.exception("Assertion failed")
+ else:
+ handle_uncache_succeeds += 1
bpf["utxocache_uncache"].open_perf_buffer(handle_utxocache_uncache)
@@ -260,24 +263,32 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
self.log.info(f"handle_utxocache_add(): {event}")
add = expected_utxocache_adds.pop(0)
- assert_equal(add["txid"], bytes(event.txid[::-1]).hex())
- assert_equal(add["index"], event.index)
- assert_equal(add["height"], event.height)
- assert_equal(add["value"], event.value)
- assert_equal(add["is_coinbase"], event.is_coinbase)
- handle_add_succeeds += 1
+ try:
+ assert_equal(add["txid"], bytes(event.txid[::-1]).hex())
+ assert_equal(add["index"], event.index)
+ assert_equal(add["height"], event.height)
+ assert_equal(add["value"], event.value)
+ assert_equal(add["is_coinbase"], event.is_coinbase)
+ except AssertionError:
+ self.log.exception("Assertion failed")
+ else:
+ handle_add_succeeds += 1
def handle_utxocache_spent(_, data, __):
nonlocal handle_spent_succeeds
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
self.log.info(f"handle_utxocache_spent(): {event}")
spent = expected_utxocache_spents.pop(0)
- assert_equal(spent["txid"], bytes(event.txid[::-1]).hex())
- assert_equal(spent["index"], event.index)
- assert_equal(spent["height"], event.height)
- assert_equal(spent["value"], event.value)
- assert_equal(spent["is_coinbase"], event.is_coinbase)
- handle_spent_succeeds += 1
+ try:
+ assert_equal(spent["txid"], bytes(event.txid[::-1]).hex())
+ assert_equal(spent["index"], event.index)
+ assert_equal(spent["height"], event.height)
+ assert_equal(spent["value"], event.value)
+ assert_equal(spent["is_coinbase"], event.is_coinbase)
+ except AssertionError:
+ self.log.exception("Assertion failed")
+ else:
+ handle_spent_succeeds += 1
bpf["utxocache_add"].open_perf_buffer(handle_utxocache_add)
bpf["utxocache_spent"].open_perf_buffer(handle_utxocache_spent)
@@ -363,7 +374,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
self.log.info("stop the node to flush the UTXO cache")
- UTXOS_IN_CACHE = 2 # might need to be changed if the eariler tests are modified
+ UTXOS_IN_CACHE = 2 # might need to be changed if the earlier tests are modified
# A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE
# UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the
# second flush, however it can happen that the order changes.
diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py
index 4323aef771..f9d9b525cd 100755
--- a/test/functional/interface_usdt_validation.py
+++ b/test/functional/interface_usdt_validation.py
@@ -85,13 +85,10 @@ class ValidationTracepointTest(BitcoinTestFramework):
self.sigops,
self.duration)
- # The handle_* function is a ctypes callback function called from C. When
- # we assert in the handle_* function, the AssertError doesn't propagate
- # back to Python. The exception is ignored. We manually count and assert
- # that the handle_* functions succeeded.
BLOCKS_EXPECTED = 2
blocks_checked = 0
expected_blocks = dict()
+ events = []
self.log.info("hook into the validation:block_connected tracepoint")
ctx = USDT(pid=self.nodes[0].process.pid)
@@ -101,19 +98,10 @@ class ValidationTracepointTest(BitcoinTestFramework):
usdt_contexts=[ctx], debug=0)
def handle_blockconnected(_, data, __):
- nonlocal expected_blocks, blocks_checked
+ nonlocal events, blocks_checked
event = ctypes.cast(data, ctypes.POINTER(Block)).contents
self.log.info(f"handle_blockconnected(): {event}")
- block_hash = bytes(event.hash[::-1]).hex()
- block = expected_blocks[block_hash]
- assert_equal(block["hash"], block_hash)
- assert_equal(block["height"], event.height)
- assert_equal(len(block["tx"]), event.transactions)
- assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs)
- assert_equal(0, event.sigops) # no sigops in coinbase tx
- # only plausibility checks
- assert event.duration > 0
- del expected_blocks[block_hash]
+ events.append(event)
blocks_checked += 1
bpf["block_connected"].open_perf_buffer(
@@ -126,12 +114,24 @@ class ValidationTracepointTest(BitcoinTestFramework):
expected_blocks[block_hash] = self.nodes[0].getblock(block_hash, 2)
bpf.perf_buffer_poll(timeout=200)
- bpf.cleanup()
- self.log.info(f"check that we traced {BLOCKS_EXPECTED} blocks")
+ self.log.info(f"check that we correctly traced {BLOCKS_EXPECTED} blocks")
+ for event in events:
+ block_hash = bytes(event.hash[::-1]).hex()
+ block = expected_blocks[block_hash]
+ assert_equal(block["hash"], block_hash)
+ assert_equal(block["height"], event.height)
+ assert_equal(len(block["tx"]), event.transactions)
+ assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs)
+ assert_equal(0, event.sigops) # no sigops in coinbase tx
+ # only plausibility checks
+ assert event.duration > 0
+ del expected_blocks[block_hash]
assert_equal(BLOCKS_EXPECTED, blocks_checked)
assert_equal(0, len(expected_blocks))
+ bpf.cleanup()
+
if __name__ == '__main__':
ValidationTracepointTest().main()
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 2f41f9aa53..2358dd4387 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the ZMQ notification interface."""
import struct
+from time import sleep
from test_framework.address import (
ADDRESS_BCRT1_P2WSH_OP_TRUE,
@@ -16,8 +17,8 @@ from test_framework.blocktools import (
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
- CTransaction,
hash256,
+ tx_from_hex,
)
from test_framework.util import (
assert_equal,
@@ -28,8 +29,7 @@ from test_framework.wallet import (
MiniWallet,
)
from test_framework.netutil import test_ipv6_local
-from io import BytesIO
-from time import sleep
+
# Test may be skipped and not have zmq installed
try:
@@ -198,9 +198,7 @@ class ZMQTest (BitcoinTestFramework):
txid = hashtx.receive()
# Should receive the coinbase raw transaction.
- hex = rawtx.receive()
- tx = CTransaction()
- tx.deserialize(BytesIO(hex))
+ tx = tx_from_hex(rawtx.receive().hex())
tx.calc_sha256()
assert_equal(tx.hash, txid.hex())
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index 362b407062..8f3aec96a7 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -9,7 +9,6 @@ from decimal import Decimal
import math
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.key import ECKey
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
COIN,
@@ -44,6 +43,7 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import generate_keypair
class MempoolAcceptanceTest(BitcoinTestFramework):
@@ -283,9 +283,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
rawtxs=[tx.serialize().hex()],
)
tx = tx_from_hex(raw_tx_reference)
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
+ _, pubkey = generate_keypair()
tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=2) # Some bare multisig script (2-of-3)
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
@@ -350,7 +348,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A tiny transaction(in non-witness bytes) that is disallowed')
tx = CTransaction()
- tx.vin.append(CTxIn(COutPoint(int(seed_tx[0], 16), seed_tx[1]), b"", SEQUENCE_FINAL))
+ tx.vin.append(CTxIn(COutPoint(int(seed_tx["txid"], 16), seed_tx["sent_vout"]), b"", SEQUENCE_FINAL))
tx.wit.vtxinwit = [CTxInWitness()]
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2)))))
diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py
index a7bdc49695..7337802aea 100755
--- a/test/functional/mempool_compatibility.py
+++ b/test/functional/mempool_compatibility.py
@@ -47,12 +47,12 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
# unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`.
self.connect_nodes(0, 1)
self.sync_blocks()
- self.stop_node(1)
self.log.info("Add a transaction to mempool on old node and shutdown")
old_tx_hash = new_wallet.send_self_transfer(from_node=old_node)["txid"]
assert old_tx_hash in old_node.getrawmempool()
self.stop_node(0)
+ self.stop_node(1)
self.log.info("Move mempool.dat from old to new node")
old_node_mempool = os.path.join(old_node.datadir, self.chain, 'mempool.dat')
diff --git a/test/functional/mempool_dust.py b/test/functional/mempool_dust.py
index 41a26e82da..f4e385a112 100755
--- a/test/functional/mempool_dust.py
+++ b/test/functional/mempool_dust.py
@@ -5,7 +5,6 @@
"""Test dust limit mempool policy (`-dustrelayfee` parameter)"""
from decimal import Decimal
-from test_framework.key import ECKey
from test_framework.messages import (
COIN,
CTxOut,
@@ -32,6 +31,7 @@ from test_framework.util import (
get_fee,
)
from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import generate_keypair
DUST_RELAY_TX_FEE = 3000 # default setting [sat/kvB]
@@ -74,11 +74,8 @@ class DustRelayFeeTest(BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
# prepare output scripts of each standard type
- key = ECKey()
- key.generate(compressed=False)
- uncompressed_pubkey = key.get_pubkey().get_bytes()
- key.generate(compressed=True)
- pubkey = key.get_pubkey().get_bytes()
+ _, uncompressed_pubkey = generate_keypair(compressed=False)
+ _, pubkey = generate_keypair(compressed=True)
output_scripts = (
(key_to_p2pk_script(uncompressed_pubkey), "P2PK (uncompressed)"),
diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py
index 15a5f765df..18b3a8def4 100755
--- a/test/functional/mempool_expiry.py
+++ b/test/functional/mempool_expiry.py
@@ -12,7 +12,10 @@ definable expiry timeout via the '-mempoolexpiry=<n>' command line argument
from datetime import timedelta
-from test_framework.messages import DEFAULT_MEMPOOL_EXPIRY_HOURS
+from test_framework.messages import (
+ COIN,
+ DEFAULT_MEMPOOL_EXPIRY_HOURS,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -37,6 +40,10 @@ class MempoolExpiryTest(BitcoinTestFramework):
parent_utxo = self.wallet.get_utxo(txid=parent_txid)
independent_utxo = self.wallet.get_utxo()
+ # Add prioritisation to this transaction to check that it persists after the expiry
+ node.prioritisetransaction(parent_txid, 0, COIN)
+ assert_equal(node.getprioritisedtransactions()[parent_txid], { "fee_delta" : COIN, "in_mempool" : True})
+
# Ensure the transactions we send to trigger the mempool check spend utxos that are independent of
# the transactions being tested for expiration.
trigger_utxo1 = self.wallet.get_utxo()
@@ -79,6 +86,9 @@ class MempoolExpiryTest(BitcoinTestFramework):
assert_raises_rpc_error(-5, 'Transaction not in mempool',
node.getmempoolentry, parent_txid)
+ # Prioritisation does not disappear when transaction expires
+ assert_equal(node.getprioritisedtransactions()[parent_txid], { "fee_delta" : COIN, "in_mempool" : False})
+
# The child transaction should be removed from the mempool as well.
self.log.info('Test child tx is evicted as well.')
assert_raises_rpc_error(-5, 'Transaction not in mempool',
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index d38a37f952..f3f4b42ad0 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -7,15 +7,21 @@
from decimal import Decimal
from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.p2p import P2PTxInvStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_fee_amount,
assert_greater_than,
assert_raises_rpc_error,
create_lots_of_big_transactions,
gen_return_txouts,
)
-from test_framework.wallet import MiniWallet
+from test_framework.wallet import (
+ COIN,
+ DEFAULT_FEE,
+ MiniWallet,
+)
class MempoolLimitTest(BitcoinTestFramework):
@@ -38,13 +44,14 @@ class MempoolLimitTest(BitcoinTestFramework):
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
- tx_batch_size = 25
- num_of_batches = 3
+ tx_batch_size = 1
+ num_of_batches = 75
# Generate UTXOs to flood the mempool
# 1 to create a tx initially that will be evicted from the mempool later
# 3 batches of multiple transactions with a fee rate much higher than the previous UTXO
# And 1 more to verify that this tx does not get added to the mempool with a fee rate less than the mempoolminfee
- self.generate(miniwallet, 1 + (num_of_batches * tx_batch_size) + 1)
+ # And 2 more for the package cpfp test
+ self.generate(miniwallet, 1 + (num_of_batches * tx_batch_size) + 1 + 2)
# Mine 99 blocks so that the UTXOs are allowed to be spent
self.generate(node, COINBASE_MATURITY - 1)
@@ -76,6 +83,68 @@ class MempoolLimitTest(BitcoinTestFramework):
self.log.info('Create a mempool tx that will not pass mempoolminfee')
assert_raises_rpc_error(-26, "mempool min fee not met", miniwallet.send_self_transfer, from_node=node, fee_rate=relayfee)
+ self.log.info("Check that submitpackage allows cpfp of a parent below mempool min feerate")
+ node = self.nodes[0]
+ peer = node.add_p2p_connection(P2PTxInvStore())
+
+ # Package with 2 parents and 1 child. One parent has a high feerate due to modified fees,
+ # another is below the mempool minimum feerate but bumped by the child.
+ tx_poor = miniwallet.create_self_transfer(fee_rate=relayfee)
+ tx_rich = miniwallet.create_self_transfer(fee=0, fee_rate=0)
+ node.prioritisetransaction(tx_rich["txid"], 0, int(DEFAULT_FEE * COIN))
+ package_txns = [tx_rich, tx_poor]
+ coins = [tx["new_utxo"] for tx in package_txns]
+ tx_child = miniwallet.create_self_transfer_multi(utxos_to_spend=coins, fee_per_output=10000) #DEFAULT_FEE
+ package_txns.append(tx_child)
+
+ submitpackage_result = node.submitpackage([tx["hex"] for tx in package_txns])
+
+ rich_parent_result = submitpackage_result["tx-results"][tx_rich["wtxid"]]
+ poor_parent_result = submitpackage_result["tx-results"][tx_poor["wtxid"]]
+ child_result = submitpackage_result["tx-results"][tx_child["tx"].getwtxid()]
+ assert_fee_amount(poor_parent_result["fees"]["base"], tx_poor["tx"].get_vsize(), relayfee)
+ assert_equal(rich_parent_result["fees"]["base"], 0)
+ assert_equal(child_result["fees"]["base"], DEFAULT_FEE)
+ # The "rich" parent does not require CPFP so its effective feerate is just its individual feerate.
+ assert_fee_amount(DEFAULT_FEE, tx_rich["tx"].get_vsize(), rich_parent_result["fees"]["effective-feerate"])
+ assert_equal(rich_parent_result["fees"]["effective-includes"], [tx_rich["wtxid"]])
+ # The "poor" parent and child's effective feerates are the same, composed of their total
+ # fees divided by their combined vsize.
+ package_fees = poor_parent_result["fees"]["base"] + child_result["fees"]["base"]
+ package_vsize = tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize()
+ assert_fee_amount(package_fees, package_vsize, poor_parent_result["fees"]["effective-feerate"])
+ assert_fee_amount(package_fees, package_vsize, child_result["fees"]["effective-feerate"])
+ assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], poor_parent_result["fees"]["effective-includes"])
+ assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], child_result["fees"]["effective-includes"])
+
+ # The node will broadcast each transaction, still abiding by its peer's fee filter
+ peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns])
+
+ self.log.info("Check a package that passes mempoolminfee but is evicted immediately after submission")
+ mempoolmin_feerate = node.getmempoolinfo()["mempoolminfee"]
+ current_mempool = node.getrawmempool(verbose=False)
+ worst_feerate_btcvb = Decimal("21000000")
+ for txid in current_mempool:
+ entry = node.getmempoolentry(txid)
+ worst_feerate_btcvb = min(worst_feerate_btcvb, entry["fees"]["descendant"] / entry["descendantsize"])
+ # Needs to be large enough to trigger eviction
+ target_weight_each = 200000
+ assert_greater_than(target_weight_each * 2, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"])
+ # Should be a true CPFP: parent's feerate is just below mempool min feerate
+ parent_fee = (mempoolmin_feerate / 1000) * (target_weight_each // 4) - Decimal("0.00001")
+ # Parent + child is above mempool minimum feerate
+ child_fee = (worst_feerate_btcvb) * (target_weight_each // 4) - Decimal("0.00001")
+ # However, when eviction is triggered, these transactions should be at the bottom.
+ # This assertion assumes parent and child are the same size.
+ miniwallet.rescan_utxos()
+ tx_parent_just_below = miniwallet.create_self_transfer(fee=parent_fee, target_weight=target_weight_each)
+ tx_child_just_above = miniwallet.create_self_transfer(utxo_to_spend=tx_parent_just_below["new_utxo"], fee=child_fee, target_weight=target_weight_each)
+ # This package ranks below the lowest descendant package in the mempool
+ assert_greater_than(worst_feerate_btcvb, (parent_fee + child_fee) / (tx_parent_just_below["tx"].get_vsize() + tx_child_just_above["tx"].get_vsize()))
+ assert_greater_than(mempoolmin_feerate, (parent_fee) / (tx_parent_just_below["tx"].get_vsize()))
+ assert_greater_than((parent_fee + child_fee) / (tx_parent_just_below["tx"].get_vsize() + tx_child_just_above["tx"].get_vsize()), mempoolmin_feerate / 1000)
+ assert_raises_rpc_error(-26, "mempool full", node.submitpackage, [tx_parent_just_below["hex"], tx_child_just_above["hex"]])
+
self.log.info('Test passing a value below the minimum (5 MB) to -maxmempool throws an error')
self.stop_node(0)
self.nodes[0].assert_start_raises_init_error(["-maxmempool=4"], "Error: -maxmempool must be at least 5 MB")
diff --git a/test/functional/mempool_package_limits.py b/test/functional/mempool_package_limits.py
index 63f5a3e3d3..81451bf2a5 100755
--- a/test/functional/mempool_package_limits.py
+++ b/test/functional/mempool_package_limits.py
@@ -3,20 +3,41 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test logic for limiting mempool and package ancestors/descendants."""
-
-from decimal import Decimal
-
from test_framework.blocktools import COINBASE_MATURITY
-from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import (
- COIN,
WITNESS_SCALE_FACTOR,
)
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
)
from test_framework.wallet import MiniWallet
+# Decorator to
+# 1) check that mempool is empty at the start of a subtest
+# 2) run the subtest, which may submit some transaction(s) to the mempool and
+# create a list of hex transactions
+# 3) testmempoolaccept the package hex and check that it fails with the error
+# "package-mempool-limits" for each tx
+# 4) after mining a block, clearing the pre-submitted transactions from mempool,
+# check that submitting the created package succeeds
+def check_package_limits(func):
+ def func_wrapper(self, *args, **kwargs):
+ node = self.nodes[0]
+ assert_equal(0, node.getmempoolinfo()["size"])
+ package_hex = func(self, *args, **kwargs)
+ testres_error_expected = node.testmempoolaccept(rawtxs=package_hex)
+ assert_equal(len(testres_error_expected), len(package_hex))
+ for txres in testres_error_expected:
+ assert_equal(txres["package-error"], "package-mempool-limits")
+
+ # Clear mempool and check that the package passes now
+ self.generate(node, 1)
+ assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
+
+ return func_wrapper
+
+
class MempoolPackageLimitsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
@@ -25,8 +46,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
# Add enough mature utxos to the wallet so that all txs spend confirmed coins.
- self.generate(self.wallet, 35)
- self.generate(self.nodes[0], COINBASE_MATURITY)
+ self.generate(self.wallet, COINBASE_MATURITY + 35)
self.test_chain_limits()
self.test_desc_count_limits()
@@ -40,9 +60,9 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
self.test_anc_size_limits()
self.test_desc_size_limits()
+ @check_package_limits
def test_chain_limits_helper(self, mempool_count, package_count):
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
chain_hex = []
chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)[-1]["new_utxo"]
@@ -51,13 +71,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo)
chaintip_utxo = tx["new_utxo"]
chain_hex.append(tx["hex"])
- testres_too_long = node.testmempoolaccept(rawtxs=chain_hex)
- for txres in testres_too_long:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=chain_hex)])
+ return chain_hex
def test_chain_limits(self):
"""Create chains from mempool and package transactions that are longer than 25,
@@ -76,6 +90,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
# 13 transactions in the mempool and 13 in the package.
self.test_chain_limits_helper(13, 13)
+ @check_package_limits
def test_desc_count_limits(self):
"""Create an 'A' shaped package with 24 transactions in the mempool and 2 in the package:
M1
@@ -93,7 +108,6 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
package transactions).
"""
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
self.log.info("Check that in-mempool and in-package descendants are calculated properly in packages")
# Top parent in mempool, M1
m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
@@ -113,14 +127,9 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
- testres_too_long = node.testmempoolaccept(rawtxs=package_hex)
- for txres in testres_too_long:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
+ return package_hex
+ @check_package_limits
def test_desc_count_limits_2(self):
"""Create a Package with 24 transaction in mempool and 2 transaction in package:
M1
@@ -157,15 +166,9 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
- testres = node.testmempoolaccept(rawtxs=package_hex)
- assert_equal(len(testres), len(package_hex))
- for txres in testres:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
+ return package_hex
+ @check_package_limits
def test_anc_count_limits(self):
"""Create a 'V' shaped chain with 24 transactions in the mempool and 3 in the package:
M1a M1b
@@ -183,7 +186,6 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
and in-package ancestors are all considered together.
"""
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
package_hex = []
pc_parent_utxos = []
@@ -203,14 +205,9 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(24, node.getmempoolinfo()["size"])
assert_equal(3, len(package_hex))
- testres_too_long = node.testmempoolaccept(rawtxs=package_hex)
- for txres in testres_too_long:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
+ return package_hex
+ @check_package_limits
def test_anc_count_limits_2(self):
"""Create a 'Y' shaped chain with 24 transactions in the mempool and 2 in the package:
M1a M1b
@@ -228,7 +225,6 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
and in-package ancestors are all considered together.
"""
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
pc_parent_utxos = []
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
@@ -245,14 +241,9 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0])
assert_equal(24, node.getmempoolinfo()["size"])
- testres_too_long = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
- for txres in testres_too_long:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
+ return [pc_tx["hex"], pd_tx["hex"]]
+ @check_package_limits
def test_anc_count_limits_bushy(self):
"""Create a tree with 20 transactions in the mempool and 6 in the package:
M1...M4 M5...M8 M9...M12 M13...M16 M17...M20
@@ -265,7 +256,6 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
combined, PC has 25 in-mempool and in-package parents.
"""
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
package_hex = []
pc_parent_utxos = []
for _ in range(5): # Make package transactions P0 ... P4
@@ -282,14 +272,9 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(20, node.getmempoolinfo()["size"])
assert_equal(6, len(package_hex))
- testres = node.testmempoolaccept(rawtxs=package_hex)
- for txres in testres:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
+ return package_hex
+ @check_package_limits
def test_anc_size_limits(self):
"""Test Case with 2 independent transactions in the mempool and a parent + child in the
package, where the package parent is the child of both mempool transactions (30KvB each):
@@ -302,10 +287,10 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
and in-package ancestors are all considered together.
"""
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
parent_utxos = []
- target_weight = WITNESS_SCALE_FACTOR * 1000 * 30 # 30KvB
- high_fee = Decimal("0.003") # 10 sats/vB
+ target_vsize = 30_000
+ high_fee = 10 * target_vsize # 10 sats/vB
+ target_weight = target_vsize * WITNESS_SCALE_FACTOR
self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages")
# Mempool transactions A and B
for _ in range(2):
@@ -314,22 +299,17 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
parent_utxos.append(bulked_tx["new_utxo"])
# Package transaction C
- pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=int(high_fee * COIN), target_weight=target_weight)
+ pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_weight=target_weight)
# Package transaction D
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight)
assert_equal(2, node.getmempoolinfo()["size"])
- testres_too_heavy = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
- for txres in testres_too_heavy:
- assert_equal(txres["package-error"], "package-mempool-limits")
-
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
+ return [pc_tx["hex"], pd_tx["hex"]]
+ @check_package_limits
def test_desc_size_limits(self):
- """Create 3 mempool transactions and 2 package transactions (25KvB each):
+ """Create 3 mempool transactions and 2 package transactions (21KvB each):
Ma
^ ^
Mb Mc
@@ -339,12 +319,12 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
and in-package descendants are all considered together.
"""
node = self.nodes[0]
- assert_equal(0, node.getmempoolinfo()["size"])
- target_weight = 21 * 1000 * WITNESS_SCALE_FACTOR
- high_fee = Decimal("0.0021") # 10 sats/vB
+ target_vsize = 21_000
+ high_fee = 10 * target_vsize # 10 sats/vB
+ target_weight = target_vsize * WITNESS_SCALE_FACTOR
self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
# Top parent in mempool, Ma
- ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=int(high_fee / 2 * COIN), target_weight=target_weight)
+ ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_weight=target_weight)
self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])
package_hex = []
@@ -359,13 +339,8 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
assert_equal(3, node.getmempoolinfo()["size"])
assert_equal(2, len(package_hex))
- testres_too_heavy = node.testmempoolaccept(rawtxs=package_hex)
- for txres in testres_too_heavy:
- assert_equal(txres["package-error"], "package-mempool-limits")
+ return package_hex
- # Clear mempool and check that the package passes now
- self.generate(node, 1)
- assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
if __name__ == "__main__":
MempoolPackageLimitsTest().main()
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 0387282862..95f7939412 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -7,7 +7,6 @@
from decimal import Decimal
from test_framework.messages import (
- COIN,
DEFAULT_ANCESTOR_LIMIT,
DEFAULT_DESCENDANT_LIMIT,
)
@@ -26,9 +25,6 @@ assert CUSTOM_DESCENDANT_LIMIT >= CUSTOM_ANCESTOR_LIMIT
class MempoolPackagesTest(BitcoinTestFramework):
- def add_options(self, parser):
- self.add_wallet_options(parser)
-
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
@@ -47,10 +43,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
self.wallet = MiniWallet(self.nodes[0])
self.wallet.rescan_utxos()
- if self.is_specified_wallet_compiled():
- self.nodes[0].createwallet("watch_wallet", disable_private_keys=True)
- self.nodes[0].importaddress(self.wallet.get_address())
-
peer_inv_store = self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs
# DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine
@@ -63,13 +55,6 @@ class MempoolPackagesTest(BitcoinTestFramework):
ancestor_vsize += t["tx"].get_vsize()
ancestor_fees += t["fee"]
self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=t["hex"])
- # Check that listunspent ancestor{count, size, fees} yield the correct results
- if self.is_specified_wallet_compiled():
- wallet_unspent = self.nodes[0].listunspent(minconf=0)
- this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info["txid"] == t["txid"])
- assert_equal(this_unspent['ancestorcount'], i + 1)
- assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
- assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
# Wait until mempool transactions have passed initial broadcast (sent inv and received getdata)
# Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index f818801136..8f74d9de20 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -191,6 +191,7 @@ class MempoolPersistTest(BitcoinTestFramework):
def test_persist_unbroadcast(self):
node0 = self.nodes[0]
self.start_node(0)
+ self.start_node(2)
# clear out mempool
self.generate(node0, 1, sync_fun=self.no_op)
diff --git a/test/functional/mempool_sigoplimit.py b/test/functional/mempool_sigoplimit.py
index b178b9feda..962b2b19bd 100755
--- a/test/functional/mempool_sigoplimit.py
+++ b/test/functional/mempool_sigoplimit.py
@@ -49,7 +49,7 @@ class BytesPerSigOpTest(BitcoinTestFramework):
"""Create a 1-input-1-output P2WSH spending transaction with only the
witness script in the witness stack and the given output script."""
# create P2WSH address and fund it via MiniWallet first
- txid, vout = self.wallet.send_to(
+ fund = self.wallet.send_to(
from_node=self.nodes[0],
scriptPubKey=script_to_p2wsh_script(witness_script),
amount=1000000,
@@ -57,7 +57,7 @@ class BytesPerSigOpTest(BitcoinTestFramework):
# create spending transaction
tx = CTransaction()
- tx.vin = [CTxIn(COutPoint(int(txid, 16), vout))]
+ tx.vin = [CTxIn(COutPoint(int(fund["txid"], 16), fund["sent_vout"]))]
tx.wit.vtxinwit = [CTxInWitness()]
tx.wit.vtxinwit[0].scriptWitness.stack = [bytes(witness_script)]
tx.vout = [CTxOut(500000, output_script)]
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index 332099516c..aabf06ee53 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -145,6 +145,7 @@ class MiningTest(BitcoinTestFramework):
assert_template(node, bad_block, 'bad-cb-missing')
self.log.info("submitblock: Test invalid coinbase transaction")
+ assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, CBlock().serialize().hex())
assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, bad_block.serialize().hex())
self.log.info("getblocktemplate: Test truncated final transaction")
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index a4481c15a0..099c0e418c 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -30,6 +30,33 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
]] * self.num_nodes
self.supports_cli = False
+ def clear_prioritisation(self, node):
+ for txid, info in node.getprioritisedtransactions().items():
+ delta = info["fee_delta"]
+ node.prioritisetransaction(txid, 0, -delta)
+ assert_equal(node.getprioritisedtransactions(), {})
+
+ def test_replacement(self):
+ self.log.info("Test tx prioritisation stays after a tx is replaced")
+ conflicting_input = self.wallet.get_utxo()
+ tx_replacee = self.wallet.create_self_transfer(utxo_to_spend=conflicting_input, fee_rate=Decimal("0.0001"))
+ tx_replacement = self.wallet.create_self_transfer(utxo_to_spend=conflicting_input, fee_rate=Decimal("0.005"))
+ # Add 1 satoshi fee delta to replacee
+ self.nodes[0].prioritisetransaction(tx_replacee["txid"], 0, 100)
+ assert_equal(self.nodes[0].getprioritisedtransactions(), { tx_replacee["txid"] : { "fee_delta" : 100, "in_mempool" : False}})
+ self.nodes[0].sendrawtransaction(tx_replacee["hex"])
+ assert_equal(self.nodes[0].getprioritisedtransactions(), { tx_replacee["txid"] : { "fee_delta" : 100, "in_mempool" : True}})
+ self.nodes[0].sendrawtransaction(tx_replacement["hex"])
+ assert tx_replacee["txid"] not in self.nodes[0].getrawmempool()
+ assert_equal(self.nodes[0].getprioritisedtransactions(), { tx_replacee["txid"] : { "fee_delta" : 100, "in_mempool" : False}})
+
+ # PrioritiseTransaction is additive
+ self.nodes[0].prioritisetransaction(tx_replacee["txid"], 0, COIN)
+ self.nodes[0].sendrawtransaction(tx_replacee["hex"])
+ assert_equal(self.nodes[0].getprioritisedtransactions(), { tx_replacee["txid"] : { "fee_delta" : COIN + 100, "in_mempool" : True}})
+ self.generate(self.nodes[0], 1)
+ assert_equal(self.nodes[0].getprioritisedtransactions(), {})
+
def test_diamond(self):
self.log.info("Test diamond-shape package with priority")
mock_time = int(time.time())
@@ -84,6 +111,13 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
raw_after = self.nodes[0].getrawmempool(verbose=True)
assert_equal(raw_before[txid_a], raw_after[txid_a])
assert_equal(raw_before, raw_after)
+ prioritisation_map_in_mempool = self.nodes[0].getprioritisedtransactions()
+ assert_equal(prioritisation_map_in_mempool[txid_b], {"fee_delta" : fee_delta_b*COIN, "in_mempool" : True})
+ assert_equal(prioritisation_map_in_mempool[txid_c], {"fee_delta" : (fee_delta_c_1 + fee_delta_c_2)*COIN, "in_mempool" : True})
+ # Clear prioritisation, otherwise the transactions' fee deltas are persisted to mempool.dat and loaded again when the node
+ # is restarted at the end of this subtest. Deltas are removed when a transaction is mined, but only at that time. We do
+ # not check whether mapDeltas transactions were mined when loading from mempool.dat.
+ self.clear_prioritisation(node=self.nodes[0])
self.log.info("Test priority while txs are not in mempool")
self.restart_node(0, extra_args=["-nopersistmempool"])
@@ -92,17 +126,26 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.nodes[0].prioritisetransaction(txid=txid_b, fee_delta=int(fee_delta_b * COIN))
self.nodes[0].prioritisetransaction(txid=txid_c, fee_delta=int(fee_delta_c_1 * COIN))
self.nodes[0].prioritisetransaction(txid=txid_c, fee_delta=int(fee_delta_c_2 * COIN))
+ prioritisation_map_not_in_mempool = self.nodes[0].getprioritisedtransactions()
+ assert_equal(prioritisation_map_not_in_mempool[txid_b], {"fee_delta" : fee_delta_b*COIN, "in_mempool" : False})
+ assert_equal(prioritisation_map_not_in_mempool[txid_c], {"fee_delta" : (fee_delta_c_1 + fee_delta_c_2)*COIN, "in_mempool" : False})
for t in [tx_o_a["hex"], tx_o_b["hex"], tx_o_c["hex"], tx_o_d["hex"]]:
self.nodes[0].sendrawtransaction(t)
raw_after = self.nodes[0].getrawmempool(verbose=True)
assert_equal(raw_before[txid_a], raw_after[txid_a])
assert_equal(raw_before, raw_after)
+ prioritisation_map_in_mempool = self.nodes[0].getprioritisedtransactions()
+ assert_equal(prioritisation_map_in_mempool[txid_b], {"fee_delta" : fee_delta_b*COIN, "in_mempool" : True})
+ assert_equal(prioritisation_map_in_mempool[txid_c], {"fee_delta" : (fee_delta_c_1 + fee_delta_c_2)*COIN, "in_mempool" : True})
# Clear mempool
self.generate(self.nodes[0], 1)
+ # Prioritisation for transactions is automatically deleted after they are mined.
+ assert_equal(self.nodes[0].getprioritisedtransactions(), {})
# Use default extra_args
self.restart_node(0)
+ assert_equal(self.nodes[0].getprioritisedtransactions(), {})
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
@@ -115,6 +158,10 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Test `prioritisetransaction` invalid extra parameters
assert_raises_rpc_error(-1, "prioritisetransaction", self.nodes[0].prioritisetransaction, '', 0, 0, 0)
+ # Test `getprioritisedtransactions` invalid parameters
+ assert_raises_rpc_error(-1, "getprioritisedtransactions",
+ self.nodes[0].getprioritisedtransactions, True)
+
# Test `prioritisetransaction` invalid `txid`
assert_raises_rpc_error(-8, "txid must be of length 64 (not 3, for 'foo')", self.nodes[0].prioritisetransaction, txid='foo', fee_delta=0)
assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000')", self.nodes[0].prioritisetransaction, txid='Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000', fee_delta=0)
@@ -127,6 +174,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Test `prioritisetransaction` invalid `fee_delta`
assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].prioritisetransaction, txid=txid, fee_delta='foo')
+ self.test_replacement()
self.test_diamond()
self.txouts = gen_return_txouts()
@@ -165,9 +213,18 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
sizes[i] += mempool[j]['vsize']
assert sizes[i] > MAX_BLOCK_WEIGHT // 4 # Fail => raise utxo_count
+ assert_equal(self.nodes[0].getprioritisedtransactions(), {})
# add a fee delta to something in the cheapest bucket and make sure it gets mined
# also check that a different entry in the cheapest bucket is NOT mined
self.nodes[0].prioritisetransaction(txid=txids[0][0], fee_delta=int(3*base_fee*COIN))
+ assert_equal(self.nodes[0].getprioritisedtransactions(), {txids[0][0] : { "fee_delta" : 3*base_fee*COIN, "in_mempool" : True}})
+
+ # Priority disappears when prioritisetransaction is called with an inverse value...
+ self.nodes[0].prioritisetransaction(txid=txids[0][0], fee_delta=int(-3*base_fee*COIN))
+ assert txids[0][0] not in self.nodes[0].getprioritisedtransactions()
+ # ... and reappears when prioritisetransaction is called again.
+ self.nodes[0].prioritisetransaction(txid=txids[0][0], fee_delta=int(3*base_fee*COIN))
+ assert txids[0][0] in self.nodes[0].getprioritisedtransactions()
self.generate(self.nodes[0], 1)
@@ -187,6 +244,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Add a prioritisation before a tx is in the mempool (de-prioritising a
# high-fee transaction so that it's now low fee).
self.nodes[0].prioritisetransaction(txid=high_fee_tx, fee_delta=-int(2*base_fee*COIN))
+ assert_equal(self.nodes[0].getprioritisedtransactions()[high_fee_tx], { "fee_delta" : -2*base_fee*COIN, "in_mempool" : False})
# Add everything back to mempool
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
@@ -206,6 +264,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
mempool = self.nodes[0].getrawmempool()
self.log.info("Assert that de-prioritised transaction is still in mempool")
assert high_fee_tx in mempool
+ assert_equal(self.nodes[0].getprioritisedtransactions()[high_fee_tx], { "fee_delta" : -2*base_fee*COIN, "in_mempool" : True})
for x in txids[2]:
if (x != high_fee_tx):
assert x not in mempool
@@ -223,10 +282,12 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# to be the minimum for a 1000-byte transaction and check that it is
# accepted.
self.nodes[0].prioritisetransaction(txid=tx_id, fee_delta=int(self.relayfee*COIN))
+ assert_equal(self.nodes[0].getprioritisedtransactions()[tx_id], { "fee_delta" : self.relayfee*COIN, "in_mempool" : False})
self.log.info("Assert that prioritised free transaction is accepted to mempool")
assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)
assert tx_id in self.nodes[0].getrawmempool()
+ assert_equal(self.nodes[0].getprioritisedtransactions()[tx_id], { "fee_delta" : self.relayfee*COIN, "in_mempool" : True})
# Test that calling prioritisetransaction is sufficient to trigger
# getblocktemplate to (eventually) return a new block.
@@ -234,6 +295,10 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.nodes[0].setmocktime(mock_time)
template = self.nodes[0].getblocktemplate({'rules': ['segwit']})
self.nodes[0].prioritisetransaction(txid=tx_id, fee_delta=-int(self.relayfee*COIN))
+
+ # Calling prioritisetransaction with the inverse amount should delete its prioritisation entry
+ assert tx_id not in self.nodes[0].getprioritisedtransactions()
+
self.nodes[0].setmocktime(mock_time+10)
new_template = self.nodes[0].getblocktemplate({'rules': ['segwit']})
diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py
index 2da9037a69..e4908735c9 100755
--- a/test/functional/p2p_blockfilters.py
+++ b/test/functional/p2p_blockfilters.py
@@ -255,13 +255,6 @@ class CompactFiltersTest(BitcoinTestFramework):
msg = "Error: Unknown -blockfilterindex value abc."
self.nodes[0].assert_start_raises_init_error(expected_msg=msg)
- self.log.info("Test -blockfilterindex with -reindex-chainstate raises an error")
- self.nodes[0].assert_start_raises_init_error(
- expected_msg='Error: -reindex-chainstate option is not compatible with -blockfilterindex. '
- 'Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.',
- extra_args=['-blockfilterindex', '-reindex-chainstate'],
- )
-
def compute_last_header(prev_header, hashes):
"""Compute the last filter header from a starting header and a sequence of filter hashes."""
header = ser_uint256(prev_header)
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 23eeea50bc..d6c06fdeed 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -105,6 +105,10 @@ class TestP2PConn(P2PInterface):
self.last_message.pop("headers", None)
self.last_message.pop("cmpctblock", None)
+ def clear_getblocktxn(self):
+ with p2p_lock:
+ self.last_message.pop("getblocktxn", None)
+
def get_headers(self, locator, hashstop):
msg = msg_getheaders()
msg.locator.vHave = locator
@@ -745,7 +749,7 @@ class CompactBlocksTest(BitcoinTestFramework):
peer.get_headers(locator=[int(tip, 16)], hashstop=0)
peer.send_and_ping(msg_sendcmpct(announce=True, version=2))
- def test_compactblock_reconstruction_multiple_peers(self, stalling_peer, delivery_peer):
+ def test_compactblock_reconstruction_stalling_peer(self, stalling_peer, delivery_peer):
node = self.nodes[0]
assert len(self.utxos)
@@ -823,12 +827,85 @@ class CompactBlocksTest(BitcoinTestFramework):
hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False)
+ def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):
+ """ All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot
+ can only be taken by an outbound node unless prior attempts were done by an outbound
+ """
+ node = self.nodes[0]
+ assert len(self.utxos)
+
+ def announce_cmpct_block(node, peer, txn_count):
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, txn_count)
+
+ cmpct_block = HeaderAndShortIDs()
+ cmpct_block.initialize_from_block(block)
+ msg = msg_cmpctblock(cmpct_block.to_p2p())
+ peer.send_and_ping(msg)
+ with p2p_lock:
+ assert "getblocktxn" in peer.last_message
+ return block, cmpct_block
+
+ for name, peer in [("delivery", delivery_peer), ("inbound", inbound_peer), ("outbound", outbound_peer)]:
+ self.log.info(f"Setting {name} as high bandwidth peer")
+ block, cmpct_block = announce_cmpct_block(node, peer, 1)
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = block.vtx[1:]
+ peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+ peer.clear_getblocktxn()
+
+ # Test the simple parallel download case...
+ for num_missing in [1, 5, 20]:
+
+ # Remaining low-bandwidth peer is stalling_peer, who announces first
+ assert_equal([peer['bip152_hb_to'] for peer in node.getpeerinfo()], [False, True, True, True])
+
+ block, cmpct_block = announce_cmpct_block(node, stalling_peer, num_missing)
+
+ delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ with p2p_lock:
+ # The second peer to announce should still get a getblocktxn
+ assert "getblocktxn" in delivery_peer.last_message
+ assert int(node.getbestblockhash(), 16) != block.sha256
+
+ inbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ with p2p_lock:
+ # The third inbound peer to announce should *not* get a getblocktxn
+ assert "getblocktxn" not in inbound_peer.last_message
+ assert int(node.getbestblockhash(), 16) != block.sha256
+
+ outbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ with p2p_lock:
+ # The third peer to announce should get a getblocktxn if outbound
+ assert "getblocktxn" in outbound_peer.last_message
+ assert int(node.getbestblockhash(), 16) != block.sha256
+
+ # Second peer completes the compact block first
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = block.vtx[1:]
+ delivery_peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ # Nothing bad should happen if we get a late fill from the first peer...
+ stalling_peer.send_and_ping(msg)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+
+ delivery_peer.clear_getblocktxn()
+ inbound_peer.clear_getblocktxn()
+ outbound_peer.clear_getblocktxn()
+
+
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
# Setup the p2p connections
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
self.additional_segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ self.onemore_inbound_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ self.outbound_node = self.nodes[0].add_outbound_p2p_connection(TestP2PConn(), p2p_idx=3, connection_type="outbound-full-relay")
# We will need UTXOs to construct transactions in later tests.
self.make_utxos()
@@ -838,6 +915,8 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Testing SENDCMPCT p2p message... ")
self.test_sendcmpct(self.segwit_node)
self.test_sendcmpct(self.additional_segwit_node)
+ self.test_sendcmpct(self.onemore_inbound_node)
+ self.test_sendcmpct(self.outbound_node)
self.log.info("Testing compactblock construction...")
self.test_compactblock_construction(self.segwit_node)
@@ -860,8 +939,11 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Testing handling of incorrect blocktxn responses...")
self.test_incorrect_blocktxn_response(self.segwit_node)
- self.log.info("Testing reconstructing compact blocks from all peers...")
- self.test_compactblock_reconstruction_multiple_peers(self.segwit_node, self.additional_segwit_node)
+ self.log.info("Testing reconstructing compact blocks with a stalling peer...")
+ self.test_compactblock_reconstruction_stalling_peer(self.segwit_node, self.additional_segwit_node)
+
+ self.log.info("Testing reconstructing compact blocks from multiple peers...")
+ self.test_compactblock_reconstruction_parallel_reconstruction(stalling_peer=self.segwit_node, inbound_peer=self.onemore_inbound_node, delivery_peer=self.additional_segwit_node, outbound_peer=self.outbound_node)
# Test that if we submitblock to node1, we'll get a compact block
# announcement to all peers.
diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py
index 394009f30f..c389ff732f 100755
--- a/test/functional/p2p_disconnect_ban.py
+++ b/test/functional/p2p_disconnect_ban.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node disconnect and ban behavior"""
import time
+from pathlib import Path
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -36,6 +37,17 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("clearbanned: successfully clear ban list")
self.nodes[1].clearbanned()
assert_equal(len(self.nodes[1].listbanned()), 0)
+
+ self.log.info('Test banlist database recreation')
+ self.stop_node(1)
+ target_file = self.nodes[1].chain_path / "banlist.json"
+ Path.unlink(target_file)
+ with self.nodes[1].assert_debug_log(["Recreating the banlist database"]):
+ self.start_node(1)
+
+ assert Path.exists(target_file)
+ assert_equal(self.nodes[1].listbanned(), [])
+
self.nodes[1].setban("127.0.0.0/24", "add")
self.log.info("setban: fail to ban an already banned subnet")
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index b3e68ca536..6699cc3528 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -136,7 +136,7 @@ class FilterTest(BitcoinTestFramework):
filter_peer = P2PBloomFilter()
self.log.debug("Create a tx relevant to the peer before connecting")
- txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)
+ txid = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)["txid"]
self.log.debug("Send a mempool msg after connecting and check that the tx is received")
self.nodes[0].add_p2p_connection(filter_peer)
@@ -183,14 +183,14 @@ class FilterTest(BitcoinTestFramework):
self.log.info('Check that we receive a tx if the filter matches a mempool tx')
filter_peer.merkleblock_received = False
- txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)
+ txid = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN)["txid"]
filter_peer.wait_for_tx(txid)
assert not filter_peer.merkleblock_received
self.log.info('Check that after deleting filter all txs get relayed again')
filter_peer.send_and_ping(msg_filterclear())
for _ in range(5):
- txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=7 * COIN)
+ txid = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=7 * COIN)["txid"]
filter_peer.wait_for_tx(txid)
self.log.info('Check that request for filtered blocks is ignored if no filter is set')
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 644abda914..2fb88b828f 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid network messages."""
+import random
import struct
import time
@@ -75,6 +76,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.test_oversized_getdata_msg()
self.test_oversized_headers_msg()
self.test_invalid_pow_headers_msg()
+ self.test_noncontinuous_headers_msg()
self.test_resource_exhaustion()
def test_buffer(self):
@@ -283,6 +285,25 @@ class InvalidMessagesTest(BitcoinTestFramework):
peer.send_message(msg_headers([blockheader]))
peer.wait_for_disconnect()
+ def test_noncontinuous_headers_msg(self):
+ self.log.info("Test headers message with non-continuous headers sequence is logged as misbehaving")
+ block_hashes = self.generate(self.nodes[0], 10)
+ block_headers = []
+ for block_hash in block_hashes:
+ block_headers.append(from_hex(CBlockHeader(), self.nodes[0].getblockheader(block_hash, False)))
+
+ # continuous headers sequence should be fine
+ MISBEHAVING_NONCONTINUOUS_HEADERS_MSGS = ['Misbehaving', 'non-continuous headers sequence']
+ peer = self.nodes[0].add_p2p_connection(P2PInterface())
+ with self.nodes[0].assert_debug_log([], unexpected_msgs=MISBEHAVING_NONCONTINUOUS_HEADERS_MSGS):
+ peer.send_and_ping(msg_headers(block_headers))
+
+ # delete arbitrary block header somewhere in the middle to break link
+ del block_headers[random.randrange(1, len(block_headers)-1)]
+ with self.nodes[0].assert_debug_log(expected_msgs=MISBEHAVING_NONCONTINUOUS_HEADERS_MSGS):
+ peer.send_and_ping(msg_headers(block_headers))
+ self.nodes[0].disconnect_p2ps()
+
def test_resource_exhaustion(self):
self.log.info("Test node stays up despite many large junk messages")
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
index 6283dd89ac..f53f98e06d 100755
--- a/test/functional/p2p_leak_tx.py
+++ b/test/functional/p2p_leak_tx.py
@@ -2,10 +2,10 @@
# 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"""
+"""Test transaction upload"""
-from test_framework.messages import msg_getdata, CInv, MSG_TX
-from test_framework.p2p import p2p_lock, P2PDataStore
+from test_framework.messages import msg_getdata, CInv, MSG_TX, MSG_WTX
+from test_framework.p2p import p2p_lock, P2PDataStore, P2PTxInvStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -23,16 +23,67 @@ class P2PLeakTxTest(BitcoinTestFramework):
self.num_nodes = 1
def run_test(self):
- gen_node = self.nodes[0] # The block and tx generating node
- miniwallet = MiniWallet(gen_node)
+ self.gen_node = self.nodes[0] # The block and tx generating node
+ self.miniwallet = MiniWallet(self.gen_node)
- inbound_peer = self.nodes[0].add_p2p_connection(P2PNode()) # An "attacking" inbound peer
+ self.test_tx_in_block()
+ self.test_notfound_on_replaced_tx()
+ self.test_notfound_on_unannounced_tx()
+
+ def test_tx_in_block(self):
+ self.log.info("Check that a transaction in the last block is uploaded (beneficial for compact block relay)")
+ inbound_peer = self.gen_node.add_p2p_connection(P2PNode())
+
+ self.log.debug("Generate transaction and block")
+ inbound_peer.last_message.pop("inv", None)
+ wtxid = self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"]
+ inbound_peer.wait_until(lambda: "inv" in inbound_peer.last_message and inbound_peer.last_message.get("inv").inv[0].hash == int(wtxid, 16))
+ want_tx = msg_getdata(inv=inbound_peer.last_message.get("inv").inv)
+ self.generate(self.gen_node, 1)
+
+ self.log.debug("Request transaction")
+ inbound_peer.last_message.pop("tx", None)
+ inbound_peer.send_and_ping(want_tx)
+ assert_equal(inbound_peer.last_message.get("tx").tx.getwtxid(), wtxid)
+
+ def test_notfound_on_replaced_tx(self):
+ self.gen_node.disconnect_p2ps()
+ inbound_peer = self.gen_node.add_p2p_connection(P2PTxInvStore())
+
+ self.log.info("Transaction tx_a is broadcast")
+ tx_a = self.miniwallet.send_self_transfer(from_node=self.gen_node)
+ inbound_peer.wait_for_broadcast(txns=[tx_a["wtxid"]])
+
+ tx_b = tx_a["tx"]
+ tx_b.vout[0].nValue -= 9000
+ self.gen_node.sendrawtransaction(tx_b.serialize().hex())
+ inbound_peer.wait_until(lambda: "tx" in inbound_peer.last_message and inbound_peer.last_message.get("tx").tx.getwtxid() == tx_b.getwtxid())
+
+ self.log.info("Re-request of tx_a after replacement is answered with notfound")
+ req_vec = [
+ CInv(t=MSG_TX, h=int(tx_a["txid"], 16)),
+ CInv(t=MSG_WTX, h=int(tx_a["wtxid"], 16)),
+ ]
+ want_tx = msg_getdata()
+ want_tx.inv = req_vec
+ with p2p_lock:
+ inbound_peer.last_message.pop("notfound", None)
+ inbound_peer.last_message.pop("tx", None)
+ inbound_peer.send_and_ping(want_tx)
+
+ assert_equal(inbound_peer.last_message.get("notfound").vec, req_vec)
+ assert "tx" not in inbound_peer.last_message
+
+ def test_notfound_on_unannounced_tx(self):
+ self.log.info("Check that we don't leak txs to inbound peers that we haven't yet announced to")
+ self.gen_node.disconnect_p2ps()
+ inbound_peer = self.gen_node.add_p2p_connection(P2PNode()) # An "attacking" inbound peer
MAX_REPEATS = 100
self.log.info("Running test up to {} times.".format(MAX_REPEATS))
for i in range(MAX_REPEATS):
self.log.info('Run repeat {}'.format(i + 1))
- txid = miniwallet.send_self_transfer(from_node=gen_node)['wtxid']
+ txid = self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"]
want_tx = msg_getdata()
want_tx.inv.append(CInv(t=MSG_TX, h=int(txid, 16)))
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index b0900e49b8..bfae190c66 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -14,7 +14,6 @@ from test_framework.blocktools import (
create_block,
create_coinbase,
)
-from test_framework.key import ECKey
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
CBlockHeader,
@@ -89,6 +88,7 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import MiniWallet
+from test_framework.wallet_util import generate_keypair
MAX_SIGOP_COST = 80000
@@ -1448,9 +1448,7 @@ class SegWitTest(BitcoinTestFramework):
# Segwit transactions using uncompressed pubkeys are not accepted
# under default policy, but should still pass consensus.
- key = ECKey()
- key.generate(False)
- pubkey = key.get_pubkey().get_bytes()
+ key, pubkey = generate_keypair(compressed=False)
assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
utxo = self.utxo.pop(0)
@@ -1544,11 +1542,7 @@ class SegWitTest(BitcoinTestFramework):
@subtest
def test_signature_version_1(self):
-
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
-
+ key, pubkey = generate_keypair()
witness_script = key_to_p2pk_script(pubkey)
script_pubkey = script_to_p2wsh_script(witness_script)
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index 1ccc447b89..508d6fe403 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -546,15 +546,15 @@ class SendHeadersTest(BitcoinTestFramework):
blocks = []
# Now we test that if we repeatedly don't send connecting headers, we
# don't go into an infinite loop trying to get them to connect.
- MAX_UNCONNECTING_HEADERS = 10
- for _ in range(MAX_UNCONNECTING_HEADERS + 1):
+ MAX_NUM_UNCONNECTING_HEADERS_MSGS = 10
+ for _ in range(MAX_NUM_UNCONNECTING_HEADERS_MSGS + 1):
blocks.append(create_block(tip, create_coinbase(height), block_time))
blocks[-1].solve()
tip = blocks[-1].sha256
block_time += 1
height += 1
- for i in range(1, MAX_UNCONNECTING_HEADERS):
+ for i in range(1, MAX_NUM_UNCONNECTING_HEADERS_MSGS):
# Send a header that doesn't connect, check that we get a getheaders.
with p2p_lock:
test_node.last_message.pop("getheaders", None)
@@ -568,8 +568,8 @@ class SendHeadersTest(BitcoinTestFramework):
blocks = blocks[2:]
# Now try to see how many unconnecting headers we can send
- # before we get disconnected. Should be 5*MAX_UNCONNECTING_HEADERS
- for i in range(5 * MAX_UNCONNECTING_HEADERS - 1):
+ # before we get disconnected. Should be 5*MAX_NUM_UNCONNECTING_HEADERS_MSGS
+ for i in range(5 * MAX_NUM_UNCONNECTING_HEADERS_MSGS - 1):
# Send a header that doesn't connect, check that we get a getheaders.
with p2p_lock:
test_node.last_message.pop("getheaders", None)
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 7d03ed2951..34e60d70f0 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -8,16 +8,17 @@ import itertools
import json
import os
+from test_framework.address import address_to_scriptpubkey
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create, drop_origins
-from test_framework.key import ECPubKey, ECKey
+from test_framework.key import ECPubKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_raises_rpc_error,
assert_equal,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
from test_framework.wallet import (
MiniWallet,
getnewdestination,
@@ -37,10 +38,9 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
self.priv = []
node0, node1, node2 = self.nodes
for _ in range(self.nkeys):
- k = ECKey()
- k.generate()
- self.pub.append(k.get_pubkey().get_bytes().hex())
- self.priv.append(bytes_to_wif(k.get_bytes(), k.is_compressed))
+ privkey, pubkey = generate_keypair(wif=True)
+ self.pub.append(pubkey.hex())
+ self.priv.append(privkey)
if self.is_bdb_compiled():
self.final = node2.getnewaddress()
else:
@@ -193,8 +193,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
assert mredeemw == mredeem
wmulti.unloadwallet()
- spk = bytes.fromhex(node0.validateaddress(madd)["scriptPubKey"])
- txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=spk, amount=1300)
+ spk = address_to_scriptpubkey(madd)
+ txid = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=spk, amount=1300)["txid"]
tx = node0.getrawtransaction(txid, True)
vout = [v["n"] for v in tx["vout"] if madd == v["scriptPubKey"]["address"]]
assert len(vout) == 1
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py
index 2f093bebff..1ab1023cf1 100755
--- a/test/functional/rpc_getblockfrompeer.py
+++ b/test/functional/rpc_getblockfrompeer.py
@@ -117,9 +117,11 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, error_msg, self.nodes[1].getblockfrompeer, blockhash, node1_interface_id)
self.log.info("Connect pruned node")
- # We need to generate more blocks to be able to prune
self.connect_nodes(0, 2)
pruned_node = self.nodes[2]
+ self.sync_blocks([self.nodes[0], pruned_node])
+
+ # We need to generate more blocks to be able to prune
self.generate(self.nodes[0], 400, sync_fun=self.no_op)
self.sync_blocks([self.nodes[0], pruned_node])
pruneheight = pruned_node.pruneblockchain(300)
diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py
index 1b0f411e52..2eb36f260c 100755
--- a/test/functional/rpc_getdescriptorinfo.py
+++ b/test/functional/rpc_getdescriptorinfo.py
@@ -55,9 +55,9 @@ class DescriptorTest(BitcoinTestFramework):
# A P2PK output with the public key of the specified xpub.
self.test_desc('pk(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B)', isrange=False, issolvable=True, hasprivatekeys=False)
# A P2PKH output with child key *1'/2* of the specified xpub.
- self.test_desc("pkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/2)", isrange=False, issolvable=True, hasprivatekeys=False)
+ self.test_desc("pkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1h/2)", isrange=False, issolvable=True, hasprivatekeys=False)
# A set of P2PKH outputs, but additionally specifies that the specified xpub is a child of a master with fingerprint `d34db33f`, and derived using path `44'/0'/0'`.
- self.test_desc("pkh([d34db33f/44'/0'/0']tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)", isrange=True, issolvable=True, hasprivatekeys=False)
+ self.test_desc("pkh([d34db33f/44h/0h/0h]tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)", isrange=True, issolvable=True, hasprivatekeys=False)
# A set of *1-of-2* P2WSH multisig outputs where the first multisig key is the *1/0/`i`* child of the first specified xpub and the second multisig key is the *0/0/`i`* child of the second specified xpub, and `i` is any number in a configurable range (`0-1000` by default).
self.test_desc("wsh(multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/0/*,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/0/*))", isrange=True, issolvable=True, hasprivatekeys=False)
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
index 7acc3cbbd5..53c5aa05e5 100755
--- a/test/functional/rpc_help.py
+++ b/test/functional/rpc_help.py
@@ -85,8 +85,8 @@ class HelpRpcTest(BitcoinTestFramework):
for argname, convert in converts_by_argname.items():
if all(convert) != any(convert):
- # Only allow dummy to fail consistency check
- assert argname == 'dummy', ('WARNING: conversion mismatch for argument named %s (%s)' % (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
+ # Only allow dummy and psbt to fail consistency check
+ assert argname in ['dummy', "psbt"], ('WARNING: conversion mismatch for argument named %s (%s)' % (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
def test_categories(self):
node = self.nodes[0]
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
index fd282a9bc1..6759b69dd1 100755
--- a/test/functional/rpc_invalid_address_message.py
+++ b/test/functional/rpc_invalid_address_message.py
@@ -63,12 +63,12 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
def test_validateaddress(self):
# Invalid Bech32
- self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address data size')
+ self.check_invalid(BECH32_INVALID_SIZE, "Invalid Bech32 address program size (41 bytes)")
self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid or unsupported Segwit (Bech32) or Base58 encoding.')
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_INVALID_V0_SIZE, "Invalid Bech32 v0 address program size (21 bytes), per BIP141")
self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 108)))
self.check_invalid(BECH32_ONE_ERROR, 'Invalid Bech32 checksum', [9])
self.check_invalid(BECH32_TWO_ERRORS, 'Invalid Bech32 checksum', [22, 43])
@@ -105,7 +105,7 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
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 Bech32 address program size (41 bytes)", node.getaddressinfo, BECH32_INVALID_SIZE)
assert_raises_rpc_error(-5, "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", node.getaddressinfo, BECH32_INVALID_PREFIX)
assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", node.getaddressinfo, BASE58_INVALID_PREFIX)
assert_raises_rpc_error(-5, "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", node.getaddressinfo, INVALID_ADDRESS)
diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py
index 6cb9760b3d..ae1a498e28 100755
--- a/test/functional/rpc_packages.py
+++ b/test/functional/rpc_packages.py
@@ -20,7 +20,6 @@ from test_framework.util import (
assert_raises_rpc_error,
)
from test_framework.wallet import (
- COIN,
DEFAULT_FEE,
MiniWallet,
)
@@ -325,42 +324,6 @@ class RPCPackagesTest(BitcoinTestFramework):
peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns])
self.generate(node, 1)
- def test_submit_cpfp(self):
- node = self.nodes[0]
- peer = node.add_p2p_connection(P2PTxInvStore())
-
- # Package with 2 parents and 1 child. One parent pays for itself using modified fees, and
- # another has 0 fees but is bumped by child.
- tx_poor = self.wallet.create_self_transfer(fee=0, fee_rate=0)
- tx_rich = self.wallet.create_self_transfer(fee=0, fee_rate=0)
- node.prioritisetransaction(tx_rich["txid"], 0, int(DEFAULT_FEE * COIN))
- package_txns = [tx_rich, tx_poor]
- coins = [tx["new_utxo"] for tx in package_txns]
- tx_child = self.wallet.create_self_transfer_multi(utxos_to_spend=coins, fee_per_output=10000) #DEFAULT_FEE
- package_txns.append(tx_child)
-
- submitpackage_result = node.submitpackage([tx["hex"] for tx in package_txns])
-
- rich_parent_result = submitpackage_result["tx-results"][tx_rich["wtxid"]]
- poor_parent_result = submitpackage_result["tx-results"][tx_poor["wtxid"]]
- child_result = submitpackage_result["tx-results"][tx_child["tx"].getwtxid()]
- assert_equal(rich_parent_result["fees"]["base"], 0)
- assert_equal(poor_parent_result["fees"]["base"], 0)
- assert_equal(child_result["fees"]["base"], DEFAULT_FEE)
- # The "rich" parent does not require CPFP so its effective feerate.
- assert_fee_amount(DEFAULT_FEE, tx_rich["tx"].get_vsize(), rich_parent_result["fees"]["effective-feerate"])
- assert_equal(rich_parent_result["fees"]["effective-includes"], [tx_rich["wtxid"]])
- # The "poor" parent and child's effective feerates are the same, composed of the child's fee
- # divided by their combined vsize.
- assert_fee_amount(DEFAULT_FEE, tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize(), poor_parent_result["fees"]["effective-feerate"])
- assert_fee_amount(DEFAULT_FEE, tx_poor["tx"].get_vsize() + tx_child["tx"].get_vsize(), child_result["fees"]["effective-feerate"])
- assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], poor_parent_result["fees"]["effective-includes"])
- assert_equal([tx_poor["wtxid"], tx_child["tx"].getwtxid()], child_result["fees"]["effective-includes"])
-
- # The node will broadcast each transaction, still abiding by its peer's fee filter
- peer.wait_for_broadcast([tx["tx"].getwtxid() for tx in package_txns])
- self.generate(node, 1)
-
def test_submitpackage(self):
node = self.nodes[0]
@@ -369,9 +332,6 @@ class RPCPackagesTest(BitcoinTestFramework):
self.test_submit_child_with_parents(num_parents, False)
self.test_submit_child_with_parents(num_parents, True)
- self.log.info("Submitpackage valid packages with CPFP")
- self.test_submit_cpfp()
-
self.log.info("Submitpackage only allows packages of 1 child with its parents")
# Chain of 3 transactions has too many generations
chain_hex = [t["hex"] for t in self.wallet.create_self_transfer_chain(chain_length=25)]
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 0fc0c0df8b..c4ed4da0f2 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -8,7 +8,7 @@ from decimal import Decimal
from itertools import product
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey, H_POINT
+from test_framework.key import H_POINT
from test_framework.messages import (
COutPoint,
CTransaction,
@@ -42,7 +42,10 @@ from test_framework.util import (
find_vout_for_address,
random_bytes,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import (
+ generate_keypair,
+ get_generate_key,
+)
import json
import os
@@ -373,7 +376,7 @@ class PSBTTest(BitcoinTestFramework):
self.log.info("Test various PSBT operations")
# partially sign multisig things with node 1
- psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():29.99}, options={'changeAddress': self.nodes[1].getrawchangeaddress()})['psbt']
+ psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():29.99}, changeAddress=self.nodes[1].getrawchangeaddress())['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
psbtx = walletprocesspsbt_out['psbt']
assert_equal(walletprocesspsbt_out['complete'], False)
@@ -397,17 +400,15 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].decodepsbt(new_psbt)
# Make sure that a non-psbt with signatures cannot be converted
- # Error could be either "TX decode failed" (segwit inputs causes parsing to fail) or "Inputs must not have scriptSigs and scriptWitnesses"
- # We must set iswitness=True because the serialized transaction has inputs and is therefore a witness transaction
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
- assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], iswitness=True)
- assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], permitsigdata=False, iswitness=True)
+ assert_raises_rpc_error(-22, "Inputs must not have scriptSigs and scriptWitnesses",
+ self.nodes[0].converttopsbt, hexstring=signedtx['hex']) # permitsigdata=False by default
+ assert_raises_rpc_error(-22, "Inputs must not have scriptSigs and scriptWitnesses",
+ self.nodes[0].converttopsbt, hexstring=signedtx['hex'], permitsigdata=False)
+ assert_raises_rpc_error(-22, "Inputs must not have scriptSigs and scriptWitnesses",
+ self.nodes[0].converttopsbt, hexstring=signedtx['hex'], permitsigdata=False, iswitness=True)
# Unless we allow it to convert and strip signatures
- self.nodes[0].converttopsbt(signedtx['hex'], True)
-
- # Explicitly allow converting non-empty txs
- new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
- self.nodes[0].decodepsbt(new_psbt)
+ self.nodes[0].converttopsbt(hexstring=signedtx['hex'], permitsigdata=True)
# Create outputs to nodes 1 and 2
node1_addr = self.nodes[1].getnewaddress()
@@ -621,17 +622,17 @@ class PSBTTest(BitcoinTestFramework):
# Bech32 inputs should be filled with witness UTXO. Other inputs should not be filled because they are non-witness
updated = self.nodes[1].utxoupdatepsbt(psbt)
decoded = self.nodes[1].decodepsbt(updated)
- test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo'])
- test_psbt_input_keys(decoded['inputs'][1], [])
- test_psbt_input_keys(decoded['inputs'][2], [])
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo'])
+ test_psbt_input_keys(decoded['inputs'][1], ['non_witness_utxo'])
+ test_psbt_input_keys(decoded['inputs'][2], ['non_witness_utxo'])
# Try again, now while providing descriptors, making P2SH-segwit work, and causing bip32_derivs and redeem_script to be filled in
descs = [self.nodes[1].getaddressinfo(addr)['desc'] for addr in [addr1,addr2,addr3]]
updated = self.nodes[1].utxoupdatepsbt(psbt=psbt, descriptors=descs)
decoded = self.nodes[1].decodepsbt(updated)
- test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'bip32_derivs'])
- test_psbt_input_keys(decoded['inputs'][1], [])
- test_psbt_input_keys(decoded['inputs'][2], ['witness_utxo', 'bip32_derivs', 'redeem_script'])
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo', 'bip32_derivs'])
+ test_psbt_input_keys(decoded['inputs'][1], ['non_witness_utxo', 'bip32_derivs'])
+ test_psbt_input_keys(decoded['inputs'][2], ['non_witness_utxo','witness_utxo', 'bip32_derivs', 'redeem_script'])
# Two PSBTs with a common input should not be joinable
psbt1 = self.nodes[1].createpsbt([{"txid":txid1, "vout":vout1}], {self.nodes[0].getnewaddress():Decimal('10.999')})
@@ -709,9 +710,7 @@ class PSBTTest(BitcoinTestFramework):
self.log.info("Test that we can fund psbts with external inputs specified")
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, _ = generate_keypair(wif=True)
self.nodes[1].createwallet("extfund")
wallet = self.nodes[1].get_wallet_rpc("extfund")
@@ -778,7 +777,7 @@ class PSBTTest(BitcoinTestFramework):
psbt = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
outputs={self.nodes[0].getnewaddress(): 15},
- options={"add_inputs": True}
+ add_inputs=True,
)
signed = wallet.walletprocesspsbt(psbt["psbt"])
signed = self.nodes[0].walletprocesspsbt(signed["psbt"])
@@ -788,21 +787,21 @@ class PSBTTest(BitcoinTestFramework):
psbt2 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15},
- options={"add_inputs": True}
+ add_inputs=True,
)
assert_greater_than(psbt["fee"], psbt2["fee"])
# Increasing the weight should have a higher fee
psbt2 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15},
- options={"add_inputs": True}
+ add_inputs=True,
)
assert_greater_than(psbt2["fee"], psbt["fee"])
# The provided weight should override the calculated weight when solving data is provided
psbt3 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15},
- options={'add_inputs': True, "solving_data":{"descriptors": [desc]}}
+ add_inputs=True, solving_data={"descriptors": [desc]},
)
assert_equal(psbt2["fee"], psbt3["fee"])
@@ -816,7 +815,7 @@ class PSBTTest(BitcoinTestFramework):
psbt3 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15},
- options={"add_inputs": True}
+ add_inputs=True,
)
assert_equal(psbt2["fee"], psbt3["fee"])
@@ -824,11 +823,9 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[1].createwallet(wallet_name="scriptwatchonly", disable_private_keys=True)
watchonly = self.nodes[1].get_wallet_rpc("scriptwatchonly")
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
- desc = descsum_create("wsh(pkh({}))".format(eckey.get_pubkey().get_bytes().hex()))
+ desc = descsum_create("wsh(pkh({}))".format(pubkey.hex()))
if self.options.descriptors:
res = watchonly.importdescriptors([{"desc": desc, "timestamp": "now"}])
else:
@@ -845,11 +842,9 @@ class PSBTTest(BitcoinTestFramework):
# Same test but for taproot
if self.options.descriptors:
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
- desc = descsum_create("tr({},pk({}))".format(H_POINT, eckey.get_pubkey().get_bytes().hex()))
+ desc = descsum_create("tr({},pk({}))".format(H_POINT, pubkey.hex()))
res = watchonly.importdescriptors([{"desc": desc, "timestamp": "now"}])
assert res[0]["success"]
addr = self.nodes[0].deriveaddresses(desc)[0]
@@ -944,6 +939,48 @@ class PSBTTest(BitcoinTestFramework):
self.log.info("Test we don't crash when making a 0-value funded transaction at 0 fee without forcing an input selection")
assert_raises_rpc_error(-4, "Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input", self.nodes[0].walletcreatefundedpsbt, [], [{"data": "deadbeef"}], 0, {"fee_rate": "0"})
+ self.log.info("Test descriptorprocesspsbt updates and signs a psbt with descriptors")
+
+ self.generate(self.nodes[2], 1)
+
+ # Disable the wallet for node 2 since `descriptorprocesspsbt` does not use the wallet
+ self.restart_node(2, extra_args=["-disablewallet"])
+ self.connect_nodes(0, 2)
+ self.connect_nodes(1, 2)
+
+ key_info = get_generate_key()
+ key = key_info.privkey
+ address = key_info.p2wpkh_addr
+
+ descriptor = descsum_create(f"wpkh({key})")
+
+ txid = self.nodes[0].sendtoaddress(address, 1)
+ self.sync_all()
+ vout = find_output(self.nodes[0], txid, 1)
+
+ psbt = self.nodes[2].createpsbt([{"txid": txid, "vout": vout}], {self.nodes[0].getnewaddress(): 0.99999})
+ decoded = self.nodes[2].decodepsbt(psbt)
+ test_psbt_input_keys(decoded['inputs'][0], [])
+
+ # Test that even if the wrong descriptor is given, `witness_utxo` and `non_witness_utxo`
+ # are still added to the psbt
+ alt_descriptor = descsum_create(f"wpkh({get_generate_key().privkey})")
+ alt_psbt = self.nodes[2].descriptorprocesspsbt(psbt=psbt, descriptors=[alt_descriptor], sighashtype="ALL")["psbt"]
+ decoded = self.nodes[2].decodepsbt(alt_psbt)
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo'])
+
+ # Test that the psbt is not finalized and does not have bip32_derivs unless specified
+ psbt = self.nodes[2].descriptorprocesspsbt(psbt=psbt, descriptors=[descriptor], sighashtype="ALL", bip32derivs=True, finalize=False)["psbt"]
+ decoded = self.nodes[2].decodepsbt(psbt)
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo', 'partial_signatures', 'bip32_derivs'])
+
+ psbt = self.nodes[2].descriptorprocesspsbt(psbt=psbt, descriptors=[descriptor], sighashtype="ALL", bip32derivs=False, finalize=True)["psbt"]
+ decoded = self.nodes[2].decodepsbt(psbt)
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo', 'final_scriptwitness'])
+
+ # Broadcast transaction
+ rawtx = self.nodes[2].finalizepsbt(psbt)["hex"]
+ self.nodes[2].sendrawtransaction(rawtx)
if __name__ == '__main__':
PSBTTest().main()
diff --git a/test/functional/rpc_scanblocks.py b/test/functional/rpc_scanblocks.py
index 126e95362b..8b4aebc77a 100755
--- a/test/functional/rpc_scanblocks.py
+++ b/test/functional/rpc_scanblocks.py
@@ -3,6 +3,7 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the scanblocks RPC call."""
+from test_framework.address import address_to_scriptpubkey
from test_framework.blockfilter import (
bip158_basic_element_hash,
bip158_relevant_scriptpubkeys,
@@ -36,7 +37,7 @@ class ScanblocksTest(BitcoinTestFramework):
# send 1.0, mempool only
# childkey 5 of `parent_key`
wallet.send_to(from_node=node,
- scriptPubKey=bytes.fromhex(node.validateaddress("mkS4HXoTYWRTescLGaUTGbtTTYX5EjJyEE")['scriptPubKey']),
+ scriptPubKey=address_to_scriptpubkey("mkS4HXoTYWRTescLGaUTGbtTTYX5EjJyEE"),
amount=1 * COIN)
# mine a block and assure that the mined blockhash is in the filterresult
@@ -48,6 +49,7 @@ class ScanblocksTest(BitcoinTestFramework):
assert blockhash in out['relevant_blocks']
assert_equal(height, out['to_height'])
assert_equal(0, out['from_height'])
+ assert_equal(True, out['completed'])
# mine another block
blockhash_new = self.generate(node, 1)[0]
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
index 507a4f48e5..9f77f209ef 100755
--- a/test/functional/rpc_scantxoutset.py
+++ b/test/functional/rpc_scantxoutset.py
@@ -3,12 +3,12 @@
# 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."""
+from test_framework.address import address_to_scriptpubkey
from test_framework.messages import COIN
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
from test_framework.wallet import (
MiniWallet,
- address_to_scriptpubkey,
getnewdestination,
)
@@ -112,7 +112,7 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": [1500, 1500]}])['total_amount'], Decimal("16.384"))
# Test the reported descriptors for a few matches
- assert_equal(descriptors(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0'/*)", "range": 1499}])), ["pkh([0c5f9a1e/0'/0'/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#dzxw429x", "pkh([0c5f9a1e/0'/0'/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#43rvceed"])
+ assert_equal(descriptors(self.nodes[0].scantxoutset("start", [{"desc": "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0h/0h/*)", "range": 1499}])), ["pkh([0c5f9a1e/0h/0h/0]026dbd8b2315f296d36e6b6920b1579ca75569464875c7ebe869b536a7d9503c8c)#rthll0rg", "pkh([0c5f9a1e/0h/0h/1]033e6f25d76c00bedb3a8993c7d5739ee806397f0529b1b31dda31ef890f19a60c)#mcjajulr"])
assert_equal(descriptors(self.nodes[0].scantxoutset("start", ["combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"])), ["pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8"])
assert_equal(descriptors(self.nodes[0].scantxoutset("start", [{"desc": "combo(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/*)", "range": 1500}])), ['pkh([0c5f9a1e/1/1/0]03e1c5b6e650966971d7e71ef2674f80222752740fc1dfd63bbbd220d2da9bd0fb)#cxmct4w8', 'pkh([0c5f9a1e/1/1/1500]03832901c250025da2aebae2bfb38d5c703a57ab66ad477f9c578bfbcd78abca6f)#vchwd07g', 'pkh([0c5f9a1e/1/1/1]030d820fc9e8211c4169be8530efbc632775d8286167afd178caaf1089b77daba7)#z2t3ypsa'])
@@ -120,9 +120,15 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].scantxoutset("status"), None)
assert_equal(self.nodes[0].scantxoutset("abort"), False)
+ # check that first arg is needed
+ assert_raises_rpc_error(-1, "scantxoutset \"action\" ( [scanobjects,...] )", self.nodes[0].scantxoutset)
+
# Check that second arg is needed for start
assert_raises_rpc_error(-1, "scanobjects argument is required for the start action", self.nodes[0].scantxoutset, "start")
+ # Check that invalid command give error
+ assert_raises_rpc_error(-8, "Invalid action 'invalid_command'", self.nodes[0].scantxoutset, "invalid_command")
+
if __name__ == "__main__":
ScantxoutsetTest().main()
diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py
index 97354f480c..b4f3d77e5b 100755
--- a/test/functional/rpc_setban.py
+++ b/test/functional/rpc_setban.py
@@ -6,7 +6,8 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
- p2p_port
+ p2p_port,
+ assert_equal,
)
class SetBanTests(BitcoinTestFramework):
@@ -70,6 +71,11 @@ class SetBanTests(BitcoinTestFramework):
assert not self.is_banned(node, tor_addr)
assert not self.is_banned(node, ip_addr)
+ self.log.info("Test -bantime")
+ self.restart_node(1, ["-bantime=1234"])
+ self.nodes[1].setban("127.0.0.1", "add")
+ banned = self.nodes[1].listbanned()[0]
+ assert_equal(banned['ban_duration'], 1234)
if __name__ == '__main__':
SetBanTests().main()
diff --git a/test/functional/rpc_signrawtransactionwithkey.py b/test/functional/rpc_signrawtransactionwithkey.py
index 0da5a99fdb..ac7a86704f 100755
--- a/test/functional/rpc_signrawtransactionwithkey.py
+++ b/test/functional/rpc_signrawtransactionwithkey.py
@@ -8,9 +8,9 @@ from test_framework.blocktools import (
COINBASE_MATURITY,
)
from test_framework.address import (
+ address_to_scriptpubkey,
script_to_p2sh,
)
-from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -22,16 +22,16 @@ from test_framework.script_util import (
script_to_p2sh_p2wsh_script,
script_to_p2wsh_script,
)
+from test_framework.wallet import (
+ getnewdestination,
+)
from test_framework.wallet_util import (
- bytes_to_wif,
+ generate_keypair,
)
from decimal import (
Decimal,
)
-from test_framework.wallet import (
- getnewdestination,
-)
class SignRawTransactionWithKeyTest(BitcoinTestFramework):
@@ -79,11 +79,8 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework):
def witness_script_test(self):
self.log.info("Test signing transaction to P2SH-P2WSH addresses without wallet")
# Create a new P2SH-P2WSH 1-of-1 multisig address:
- eckey = ECKey()
- eckey.generate()
- embedded_privkey = bytes_to_wif(eckey.get_bytes())
- embedded_pubkey = eckey.get_pubkey().get_bytes().hex()
- p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey], "p2sh-segwit")
+ embedded_privkey, embedded_pubkey = generate_keypair(wif=True)
+ p2sh_p2wsh_address = self.nodes[1].createmultisig(1, [embedded_pubkey.hex()], "p2sh-segwit")
# send transaction to P2SH-P2WSH 1-of-1 multisig address
self.block_hash = self.generate(self.nodes[0], COINBASE_MATURITY + 1)
self.blk_idx = 0
@@ -108,17 +105,14 @@ class SignRawTransactionWithKeyTest(BitcoinTestFramework):
def verify_txn_with_witness_script(self, tx_type):
self.log.info("Test with a {} script as the witnessScript".format(tx_type))
- eckey = ECKey()
- eckey.generate()
- embedded_privkey = bytes_to_wif(eckey.get_bytes())
- embedded_pubkey = eckey.get_pubkey().get_bytes().hex()
+ embedded_privkey, embedded_pubkey = generate_keypair(wif=True)
witness_script = {
'P2PKH': key_to_p2pkh_script(embedded_pubkey).hex(),
'P2PK': key_to_p2pk_script(embedded_pubkey).hex()
}.get(tx_type, "Invalid tx_type")
redeem_script = script_to_p2wsh_script(witness_script).hex()
addr = script_to_p2sh(redeem_script)
- script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey']
+ script_pub_key = address_to_scriptpubkey(addr).hex()
# Fund that address
txid = self.send_to_address(addr, 10)
vout = find_vout_for_address(self.nodes[0], txid, addr)
diff --git a/test/functional/rpc_validateaddress.py b/test/functional/rpc_validateaddress.py
new file mode 100755
index 0000000000..d87ba098c3
--- /dev/null
+++ b/test/functional/rpc_validateaddress.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 validateaddress for main chain"""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+from test_framework.util import assert_equal
+
+INVALID_DATA = [
+ # BIP 173
+ (
+ "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # Invalid hrp
+ [],
+ ),
+ ("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "Invalid Bech32 checksum", [41]),
+ (
+ "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
+ "Version 1+ witness address must use Bech32m checksum",
+ [],
+ ),
+ (
+ "bc1rw5uspcuh",
+ "Version 1+ witness address must use Bech32m checksum", # Invalid program length
+ [],
+ ),
+ (
+ "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
+ "Version 1+ witness address must use Bech32m checksum", # Invalid program length
+ [],
+ ),
+ (
+ "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
+ "Invalid Bech32 v0 address program size (16 bytes), per BIP141",
+ [],
+ ),
+ (
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Mixed case
+ [],
+ ),
+ (
+ "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3t4",
+ "Invalid character or mixed case", # bc1, Mixed case, not in BIP 173 test vectors
+ [40],
+ ),
+ (
+ "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
+ "Version 1+ witness address must use Bech32m checksum", # Wrong padding
+ [],
+ ),
+ (
+ "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Non-zero padding in 8-to-5 conversion
+ [],
+ ),
+ ("bc1gmk9yu", "Empty Bech32 data section", []),
+ # BIP 350
+ (
+ "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # Invalid human-readable part
+ [],
+ ),
+ (
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
+ "Version 1+ witness address must use Bech32m checksum", # Invalid checksum (Bech32 instead of Bech32m)
+ [],
+ ),
+ (
+ "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Invalid checksum (Bech32 instead of Bech32m)
+ [],
+ ),
+ (
+ "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
+ "Version 1+ witness address must use Bech32m checksum", # Invalid checksum (Bech32 instead of Bech32m)
+ [],
+ ),
+ (
+ "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh",
+ "Version 0 witness address must use Bech32 checksum", # Invalid checksum (Bech32m instead of Bech32)
+ [],
+ ),
+ (
+ "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Invalid checksum (Bech32m instead of Bech32)
+ [],
+ ),
+ (
+ "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
+ "Invalid Base 32 character", # Invalid character in checksum
+ [59],
+ ),
+ (
+ "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
+ "Invalid Bech32 address witness version",
+ [],
+ ),
+ ("bc1pw5dgrnzv", "Invalid Bech32 address program size (1 byte)", []),
+ (
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav",
+ "Invalid Bech32 address program size (41 bytes)",
+ [],
+ ),
+ (
+ "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
+ "Invalid Bech32 v0 address program size (16 bytes), per BIP141",
+ [],
+ ),
+ (
+ "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Mixed case
+ [],
+ ),
+ (
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf",
+ "Invalid padding in Bech32 data section", # zero padding of more than 4 bits
+ [],
+ ),
+ (
+ "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
+ "Invalid or unsupported Segwit (Bech32) or Base58 encoding.", # tb1, Non-zero padding in 8-to-5 conversion
+ [],
+ ),
+ ("bc1gmk9yu", "Empty Bech32 data section", []),
+]
+VALID_DATA = [
+ # BIP 350
+ (
+ "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
+ "0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ ),
+ # (
+ # "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
+ # "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ # ),
+ (
+ "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3",
+ "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ ),
+ (
+ "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
+ "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
+ ),
+ ("BC1SW50QGDZ25J", "6002751e"),
+ ("bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", "5210751e76e8199196d454941c45d1b3a323"),
+ # (
+ # "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
+ # "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ # ),
+ (
+ "bc1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvses5wp4dt",
+ "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ ),
+ # (
+ # "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c",
+ # "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ # ),
+ (
+ "bc1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvses7epu4h",
+ "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
+ ),
+ (
+ "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0",
+ "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ ),
+]
+
+
+class ValidateAddressMainTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.chain = "" # main
+ self.num_nodes = 1
+ self.extra_args = [["-prune=899"]] * self.num_nodes
+
+ def check_valid(self, addr, spk):
+ info = self.nodes[0].validateaddress(addr)
+ assert_equal(info["isvalid"], True)
+ assert_equal(info["scriptPubKey"], spk)
+ assert "error" not in info
+ assert "error_locations" not in info
+
+ def check_invalid(self, addr, error_str, error_locations):
+ res = self.nodes[0].validateaddress(addr)
+ assert_equal(res["isvalid"], False)
+ assert_equal(res["error"], error_str)
+ assert_equal(res["error_locations"], error_locations)
+
+ def test_validateaddress(self):
+ for (addr, error, locs) in INVALID_DATA:
+ self.check_invalid(addr, error, locs)
+ for (addr, spk) in VALID_DATA:
+ self.check_valid(addr, spk)
+
+ def run_test(self):
+ self.test_validateaddress()
+
+
+if __name__ == "__main__":
+ ValidateAddressMainTest().main()
diff --git a/test/functional/test-shell.md b/test/functional/test-shell.md
index 80f4e88109..b89b40f13d 100644
--- a/test/functional/test-shell.md
+++ b/test/functional/test-shell.md
@@ -37,13 +37,13 @@ importing the `TestShell` class from the `test_shell` sub-package.
The following `TestShell` methods manage the lifetime of the underlying bitcoind
processes and logging utilities.
-* `TestShell.setup()`
-* `TestShell.shutdown()`
+* `TestShell().setup()`
+* `TestShell().shutdown()`
The `TestShell` inherits all `BitcoinTestFramework` members and methods, such
as:
-* `TestShell.nodes[index].rpc_method()`
-* `TestShell.log.info("Custom log message")`
+* `TestShell().nodes[index].rpc_method()`
+* `TestShell().log.info("Custom log message")`
The following sections demonstrate how to initialize, run, and shut down a
`TestShell` object.
@@ -143,7 +143,7 @@ instances and remove all temporary data and logging directories.
20XX-XX-XXTXX:XX:XX.XXXXXXX TestFramework (INFO): Tests successful
```
To prevent the logs from being removed after a shutdown, simply set the
-`TestShell.options.nocleanup` member to `True`.
+`TestShell().options.nocleanup` member to `True`.
```
>>> test.options.nocleanup = True
>>> test.shutdown()
@@ -162,9 +162,9 @@ underlying `BitcoinTestFramework`:
The `TestShell` object initializes with the default settings inherited from the
`BitcoinTestFramework` class. The user can override these in
-`TestShell.setup(key=value)`.
+`TestShell().setup(key=value)`.
-**Note:** `TestShell.reset()` will reset test parameters to default values and
+**Note:** `TestShell().reset()` will reset test parameters to default values and
can be called after the TestShell is shut down.
| Test parameter key | Default Value | Description |
@@ -181,7 +181,7 @@ can be called after the TestShell is shut down.
| `perf` | False | Profiles running nodes with `perf` for the duration of the test if set to `True`. |
| `rpc_timeout` | `60` | Sets the RPC server timeout for the underlying bitcoind processes. |
| `setup_clean_chain` | `False` | A 200-block-long chain is initialized from cache by default. Instead, `setup_clean_chain` initializes an empty blockchain if set to `True`. |
-| `randomseed` | Random Integer | `TestShell.options.randomseed` is a member of `TestShell` which can be accessed during a test to seed a random generator. User can override default with a constant value for reproducible test runs. |
+| `randomseed` | Random Integer | `TestShell().options.randomseed` is a member of `TestShell` which can be accessed during a test to seed a random generator. User can override default with a constant value for reproducible test runs. |
| `supports_cli` | `False` | Whether the bitcoin-cli utility is compiled and available for the test. |
| `tmpdir` | `"/var/folders/.../"` | Sets directory for test logs. Will be deleted upon a successful test run unless `nocleanup` is set to `True` |
| `trace_rpc` | `False` | Logs all RPC calls if set to `True`. |
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index d1bf186b9d..5b2e3289a9 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -21,11 +21,17 @@ from .script import (
taproot_construct,
)
from .util import assert_equal
+from test_framework.script_util import (
+ keyhash_to_p2pkh_script,
+ program_to_witness_script,
+ scripthash_to_p2sh_script,
+)
from test_framework.segwit_addr import (
decode_segwit_address,
encode_segwit_address,
)
+
ADDRESS_BCRT1_UNSPENDABLE = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj'
ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR = 'addr(bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj)#juyq9d97'
# Coins sent to this address can be spent with a witness stack of just OP_TRUE
@@ -172,6 +178,21 @@ def bech32_to_bytes(address):
return version, bytearray(payload)
+def address_to_scriptpubkey(address):
+ """Converts a given address to the corresponding output script (scriptPubKey)."""
+ version, payload = bech32_to_bytes(address)
+ if version is not None:
+ return program_to_witness_script(version, payload) # testnet segwit scriptpubkey
+ payload, version = base58_to_byte(address)
+ if version == 111: # testnet pubkey hash
+ return keyhash_to_p2pkh_script(payload)
+ elif version == 196: # testnet script hash
+ return scripthash_to_p2sh_script(payload)
+ # TODO: also support other address formats
+ else:
+ assert False
+
+
class TestFrameworkScript(unittest.TestCase):
def test_base58encodedecode(self):
def check_base58(data, version):
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index 61f92aeac3..f7765a9dfa 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -39,7 +39,6 @@ from http import HTTPStatus
import http.client
import json
import logging
-import os
import socket
import time
import urllib.parse
@@ -94,36 +93,14 @@ class AuthServiceProxy():
def _request(self, method, path, postdata):
'''
- Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout).
- This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5.
+ Do a HTTP request.
'''
headers = {'Host': self.__url.hostname,
'User-Agent': USER_AGENT,
'Authorization': self.__auth_header,
'Content-type': 'application/json'}
- if os.name == 'nt':
- # Windows somehow does not like to re-use connections
- # TODO: Find out why the connection would disconnect occasionally and make it reusable on Windows
- # Avoid "ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine"
- self._set_conn()
- try:
- self.__conn.request(method, path, postdata, headers)
- return self._get_response()
- except (BrokenPipeError, ConnectionResetError):
- # Python 3.5+ raises BrokenPipeError when the connection was reset
- # ConnectionResetError happens on FreeBSD
- self.__conn.close()
- self.__conn.request(method, path, postdata, headers)
- return self._get_response()
- except OSError as e:
- # Workaround for a bug on macOS. See https://bugs.python.org/issue33450
- retry = '[Errno 41] Protocol wrong type for socket' in str(e)
- if retry:
- self.__conn.close()
- self.__conn.request(method, path, postdata, headers)
- return self._get_response()
- else:
- raise
+ self.__conn.request(method, path, postdata, headers)
+ return self._get_response()
def get_request(self, *args, **argsn):
AuthServiceProxy.__id_count += 1
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index b08cc6a3f9..cfd923bab3 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -9,6 +9,7 @@ import time
import unittest
from .address import (
+ address_to_scriptpubkey,
key_to_p2sh_p2wpkh,
key_to_p2wpkh,
script_to_p2sh_p2wsh,
@@ -205,7 +206,7 @@ def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
else:
addr = key_to_p2sh_p2wpkh(pubkey) if encode_p2sh else key_to_p2wpkh(pubkey)
if not encode_p2sh:
- assert_equal(node.getaddressinfo(addr)['scriptPubKey'], witness_script(use_p2wsh, pubkey))
+ assert_equal(address_to_scriptpubkey(addr).hex(), witness_script(use_p2wsh, pubkey))
return node.createrawtransaction([utxo], {addr: amount})
def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index ad305ce1ef..efb4934ff0 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -13,8 +13,6 @@ import os
import random
import unittest
-from .util import modinv
-
# Point with no known discrete log.
H_POINT = "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"
@@ -78,7 +76,7 @@ class EllipticCurve:
x1, y1, z1 = p1
if z1 == 0:
return None
- inv = modinv(z1, self.p)
+ inv = pow(z1, -1, self.p)
inv_2 = (inv**2) % self.p
inv_3 = (inv_2 * inv) % self.p
return ((inv_2 * x1) % self.p, (inv_3 * y1) % self.p, 1)
@@ -319,7 +317,7 @@ class ECPubKey():
z = int.from_bytes(msg, 'big')
# Run verifier algorithm on r, s
- w = modinv(s, SECP256K1_ORDER)
+ w = pow(s, -1, SECP256K1_ORDER)
u1 = z*w % SECP256K1_ORDER
u2 = r*w % SECP256K1_ORDER
R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, u1), (self.p, u2)]))
@@ -397,7 +395,7 @@ class ECKey():
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
+ s = (pow(k, -1, SECP256K1_ORDER) * (z + self.secret * r)) % SECP256K1_ORDER
if low_s and s > SECP256K1_ORDER_HALF:
s = SECP256K1_ORDER - s
# Represent in DER format. The byte representations of r and s have
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 8c6f68cacb..a6764365c5 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -93,6 +93,7 @@ def ser_compact_size(l):
r = struct.pack("<BQ", 255, l)
return r
+
def deser_compact_size(f):
nit = struct.unpack("<B", f.read(1))[0]
if nit == 253:
@@ -103,35 +104,26 @@ def deser_compact_size(f):
nit = struct.unpack("<Q", f.read(8))[0]
return nit
+
def deser_string(f):
nit = deser_compact_size(f)
return f.read(nit)
+
def ser_string(s):
return ser_compact_size(len(s)) + s
+
def deser_uint256(f):
- r = 0
- for i in range(8):
- t = struct.unpack("<I", f.read(4))[0]
- r += t << (i * 32)
- return r
+ return int.from_bytes(f.read(32), 'little')
def ser_uint256(u):
- rs = b""
- for _ in range(8):
- rs += struct.pack("<I", u & 0xFFFFFFFF)
- u >>= 32
- return rs
+ return u.to_bytes(32, 'little')
def uint256_from_str(s):
- r = 0
- t = struct.unpack("<IIIIIIII", s[:32])
- for i in range(8):
- r += t[i] << (i * 32)
- return r
+ return int.from_bytes(s[:32], 'little')
def uint256_from_compact(c):
diff --git a/test/functional/test_framework/muhash.py b/test/functional/test_framework/muhash.py
index 183548f71f..0d96114e3e 100644
--- a/test/functional/test_framework/muhash.py
+++ b/test/functional/test_framework/muhash.py
@@ -6,8 +6,6 @@
import hashlib
import unittest
-from .util import modinv
-
def rot32(v, bits):
"""Rotate the 32-bit value v left by bits bits."""
bits %= 32 # Make sure the term below does not throw an exception
@@ -88,7 +86,7 @@ class MuHash3072:
def digest(self):
"""Extract the final hash. Does not modify this object."""
- val = (self.numerator * modinv(self.denominator, self.MODULUS)) % self.MODULUS
+ val = (self.numerator * pow(self.denominator, -1, self.MODULUS)) % self.MODULUS
bytes384 = val.to_bytes(384, 'little')
return hashlib.sha256(bytes384).digest()
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 66a23b443c..d4dc90a517 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -228,6 +228,23 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
PortSeed.n = self.options.port_seed
+ def set_binary_paths(self):
+ """Update self.options with the paths of all binaries from environment variables or their default values"""
+
+ binaries = {
+ "bitcoind": ("bitcoind", "BITCOIND"),
+ "bitcoin-cli": ("bitcoincli", "BITCOINCLI"),
+ "bitcoin-util": ("bitcoinutil", "BITCOINUTIL"),
+ "bitcoin-wallet": ("bitcoinwallet", "BITCOINWALLET"),
+ }
+ for binary, [attribute_name, env_variable_name] in binaries.items():
+ default_filename = os.path.join(
+ self.config["environment"]["BUILDDIR"],
+ "src",
+ binary + self.config["environment"]["EXEEXT"],
+ )
+ setattr(self.options, attribute_name, os.getenv(env_variable_name, default=default_filename))
+
def setup(self):
"""Call this method to start up the test framework object with options set."""
@@ -237,24 +254,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
config = self.config
- fname_bitcoind = os.path.join(
- config["environment"]["BUILDDIR"],
- "src",
- "bitcoind" + config["environment"]["EXEEXT"],
- )
- fname_bitcoincli = os.path.join(
- config["environment"]["BUILDDIR"],
- "src",
- "bitcoin-cli" + config["environment"]["EXEEXT"],
- )
- fname_bitcoinutil = os.path.join(
- config["environment"]["BUILDDIR"],
- "src",
- "bitcoin-util" + config["environment"]["EXEEXT"],
- )
- self.options.bitcoind = os.getenv("BITCOIND", default=fname_bitcoind)
- self.options.bitcoincli = os.getenv("BITCOINCLI", default=fname_bitcoincli)
- self.options.bitcoinutil = os.getenv("BITCOINUTIL", default=fname_bitcoinutil)
+ self.set_binary_paths()
os.environ['PATH'] = os.pathsep.join([
os.path.join(config['environment']['BUILDDIR'], 'src'),
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 56abe5f26a..9583d6f7d7 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -190,7 +190,7 @@ class TestNode():
assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection")
return getattr(RPCOverloadWrapper(self.rpc, descriptors=self.descriptors), name)
- def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs):
+ def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, env=None, **kwargs):
"""Start the node."""
if extra_args is None:
extra_args = self.extra_args
@@ -213,6 +213,8 @@ class TestNode():
# add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal
subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1")
+ if env is not None:
+ subp_env.update(env)
self.process = subprocess.Popen(self.args + extra_args, env=subp_env, stdout=stdout, stderr=stderr, cwd=cwd, **kwargs)
@@ -363,7 +365,7 @@ class TestNode():
if wait_until_stopped:
self.wait_until_stopped()
- def is_node_stopped(self):
+ def is_node_stopped(self, expected_ret_code=0):
"""Checks whether the node has stopped.
Returns True if the node has stopped. False otherwise.
@@ -375,8 +377,8 @@ class TestNode():
return False
# process has stopped. Assert that it didn't return an error code.
- assert return_code == 0, self._node_msg(
- "Node returned non-zero exit code (%d) when stopping" % return_code)
+ assert return_code == expected_ret_code, self._node_msg(
+ f"Node returned unexpected exit code ({return_code}) vs ({expected_ret_code}) when stopping")
self.running = False
self.process = None
self.rpc_connected = False
@@ -384,8 +386,9 @@ class TestNode():
self.log.debug("Node stopped")
return True
- def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
- wait_until_helper(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor)
+ def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT, expect_error=False):
+ expected_ret_code = 1 if expect_error else 0 # Whether node shutdown return EXIT_FAILURE or EXIT_SUCCESS
+ wait_until_helper(lambda: self.is_node_stopped(expected_ret_code=expected_ret_code), timeout=timeout, timeout_factor=self.timeout_factor)
def replace_in_config(self, replacements):
"""
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 9048a915b2..d3b3e4d536 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -12,14 +12,15 @@ import inspect
import json
import logging
import os
+import pathlib
import random
import re
+import sys
import time
-import unittest
from . import coverage
from .authproxy import AuthServiceProxy, JSONRPCException
-from typing import Callable, Optional
+from typing import Callable, Optional, Tuple
logger = logging.getLogger("TestFramework.utils")
@@ -390,6 +391,8 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect=
f.write("[{}]\n".format(chain_name_conf_section))
f.write("port=" + str(p2p_port(n)) + "\n")
f.write("rpcport=" + str(rpc_port(n)) + "\n")
+ # Disable server-side timeouts to avoid intermittent issues
+ f.write("rpcservertimeout=99000\n")
f.write("rpcdoccheck=1\n")
f.write("fallbackfee=0.0002\n")
f.write("server=1\n")
@@ -418,6 +421,22 @@ def get_datadir_path(dirname, n):
return os.path.join(dirname, "node" + str(n))
+def get_temp_default_datadir(temp_dir: pathlib.Path) -> Tuple[dict, pathlib.Path]:
+ """Return os-specific environment variables that can be set to make the
+ GetDefaultDataDir() function return a datadir path under the provided
+ temp_dir, as well as the complete path it would return."""
+ if sys.platform == "win32":
+ env = dict(APPDATA=str(temp_dir))
+ datadir = temp_dir / "Bitcoin"
+ else:
+ env = dict(HOME=str(temp_dir))
+ if sys.platform == "darwin":
+ datadir = temp_dir / "Library/Application Support/Bitcoin"
+ else:
+ datadir = temp_dir / ".bitcoin"
+ return env, datadir
+
+
def append_config(datadir, options):
with open(os.path.join(datadir, "bitcoin.conf"), 'a', encoding='utf8') as f:
for option in options:
@@ -535,33 +554,3 @@ def find_vout_for_address(node, txid, addr):
if addr == tx["vout"][i]["scriptPubKey"]["address"]:
return i
raise RuntimeError("Vout not found for address: txid=%s, addr=%s" % (txid, addr))
-
-def modinv(a, n):
- """Compute the modular inverse of a modulo n using the extended Euclidean
- Algorithm. See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers.
- """
- # TODO: Change to pow(a, -1, n) available in Python 3.8
- t1, t2 = 0, 1
- r1, r2 = n, a
- while r2 != 0:
- q = r1 // r2
- t1, t2 = t2, t1 - q * t2
- r1, r2 = r2, r1 - q * r2
- if r1 > 1:
- return None
- if t1 < 0:
- t1 += n
- return t1
-
-class TestFrameworkUtil(unittest.TestCase):
- def test_modinv(self):
- test_vectors = [
- [7, 11],
- [11, 29],
- [90, 13],
- [1891, 3797],
- [6003722857, 77695236973],
- ]
-
- for a, n in test_vectors:
- self.assertEqual(modinv(a, n), pow(a, n-2, n))
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index eab8fbda47..271095ea21 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -13,14 +13,14 @@ from typing import (
Optional,
)
from test_framework.address import (
- base58_to_byte,
- bech32_to_bytes,
+ address_to_scriptpubkey,
create_deterministic_address_bcrt1_p2tr_op_true,
key_to_p2pkh,
key_to_p2sh_p2wpkh,
key_to_p2wpkh,
output_key_to_p2tr,
)
+from test_framework.blocktools import COINBASE_MATURITY
from test_framework.descriptors import descsum_create
from test_framework.key import (
ECKey,
@@ -49,15 +49,12 @@ from test_framework.script_util import (
key_to_p2pkh_script,
key_to_p2sh_p2wpkh_script,
key_to_p2wpkh_script,
- keyhash_to_p2pkh_script,
- program_to_witness_script,
- scripthash_to_p2sh_script,
)
from test_framework.util import (
assert_equal,
assert_greater_than_or_equal,
)
-from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.wallet_util import generate_keypair
DEFAULT_FEE = Decimal("0.0001")
@@ -101,7 +98,7 @@ class MiniWallet:
self._scriptPubKey = key_to_p2pk_script(pub_key.get_bytes())
elif mode == MiniWalletMode.ADDRESS_OP_TRUE:
self._address, self._internal_key = create_deterministic_address_bcrt1_p2tr_op_true()
- self._scriptPubKey = bytes.fromhex(self._test_node.validateaddress(self._address)['scriptPubKey'])
+ self._scriptPubKey = address_to_scriptpubkey(self._address)
# When the pre-mined test framework chain is used, it contains coinbase
# outputs to the MiniWallet's default address in blocks 76-100
@@ -222,10 +219,12 @@ class MiniWallet:
txid: get the first utxo we find from a specific transaction
"""
self._utxos = sorted(self._utxos, key=lambda k: (k['value'], -k['height'])) # Put the largest utxo last
+ blocks_height = self._test_node.getblockchaininfo()['blocks']
+ mature_coins = list(filter(lambda utxo: not utxo['coinbase'] or COINBASE_MATURITY - 1 <= blocks_height - utxo['height'], self._utxos))
if txid:
utxo_filter: Any = filter(lambda utxo: txid == utxo['txid'], self._utxos)
else:
- utxo_filter = reversed(self._utxos) # By default the largest utxo
+ utxo_filter = reversed(mature_coins) # By default the largest utxo
if vout is not None:
utxo_filter = filter(lambda utxo: vout == utxo['vout'], utxo_filter)
index = self._utxos.index(next(utxo_filter))
@@ -237,7 +236,8 @@ class MiniWallet:
def get_utxos(self, *, include_immature_coinbase=False, mark_as_spent=True):
"""Returns the list of all utxos and optionally mark them as spent"""
if not include_immature_coinbase:
- utxo_filter = filter(lambda utxo: not utxo['coinbase'] or COINBASE_MATURITY <= utxo['confirmations'], self._utxos)
+ blocks_height = self._test_node.getblockchaininfo()['blocks']
+ utxo_filter = filter(lambda utxo: not utxo['coinbase'] or COINBASE_MATURITY - 1 <= blocks_height - utxo['height'], self._utxos)
else:
utxo_filter = self._utxos
utxos = deepcopy(list(utxo_filter))
@@ -260,15 +260,19 @@ class MiniWallet:
Note that this method fails if there is no single internal utxo
available that can cover the cost for the amount and the fixed fee
(the utxo with the largest value is taken).
-
- Returns a tuple (txid, n) referring to the created external utxo outpoint.
"""
tx = self.create_self_transfer(fee_rate=0)["tx"]
assert_greater_than_or_equal(tx.vout[0].nValue, amount + fee)
tx.vout[0].nValue -= (amount + fee) # change output -> MiniWallet
tx.vout.append(CTxOut(amount, scriptPubKey)) # arbitrary output -> to be returned
txid = self.sendrawtransaction(from_node=from_node, tx_hex=tx.serialize().hex())
- return txid, 1
+ return {
+ "sent_vout": 1,
+ "txid": txid,
+ "wtxid": tx.getwtxid(),
+ "hex": tx.serialize().hex(),
+ "tx": tx,
+ }
def send_self_transfer_multi(self, *, from_node, **kwargs):
"""Call create_self_transfer_multi and send the transaction."""
@@ -392,9 +396,7 @@ def getnewdestination(address_type='bech32m'):
'legacy', 'p2sh-segwit', 'bech32' and 'bech32m'. Can be used when a random
destination is needed, but no compiled wallet is available (e.g. as
replacement to the getnewaddress/getaddressinfo RPCs)."""
- key = ECKey()
- key.generate()
- pubkey = key.get_pubkey().get_bytes()
+ key, pubkey = generate_keypair()
if address_type == 'legacy':
scriptpubkey = key_to_p2pkh_script(pubkey)
address = key_to_p2pkh(pubkey)
@@ -412,18 +414,3 @@ def getnewdestination(address_type='bech32m'):
else:
assert False
return pubkey, scriptpubkey, address
-
-
-def address_to_scriptpubkey(address):
- """Converts a given address to the corresponding output script (scriptPubKey)."""
- version, payload = bech32_to_bytes(address)
- if version is not None:
- return program_to_witness_script(version, payload) # testnet segwit scriptpubkey
- payload, version = base58_to_byte(address)
- if version == 111: # testnet pubkey hash
- return keyhash_to_p2pkh_script(payload)
- elif version == 196: # testnet script hash
- return scripthash_to_p2sh_script(payload)
- # TODO: also support other address formats
- else:
- assert False
diff --git a/test/functional/test_framework/wallet_util.py b/test/functional/test_framework/wallet_util.py
index 410d85cd8c..319f120297 100755
--- a/test/functional/test_framework/wallet_util.py
+++ b/test/functional/test_framework/wallet_util.py
@@ -63,12 +63,9 @@ def get_generate_key():
"""Generate a fresh key
Returns a named tuple of privkey, pubkey and all address and scripts."""
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
- pubkey = eckey.get_pubkey().get_bytes().hex()
+ privkey, pubkey = generate_keypair(wif=True)
return Key(privkey=privkey,
- pubkey=pubkey,
+ pubkey=pubkey.hex(),
p2pkh_script=key_to_p2pkh_script(pubkey).hex(),
p2pkh_addr=key_to_p2pkh(pubkey),
p2wpkh_script=key_to_p2wpkh_script(pubkey).hex(),
@@ -114,8 +111,14 @@ def bytes_to_wif(b, compressed=True):
b += b'\x01'
return byte_to_base58(b, 239)
-def generate_wif_key():
- # Makes a WIF privkey for imports
- k = ECKey()
- k.generate()
- return bytes_to_wif(k.get_bytes(), k.is_compressed)
+def generate_keypair(compressed=True, wif=False):
+ """Generate a new random keypair and return the corresponding ECKey /
+ bytes objects. The private key can also be provided as WIF (wallet
+ import format) string instead, which is often useful for wallet RPC
+ interaction."""
+ privkey = ECKey()
+ privkey.generate(compressed)
+ pubkey = privkey.get_pubkey().get_bytes()
+ if wif:
+ privkey = bytes_to_wif(privkey.get_bytes(), compressed)
+ return privkey, pubkey
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index bcedc0c9af..c834086b6f 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -69,11 +69,14 @@ if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393): #type:ignore
TEST_EXIT_PASSED = 0
TEST_EXIT_SKIPPED = 77
+# List of framework modules containing unit tests. Should be kept in sync with
+# the output of `git grep unittest.TestCase ./test/functional/test_framework`
TEST_FRAMEWORK_MODULES = [
"address",
"blocktools",
"muhash",
"key",
+ "ripemd160",
"script",
"segwit_addr",
"util",
@@ -163,11 +166,14 @@ BASE_SCRIPTS = [
'p2p_compactblocks_blocksonly.py',
'wallet_hd.py --legacy-wallet',
'wallet_hd.py --descriptors',
+ 'wallet_blank.py --legacy-wallet',
+ 'wallet_blank.py --descriptors',
'wallet_keypool_topup.py --legacy-wallet',
'wallet_keypool_topup.py --descriptors',
'wallet_fast_rescan.py --descriptors',
'interface_zmq.py',
'rpc_invalid_address_message.py',
+ 'rpc_validateaddress.py',
'interface_bitcoin_cli.py --legacy-wallet',
'interface_bitcoin_cli.py --descriptors',
'feature_bind_extra.py',
@@ -192,6 +198,8 @@ BASE_SCRIPTS = [
'wallet_watchonly.py --legacy-wallet',
'wallet_watchonly.py --usecli --legacy-wallet',
'wallet_reorgsrestore.py',
+ 'wallet_conflicts.py --legacy-wallet',
+ 'wallet_conflicts.py --descriptors',
'interface_http.py',
'interface_rpc.py',
'interface_usdt_coinselection.py',
@@ -320,6 +328,7 @@ BASE_SCRIPTS = [
'feature_includeconf.py',
'feature_addrman.py',
'feature_asmap.py',
+ 'feature_fastprune.py',
'mempool_unbroadcast.py',
'mempool_compatibility.py',
'mempool_accept_wtxid.py',
@@ -524,6 +533,12 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
# Test Framework Tests
print("Running Unit Tests for Test Framework Modules")
+
+ tests_dir = src_dir + '/test/functional/'
+ # This allows `test_runner.py` to work from an out-of-source build directory using a symlink,
+ # a hard link or a copy on any platform. See https://github.com/bitcoin/bitcoin/pull/27561.
+ sys.path.append(tests_dir)
+
test_framework_tests = unittest.TestSuite()
for module in TEST_FRAMEWORK_MODULES:
test_framework_tests.addTest(unittest.TestLoader().loadTestsFromName("test_framework.{}".format(module)))
@@ -532,8 +547,6 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
logging.debug("Early exiting after failure in TestFramework unit tests")
sys.exit(False)
- tests_dir = src_dir + '/test/functional/'
-
flags = ['--cachedir={}'.format(cache_dir)] + args
if enable_coverage:
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index a888f93b03..95999649b4 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -32,12 +32,11 @@ class ToolWalletTest(BitcoinTestFramework):
self.skip_if_no_wallet_tool()
def bitcoin_wallet_process(self, *args):
- binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"]
default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain]
if not self.options.descriptors and 'create' in args:
default_args.append('-legacy')
- return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
+ return subprocess.Popen([self.options.bitcoinwallet] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
def assert_raises_tool_error(self, error, *args):
p = self.bitcoin_wallet_process(*args)
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index 934f44588d..2691507773 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -226,20 +226,16 @@ class AbandonConflictTest(BitcoinTestFramework):
assert_equal(double_spend["walletconflicts"], [txAB1])
# Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
+ assert_equal(alice.gettransaction(txAB1)["confirmations"], -1)
newbalance = alice.getbalance()
assert_equal(newbalance, balance + Decimal("20"))
balance = newbalance
- # There is currently a minor bug around this and so this test doesn't work. See Issue #7315
- # Invalidate the block with the double spend and B's 10 BTC output should no longer be available
- # Don't think C's should either
+ # Invalidate the block with the double spend. B & C's 10 BTC outputs should no longer be available
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
+ assert_equal(alice.gettransaction(txAB1)["confirmations"], 0)
newbalance = alice.getbalance()
- #assert_equal(newbalance, balance - Decimal("10"))
- self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
- self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
- assert_equal(balance, newbalance)
-
+ assert_equal(newbalance, balance - Decimal("20"))
if __name__ == '__main__':
AbandonConflictTest().main()
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index ebeb5620e5..be5b3ebadb 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -176,7 +176,7 @@ class AddressTypeTest(BitcoinTestFramework):
for deriv in decode['inputs'][0]['bip32_derivs']:
assert_equal(len(deriv['master_fingerprint']), 8)
assert_equal(deriv['path'][0], 'm')
- key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + deriv['path'][1:] + ']' + deriv['pubkey']
+ key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + deriv['path'][1:].replace("'","h") + ']' + deriv['pubkey']
# Verify the descriptor checksum against the Python implementation
assert descsum_check(info['desc'])
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
index 5601d81227..c257bda452 100755
--- a/test/functional/wallet_avoidreuse.py
+++ b/test/functional/wallet_avoidreuse.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the avoid_reuse and setwalletflag features."""
+from test_framework.address import address_to_scriptpubkey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
@@ -257,7 +258,7 @@ class AvoidReuseTest(BitcoinTestFramework):
if not self.options.descriptors:
# For the second send, we transmute it to a related single-key address
# to make sure it's also detected as re-use
- fund_spk = self.nodes[0].getaddressinfo(fundaddr)["scriptPubKey"]
+ fund_spk = address_to_scriptpubkey(fundaddr).hex()
fund_decoded = self.nodes[0].decodescript(fund_spk)
if second_addr_type == "p2sh-segwit":
new_fundaddr = fund_decoded["segwit"]["p2sh-segwit"]
diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py
index 76aac3e486..5088e11eda 100755
--- a/test/functional/wallet_backwards_compatibility.py
+++ b/test/functional/wallet_backwards_compatibility.py
@@ -253,7 +253,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
wallet = node_v17.get_wallet_rpc("u1_v17")
address = wallet.getnewaddress("bech32")
v17_info = wallet.getaddressinfo(address)
- hdkeypath = v17_info["hdkeypath"]
+ hdkeypath = v17_info["hdkeypath"].replace("'", "h")
pubkey = v17_info["pubkey"]
if self.is_bdb_compiled():
@@ -265,7 +265,12 @@ class BackwardsCompatibilityTest(BitcoinTestFramework):
)
load_res = node_master.loadwallet("u1_v16")
# Make sure this wallet opens without warnings. See https://github.com/bitcoin/bitcoin/pull/19054
- assert_equal(load_res['warning'], '')
+ if int(node_master.getnetworkinfo()["version"]) >= 249900:
+ # loadwallet#warnings (added in v25) -- only present if there is a warning
+ assert "warnings" not in load_res
+ else:
+ # loadwallet#warning (deprecated in v25) -- always present, but empty string if no warning
+ assert_equal(load_res["warning"], '')
wallet = node_master.get_wallet_rpc("u1_v16")
info = wallet.getaddressinfo(v16_addr)
descriptor = f"wpkh([{info['hdmasterfingerprint']}{hdkeypath[1:]}]{v16_pubkey})"
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index 9ed2caefb7..af9270a321 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -11,6 +11,7 @@ from test_framework.blocktools import COINBASE_MATURITY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_is_hash_string,
assert_raises_rpc_error,
)
@@ -183,8 +184,13 @@ class WalletTest(BitcoinTestFramework):
'untrusted_pending': Decimal('30.0') - fee_node_1}} # Doesn't include output of node 0's send since it was spent
if self.options.descriptors:
del expected_balances_0["watchonly"]
- assert_equal(self.nodes[0].getbalances(), expected_balances_0)
- assert_equal(self.nodes[1].getbalances(), expected_balances_1)
+ balances_0 = self.nodes[0].getbalances()
+ balances_1 = self.nodes[1].getbalances()
+ # remove lastprocessedblock keys (they will be tested later)
+ del balances_0['lastprocessedblock']
+ del balances_1['lastprocessedblock']
+ assert_equal(balances_0, expected_balances_0)
+ assert_equal(balances_1, expected_balances_1)
# getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions
assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send
assert_equal(self.nodes[1].getbalance(), Decimal('0')) # node 1's send had an unsafe input
@@ -309,5 +315,30 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getbalances()['mine']['untrusted_pending'], Decimal('0.1'))
+ # Tests the lastprocessedblock JSON object in getbalances, getwalletinfo
+ # and gettransaction by checking for valid hex strings and by comparing
+ # the hashes & heights between generated blocks.
+ self.log.info("Test getbalances returns expected lastprocessedblock json object")
+ prev_hash = self.nodes[0].getbestblockhash()
+ prev_height = self.nodes[0].getblock(prev_hash)['height']
+ self.generatetoaddress(self.nodes[0], 5, self.nodes[0].get_deterministic_priv_key().address)
+ lastblock = self.nodes[0].getbalances()['lastprocessedblock']
+ assert_is_hash_string(lastblock['hash'])
+ assert_equal((prev_hash == lastblock['hash']), False)
+ assert_equal(lastblock['height'], prev_height + 5)
+
+ prev_hash = self.nodes[0].getbestblockhash()
+ prev_height = self.nodes[0].getblock(prev_hash)['height']
+ self.log.info("Test getwalletinfo returns expected lastprocessedblock json object")
+ walletinfo = self.nodes[0].getwalletinfo()
+ assert_equal(walletinfo['lastprocessedblock']['height'], prev_height)
+ assert_equal(walletinfo['lastprocessedblock']['hash'], prev_hash)
+
+ self.log.info("Test gettransaction returns expected lastprocessedblock json object")
+ txid = self.nodes[1].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
+ tx_info = self.nodes[1].gettransaction(txid)
+ assert_equal(tx_info['lastprocessedblock']['height'], prev_height)
+ assert_equal(tx_info['lastprocessedblock']['hash'], prev_hash)
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 53ac01686a..a1b805c09e 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -8,6 +8,10 @@ from itertools import product
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.descriptors import descsum_create
+from test_framework.messages import (
+ COIN,
+ DEFAULT_ANCESTOR_LIMIT,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
@@ -17,6 +21,7 @@ from test_framework.util import (
find_vout_for_address,
)
from test_framework.wallet_util import test_address
+from test_framework.wallet import MiniWallet
NOT_A_NUMBER_OR_STRING = "Amount is not a number or string"
OUT_OF_RANGE = "Amount out of range"
@@ -267,6 +272,20 @@ class WalletTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), node_2_bal)
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
+ # Sendmany 5 BTC to two addresses with subtracting fee from both addresses
+ a0 = self.nodes[0].getnewaddress()
+ a1 = self.nodes[0].getnewaddress()
+ txid = self.nodes[2].sendmany(dummy='', amounts={a0: 5, a1: 5}, subtractfeefrom=[a0, a1])
+ self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3]))
+ node_2_bal -= Decimal('10')
+ assert_equal(self.nodes[2].getbalance(), node_2_bal)
+ tx = self.nodes[2].gettransaction(txid)
+ node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(tx['hex']))
+ assert_equal(self.nodes[0].getbalance(), node_0_bal)
+ expected_bal = Decimal('5') + (tx['fee'] / 2)
+ assert_equal(self.nodes[0].getreceivedbyaddress(a0), expected_bal)
+ assert_equal(self.nodes[0].getreceivedbyaddress(a1), expected_bal)
+
self.log.info("Test sendmany with fee_rate param (explicit fee rate in sat/vB)")
fee_rate_sat_vb = 2
fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8
@@ -666,7 +685,7 @@ class WalletTest(BitcoinTestFramework):
"category": baz["category"],
"vout": baz["vout"]}
expected_fields = frozenset({'amount', 'bip125-replaceable', 'confirmations', 'details', 'fee',
- 'hex', 'time', 'timereceived', 'trusted', 'txid', 'wtxid', 'walletconflicts'})
+ 'hex', 'lastprocessedblock', 'time', 'timereceived', 'trusted', 'txid', 'wtxid', 'walletconflicts'})
verbose_field = "decoded"
expected_verbose_fields = expected_fields | {verbose_field}
@@ -770,6 +789,34 @@ class WalletTest(BitcoinTestFramework):
zeroconf_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('0.5'))
+ self.test_chain_listunspent()
+
+ def test_chain_listunspent(self):
+ if not self.options.descriptors:
+ return
+ self.wallet = MiniWallet(self.nodes[0])
+ self.nodes[0].get_wallet_rpc(self.default_wallet_name).sendtoaddress(self.wallet.get_address(), "5")
+ self.generate(self.wallet, 1, sync_fun=self.no_op)
+ self.nodes[0].createwallet("watch_wallet", disable_private_keys=True)
+ watch_wallet = self.nodes[0].get_wallet_rpc("watch_wallet")
+ watch_wallet.importaddress(self.wallet.get_address())
+
+ # DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine
+ chain = self.wallet.create_self_transfer_chain(chain_length=DEFAULT_ANCESTOR_LIMIT)
+ ancestor_vsize = 0
+ ancestor_fees = Decimal(0)
+
+ for i, t in enumerate(chain):
+ ancestor_vsize += t["tx"].get_vsize()
+ ancestor_fees += t["fee"]
+ self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=t["hex"])
+ # Check that listunspent ancestor{count, size, fees} yield the correct results
+ wallet_unspent = watch_wallet.listunspent(minconf=0)
+ this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info["txid"] == t["txid"])
+ assert_equal(this_unspent['ancestorcount'], i + 1)
+ assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
+ assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_blank.py b/test/functional/wallet_blank.py
new file mode 100755
index 0000000000..4836eba3b2
--- /dev/null
+++ b/test/functional/wallet_blank.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+import os
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.address import (
+ ADDRESS_BCRT1_UNSPENDABLE,
+ ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR,
+)
+from test_framework.util import (
+ assert_equal,
+)
+from test_framework.wallet_util import generate_keypair
+
+
+class WalletBlankTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def add_options(self, options):
+ self.add_wallet_options(options)
+
+ def test_importaddress(self):
+ if self.options.descriptors:
+ return
+ self.log.info("Test that importaddress unsets the blank flag")
+ self.nodes[0].createwallet(wallet_name="iaddr", disable_private_keys=True, blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("iaddr")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["blank"], True)
+ wallet.importaddress(ADDRESS_BCRT1_UNSPENDABLE)
+ assert_equal(wallet.getwalletinfo()["blank"], False)
+
+ def test_importpubkey(self):
+ if self.options.descriptors:
+ return
+ self.log.info("Test that importpubkey unsets the blank flag")
+ for i, comp in enumerate([True, False]):
+ self.nodes[0].createwallet(wallet_name=f"ipub{i}", disable_private_keys=True, blank=True)
+ wallet = self.nodes[0].get_wallet_rpc(f"ipub{i}")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["blank"], True)
+
+ _, pubkey = generate_keypair(compressed=comp)
+ wallet.importpubkey(pubkey.hex())
+ assert_equal(wallet.getwalletinfo()["blank"], False)
+
+ def test_importprivkey(self):
+ if self.options.descriptors:
+ return
+ self.log.info("Test that importprivkey unsets the blank flag")
+ for i, comp in enumerate([True, False]):
+ self.nodes[0].createwallet(wallet_name=f"ipriv{i}", blank=True)
+ wallet = self.nodes[0].get_wallet_rpc(f"ipriv{i}")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["blank"], True)
+
+ wif, _ = generate_keypair(compressed=comp, wif=True)
+ wallet.importprivkey(wif)
+ assert_equal(wallet.getwalletinfo()["blank"], False)
+
+ def test_importmulti(self):
+ if self.options.descriptors:
+ return
+ self.log.info("Test that importmulti unsets the blank flag")
+ self.nodes[0].createwallet(wallet_name="imulti", disable_private_keys=True, blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("imulti")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["blank"], True)
+ wallet.importmulti([{
+ "desc": ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR,
+ "timestamp": "now",
+ }])
+ assert_equal(wallet.getwalletinfo()["blank"], False)
+
+ def test_importdescriptors(self):
+ if not self.options.descriptors:
+ return
+ self.log.info("Test that importdescriptors preserves the blank flag")
+ self.nodes[0].createwallet(wallet_name="idesc", disable_private_keys=True, blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("idesc")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["blank"], True)
+ wallet.importdescriptors([{
+ "desc": ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR,
+ "timestamp": "now",
+ }])
+ assert_equal(wallet.getwalletinfo()["blank"], True)
+
+ def test_importwallet(self):
+ if self.options.descriptors:
+ return
+ self.log.info("Test that importwallet unsets the blank flag")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ self.nodes[0].createwallet(wallet_name="iwallet", blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("iwallet")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["blank"], True)
+
+ wallet_dump_path = os.path.join(self.nodes[0].datadir, "wallet.dump")
+ def_wallet.dumpwallet(wallet_dump_path)
+
+ wallet.importwallet(wallet_dump_path)
+ assert_equal(wallet.getwalletinfo()["blank"], False)
+
+ def test_encrypt_legacy(self):
+ if self.options.descriptors:
+ return
+ self.log.info("Test that encrypting a blank legacy wallet preserves the blank flag and does not generate a seed")
+ self.nodes[0].createwallet(wallet_name="encblanklegacy", blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("encblanklegacy")
+
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["blank"], True)
+ assert "hdseedid" not in info
+
+ wallet.encryptwallet("pass")
+ info = wallet.getwalletinfo()
+ assert_equal(info["blank"], True)
+ assert "hdseedid" not in info
+
+ def test_encrypt_descriptors(self):
+ if not self.options.descriptors:
+ return
+ self.log.info("Test that encrypting a blank descriptor wallet preserves the blank flag and descriptors remain the same")
+ self.nodes[0].createwallet(wallet_name="encblankdesc", blank=True)
+ wallet = self.nodes[0].get_wallet_rpc("encblankdesc")
+
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["blank"], True)
+ descs = wallet.listdescriptors()
+
+ wallet.encryptwallet("pass")
+ assert_equal(wallet.getwalletinfo()["blank"], True)
+ assert_equal(descs, wallet.listdescriptors())
+
+ def run_test(self):
+ self.test_importaddress()
+ self.test_importpubkey()
+ self.test_importprivkey()
+ self.test_importmulti()
+ self.test_importdescriptors()
+ self.test_importwallet()
+ self.test_encrypt_legacy()
+ self.test_encrypt_descriptors()
+
+
+if __name__ == '__main__':
+ WalletBlankTest().main()
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index ad79e0288c..b9ebf64c22 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -26,6 +26,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
+ get_fee,
)
from test_framework.wallet import MiniWallet
@@ -40,6 +41,10 @@ NORMAL = 100
HIGH = 500
TOO_HIGH = 100000
+def get_change_address(tx, node):
+ tx_details = node.getrawtransaction(tx, 1)
+ txout_addresses = [txout['scriptPubKey']['address'] for txout in tx_details["vout"]]
+ return [address for address in txout_addresses if node.getaddressinfo(address)["ischange"]]
class BumpFeeTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -103,6 +108,10 @@ class BumpFeeTest(BitcoinTestFramework):
# These tests wipe out a number of utxos that are expected in other tests
test_small_output_with_feerate_succeeds(self, rbf_node, dest_address)
test_no_more_inputs_fails(self, rbf_node, dest_address)
+ self.test_bump_back_to_yourself()
+
+ # Context independent tests
+ test_feerate_checks_replaced_outputs(self, rbf_node, peer_node)
def test_invalid_parameters(self, rbf_node, peer_node, dest_address):
self.log.info('Test invalid parameters')
@@ -114,36 +123,36 @@ class BumpFeeTest(BitcoinTestFramework):
assert_raises_rpc_error(-3, "Unexpected key {}".format(key), rbf_node.bumpfee, rbfid, {key: NORMAL})
# Bumping to just above minrelay should fail to increase the total fee enough.
- assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141", rbf_node.bumpfee, rbfid, {"fee_rate": INSUFFICIENT})
+ assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141", rbf_node.bumpfee, rbfid, fee_rate=INSUFFICIENT)
self.log.info("Test invalid fee rate settings")
assert_raises_rpc_error(-4, "Specified or calculated fee 0.141 is too high (cannot be higher than -maxtxfee 0.10",
- rbf_node.bumpfee, rbfid, {"fee_rate": TOO_HIGH})
+ rbf_node.bumpfee, rbfid, fee_rate=TOO_HIGH)
# Test fee_rate with zero values.
msg = "Insufficient total fee 0.00"
for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]:
- assert_raises_rpc_error(-8, msg, rbf_node.bumpfee, rbfid, {"fee_rate": zero_value})
+ assert_raises_rpc_error(-8, msg, rbf_node.bumpfee, rbfid, fee_rate=zero_value)
msg = "Invalid amount"
# Test fee_rate values that don't pass fixed-point parsing checks.
for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]:
- assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, {"fee_rate": invalid_value})
+ assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value)
# Test fee_rate values that cannot be represented in sat/vB.
for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]:
- assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, {"fee_rate": invalid_value})
+ assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value)
# Test fee_rate out of range (negative number).
- assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, {"fee_rate": -1})
+ assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, fee_rate=-1)
# Test type error.
for value in [{"foo": "bar"}, True]:
- assert_raises_rpc_error(-3, "Amount is not a number or string", rbf_node.bumpfee, rbfid, {"fee_rate": value})
+ assert_raises_rpc_error(-3, "Amount is not a number or string", rbf_node.bumpfee, rbfid, fee_rate=value)
self.log.info("Test explicit fee rate raises RPC error if both fee_rate and conf_target are passed")
assert_raises_rpc_error(-8, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation "
"target in blocks for automatic fee estimation, or an explicit fee rate.",
- rbf_node.bumpfee, rbfid, {"conf_target": NORMAL, "fee_rate": NORMAL})
+ rbf_node.bumpfee, rbfid, conf_target=NORMAL, fee_rate=NORMAL)
self.log.info("Test explicit fee rate raises RPC error if both fee_rate and estimate_mode are passed")
assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate",
- rbf_node.bumpfee, rbfid, {"estimate_mode": "economical", "fee_rate": NORMAL})
+ rbf_node.bumpfee, rbfid, estimate_mode="economical", fee_rate=NORMAL)
self.log.info("Test invalid conf_target settings")
assert_raises_rpc_error(-8, "confTarget and conf_target options should not both be set",
@@ -152,10 +161,10 @@ class BumpFeeTest(BitcoinTestFramework):
self.log.info("Test invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
- rbf_node.bumpfee, rbfid, {"estimate_mode": v})
+ rbf_node.bumpfee, rbfid, estimate_mode=v)
for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
- rbf_node.bumpfee, rbfid, {"estimate_mode": mode})
+ rbf_node.bumpfee, rbfid, estimate_mode=mode)
self.log.info("Test invalid outputs values")
assert_raises_rpc_error(-8, "Invalid parameter, output argument cannot be an empty array",
@@ -167,6 +176,54 @@ class BumpFeeTest(BitcoinTestFramework):
self.clear_mempool()
+ def test_bump_back_to_yourself(self):
+ self.log.info("Test that bumpfee can send coins back to yourself")
+ node = self.nodes[1]
+
+ node.createwallet("back_to_yourself")
+ wallet = node.get_wallet_rpc("back_to_yourself")
+
+ # Make 3 UTXOs
+ addr = wallet.getnewaddress()
+ for _ in range(3):
+ self.nodes[0].sendtoaddress(addr, 5)
+ self.generate(self.nodes[0], 1)
+
+ # Create a tx with two outputs. recipient and change.
+ tx = wallet.send(outputs={wallet.getnewaddress(): 9}, fee_rate=2)
+ tx_info = wallet.gettransaction(txid=tx["txid"], verbose=True)
+ assert_equal(len(tx_info["decoded"]["vout"]), 2)
+ assert_equal(len(tx_info["decoded"]["vin"]), 2)
+
+ # Bump tx, send coins back to change address.
+ change_addr = get_change_address(tx["txid"], wallet)[0]
+ out_amount = 10
+ bumped = wallet.bumpfee(txid=tx["txid"], options={"fee_rate": 20, "outputs": [{change_addr: out_amount}]})
+ bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True)
+ assert_equal(len(bumped_tx["decoded"]["vout"]), 1)
+ assert_equal(len(bumped_tx["decoded"]["vin"]), 2)
+ assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped["fee"], out_amount)
+
+ # Bump tx again, now test send fewer coins back to change address.
+ out_amount = 6
+ bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 40, "outputs": [{change_addr: out_amount}]})
+ bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True)
+ assert_equal(len(bumped_tx["decoded"]["vout"]), 2)
+ assert_equal(len(bumped_tx["decoded"]["vin"]), 2)
+ assert any(txout['value'] == out_amount - bumped["fee"] and txout['scriptPubKey']['address'] == change_addr for txout in bumped_tx['decoded']['vout'])
+ # Check that total out amount is still equal to the previously bumped tx
+ assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped_tx["decoded"]["vout"][1]["value"] + bumped["fee"], 10)
+
+ # Bump tx again, send more coins back to change address. The process will add another input to cover the target.
+ out_amount = 12
+ bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 80, "outputs": [{change_addr: out_amount}]})
+ bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True)
+ assert_equal(len(bumped_tx["decoded"]["vout"]), 2)
+ assert_equal(len(bumped_tx["decoded"]["vin"]), 3)
+ assert any(txout['value'] == out_amount - bumped["fee"] and txout['scriptPubKey']['address'] == change_addr for txout in bumped_tx['decoded']['vout'])
+ assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped_tx["decoded"]["vout"][1]["value"] + bumped["fee"], 15)
+
+ node.unloadwallet("back_to_yourself")
def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
self.log.info('Test simple bumpfee: {}'.format(mode))
@@ -175,12 +232,12 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
self.sync_mempools((rbf_node, peer_node))
assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
if mode == "fee_rate":
- bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": str(NORMAL)})
- bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": NORMAL})
+ bumped_psbt = rbf_node.psbtbumpfee(rbfid, fee_rate=str(NORMAL))
+ bumped_tx = rbf_node.bumpfee(rbfid, fee_rate=NORMAL)
elif mode == "new_outputs":
new_address = peer_node.getnewaddress()
- bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"outputs": {new_address: 0.0003}})
- bumped_tx = rbf_node.bumpfee(rbfid, {"outputs": {new_address: 0.0003}})
+ bumped_psbt = rbf_node.psbtbumpfee(rbfid, outputs={new_address: 0.0003})
+ bumped_tx = rbf_node.bumpfee(rbfid, outputs={new_address: 0.0003})
else:
bumped_psbt = rbf_node.psbtbumpfee(rbfid)
bumped_tx = rbf_node.bumpfee(rbfid)
@@ -248,7 +305,7 @@ def test_notmine_bumpfee(self, rbf_node, peer_node, dest_address):
# Note that this test depends upon the RPC code checking input ownership prior to change outputs
# (since it can't use fundrawtransaction, it lacks a proper change output)
fee = Decimal("0.001")
- utxos = [node.listunspent(query_options={'minimumAmount': fee})[-1] for node in (rbf_node, peer_node)]
+ utxos = [node.listunspent(minimumAmount=fee)[-1] for node in (rbf_node, peer_node)]
inputs = [{
"txid": utxo["txid"],
"vout": utxo["vout"],
@@ -278,7 +335,7 @@ def test_notmine_bumpfee(self, rbf_node, peer_node, dest_address):
psbt = rbf_node.psbtbumpfee(txid=rbfid)
finish_psbtbumpfee(psbt["psbt"])
- psbt = rbf_node.psbtbumpfee(txid=rbfid, options={"fee_rate": old_feerate + 10})
+ psbt = rbf_node.psbtbumpfee(txid=rbfid, fee_rate=old_feerate + 10)
finish_psbtbumpfee(psbt["psbt"])
self.clear_mempool()
@@ -388,7 +445,7 @@ def test_dust_to_fee(self, rbf_node, dest_address):
# Expected fee is 141 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049385 BTC.
# or occasionally 140 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049035 BTC.
# Dust should be dropped to the fee, so actual bump fee is 0.00050000 BTC.
- bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": 350.25})
+ bumped_tx = rbf_node.bumpfee(rbfid, fee_rate=350.25)
full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
assert_equal(bumped_tx["fee"], Decimal("0.00050000"))
assert_equal(len(fulltx["vout"]), 2)
@@ -512,7 +569,7 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
assert_raises_rpc_error(-4, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.", watcher.bumpfee, original_txid)
# Bump fee, obnoxiously high to add additional watchonly input
- bumped_psbt = watcher.psbtbumpfee(original_txid, {"fee_rate": HIGH})
+ bumped_psbt = watcher.psbtbumpfee(original_txid, fee_rate=HIGH)
assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1)
assert "txid" not in bumped_psbt
assert_equal(bumped_psbt["origfee"], -watcher.gettransaction(original_txid)["fee"])
@@ -536,17 +593,17 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
def test_rebumping(self, rbf_node, dest_address):
self.log.info('Test that re-bumping the original tx fails, but bumping successor works')
rbfid = spend_one_input(rbf_node, dest_address)
- bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL})
+ bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL)
assert_raises_rpc_error(-4, f"Cannot bump transaction {rbfid} which was already bumped by transaction {bumped['txid']}",
- rbf_node.bumpfee, rbfid, {"fee_rate": NORMAL})
- rbf_node.bumpfee(bumped["txid"], {"fee_rate": NORMAL})
+ rbf_node.bumpfee, rbfid, fee_rate=NORMAL)
+ rbf_node.bumpfee(bumped["txid"], fee_rate=NORMAL)
self.clear_mempool()
def test_rebumping_not_replaceable(self, rbf_node, dest_address):
self.log.info('Test that re-bumping non-replaceable fails')
rbfid = spend_one_input(rbf_node, dest_address)
- bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL, "replaceable": False})
+ bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL, replaceable=False)
assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
{"fee_rate": NORMAL})
self.clear_mempool()
@@ -558,7 +615,7 @@ def test_bumpfee_already_spent(self, rbf_node, dest_address):
self.generate(rbf_node, 1) # spend coin simply by mining block with tx
spent_input = rbf_node.gettransaction(txid=txid, verbose=True)['decoded']['vin'][0]
assert_raises_rpc_error(-1, f"{spent_input['txid']}:{spent_input['vout']} is already spent",
- rbf_node.bumpfee, txid, {"fee_rate": NORMAL})
+ rbf_node.bumpfee, txid, fee_rate=NORMAL)
def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address):
@@ -585,6 +642,11 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address):
# Call abandon to make sure the wallet doesn't attempt to resubmit
# the bump tx and hope the wallet does not rebroadcast before we call.
rbf_node.abandontransaction(bumpid)
+
+ tx_bump_abandoned = rbf_node.gettransaction(bumpid)
+ for tx in tx_bump_abandoned['details']:
+ assert_equal(tx['abandoned'], True)
+
assert bumpid not in rbf_node.getrawmempool()
assert rbfid in rbf_node.getrawmempool()
@@ -626,21 +688,16 @@ def test_locked_wallet_fails(self, rbf_node, dest_address):
def test_change_script_match(self, rbf_node, dest_address):
self.log.info('Test that the same change addresses is used for the replacement transaction when possible')
- def get_change_address(tx):
- tx_details = rbf_node.getrawtransaction(tx, 1)
- txout_addresses = [txout['scriptPubKey']['address'] for txout in tx_details["vout"]]
- return [address for address in txout_addresses if rbf_node.getaddressinfo(address)["ischange"]]
-
# Check that there is only one change output
rbfid = spend_one_input(rbf_node, dest_address)
- change_addresses = get_change_address(rbfid)
+ change_addresses = get_change_address(rbfid, rbf_node)
assert_equal(len(change_addresses), 1)
# Now find that address in each subsequent tx, and no other change
- bumped_total_tx = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL})
- assert_equal(change_addresses, get_change_address(bumped_total_tx['txid']))
+ bumped_total_tx = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL)
+ assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'], rbf_node))
bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"])
- assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid']))
+ assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'], rbf_node))
self.clear_mempool()
@@ -668,5 +725,35 @@ def test_no_more_inputs_fails(self, rbf_node, dest_address):
self.clear_mempool()
+def test_feerate_checks_replaced_outputs(self, rbf_node, peer_node):
+ # Make sure there is enough balance
+ peer_node.sendtoaddress(rbf_node.getnewaddress(), 60)
+ self.generate(peer_node, 1)
+
+ self.log.info("Test that feerate checks use replaced outputs")
+ outputs = []
+ for i in range(50):
+ outputs.append({rbf_node.getnewaddress(address_type="bech32"): 1})
+ tx_res = rbf_node.send(outputs=outputs, fee_rate=5)
+ tx_details = rbf_node.gettransaction(txid=tx_res["txid"], verbose=True)
+
+ # Calculate the minimum feerate required for the bump to work.
+ # Since the bumped tx will replace all of the outputs with a single output, we can estimate that its size will 31 * (len(outputs) - 1) bytes smaller
+ tx_size = tx_details["decoded"]["vsize"]
+ est_bumped_size = tx_size - (len(tx_details["decoded"]["vout"]) - 1) * 31
+ inc_fee_rate = max(rbf_node.getmempoolinfo()["incrementalrelayfee"], Decimal(0.00005000)) # Wallet has a fixed incremental relay fee of 5 sat/vb
+ # RPC gives us fee as negative
+ min_fee = (-tx_details["fee"] + get_fee(est_bumped_size, inc_fee_rate)) * Decimal(1e8)
+ min_fee_rate = (min_fee / est_bumped_size).quantize(Decimal("1.000"))
+
+ # Attempt to bumpfee and replace all outputs with a single one using a feerate slightly less than the minimum
+ new_outputs = [{rbf_node.getnewaddress(address_type="bech32"): 49}]
+ assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx_res["txid"], {"fee_rate": min_fee_rate - 1, "outputs": new_outputs})
+
+ # Bumpfee and replace all outputs with a single one using the minimum feerate
+ rbf_node.bumpfee(tx_res["txid"], {"fee_rate": min_fee_rate, "outputs": new_outputs})
+ self.clear_mempool()
+
+
if __name__ == "__main__":
BumpFeeTest().main()
diff --git a/test/functional/wallet_conflicts.py b/test/functional/wallet_conflicts.py
new file mode 100755
index 0000000000..802b718cd5
--- /dev/null
+++ b/test/functional/wallet_conflicts.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python3
+# Copyright (c) 2023 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 wallet correctly tracks transactions that have been conflicted by blocks, particularly during reorgs.
+"""
+
+from decimal import Decimal
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+)
+
+class TxConflicts(BitcoinTestFramework):
+ def add_options(self, parser):
+ self.add_wallet_options(parser)
+
+ def set_test_params(self):
+ self.num_nodes = 3
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def get_utxo_of_value(self, from_tx_id, search_value):
+ return next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(from_tx_id)["details"] if tx_out["amount"] == Decimal(f"{search_value}"))
+
+ def run_test(self):
+ self.log.info("Send tx from which to conflict outputs later")
+ txid_conflict_from_1 = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
+ txid_conflict_from_2 = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
+ self.generate(self.nodes[0], 1)
+ self.sync_blocks()
+
+ self.log.info("Disconnect nodes to broadcast conflicts on their respective chains")
+ self.disconnect_nodes(0, 1)
+ self.disconnect_nodes(2, 1)
+
+ self.log.info("Create transactions that conflict with each other")
+ output_A = self.get_utxo_of_value(from_tx_id=txid_conflict_from_1, search_value=10)
+ output_B = self.get_utxo_of_value(from_tx_id=txid_conflict_from_2, search_value=10)
+
+ # First create a transaction that consumes both A and B outputs.
+ #
+ # | tx1 | -----> | | | |
+ # | AB_parent_tx | ----> | Child_Tx |
+ # | tx2 | -----> | | | |
+ #
+ inputs_tx_AB_parent = [{"txid": txid_conflict_from_1, "vout": output_A}, {"txid": txid_conflict_from_2, "vout": output_B}]
+ tx_AB_parent = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs_tx_AB_parent, {self.nodes[0].getnewaddress(): Decimal("19.99998")}))
+
+ # Secondly, create two transactions: One consuming output_A, and another one consuming output_B
+ #
+ # | tx1 | -----> | Tx_A_1 |
+ # ----------------
+ # | tx2 | -----> | Tx_B_1 |
+ #
+ inputs_tx_A_1 = [{"txid": txid_conflict_from_1, "vout": output_A}]
+ inputs_tx_B_1 = [{"txid": txid_conflict_from_2, "vout": output_B}]
+ tx_A_1 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs_tx_A_1, {self.nodes[0].getnewaddress(): Decimal("9.99998")}))
+ tx_B_1 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs_tx_B_1, {self.nodes[0].getnewaddress(): Decimal("9.99998")}))
+
+ self.log.info("Broadcast conflicted transaction")
+ txid_AB_parent = self.nodes[0].sendrawtransaction(tx_AB_parent["hex"])
+ self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+
+ # Now that 'AB_parent_tx' was broadcast, build 'Child_Tx'
+ output_c = self.get_utxo_of_value(from_tx_id=txid_AB_parent, search_value=19.99998)
+ inputs_tx_C_child = [({"txid": txid_AB_parent, "vout": output_c})]
+
+ tx_C_child = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs_tx_C_child, {self.nodes[0].getnewaddress() : Decimal("19.99996")}))
+ tx_C_child_txid = self.nodes[0].sendrawtransaction(tx_C_child["hex"])
+ self.generate(self.nodes[0], 1, sync_fun=self.no_op)
+
+ self.log.info("Broadcast conflicting tx to node 1 and generate a longer chain")
+ conflicting_txid_A = self.nodes[1].sendrawtransaction(tx_A_1["hex"])
+ self.generate(self.nodes[1], 4, sync_fun=self.no_op)
+ conflicting_txid_B = self.nodes[1].sendrawtransaction(tx_B_1["hex"])
+ self.generate(self.nodes[1], 4, sync_fun=self.no_op)
+
+ self.log.info("Connect nodes 0 and 1, trigger reorg and ensure that the tx is effectively conflicted")
+ self.connect_nodes(0, 1)
+ self.sync_blocks([self.nodes[0], self.nodes[1]])
+ conflicted_AB_tx = self.nodes[0].gettransaction(txid_AB_parent)
+ tx_C_child = self.nodes[0].gettransaction(tx_C_child_txid)
+ conflicted_A_tx = self.nodes[0].gettransaction(conflicting_txid_A)
+
+ self.log.info("Verify, after the reorg, that Tx_A was accepted, and tx_AB and its Child_Tx are conflicting now")
+ # Tx A was accepted, Tx AB was not.
+ assert conflicted_AB_tx["confirmations"] < 0
+ assert conflicted_A_tx["confirmations"] > 0
+
+ # Conflicted tx should have confirmations set to the confirmations of the most conflicting tx
+ assert_equal(-conflicted_AB_tx["confirmations"], conflicted_A_tx["confirmations"])
+ # Child should inherit conflicted state from parent
+ assert_equal(-tx_C_child["confirmations"], conflicted_A_tx["confirmations"])
+ # Check the confirmations of the conflicting transactions
+ assert_equal(conflicted_A_tx["confirmations"], 8)
+ assert_equal(self.nodes[0].gettransaction(conflicting_txid_B)["confirmations"], 4)
+
+ self.log.info("Now generate a longer chain that does not contain any tx")
+ # Node2 chain without conflicts
+ self.generate(self.nodes[2], 15, sync_fun=self.no_op)
+
+ # Connect node0 and node2 and wait reorg
+ self.connect_nodes(0, 2)
+ self.sync_blocks()
+ conflicted = self.nodes[0].gettransaction(txid_AB_parent)
+ tx_C_child = self.nodes[0].gettransaction(tx_C_child_txid)
+
+ self.log.info("Test that formerly conflicted transaction are inactive after reorg")
+ # Former conflicted tx should be unconfirmed as it hasn't been yet rebroadcast
+ assert_equal(conflicted["confirmations"], 0)
+ # Former conflicted child tx should be unconfirmed as it hasn't been rebroadcast
+ assert_equal(tx_C_child["confirmations"], 0)
+ # Rebroadcast former conflicted tx and check it confirms smoothly
+ self.nodes[2].sendrawtransaction(conflicted["hex"])
+ self.generate(self.nodes[2], 1)
+ self.sync_blocks()
+ former_conflicted = self.nodes[0].gettransaction(txid_AB_parent)
+ assert_equal(former_conflicted["confirmations"], 1)
+ assert_equal(former_conflicted["blockheight"], 217)
+
+if __name__ == '__main__':
+ TxConflicts().main()
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index 11c82e15b7..4e31b48ec0 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -92,6 +92,7 @@ class CreateTxWalletTest(BitcoinTestFramework):
txid = tx_data['txid']
vout = 1
+ self.nodes[0].syncwithvalidationinterfacequeue()
options = {"change_position": 0, "add_inputs": False}
for i in range(1, 25):
options['inputs'] = [{'txid': txid, 'vout': vout}]
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index 22c491441b..75b507c387 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -7,13 +7,17 @@
from test_framework.address import key_to_p2wpkh
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import bytes_to_wif, generate_wif_key
+from test_framework.wallet_util import generate_keypair
+
+
+EMPTY_PASSPHRASE_MSG = "Empty string given as passphrase, wallet will not be encrypted."
+LEGACY_WALLET_MSG = "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."
+
class CreateWalletTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -46,16 +50,14 @@ class CreateWalletTest(BitcoinTestFramework):
w1.importpubkey(w0.getaddressinfo(address1)['pubkey'])
self.log.info('Test that private keys cannot be imported')
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey)
if self.options.descriptors:
result = w1.importdescriptors([{'desc': descsum_create('wpkh(' + privkey + ')'), 'timestamp': 'now'}])
else:
- result = w1.importmulti([{'scriptPubKey': {'address': key_to_p2wpkh(eckey.get_pubkey().get_bytes())}, 'timestamp': 'now', 'keys': [privkey]}])
+ result = w1.importmulti([{'scriptPubKey': {'address': key_to_p2wpkh(pubkey)}, 'timestamp': 'now', 'keys': [privkey]}])
assert not result[0]['success']
- assert 'warning' not in result[0]
+ assert 'warnings' not in result[0]
assert_equal(result[0]['error']['code'], -4)
assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled')
@@ -73,7 +75,7 @@ class CreateWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getrawchangeaddress)
# Import private key
- w3.importprivkey(generate_wif_key())
+ w3.importprivkey(generate_keypair(wif=True)[0])
# Imported private keys are currently ignored by the keypool
assert_equal(w3.getwalletinfo()['keypoolsize'], 0)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)
@@ -159,7 +161,8 @@ class CreateWalletTest(BitcoinTestFramework):
assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
# Allow empty passphrase, but there should be a warning
resp = self.nodes[0].createwallet(wallet_name='w7', disable_private_keys=False, blank=False, passphrase='')
- assert 'Empty string given as passphrase, wallet will not be encrypted.' in resp['warning']
+ assert_equal(resp["warnings"], [EMPTY_PASSPHRASE_MSG] if self.options.descriptors else [EMPTY_PASSPHRASE_MSG, LEGACY_WALLET_MSG])
+
w7 = node.get_wallet_rpc('w7')
assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 60)
@@ -174,8 +177,17 @@ class CreateWalletTest(BitcoinTestFramework):
if self.is_bdb_compiled():
self.log.info("Test legacy wallet deprecation")
- res = self.nodes[0].createwallet(wallet_name="legacy_w0", descriptors=False, passphrase=None)
- assert_equal(res["warning"], "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.")
+ result = self.nodes[0].createwallet(wallet_name="legacy_w0", descriptors=False, passphrase=None)
+ assert_equal(result, {
+ "name": "legacy_w0",
+ "warnings": [LEGACY_WALLET_MSG],
+ })
+ result = self.nodes[0].createwallet(wallet_name="legacy_w1", descriptors=False, passphrase="")
+ assert_equal(result, {
+ "name": "legacy_w1",
+ "warnings": [EMPTY_PASSPHRASE_MSG, LEGACY_WALLET_MSG],
+ })
+
if __name__ == '__main__':
CreateWalletTest().main()
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index b0e93df36a..4673eb091c 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -60,43 +60,43 @@ class WalletDescriptorTest(BitcoinTestFramework):
addr = self.nodes[0].getnewaddress("", "legacy")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('pkh(')
- assert_equal(addr_info['hdkeypath'], 'm/44\'/1\'/0\'/0/0')
+ assert_equal(addr_info['hdkeypath'], 'm/44h/1h/0h/0/0')
addr = self.nodes[0].getnewaddress("", "p2sh-segwit")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('sh(wpkh(')
- assert_equal(addr_info['hdkeypath'], 'm/49\'/1\'/0\'/0/0')
+ assert_equal(addr_info['hdkeypath'], 'm/49h/1h/0h/0/0')
addr = self.nodes[0].getnewaddress("", "bech32")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('wpkh(')
- assert_equal(addr_info['hdkeypath'], 'm/84\'/1\'/0\'/0/0')
+ assert_equal(addr_info['hdkeypath'], 'm/84h/1h/0h/0/0')
addr = self.nodes[0].getnewaddress("", "bech32m")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('tr(')
- assert_equal(addr_info['hdkeypath'], 'm/86\'/1\'/0\'/0/0')
+ assert_equal(addr_info['hdkeypath'], 'm/86h/1h/0h/0/0')
# Check that getrawchangeaddress works
addr = self.nodes[0].getrawchangeaddress("legacy")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('pkh(')
- assert_equal(addr_info['hdkeypath'], 'm/44\'/1\'/0\'/1/0')
+ assert_equal(addr_info['hdkeypath'], 'm/44h/1h/0h/1/0')
addr = self.nodes[0].getrawchangeaddress("p2sh-segwit")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('sh(wpkh(')
- assert_equal(addr_info['hdkeypath'], 'm/49\'/1\'/0\'/1/0')
+ assert_equal(addr_info['hdkeypath'], 'm/49h/1h/0h/1/0')
addr = self.nodes[0].getrawchangeaddress("bech32")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('wpkh(')
- assert_equal(addr_info['hdkeypath'], 'm/84\'/1\'/0\'/1/0')
+ assert_equal(addr_info['hdkeypath'], 'm/84h/1h/0h/1/0')
addr = self.nodes[0].getrawchangeaddress("bech32m")
addr_info = self.nodes[0].getaddressinfo(addr)
assert addr_info['desc'].startswith('tr(')
- assert_equal(addr_info['hdkeypath'], 'm/86\'/1\'/0\'/1/0')
+ assert_equal(addr_info['hdkeypath'], 'm/86h/1h/0h/1/0')
# Make a wallet to receive coins at
self.nodes[0].createwallet(wallet_name="desc2", descriptors=True)
@@ -178,14 +178,14 @@ class WalletDescriptorTest(BitcoinTestFramework):
self.nodes[0].createwallet(wallet_name='desc_import', disable_private_keys=True, descriptors=True)
imp_rpc = self.nodes[0].get_wallet_rpc('desc_import')
- addr_types = [('legacy', False, 'pkh(', '44\'/1\'/0\'', -13),
- ('p2sh-segwit', False, 'sh(wpkh(', '49\'/1\'/0\'', -14),
- ('bech32', False, 'wpkh(', '84\'/1\'/0\'', -13),
- ('bech32m', False, 'tr(', '86\'/1\'/0\'', -13),
- ('legacy', True, 'pkh(', '44\'/1\'/0\'', -13),
- ('p2sh-segwit', True, 'sh(wpkh(', '49\'/1\'/0\'', -14),
- ('bech32', True, 'wpkh(', '84\'/1\'/0\'', -13),
- ('bech32m', True, 'tr(', '86\'/1\'/0\'', -13)]
+ addr_types = [('legacy', False, 'pkh(', '44h/1h/0h', -13),
+ ('p2sh-segwit', False, 'sh(wpkh(', '49h/1h/0h', -14),
+ ('bech32', False, 'wpkh(', '84h/1h/0h', -13),
+ ('bech32m', False, 'tr(', '86h/1h/0h', -13),
+ ('legacy', True, 'pkh(', '44h/1h/0h', -13),
+ ('p2sh-segwit', True, 'sh(wpkh(', '49h/1h/0h', -14),
+ ('bech32', True, 'wpkh(', '84h/1h/0h', -13),
+ ('bech32m', True, 'tr(', '86h/1h/0h', -13)]
for addr_type, internal, desc_prefix, deriv_path, int_idx in addr_types:
int_str = 'internal' if internal else 'external'
diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py
index 1ab24f1a96..112aa25e86 100755
--- a/test/functional/wallet_fast_rescan.py
+++ b/test/functional/wallet_fast_rescan.py
@@ -7,6 +7,7 @@
import os
from typing import List
+from test_framework.address import address_to_scriptpubkey
from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.test_node import TestNode
@@ -58,7 +59,7 @@ class WalletFastRescanTest(BitcoinTestFramework):
if 'range' in desc_info:
start_range, end_range = desc_info['range']
addr = w.deriveaddresses(desc_info['desc'], [end_range, end_range])[0]
- spk = bytes.fromhex(w.getaddressinfo(addr)['scriptPubKey'])
+ spk = address_to_scriptpubkey(addr)
self.log.info(f"-> range [{start_range},{end_range}], last address {addr}")
else:
spk = bytes.fromhex(fixed_key.p2wpkh_script)
diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py
index 29ddb77b41..46706d6ad2 100755
--- a/test/functional/wallet_fundrawtransaction.py
+++ b/test/functional/wallet_fundrawtransaction.py
@@ -10,7 +10,6 @@ from itertools import product
from math import ceil
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.messages import (
COIN,
)
@@ -25,7 +24,7 @@ from test_framework.util import (
count_bytes,
find_vout_for_address,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
ERR_NOT_ENOUGH_PRESET_INPUTS = "The preselected coins total amount does not cover the transaction target. " \
"Please allow other inputs to be automatically selected or include more coins manually"
@@ -154,7 +153,7 @@ class RawTransactionsTest(BitcoinTestFramework):
"""Ensure setting changePosition in fundraw with an exact match is handled properly."""
self.log.info("Test fundrawtxn changePosition option")
rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50})
- rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {"changePosition":1, "subtractFeeFromOutputs":[0]})
+ rawmatch = self.nodes[2].fundrawtransaction(rawmatch, changePosition=1, subtractFeeFromOutputs=[0])
assert_equal(rawmatch["changepos"], -1)
self.nodes[3].createwallet(wallet_name="wwatch", disable_private_keys=True)
@@ -268,10 +267,10 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
- assert_raises_rpc_error(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'})
+ assert_raises_rpc_error(-8, "Unknown named parameter foo", self.nodes[2].fundrawtransaction, rawtx, foo='bar')
# reserveChangeKey was deprecated and is now removed
- assert_raises_rpc_error(-3, "Unexpected key reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, options={'reserveChangeKey': True}))
+ assert_raises_rpc_error(-8, "Unknown named parameter reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, reserveChangeKey=True))
def test_invalid_change_address(self):
self.log.info("Test fundrawtxn with an invalid change address")
@@ -283,7 +282,7 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
- assert_raises_rpc_error(-5, "Change address must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
+ assert_raises_rpc_error(-5, "Change address must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, changeAddress='foobar')
def test_valid_change_address(self):
self.log.info("Test fundrawtxn with a provided change address")
@@ -296,8 +295,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
change = self.nodes[2].getnewaddress()
- assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2})
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
+ assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, changeAddress=change, changePosition=2)
+ rawtxfund = self.nodes[2].fundrawtransaction(rawtx, changeAddress=change, changePosition=0)
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
out = dec_tx['vout'][0]
assert_equal(change, out['scriptPubKey']['address'])
@@ -309,9 +308,9 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]
outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
- assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", self.nodes[2].fundrawtransaction, rawtx, {'change_type': None})
- assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, {'change_type': ''})
- rawtx = self.nodes[2].fundrawtransaction(rawtx, {'change_type': 'bech32'})
+ assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", self.nodes[2].fundrawtransaction, rawtx, change_type=None)
+ assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, change_type='')
+ rawtx = self.nodes[2].fundrawtransaction(rawtx, change_type='bech32')
dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex'])
assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type'])
@@ -331,7 +330,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])
# Should fail without add_inputs:
- assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)
# add_inputs is enabled by default
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
@@ -363,8 +362,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
# Should fail without add_inputs:
- assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True})
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)
+ rawtxfund = self.nodes[2].fundrawtransaction(rawtx, add_inputs=True)
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
@@ -397,8 +396,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
# Should fail without add_inputs:
- assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False})
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True})
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)
+ rawtxfund = self.nodes[2].fundrawtransaction(rawtx, add_inputs=True)
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0
@@ -567,7 +566,7 @@ class RawTransactionsTest(BitcoinTestFramework):
oldBalance = self.nodes[1].getbalance()
inputs = []
outputs = {self.nodes[1].getnewaddress():1.1}
- funded_psbt = wmulti.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, options={'changeAddress': w2.getrawchangeaddress()})['psbt']
+ funded_psbt = wmulti.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, changeAddress=w2.getrawchangeaddress())['psbt']
signed_psbt = w2.walletprocesspsbt(funded_psbt)
final_psbt = w2.finalizepsbt(signed_psbt['psbt'])
@@ -750,7 +749,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[3].loadwallet('wwatch')
wwatch = self.nodes[3].get_wallet_rpc('wwatch')
w3 = self.nodes[3].get_wallet_rpc(self.default_wallet_name)
- result = wwatch.fundrawtransaction(rawtx, {'includeWatching': True, 'changeAddress': w3.getrawchangeaddress(), 'subtractFeeFromOutputs': [0]})
+ result = wwatch.fundrawtransaction(rawtx, includeWatching=True, changeAddress=w3.getrawchangeaddress(), subtractFeeFromOutputs=[0])
res_dec = self.nodes[0].decoderawtransaction(result["hex"])
assert_equal(len(res_dec["vin"]), 1)
assert res_dec["vin"][0]["txid"] == self.watchonly_txid
@@ -779,10 +778,10 @@ class RawTransactionsTest(BitcoinTestFramework):
result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee)
btc_kvb_to_sat_vb = 100000 # (1e5)
- result1 = node.fundrawtransaction(rawtx, {"fee_rate": str(2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee)})
- result2 = node.fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee})
- result3 = node.fundrawtransaction(rawtx, {"fee_rate": 10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee})
- result4 = node.fundrawtransaction(rawtx, {"feeRate": str(10 * self.min_relay_tx_fee)})
+ result1 = node.fundrawtransaction(rawtx, fee_rate=str(2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee))
+ result2 = node.fundrawtransaction(rawtx, feeRate=2 * self.min_relay_tx_fee)
+ result3 = node.fundrawtransaction(rawtx, fee_rate=10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee)
+ result4 = node.fundrawtransaction(rawtx, feeRate=str(10 * self.min_relay_tx_fee))
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
assert_fee_amount(result1['fee'], count_bytes(result1['hex']), 2 * result_fee_rate)
@@ -797,54 +796,54 @@ class RawTransactionsTest(BitcoinTestFramework):
# 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})
+ 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():
assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
- node.fundrawtransaction, rawtx, {"estimate_mode": v, "conf_target": 0.1, "add_inputs": True})
+ node.fundrawtransaction, rawtx, estimate_mode=v, conf_target=0.1, add_inputs=True)
for mode in ["", "foo", Decimal("3.141592")]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
- node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": 0.1, "add_inputs": True})
+ node.fundrawtransaction, rawtx, estimate_mode=mode, conf_target=0.1, add_inputs=True)
self.log.info("Test fundrawtxn with invalid conf_target settings")
for mode in ["unset", "economical", "conservative"]:
self.log.debug("{}".format(mode))
for k, v in {"string": "", "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, f"JSON value of type {k} for field conf_target is not of expected type number",
- node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": v, "add_inputs": True})
+ node.fundrawtransaction, rawtx, estimate_mode=mode, conf_target=v, add_inputs=True)
for n in [-1, 0, 1009]:
assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h
- node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": n, "add_inputs": True})
+ node.fundrawtransaction, rawtx, estimate_mode=mode, conf_target=n, add_inputs=True)
self.log.info("Test invalid fee rate settings")
for param, value in {("fee_rate", 100000), ("feeRate", 1.000)}:
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
- node.fundrawtransaction, rawtx, {param: value, "add_inputs": True})
+ node.fundrawtransaction, rawtx, add_inputs=True, **{param: value})
assert_raises_rpc_error(-3, "Amount out of range",
- node.fundrawtransaction, rawtx, {param: -1, "add_inputs": True})
+ node.fundrawtransaction, rawtx, add_inputs=True, **{param: -1})
assert_raises_rpc_error(-3, "Amount is not a number or string",
- node.fundrawtransaction, rawtx, {param: {"foo": "bar"}, "add_inputs": True})
+ node.fundrawtransaction, rawtx, add_inputs=True, **{param: {"foo": "bar"}})
# Test fee rate values that don't pass fixed-point parsing checks.
for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]:
- assert_raises_rpc_error(-3, "Invalid amount", node.fundrawtransaction, rawtx, {param: invalid_value, "add_inputs": True})
+ assert_raises_rpc_error(-3, "Invalid amount", node.fundrawtransaction, rawtx, add_inputs=True, **{param: invalid_value})
# Test fee_rate values that cannot be represented in sat/vB.
for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]:
assert_raises_rpc_error(-3, "Invalid amount",
- node.fundrawtransaction, rawtx, {"fee_rate": invalid_value, "add_inputs": True})
+ node.fundrawtransaction, rawtx, fee_rate=invalid_value, add_inputs=True)
self.log.info("Test min fee rate checks are bypassed with fundrawtxn, e.g. a fee_rate under 1 sat/vB is allowed")
- node.fundrawtransaction(rawtx, {"fee_rate": 0.999, "add_inputs": True})
- node.fundrawtransaction(rawtx, {"feeRate": 0.00000999, "add_inputs": True})
+ node.fundrawtransaction(rawtx, fee_rate=0.999, add_inputs=True)
+ node.fundrawtransaction(rawtx, feeRate=0.00000999, add_inputs=True)
self.log.info("- raises RPC error if both feeRate and fee_rate are passed")
assert_raises_rpc_error(-8, "Cannot specify both fee_rate (sat/vB) and feeRate (BTC/kvB)",
- node.fundrawtransaction, rawtx, {"fee_rate": 0.1, "feeRate": 0.1, "add_inputs": True})
+ node.fundrawtransaction, rawtx, fee_rate=0.1, feeRate=0.1, add_inputs=True)
self.log.info("- raises RPC error if both feeRate and estimate_mode passed")
assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and feeRate",
- node.fundrawtransaction, rawtx, {"estimate_mode": "economical", "feeRate": 0.1, "add_inputs": True})
+ node.fundrawtransaction, rawtx, estimate_mode="economical", feeRate=0.1, add_inputs=True)
for param in ["feeRate", "fee_rate"]:
self.log.info("- raises RPC error if both {} and conf_target are passed".format(param))
@@ -854,7 +853,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info("- raises RPC error if both fee_rate and estimate_mode are passed")
assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate",
- node.fundrawtransaction, rawtx, {"fee_rate": 1, "estimate_mode": "economical", "add_inputs": True})
+ node.fundrawtransaction, rawtx, fee_rate=1, estimate_mode="economical", add_inputs=True)
def test_address_reuse(self):
"""Test no address reuse occurs."""
@@ -884,10 +883,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# Test subtract fee from outputs with feeRate (BTC/kvB)
result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee)
- self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
- self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses self.min_relay_tx_fee (set by settxfee)
- self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee}),
- self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee, "subtractFeeFromOutputs": [0]}),]
+ self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[]), # empty subtraction list
+ self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0]), # uses self.min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, feeRate=2 * self.min_relay_tx_fee),
+ self.nodes[3].fundrawtransaction(rawtx, feeRate=2 * self.min_relay_tx_fee, subtractFeeFromOutputs=[0]),]
dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result]
output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
@@ -904,10 +903,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# Test subtract fee from outputs with fee_rate (sat/vB)
btc_kvb_to_sat_vb = 100000 # (1e5)
result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee)
- self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list
- self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses self.min_relay_tx_fee (set by settxfee)
- self.nodes[3].fundrawtransaction(rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee}),
- self.nodes[3].fundrawtransaction(rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee, "subtractFeeFromOutputs": [0]}),]
+ self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[]), # empty subtraction list
+ self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0]), # uses self.min_relay_tx_fee (set by settxfee)
+ self.nodes[3].fundrawtransaction(rawtx, fee_rate=2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee),
+ self.nodes[3].fundrawtransaction(rawtx, fee_rate=2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee, subtractFeeFromOutputs=[0]),]
dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result]
output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
@@ -927,7 +926,7 @@ class RawTransactionsTest(BitcoinTestFramework):
result = [self.nodes[3].fundrawtransaction(rawtx),
# Split the fee between outputs 0, 2, and 3, but not output 1.
- self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})]
+ self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0, 2, 3])]
dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),
self.nodes[3].decoderawtransaction(result[1]['hex'])]
@@ -969,7 +968,7 @@ class RawTransactionsTest(BitcoinTestFramework):
vout = find_vout_for_address(self.nodes[0], txid, addr)
rawtx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(): 5}])
- fundedtx = self.nodes[0].fundrawtransaction(rawtx, {'subtractFeeFromOutputs': [0]})
+ fundedtx = self.nodes[0].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0])
signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex'])
self.nodes[0].sendrawtransaction(signedtx['hex'])
@@ -999,11 +998,7 @@ class RawTransactionsTest(BitcoinTestFramework):
def test_external_inputs(self):
self.log.info("Test funding with external inputs")
-
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
-
+ privkey, _ = generate_keypair(wif=True)
self.nodes[2].createwallet("extfund")
wallet = self.nodes[2].get_wallet_rpc("extfund")
@@ -1027,25 +1022,25 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"]), wallet.fundrawtransaction, raw_tx)
# Error conditions
- assert_raises_rpc_error(-5, "'not a pubkey' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["not a pubkey"]}})
- assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["01234567890a0b0c0d0e0f"]}})
- assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"scripts":["not a script"]}})
- assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, {"solving_data": {"descriptors":["not a descriptor"]}})
- assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"]}]})
- assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": -1}]})
- assert_raises_rpc_error(-8, "Invalid parameter, missing weight key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"]}]})
- assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 164}]})
- assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": -1}]})
- assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be greater than", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 400001}]})
+ assert_raises_rpc_error(-5, "'not a pubkey' is not hex", wallet.fundrawtransaction, raw_tx, solving_data={"pubkeys":["not a pubkey"]})
+ assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, solving_data={"pubkeys":["01234567890a0b0c0d0e0f"]})
+ assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, solving_data={"scripts":["not a script"]})
+ assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, solving_data={"descriptors":["not a descriptor"]})
+ assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"]}])
+ assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": -1}])
+ assert_raises_rpc_error(-8, "Invalid parameter, missing weight key", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"]}])
+ assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 164}])
+ assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": -1}])
+ assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be greater than", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 400001}])
# But funding should work when the solving data is provided
- funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}})
+ funded_tx = wallet.fundrawtransaction(raw_tx, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]})
signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex'])
assert not signed_tx['complete']
signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex'])
assert signed_tx['complete']
- funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}})
+ funded_tx = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]})
signed_tx1 = wallet.signrawtransactionwithwallet(funded_tx['hex'])
assert not signed_tx1['complete']
signed_tx2 = self.nodes[0].signrawtransactionwithwallet(signed_tx1['hex'])
@@ -1060,30 +1055,30 @@ class RawTransactionsTest(BitcoinTestFramework):
high_input_weight = input_weight * 2
# Funding should also work if the input weight is provided
- funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}]})
+ funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}])
signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"])
signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"])
assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True)
assert_equal(signed_tx["complete"], True)
# Reducing the weight should have a lower fee
- funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}]})
+ funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}])
assert_greater_than(funded_tx["fee"], funded_tx2["fee"])
# Increasing the weight should have a higher fee
- funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]})
+ funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}])
assert_greater_than(funded_tx2["fee"], funded_tx["fee"])
# The provided weight should override the calculated weight when solving data is provided
- funded_tx3 = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}, "input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]})
+ funded_tx3 = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]}, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}])
assert_equal(funded_tx2["fee"], funded_tx3["fee"])
# The feerate should be met
- funded_tx4 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], "fee_rate": 10})
+ funded_tx4 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], fee_rate=10)
input_add_weight = high_input_weight - (41 * 4)
tx4_weight = wallet.decoderawtransaction(funded_tx4["hex"])["weight"] + input_add_weight
tx4_vsize = int(ceil(tx4_weight / 4))
assert_fee_amount(funded_tx4["fee"], tx4_vsize, Decimal(0.0001))
# Funding with weight at csuint boundaries should not cause problems
- funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}]})
- funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}]})
+ funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}])
+ funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}])
self.nodes[2].unloadwallet("extfund")
@@ -1123,7 +1118,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Fund wallet with 2 outputs, 5 BTC each.
addr2 = wallet.getnewaddress(address_type="bech32")
- source_tx = self.nodes[0].send(outputs=[{addr1: 5}, {addr2: 5}], options={"change_position": 0})
+ source_tx = self.nodes[0].send(outputs=[{addr1: 5}, {addr2: 5}], change_position=0)
self.generate(self.nodes[0], 1)
# Select only one input.
@@ -1135,12 +1130,12 @@ class RawTransactionsTest(BitcoinTestFramework):
}
]
}
- assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 8}], options=options)
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 8}], **options)
# Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
options["add_inputs"] = True
options["add_to_wallet"] = False
- tx = wallet.send(outputs=[{addr1: 8}], options=options)
+ tx = wallet.send(outputs=[{addr1: 8}], **options)
assert tx["complete"]
# Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
@@ -1148,7 +1143,7 @@ class RawTransactionsTest(BitcoinTestFramework):
"txid": source_tx["txid"],
"vout": 2 # change position was hardcoded to index 0
})
- tx = wallet.send(outputs=[{addr1: 8}], options=options)
+ tx = wallet.send(outputs=[{addr1: 8}], **options)
assert tx["complete"]
# Check that only the preset inputs were added to the tx
decoded_psbt_inputs = self.nodes[0].decodepsbt(tx["psbt"])['tx']['vin']
@@ -1158,12 +1153,12 @@ class RawTransactionsTest(BitcoinTestFramework):
# Case (5), assert that inputs are added to the tx by explicitly setting add_inputs=true
options = {"add_inputs": True, "add_to_wallet": True}
- tx = wallet.send(outputs=[{addr1: 8}], options=options)
+ tx = wallet.send(outputs=[{addr1: 8}], **options)
assert tx["complete"]
# 6. Explicit add_inputs=false, no preset inputs:
options = {"add_inputs": False}
- assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 3}], options=options)
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 3}], **options)
################################################
@@ -1184,14 +1179,14 @@ class RawTransactionsTest(BitcoinTestFramework):
# Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
options["add_inputs"] = True
- assert "psbt" in wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options)
+ assert "psbt" in wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, **options)
# Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
inputs.append({
"txid": source_tx["txid"],
"vout": 2 # change position was hardcoded to index 0
})
- psbt_tx = wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options)
+ psbt_tx = wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, **options)
# Check that only the preset inputs were added to the tx
decoded_psbt_inputs = self.nodes[0].decodepsbt(psbt_tx["psbt"])['tx']['vin']
assert_equal(len(decoded_psbt_inputs), 2)
@@ -1203,11 +1198,11 @@ class RawTransactionsTest(BitcoinTestFramework):
options = {
"add_inputs": True
}
- assert "psbt" in wallet.walletcreatefundedpsbt(inputs=[], outputs=outputs, options=options)
+ assert "psbt" in wallet.walletcreatefundedpsbt(inputs=[], outputs=outputs, **options)
# Case (6). Explicit add_inputs=false, no preset inputs:
options = {"add_inputs": False}
- assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, options=options)
+ assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, **options)
self.nodes[2].unloadwallet("test_preset_inputs")
@@ -1271,7 +1266,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1)
rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(address_type="bech32"): 8}])
- fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10, "change_type": "bech32"})
+ fundedtx = wallet.fundrawtransaction(rawtx, fee_rate=10, change_type="bech32")
# with 71-byte signatures we should expect following tx size
# tx overhead (10) + 2 inputs (41 each) + 2 p2wpkh (31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 byte sig witnesses (107 each)) / witness scaling factor (4)
tx_size = ceil(10 + 41*2 + 31*2 + (2 + 107*2)/4)
@@ -1280,7 +1275,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Using the other output should have 72 byte sigs
rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': ext_vout}], [{self.nodes[0].getnewaddress(): 13}])
ext_desc = self.nodes[0].getaddressinfo(ext_addr)["desc"]
- fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10, "change_type": "bech32", "solving_data": {"descriptors": [ext_desc]}})
+ fundedtx = wallet.fundrawtransaction(rawtx, fee_rate=10, change_type="bech32", solving_data={"descriptors": [ext_desc]})
# tx overhead (10) + 3 inputs (41 each) + 2 p2wpkh(31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 bytes sig witnesses (107 each) + p2wpkh 72 byte sig witness (108)) / witness scaling factor (4)
tx_size = ceil(10 + 41*3 + 31*2 + (2 + 107*2 + 108)/4)
assert_equal(fundedtx['fee'] * COIN, tx_size * 10)
@@ -1307,7 +1302,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, rawtx)
# But we can opt-in to use them for funding.
- fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": True})
+ fundedtx = wallet.fundrawtransaction(rawtx, include_unsafe=True)
tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"])
signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
@@ -1315,7 +1310,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# And we can also use them once they're confirmed.
self.generate(self.nodes[0], 1)
- fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": False})
+ fundedtx = wallet.fundrawtransaction(rawtx, include_unsafe=False)
tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"])
signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
@@ -1350,7 +1345,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create transactions in order to calculate fees for the target bounds that can trigger this bug
change_tx = tester.fundrawtransaction(tester.createrawtransaction([], [{funds.getnewaddress(): 1.5}]))
tx = tester.createrawtransaction([], [{funds.getnewaddress(): 2}])
- no_change_tx = tester.fundrawtransaction(tx, {"subtractFeeFromOutputs": [0]})
+ no_change_tx = tester.fundrawtransaction(tx, subtractFeeFromOutputs=[0])
overhead_fees = feerate * len(tx) / 2 / 1000
cost_of_change = change_tx["fee"] - no_change_tx["fee"]
@@ -1402,7 +1397,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# To test this does not happen, we subtract 202 sats from the input value. If working correctly, this should
# fail with insufficient funds rather than bitcoind asserting.
rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}])
- assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, {"fee_rate": 1.85})
+ assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, fee_rate=1.85)
def test_input_confs_control(self):
self.nodes[0].createwallet("minconf")
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 0f79df6e5d..8f84d8ed60 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -41,7 +41,7 @@ class WalletHDTest(BitcoinTestFramework):
change_addr = self.nodes[1].getrawchangeaddress()
change_addrV = self.nodes[1].getaddressinfo(change_addr)
if self.options.descriptors:
- assert_equal(change_addrV["hdkeypath"], "m/84'/1'/0'/1/0")
+ assert_equal(change_addrV["hdkeypath"], "m/84h/1h/0h/1/0")
else:
assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
@@ -63,7 +63,7 @@ class WalletHDTest(BitcoinTestFramework):
hd_add = self.nodes[1].getnewaddress()
hd_info = self.nodes[1].getaddressinfo(hd_add)
if self.options.descriptors:
- assert_equal(hd_info["hdkeypath"], "m/84'/1'/0'/0/" + str(i))
+ assert_equal(hd_info["hdkeypath"], "m/84h/1h/0h/0/" + str(i))
else:
assert_equal(hd_info["hdkeypath"], "m/0'/0'/" + str(i) + "'")
assert_equal(hd_info["hdmasterfingerprint"], hd_fingerprint)
@@ -76,7 +76,7 @@ class WalletHDTest(BitcoinTestFramework):
change_addr = self.nodes[1].getrawchangeaddress()
change_addrV = self.nodes[1].getaddressinfo(change_addr)
if self.options.descriptors:
- assert_equal(change_addrV["hdkeypath"], "m/84'/1'/0'/1/1")
+ assert_equal(change_addrV["hdkeypath"], "m/84h/1h/0h/1/1")
else:
assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
@@ -101,7 +101,7 @@ class WalletHDTest(BitcoinTestFramework):
hd_add_2 = self.nodes[1].getnewaddress()
hd_info_2 = self.nodes[1].getaddressinfo(hd_add_2)
if self.options.descriptors:
- assert_equal(hd_info_2["hdkeypath"], "m/84'/1'/0'/0/" + str(i))
+ assert_equal(hd_info_2["hdkeypath"], "m/84h/1h/0h/0/" + str(i))
else:
assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/" + str(i) + "'")
assert_equal(hd_info_2["hdmasterfingerprint"], hd_fingerprint)
@@ -143,7 +143,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/84h/1h/0h/1/")
else:
assert_equal(keypath[0:7], "m/0'/1'")
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 211e939a39..0ac67607e1 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -75,7 +75,7 @@ class Variant(collections.namedtuple("Variant", "call data address_type rescan p
request.update({"redeemscript": self.address['embedded']['scriptPubKey']})
response = self.node.importmulti(
requests=[request],
- options={"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)},
+ rescan=self.rescan in (Rescan.yes, Rescan.late_timestamp),
)
assert_equal(response, [{"success": True}])
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index 4f2db2018a..ad5ae111aa 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -332,15 +332,15 @@ class ImportDescriptorsTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, 'This wallet has no available keys', w1.getrawchangeaddress, 'bech32')
assert_equal(received_addr, expected_addr)
bech32_addr_info = w1.getaddressinfo(received_addr)
- assert_equal(bech32_addr_info['desc'][:23], 'wpkh([80002067/0\'/0\'/{}]'.format(i))
+ assert_equal(bech32_addr_info['desc'][:23], 'wpkh([80002067/0h/0h/{}]'.format(i))
shwpkh_addr = w1.getnewaddress('', 'p2sh-segwit')
shwpkh_addr_info = w1.getaddressinfo(shwpkh_addr)
- assert_equal(shwpkh_addr_info['desc'][:26], 'sh(wpkh([abcdef12/0\'/0\'/{}]'.format(i))
+ assert_equal(shwpkh_addr_info['desc'][:26], 'sh(wpkh([abcdef12/0h/0h/{}]'.format(i))
pkh_addr = w1.getnewaddress('', 'legacy')
pkh_addr_info = w1.getaddressinfo(pkh_addr)
- assert_equal(pkh_addr_info['desc'][:22], 'pkh([12345678/0\'/0\'/{}]'.format(i))
+ assert_equal(pkh_addr_info['desc'][:22], 'pkh([12345678/0h/0h/{}]'.format(i))
assert_equal(w1.getwalletinfo()['keypoolsize'], 4 * 3) # After retrieving a key, we don't refill the keypool again, so it's one less for each address type
w1.keypoolrefill()
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 77b407579f..5fe7c4b591 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -7,7 +7,6 @@ from decimal import Decimal
from test_framework.address import key_to_p2wpkh
from test_framework.blocktools import COINBASE_MATURITY
-from test_framework.key import ECKey
from test_framework.messages import (
CMerkleBlock,
from_hex,
@@ -17,7 +16,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
class ImportPrunedFundsTest(BitcoinTestFramework):
@@ -40,10 +39,8 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
# pubkey
address2 = self.nodes[0].getnewaddress()
# privkey
- eckey = ECKey()
- eckey.generate()
- address3_privkey = bytes_to_wif(eckey.get_bytes())
- address3 = key_to_p2wpkh(eckey.get_pubkey().get_bytes())
+ address3_privkey, address3_pubkey = generate_keypair(wif=True)
+ address3 = key_to_p2wpkh(address3_pubkey)
self.nodes[0].importprivkey(address3_privkey)
# Check only one address
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index bd97851153..a39db3bfb8 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -178,30 +178,30 @@ class KeyPoolTest(BitcoinTestFramework):
# Using a fee rate (10 sat / byte) well above the minimum relay rate
# creating a 5,000 sat transaction with change should not be possible
- assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", w2.walletcreatefundedpsbt, inputs=[], outputs=[{addr.pop(): 0.00005000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010})
+ assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", w2.walletcreatefundedpsbt, inputs=[], outputs=[{addr.pop(): 0.00005000}], subtractFeeFromOutputs=[0], feeRate=0.00010)
# creating a 10,000 sat transaction without change, with a manual input, should still be possible
- res = w2.walletcreatefundedpsbt(inputs=w2.listunspent(), outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010})
+ res = w2.walletcreatefundedpsbt(inputs=w2.listunspent(), outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.00010)
assert_equal("psbt" in res, True)
# creating a 10,000 sat transaction without change should still be possible
- res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010})
+ res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.00010)
assert_equal("psbt" in res, True)
# should work without subtractFeeFromOutputs if the exact fee is subtracted from the amount
- res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008900}], options={"feeRate": 0.00010})
+ res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008900}], feeRate=0.00010)
assert_equal("psbt" in res, True)
# dust change should be removed
- res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008800}], options={"feeRate": 0.00010})
+ res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008800}], feeRate=0.00010)
assert_equal("psbt" in res, True)
# create a transaction without change at the maximum fee rate, such that the output is still spendable:
- res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.0008823})
+ res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.0008823)
assert_equal("psbt" in res, True)
assert_equal(res["fee"], Decimal("0.00009706"))
# creating a 10,000 sat transaction with a manual change address should be possible
- res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010, "changeAddress": addr.pop()})
+ res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.00010, changeAddress=addr.pop())
assert_equal("psbt" in res, True)
if not self.options.descriptors:
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index 18c3ae1f7c..f1458bb374 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -83,11 +83,11 @@ class KeypoolRestoreTest(BitcoinTestFramework):
# Check that we have marked all keys up to the used keypool key as used
if self.options.descriptors:
if output_type == 'legacy':
- assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/44'/1'/0'/0/110")
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/44h/1h/0h/0/110")
elif output_type == 'p2sh-segwit':
- assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/49'/1'/0'/0/110")
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/49h/1h/0h/0/110")
elif output_type == 'bech32':
- assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/84'/1'/0'/0/110")
+ assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/84h/1h/0h/0/110")
else:
assert_equal(self.nodes[idx].getaddressinfo(self.nodes[idx].getnewaddress(address_type=output_type))['hdkeypath'], "m/0'/0'/110'")
diff --git a/test/functional/wallet_labels.py b/test/functional/wallet_labels.py
index a39700f73a..f074339a2b 100755
--- a/test/functional/wallet_labels.py
+++ b/test/functional/wallet_labels.py
@@ -71,6 +71,10 @@ class WalletLabelsTest(BitcoinTestFramework):
node = self.nodes[0]
assert_equal(len(node.listunspent()), 0)
+ self.log.info("Checking listlabels' invalid parameters")
+ assert_raises_rpc_error(-8, "Invalid 'purpose' argument, must be a known purpose string, typically 'send', or 'receive'.", node.listlabels, "notavalidpurpose")
+ assert_raises_rpc_error(-8, "Invalid 'purpose' argument, must be a known purpose string, typically 'send', or 'receive'.", node.listlabels, "unknown")
+
# Note each time we call generate, all generated coins go into
# the same address, so we call twice to get two addresses w/50 each
self.generatetoaddress(node, nblocks=1, address=node.getnewaddress(label='coinbase'))
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
index c5479089c6..712b881322 100755
--- a/test/functional/wallet_listdescriptors.py
+++ b/test/functional/wallet_listdescriptors.py
@@ -65,7 +65,7 @@ class ListDescriptorsTest(BitcoinTestFramework):
self.log.info('Test descriptors with hardened derivations are listed in importable form.')
xprv = 'tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg'
xpub_acc = 'tpubDCMVLhErorrAGfApiJSJzEKwqeaf2z3NrkVMxgYQjZLzMjXMBeRw2muGNYbvaekAE8rUFLftyEar4LdrG2wXyyTJQZ26zptmeTEjPTaATts'
- hardened_path = '/84\'/1\'/0\''
+ hardened_path = '/84h/1h/0h'
wallet = node.get_wallet_rpc('w2')
wallet.importdescriptors([{
'desc': descsum_create('wpkh(' + xprv + hardened_path + '/0/*)'),
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index bfca344fd1..a19a3ac2cb 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -7,7 +7,6 @@
from test_framework.address import key_to_p2wpkh
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import MAX_BIP125_RBF_SEQUENCE
from test_framework.util import (
@@ -15,7 +14,7 @@ from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
from decimal import Decimal
@@ -202,10 +201,8 @@ class ListSinceBlockTest(BitcoinTestFramework):
self.sync_all()
# share utxo between nodes[1] and nodes[2]
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
- address = key_to_p2wpkh(eckey.get_pubkey().get_bytes())
+ privkey, pubkey = generate_keypair(wif=True)
+ address = key_to_p2wpkh(pubkey)
self.nodes[2].sendtoaddress(address, 10)
self.generate(self.nodes[2], 6)
self.nodes[2].importprivkey(privkey)
diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py
index 7c2959bb89..320f5dd9df 100755
--- a/test/functional/wallet_migration.py
+++ b/test/functional/wallet_migration.py
@@ -6,6 +6,7 @@
import os
import random
+import shutil
from test_framework.descriptors import descsum_create
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
@@ -53,7 +54,7 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(addr_info["address"], addr_info_old["address"])
assert_equal(addr_info["scriptPubKey"], addr_info_old["scriptPubKey"])
assert_equal(addr_info["ismine"], addr_info_old["ismine"])
- assert_equal(addr_info["hdkeypath"], addr_info_old["hdkeypath"])
+ assert_equal(addr_info["hdkeypath"], addr_info_old["hdkeypath"].replace("'","h"))
assert_equal(addr_info["solvable"], addr_info_old["solvable"])
assert_equal(addr_info["ischange"], addr_info_old["ischange"])
assert_equal(addr_info["hdmasterfingerprint"], addr_info_old["hdmasterfingerprint"])
@@ -91,11 +92,11 @@ class WalletMigrationTest(BitcoinTestFramework):
self.assert_is_sqlite("basic0")
# The wallet should create the following descriptors:
- # * BIP32 descriptors in the form of "0'/0'/*" and "0'/1'/*" (2 descriptors)
- # * BIP44 descriptors in the form of "44'/1'/0'/0/*" and "44'/1'/0'/1/*" (2 descriptors)
- # * BIP49 descriptors, P2SH(P2WPKH), in the form of "86'/1'/0'/0/*" and "86'/1'/0'/1/*" (2 descriptors)
- # * BIP84 descriptors, P2WPKH, in the form of "84'/1'/0'/1/*" and "84'/1'/0'/1/*" (2 descriptors)
- # * BIP86 descriptors, P2TR, in the form of "86'/1'/0'/0/*" and "86'/1'/0'/1/*" (2 descriptors)
+ # * BIP32 descriptors in the form of "0h/0h/*" and "0h/1h/*" (2 descriptors)
+ # * BIP44 descriptors in the form of "44h/1h/0h/0/*" and "44h/1h/0h/1/*" (2 descriptors)
+ # * BIP49 descriptors, P2SH(P2WPKH), in the form of "86h/1h/0h/0/*" and "86h/1h/0h/1/*" (2 descriptors)
+ # * BIP84 descriptors, P2WPKH, in the form of "84h/1h/0h/1/*" and "84h/1h/0h/1/*" (2 descriptors)
+ # * BIP86 descriptors, P2TR, in the form of "86h/1h/0h/0/*" and "86h/1h/0h/1/*" (2 descriptors)
# * A combo(PK) descriptor for the wallet master key.
# So, should have a total of 11 descriptors on it.
assert_equal(len(basic0.listdescriptors()["descriptors"]), 11)
@@ -107,7 +108,7 @@ class WalletMigrationTest(BitcoinTestFramework):
self.assert_addr_info_equal(change_addr_info, old_change_addr_info)
addr_info = basic0.getaddressinfo(basic0.getnewaddress("", "bech32"))
- assert_equal(addr_info["hdkeypath"], "m/84'/1'/0'/0/0")
+ assert_equal(addr_info["hdkeypath"], "m/84h/1h/0h/0/0")
self.log.info("Test migration of a basic keys only wallet with a balance")
basic1 = self.create_legacy_wallet("basic1")
@@ -281,7 +282,7 @@ class WalletMigrationTest(BitcoinTestFramework):
imports0.importaddress(import_sent_addr)
received_sent_watchonly_txid = default.sendtoaddress(import_sent_addr, 10)
received_sent_watchonly_vout = find_vout_for_address(self.nodes[0], received_sent_watchonly_txid, import_sent_addr)
- send = default.sendall(recipients=[default.getnewaddress()], options={"inputs": [{"txid": received_sent_watchonly_txid, "vout": received_sent_watchonly_vout}]})
+ send = default.sendall(recipients=[default.getnewaddress()], inputs=[{"txid": received_sent_watchonly_txid, "vout": received_sent_watchonly_vout}])
sent_watchonly_txid = send["txid"]
self.generate(self.nodes[0], 1)
@@ -470,6 +471,40 @@ class WalletMigrationTest(BitcoinTestFramework):
assert_equal(bals, wallet.getbalances())
+ def test_default_wallet(self):
+ self.log.info("Test migration of the wallet named as the empty string")
+ wallet = self.create_legacy_wallet("")
+
+ wallet.migratewallet()
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+
+ def test_direct_file(self):
+ self.log.info("Test migration of a wallet that is not in a wallet directory")
+ wallet = self.create_legacy_wallet("plainfile")
+ wallet.unloadwallet()
+
+ wallets_dir = os.path.join(self.nodes[0].datadir, "regtest", "wallets")
+ wallet_path = os.path.join(wallets_dir, "plainfile")
+ wallet_dat_path = os.path.join(wallet_path, "wallet.dat")
+ shutil.copyfile(wallet_dat_path, os.path.join(wallets_dir, "plainfile.bak"))
+ shutil.rmtree(wallet_path)
+ shutil.move(os.path.join(wallets_dir, "plainfile.bak"), wallet_path)
+
+ self.nodes[0].loadwallet("plainfile")
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], False)
+ assert_equal(info["format"], "bdb")
+
+ wallet.migratewallet()
+ info = wallet.getwalletinfo()
+ assert_equal(info["descriptors"], True)
+ assert_equal(info["format"], "sqlite")
+
+ assert os.path.isdir(wallet_path)
+ assert os.path.isfile(wallet_dat_path)
+
def run_test(self):
self.generate(self.nodes[0], 101)
@@ -482,6 +517,8 @@ class WalletMigrationTest(BitcoinTestFramework):
self.test_encrypted()
self.test_unloaded()
self.test_unloaded_by_path()
+ self.test_default_wallet()
+ self.test_direct_file()
if __name__ == '__main__':
WalletMigrationTest().main()
diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py
index 12069fb00d..28bee1911e 100755
--- a/test/functional/wallet_multisig_descriptor_psbt.py
+++ b/test/functional/wallet_multisig_descriptor_psbt.py
@@ -121,7 +121,7 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
to = participants["signers"][self.N - 1].getnewaddress()
value = 1
self.log.info("First, make a sending transaction, created using `walletcreatefundedpsbt` (anyone can initiate this)...")
- psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, options={"feeRate": 0.00010})
+ psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, feeRate=0.00010)
psbts = []
self.log.info("Now at least M users check the psbt with decodepsbt and (if OK) signs it with walletprocesspsbt...")
@@ -143,7 +143,7 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
assert_equal(participants["signers"][self.N - 1].getbalance(), value)
self.log.info("Send another transaction from the multisig, this time with a daisy chained signing flow (one after another in series)!")
- psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, options={"feeRate": 0.00010})
+ psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, feeRate=0.00010)
for m in range(self.M):
signers_multisig = participants["multisigs"][m]
self._check_psbt(psbt["psbt"], to, value, signers_multisig)
diff --git a/test/functional/wallet_orphanedreward.py b/test/functional/wallet_orphanedreward.py
index d8931fa620..451f8abb0a 100755
--- a/test/functional/wallet_orphanedreward.py
+++ b/test/functional/wallet_orphanedreward.py
@@ -65,7 +65,10 @@ class OrphanedBlockRewardTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getbestblockhash(), orig_chain_tip)
self.generate(self.nodes[0], 3)
- assert_equal(self.nodes[1].getbalances(), pre_reorg_conf_bals)
+ balances = self.nodes[1].getbalances()
+ del balances["lastprocessedblock"]
+ del pre_reorg_conf_bals["lastprocessedblock"]
+ assert_equal(balances, pre_reorg_conf_bals)
assert_equal(self.nodes[1].gettransaction(txid)["details"][0]["abandoned"], True)
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 7e4a4002b2..7bdb6f5e3a 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -35,7 +35,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
self.log.info("Create a new transaction and wait until it's broadcast")
parent_utxo, indep_utxo = node.listunspent()[:2]
addr = node.getnewaddress()
- txid = node.send(outputs=[{addr: 1}], options={"inputs": [parent_utxo]})["txid"]
+ txid = node.send(outputs=[{addr: 1}], inputs=[parent_utxo])["txid"]
# Can take a few seconds due to transaction trickling
peer_first.wait_for_broadcast([txid])
@@ -86,7 +86,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# ordering of mapWallet is, if the child is not before the parent, we will create a new
# child (via bumpfee) and remove the old child (via removeprunedfunds) until we get the
# ordering of child before parent.
- child_txid = node.send(outputs=[{addr: 0.5}], options={"inputs": [{"txid":txid, "vout":0}]})["txid"]
+ child_txid = node.send(outputs=[{addr: 0.5}], inputs=[{"txid":txid, "vout":0}])["txid"]
while True:
txids = node.listreceivedbyaddress(minconf=0, address_filter=addr)[0]["txids"]
if txids == [child_txid, txid]:
@@ -111,7 +111,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# Evict these txs from the mempool
evict_time = block_time + 60 * 60 * DEFAULT_MEMPOOL_EXPIRY_HOURS + 5
node.setmocktime(evict_time)
- indep_send = node.send(outputs=[{node.getnewaddress(): 1}], options={"inputs": [indep_utxo]})
+ indep_send = node.send(outputs=[{node.getnewaddress(): 1}], inputs=[indep_utxo])
node.getmempoolentry(indep_send["txid"])
assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, txid)
assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, child_txid)
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index ac3ec06eec..d7bb6ab1e7 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -9,7 +9,6 @@ from itertools import product
from test_framework.authproxy import JSONRPCException
from test_framework.descriptors import descsum_create
-from test_framework.key import ECKey
from test_framework.messages import (
ser_compact_size,
WITNESS_SCALE_FACTOR,
@@ -22,7 +21,8 @@ from test_framework.util import (
assert_raises_rpc_error,
count_bytes,
)
-from test_framework.wallet_util import bytes_to_wif
+from test_framework.wallet_util import generate_keypair
+
class WalletSendTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -500,9 +500,7 @@ class WalletSendTest(BitcoinTestFramework):
assert res["complete"]
self.log.info("External outputs")
- eckey = ECKey()
- eckey.generate()
- privkey = bytes_to_wif(eckey.get_bytes())
+ privkey, _ = generate_keypair(wif=True)
self.nodes[1].createwallet("extsend")
ext_wallet = self.nodes[1].get_wallet_rpc("extsend")
diff --git a/test/functional/wallet_sendall.py b/test/functional/wallet_sendall.py
index f6440f07d7..c2b800df21 100755
--- a/test/functional/wallet_sendall.py
+++ b/test/functional/wallet_sendall.py
@@ -151,7 +151,7 @@ class SendallTest(BitcoinTestFramework):
self.log.info("Test sending more than balance")
pre_sendall_balance = self.add_utxos([7, 14])
- expected_tx = self.wallet.sendall(recipients=[{self.recipient: 5}, self.remainder_target], options={"add_to_wallet": False})
+ expected_tx = self.wallet.sendall(recipients=[{self.recipient: 5}, self.remainder_target], add_to_wallet=False)
tx = self.wallet.decoderawtransaction(expected_tx['hex'])
fee = 21 - sum([o["value"] for o in tx["vout"]])
@@ -190,7 +190,7 @@ class SendallTest(BitcoinTestFramework):
self.add_utxos([0.00000400, 0.00000300, 1])
# sendall with send_max
- sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"send_max": True})
+ sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, send_max=True)
tx_from_wallet = self.wallet.gettransaction(txid = sendall_tx_receipt["txid"], verbose = True)
assert_equal(len(tx_from_wallet["decoded"]["vin"]), 1)
@@ -206,7 +206,7 @@ class SendallTest(BitcoinTestFramework):
self.add_utxos([17, 4])
utxo = self.wallet.listunspent()[0]
- sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], options={"inputs": [utxo]})
+ sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], inputs=[utxo])
tx_from_wallet = self.wallet.gettransaction(txid = sendall_tx_receipt["txid"], verbose = True)
assert_equal(len(tx_from_wallet["decoded"]["vin"]), 1)
assert_equal(len(tx_from_wallet["decoded"]["vout"]), 1)
@@ -227,26 +227,26 @@ class SendallTest(BitcoinTestFramework):
# fails on out of bounds vout
assert_raises_rpc_error(-8,
"Input not found. UTXO ({}:{}) is not part of wallet.".format(spent_utxo["txid"], 1000),
- self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [{"txid": spent_utxo["txid"], "vout": 1000}]})
+ self.wallet.sendall, recipients=[self.remainder_target], inputs=[{"txid": spent_utxo["txid"], "vout": 1000}])
# fails on unconfirmed spent UTXO
self.wallet.sendall(recipients=[self.remainder_target])
assert_raises_rpc_error(-8,
"Input not available. UTXO ({}:{}) was already spent.".format(spent_utxo["txid"], spent_utxo["vout"]),
- self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [spent_utxo]})
+ self.wallet.sendall, recipients=[self.remainder_target], inputs=[spent_utxo])
# fails on specific previously spent UTXO, while other UTXOs exist
self.generate(self.nodes[0], 1)
self.add_utxos([19, 2])
assert_raises_rpc_error(-8,
"Input not available. UTXO ({}:{}) was already spent.".format(spent_utxo["txid"], spent_utxo["vout"]),
- self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [spent_utxo]})
+ self.wallet.sendall, recipients=[self.remainder_target], inputs=[spent_utxo])
# fails because UTXO is unknown, while other UTXOs exist
foreign_utxo = self.def_wallet.listunspent()[0]
assert_raises_rpc_error(-8, "Input not found. UTXO ({}:{}) is not part of wallet.".format(foreign_utxo["txid"],
foreign_utxo["vout"]), self.wallet.sendall, recipients=[self.remainder_target],
- options={"inputs": [foreign_utxo]})
+ inputs=[foreign_utxo])
@cleanup
def sendall_fails_on_no_address(self):
@@ -270,7 +270,7 @@ class SendallTest(BitcoinTestFramework):
"Cannot combine send_max with specific inputs.",
self.wallet.sendall,
recipients=[self.remainder_target],
- options={"inputs": [utxo], "send_max": True})
+ inputs=[utxo], send_max=True)
@cleanup
def sendall_fails_on_high_fee(self):
@@ -308,7 +308,7 @@ class SendallTest(BitcoinTestFramework):
else:
watchonly.importmulti(import_req)
- sendall_tx_receipt = watchonly.sendall(recipients=[self.remainder_target], options={"inputs": [utxo]})
+ sendall_tx_receipt = watchonly.sendall(recipients=[self.remainder_target], inputs=[utxo])
psbt = sendall_tx_receipt["psbt"]
decoded = self.nodes[0].decodepsbt(psbt)
assert_equal(len(decoded["inputs"]), 1)
diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py
index 8d25044e43..c414147c65 100755
--- a/test/functional/wallet_signer.py
+++ b/test/functional/wallet_signer.py
@@ -109,28 +109,28 @@ class WalletSignerTest(BitcoinTestFramework):
address_info = hww.getaddressinfo(address1)
assert_equal(address_info['solvable'], True)
assert_equal(address_info['ismine'], True)
- assert_equal(address_info['hdkeypath'], "m/84'/1'/0'/0/0")
+ assert_equal(address_info['hdkeypath'], "m/84h/1h/0h/0/0")
address2 = hww.getnewaddress(address_type="p2sh-segwit")
assert_equal(address2, "2N2gQKzjUe47gM8p1JZxaAkTcoHPXV6YyVp")
address_info = hww.getaddressinfo(address2)
assert_equal(address_info['solvable'], True)
assert_equal(address_info['ismine'], True)
- assert_equal(address_info['hdkeypath'], "m/49'/1'/0'/0/0")
+ assert_equal(address_info['hdkeypath'], "m/49h/1h/0h/0/0")
address3 = hww.getnewaddress(address_type="legacy")
assert_equal(address3, "n1LKejAadN6hg2FrBXoU1KrwX4uK16mco9")
address_info = hww.getaddressinfo(address3)
assert_equal(address_info['solvable'], True)
assert_equal(address_info['ismine'], True)
- assert_equal(address_info['hdkeypath'], "m/44'/1'/0'/0/0")
+ assert_equal(address_info['hdkeypath'], "m/44h/1h/0h/0/0")
address4 = hww.getnewaddress(address_type="bech32m")
assert_equal(address4, "bcrt1phw4cgpt6cd30kz9k4wkpwm872cdvhss29jga2xpmftelhqll62ms4e9sqj")
address_info = hww.getaddressinfo(address4)
assert_equal(address_info['solvable'], True)
assert_equal(address_info['ismine'], True)
- assert_equal(address_info['hdkeypath'], "m/86'/1'/0'/0/0")
+ assert_equal(address_info['hdkeypath'], "m/86h/1h/0h/0/0")
self.log.info('Test walletdisplayaddress')
result = hww.walletdisplayaddress(address1)
@@ -153,14 +153,14 @@ class WalletSignerTest(BitcoinTestFramework):
assert mock_wallet.getwalletinfo()['private_keys_enabled']
result = mock_wallet.importdescriptors([{
- "desc": "tr([00000001/86'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0/*)#0jtt2jc9",
+ "desc": "tr([00000001/86h/1h/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0/*)#7ew68cn8",
"timestamp": 0,
"range": [0,1],
"internal": False,
"active": True
},
{
- "desc": "tr([00000001/86'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/*)#7xw2h8ga",
+ "desc": "tr([00000001/86h/1h/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/*)#0dtm6drl",
"timestamp": 0,
"range": [0, 0],
"internal": True,
@@ -182,7 +182,7 @@ class WalletSignerTest(BitcoinTestFramework):
# hww4 = self.nodes[1].get_wallet_rpc("hww4")
#
# descriptors = [{
- # "desc": "wpkh([00000001/84'/1'/0']tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/*)#x30uthjs",
+ # "desc": "wpkh([00000001/84h/1h/0']tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/0/*)#x30uthjs",
# "timestamp": "now",
# "range": [0, 1],
# "internal": False,
@@ -190,7 +190,7 @@ class WalletSignerTest(BitcoinTestFramework):
# "active": True
# },
# {
- # "desc": "wpkh([00000001/84'/1'/0']tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)#h92akzzg",
+ # "desc": "wpkh([00000001/84h/1h/0']tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/*)#h92akzzg",
# "timestamp": "now",
# "range": [0, 0],
# "internal": True,
@@ -211,13 +211,13 @@ class WalletSignerTest(BitcoinTestFramework):
self.log.info('Test send using hww1')
# Don't broadcast transaction yet so the RPC returns the raw hex
- res = hww.send(outputs={dest:0.5},options={"add_to_wallet": False})
+ res = hww.send(outputs={dest:0.5},add_to_wallet=False)
assert res["complete"]
assert_equal(res["hex"], mock_tx)
self.log.info('Test sendall using hww1')
- res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()],options={"add_to_wallet": False})
+ res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()], add_to_wallet=False)
assert res["complete"]
assert_equal(res["hex"], mock_tx)
# Broadcast transaction so we can bump the fee
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index b52892704f..a5d7445ce8 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -378,7 +378,7 @@ class WalletTaprootTest(BitcoinTestFramework):
assert psbt_online.gettransaction(txid)['confirmations'] > 0
# Cleanup
- psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"]
+ psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], psbt=True)["psbt"]
res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
txid = self.nodes[0].sendrawtransaction(rawtx)
diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py
index 57a7c3907a..0a622979a4 100755
--- a/test/functional/wallet_timelock.py
+++ b/test/functional/wallet_timelock.py
@@ -29,7 +29,7 @@ class WalletLocktimeTest(BitcoinTestFramework):
self.log.info("Send to new address with locktime")
node.send(
outputs={address: 5},
- options={"locktime": mtp_tip - 1},
+ locktime=mtp_tip - 1,
)
self.generate(node, 1)
diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py
index dd4514318c..b473f5d65c 100755
--- a/test/functional/wallet_watchonly.py
+++ b/test/functional/wallet_watchonly.py
@@ -98,13 +98,13 @@ class CreateWalletWatchonlyTest(BitcoinTestFramework):
options = {'changeAddress': wo_change}
no_wo_options = {'changeAddress': wo_change, 'includeWatching': False}
- result = wo_wallet.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, options=options)
+ result = wo_wallet.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, **options)
assert_equal("psbt" in result, True)
assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.walletcreatefundedpsbt, inputs, outputs, 0, no_wo_options)
self.log.info('Testing fundrawtransaction watch-only defaults')
rawtx = wo_wallet.createrawtransaction(inputs=inputs, outputs=outputs)
- result = wo_wallet.fundrawtransaction(hexstring=rawtx, options=options)
+ result = wo_wallet.fundrawtransaction(hexstring=rawtx, **options)
assert_equal("hex" in result, True)
assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.fundrawtransaction, rawtx, no_wo_options)
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index af21e7b956..d953f48584 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -6,6 +6,7 @@
"""
from concurrent.futures import ThreadPoolExecutor, as_completed
+from pathlib import Path
import argparse
import configparser
import logging
@@ -42,6 +43,11 @@ def main():
help='If true, run fuzzing binaries under the valgrind memory error detector',
)
parser.add_argument(
+ "--empty_min_time",
+ type=int,
+ help="If set, run at least this long, if the existing fuzz inputs directory is empty.",
+ )
+ parser.add_argument(
'-x',
'--exclude',
help="A comma-separated list of targets to exclude",
@@ -76,6 +82,7 @@ def main():
)
args = parser.parse_args()
+ args.corpus_dir = Path(args.corpus_dir)
# Set up logging
logging.basicConfig(
@@ -180,6 +187,7 @@ def main():
src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
use_valgrind=args.valgrind,
+ empty_min_time=args.empty_min_time,
)
@@ -251,16 +259,22 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir)
future.result()
-def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind):
+def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind, empty_min_time):
jobs = []
for t in test_list:
- corpus_path = os.path.join(corpus, t)
+ corpus_path = corpus / t
os.makedirs(corpus_path, exist_ok=True)
args = [
os.path.join(build_dir, 'src', 'test', 'fuzz', 'fuzz'),
- '-runs=1',
- corpus_path,
]
+ empty_dir = not any(corpus_path.iterdir())
+ if empty_min_time and empty_dir:
+ args += [f"-max_total_time={empty_min_time}"]
+ else:
+ args += [
+ "-runs=1",
+ corpus_path,
+ ]
if use_valgrind:
args = ['valgrind', '--quiet', '--error-exitcode=1'] + args
diff --git a/test/lint/lint-assertions.py b/test/lint/lint-assertions.py
index e7eecebce5..6da59b0d48 100755
--- a/test/lint/lint-assertions.py
+++ b/test/lint/lint-assertions.py
@@ -45,6 +45,16 @@ def main():
":(exclude)src/rpc/server.cpp",
], "CHECK_NONFATAL(condition) or NONFATAL_UNREACHABLE should be used instead of assert for RPC code.")
+ # The `BOOST_ASSERT` macro requires to `#include boost/assert.hpp`,
+ # which is an unnecessary Boost dependency.
+ exit_code |= git_grep([
+ "-E",
+ r"BOOST_ASSERT *\(.*\);",
+ "--",
+ "*.cpp",
+ "*.h",
+ ], "BOOST_ASSERT must be replaced with Assert, BOOST_REQUIRE, or BOOST_CHECK.")
+
sys.exit(exit_code)
diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py
index cf6a5f81f1..307b4dca5a 100755
--- a/test/lint/lint-circular-dependencies.py
+++ b/test/lint/lint-circular-dependencies.py
@@ -12,7 +12,7 @@ import subprocess
import sys
EXPECTED_CIRCULAR_DEPENDENCIES = (
- "chainparamsbase -> util/system -> chainparamsbase",
+ "chainparamsbase -> common/args -> chainparamsbase",
"node/blockstorage -> validation -> node/blockstorage",
"node/utxo_snapshot -> validation -> node/utxo_snapshot",
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel",
diff --git a/test/lint/lint-includes.py b/test/lint/lint-includes.py
index 459030bb0b..b14caa4855 100755
--- a/test/lint/lint-includes.py
+++ b/test/lint/lint-includes.py
@@ -23,15 +23,20 @@ EXCLUDED_DIRS = ["src/leveldb/",
EXPECTED_BOOST_INCLUDES = ["boost/date_time/posix_time/posix_time.hpp",
"boost/multi_index/hashed_index.hpp",
+ "boost/multi_index/identity.hpp",
+ "boost/multi_index/indexed_by.hpp",
"boost/multi_index/ordered_index.hpp",
"boost/multi_index/sequenced_index.hpp",
+ "boost/multi_index/tag.hpp",
"boost/multi_index_container.hpp",
"boost/process.hpp",
"boost/signals2/connection.hpp",
"boost/signals2/optional_last_value.hpp",
"boost/signals2/signal.hpp",
"boost/test/included/unit_test.hpp",
- "boost/test/unit_test.hpp"]
+ "boost/test/unit_test.hpp",
+ "boost/tuple/tuple.hpp",
+ ]
def get_toplevel():
diff --git a/test/lint/lint-locale-dependence.py b/test/lint/lint-locale-dependence.py
index faea643882..d84e458bb1 100755
--- a/test/lint/lint-locale-dependence.py
+++ b/test/lint/lint-locale-dependence.py
@@ -44,8 +44,6 @@ from subprocess import check_output, CalledProcessError
KNOWN_VIOLATIONS = [
"src/dbwrapper.cpp:.*vsnprintf",
"src/test/fuzz/locale.cpp:.*setlocale",
- "src/test/fuzz/string.cpp:.*strtol",
- "src/test/fuzz/string.cpp:.*strtoul",
"src/test/util_tests.cpp:.*strtoll",
"src/wallet/bdb.cpp:.*DbEnv::strerror", # False positive
"src/util/syserror.cpp:.*strerror", # Outside this function use `SysErrorString`
diff --git a/test/lint/lint-python-utf8-encoding.py b/test/lint/lint-python-utf8-encoding.py
index 364da63468..64d04bff57 100755
--- a/test/lint/lint-python-utf8-encoding.py
+++ b/test/lint/lint-python-utf8-encoding.py
@@ -12,7 +12,7 @@ import re
from subprocess import check_output, CalledProcessError
-EXCLUDED_DIRS = ["src/crc32c/"]
+EXCLUDED_DIRS = ["src/crc32c/", "src/secp256k1/"]
def get_exclude_args():
diff --git a/test/lint/lint-python.py b/test/lint/lint-python.py
index 4ec7608708..539d0acb5d 100755
--- a/test/lint/lint-python.py
+++ b/test/lint/lint-python.py
@@ -13,9 +13,15 @@ import pkg_resources
import subprocess
import sys
-DEPS = ['flake8', 'mypy', 'pyzmq']
+DEPS = ['flake8', 'lief', 'mypy', 'pyzmq']
MYPY_CACHE_DIR = f"{os.getenv('BASE_ROOT_DIR', '')}/test/.mypy_cache"
-FILES_ARGS = ['git', 'ls-files', 'test/functional/*.py', 'contrib/devtools/*.py']
+
+# All .py files, except those in src/ (to exclude subtrees there)
+FLAKE_FILES_ARGS = ['git', 'ls-files', '*.py', ':!:src/*.py']
+
+# Only .py files in test/functional and contrib/devtools have type annotations
+# enforced.
+MYPY_FILES_ARGS = ['git', 'ls-files', 'test/functional/*.py', 'contrib/devtools/*.py']
ENABLED = (
'E101,' # indentation contains mixed spaces and tabs
@@ -107,8 +113,7 @@ def main():
if len(sys.argv) > 1:
flake8_files = sys.argv[1:]
else:
- files_args = ['git', 'ls-files', '*.py']
- flake8_files = subprocess.check_output(files_args).decode("utf-8").splitlines()
+ flake8_files = subprocess.check_output(FLAKE_FILES_ARGS).decode("utf-8").splitlines()
flake8_args = ['flake8', '--ignore=B,C,E,F,I,N,W', f'--select={ENABLED}'] + flake8_files
flake8_env = os.environ.copy()
@@ -119,7 +124,7 @@ def main():
except subprocess.CalledProcessError:
exit(1)
- mypy_files = subprocess.check_output(FILES_ARGS).decode("utf-8").splitlines()
+ mypy_files = subprocess.check_output(MYPY_FILES_ARGS).decode("utf-8").splitlines()
mypy_args = ['mypy', '--show-error-codes'] + mypy_files
try:
diff --git a/test/lint/run-lint-format-strings.py b/test/lint/run-lint-format-strings.py
index 91915f05f9..d1896dba84 100755
--- a/test/lint/run-lint-format-strings.py
+++ b/test/lint/run-lint-format-strings.py
@@ -241,20 +241,32 @@ def count_format_specifiers(format_string):
3
>>> count_format_specifiers("foo %d bar %i foo %% foo %*d foo")
4
+ >>> count_format_specifiers("foo %5$d")
+ 5
+ >>> count_format_specifiers("foo %5$*7$d")
+ 7
"""
assert type(format_string) is str
format_string = format_string.replace('%%', 'X')
- n = 0
- in_specifier = False
- for i, char in enumerate(format_string):
- if char == "%":
- in_specifier = True
+ n = max_pos = 0
+ for m in re.finditer("%(.*?)[aAcdeEfFgGinopsuxX]", format_string, re.DOTALL):
+ # Increase the max position if the argument has a position number like
+ # "5$", otherwise increment the argument count.
+ pos_num, = re.match(r"(?:(^\d+)\$)?", m.group(1)).groups()
+ if pos_num is not None:
+ max_pos = max(max_pos, int(pos_num))
+ else:
n += 1
- elif char in "aAcdeEfFgGinopsuxX":
- in_specifier = False
- elif in_specifier and char == "*":
+
+ # Increase the max position if there is a "*" width argument with a
+ # position like "*7$", and increment the argument count if there is a
+ # "*" width argument with no position.
+ star, star_pos_num = re.match(r"(?:.*?(\*(?:(\d+)\$)?)|)", m.group(1)).groups()
+ if star_pos_num is not None:
+ max_pos = max(max_pos, int(star_pos_num))
+ elif star is not None:
n += 1
- return n
+ return max(n, max_pos)
def main():
diff --git a/test/lint/spelling.ignore-words.txt b/test/lint/spelling.ignore-words.txt
index d44dd70684..fa47a31725 100644
--- a/test/lint/spelling.ignore-words.txt
+++ b/test/lint/spelling.ignore-words.txt
@@ -11,6 +11,7 @@ hights
inflight
invokable
keypair
+lief
mor
nd
nin
diff --git a/test/sanitizer_suppressions/lsan b/test/sanitizer_suppressions/lsan
index 828b1676f6..7ccb22515f 100644
--- a/test/sanitizer_suppressions/lsan
+++ b/test/sanitizer_suppressions/lsan
@@ -1,5 +1,2 @@
# Suppress warnings triggered in dependencies
leak:libQt5Widgets
-
-# false-positive due to use of secure_allocator<>
-leak:GetRNGState
diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan
index d331991273..82c6885bc4 100644
--- a/test/sanitizer_suppressions/tsan
+++ b/test/sanitizer_suppressions/tsan
@@ -13,6 +13,8 @@ race:zmq::*
race:bitcoin-qt
# deadlock (TODO fix)
+# To reproduce, see:
+# https://github.com/bitcoin/bitcoin/issues/19303#issuecomment-1514926359
deadlock:Chainstate::ConnectTip
# Intentional deadlock in tests
@@ -23,6 +25,7 @@ race:src/qt/test/*
deadlock:src/qt/test/*
# External libraries
+# https://github.com/bitcoin/bitcoin/pull/27658#issuecomment-1547639621
deadlock:libdb
race:libzmq
@@ -35,7 +38,7 @@ race:libzmq
# https://github.com/bitcoin/bitcoin/issues/20618
race:CZMQAbstractPublishNotifier::SendZmqMessage
-# https://github.com/bitcoin/bitcoin/pull/20218, https://github.com/bitcoin/bitcoin/pull/20745
+# https://github.com/bitcoin/bitcoin/pull/27498#issuecomment-1517410478
race:epoll_ctl
# https://github.com/bitcoin/bitcoin/issues/23366
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 2fa4e383e2..74703b04ec 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -5,16 +5,12 @@
# names can be used.
# See https://github.com/google/sanitizers/issues/1364
-# https://github.com/bitcoin/bitcoin/pull/21798#issuecomment-829180719
-signed-integer-overflow:policy/feerate.cpp
-
# -fsanitize=integer suppressions
# ===============================
# Dependencies
# ------------
# Suppressions in dependencies that are developed outside this repository.
unsigned-integer-overflow:*/include/c++/
-unsigned-integer-overflow:bench/bench.h
# unsigned-integer-overflow in FuzzedDataProvider's ConsumeIntegralInRange
unsigned-integer-overflow:FuzzedDataProvider.h
unsigned-integer-overflow:leveldb/
@@ -27,12 +23,11 @@ implicit-integer-sign-change:crc32c/
# implicit-integer-sign-change in FuzzedDataProvider's ConsumeIntegralInRange
implicit-integer-sign-change:FuzzedDataProvider.h
implicit-integer-sign-change:minisketch/
+implicit-signed-integer-truncation:*/include/c++/
implicit-signed-integer-truncation:leveldb/
implicit-unsigned-integer-truncation:*/include/c++/
implicit-unsigned-integer-truncation:leveldb/
implicit-unsigned-integer-truncation:test/fuzz/crypto_diff_fuzz_chacha20.cpp
-# std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9
-implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage
shift-base:*/include/c++/
shift-base:leveldb/
shift-base:minisketch/
@@ -52,7 +47,6 @@ unsigned-integer-overflow:hash.cpp
unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
unsigned-integer-overflow:script/interpreter.cpp
-unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:xoroshiro128plusplus.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h
@@ -62,7 +56,6 @@ implicit-integer-sign-change:prevector.h
implicit-integer-sign-change:script/bitcoinconsensus.cpp
implicit-integer-sign-change:script/interpreter.cpp
implicit-integer-sign-change:serialize.h
-implicit-integer-sign-change:txmempool.cpp
implicit-signed-integer-truncation:crypto/
implicit-unsigned-integer-truncation:crypto/
shift-base:arith_uint256.cpp
diff --git a/test/util/test_runner.py b/test/util/test_runner.py
index e5cdd0bc3a..1cd368f6f4 100755
--- a/test/util/test_runner.py
+++ b/test/util/test_runner.py
@@ -74,6 +74,11 @@ def bctest(testDir, testObj, buildenv):
"""
# Get the exec names and arguments
execprog = os.path.join(buildenv["BUILDDIR"], "src", testObj["exec"] + buildenv["EXEEXT"])
+ if testObj["exec"] == "./bitcoin-util":
+ execprog = os.getenv("BITCOINUTIL", default=execprog)
+ elif testObj["exec"] == "./bitcoin-tx":
+ execprog = os.getenv("BITCOINTX", default=execprog)
+
execargs = testObj['args']
execrun = [execprog] + execargs