aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.test.include20
-rw-r--r--src/banman.h2
-rw-r--r--src/bech32.cpp451
-rw-r--r--src/bech32.h4
-rw-r--r--src/bench/ccoins_caching.cpp2
-rw-r--r--src/bench/rpc_mempool.cpp2
-rw-r--r--src/consensus/amount.h2
-rw-r--r--src/dbwrapper.cpp4
-rw-r--r--src/fs.h45
-rw-r--r--src/httprpc.h2
-rw-r--r--src/i2p.h2
-rw-r--r--src/init.cpp12
-rw-r--r--src/interfaces/chain.h3
-rw-r--r--src/interfaces/node.h4
-rw-r--r--src/key_io.cpp43
-rw-r--r--src/key_io.h2
-rw-r--r--src/net.cpp354
-rw-r--r--src/net.h120
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/netaddress.h6
-rw-r--r--src/node/interfaces.cpp17
-rw-r--r--src/node/minisketchwrapper.cpp (renamed from src/minisketchwrapper.cpp)2
-rw-r--r--src/node/minisketchwrapper.h (renamed from src/minisketchwrapper.h)7
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/policy.cpp11
-rw-r--r--src/policy/policy.h3
-rw-r--r--src/psbt.cpp2
-rw-r--r--src/pubkey.h6
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/forms/openuridialog.ui21
-rw-r--r--src/qt/forms/optionsdialog.ui4
-rw-r--r--src/qt/openuridialog.cpp23
-rw-r--r--src/qt/openuridialog.h9
-rw-r--r--src/qt/psbtoperationsdialog.cpp4
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/qt/test/test_main.cpp2
-rw-r--r--src/randomenv.h2
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/misc.cpp10
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/scheduler.h2
-rw-r--r--src/script/descriptor.cpp1
-rw-r--r--src/script/sign.cpp12
-rw-r--r--src/script/sign.h4
-rw-r--r--src/script/signingprovider.cpp14
-rw-r--r--src/shutdown.h2
-rw-r--r--src/span.h35
-rw-r--r--src/streams.h12
-rw-r--r--src/test/base64_tests.cpp10
-rw-r--r--src/test/bech32_tests.cpp55
-rw-r--r--src/test/denialofservice_tests.cpp24
-rw-r--r--src/test/fuzz/coins_view.cpp3
-rw-r--r--src/test/fuzz/minisketch.cpp64
-rw-r--r--src/test/fuzz/transaction.cpp3
-rw-r--r--src/test/fuzz/tx_pool.cpp2
-rw-r--r--src/test/minisketch_tests.cpp2
-rw-r--r--src/test/script_p2sh_tests.cpp6
-rw-r--r--src/test/scriptnum10.h2
-rw-r--r--src/test/streams_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/test/txpackage_tests.cpp16
-rw-r--r--src/test/util/net.h10
-rw-r--r--src/test/util/setup_common.h2
-rw-r--r--src/test/util_tests.cpp71
-rw-r--r--src/test/validation_block_tests.cpp2
-rw-r--r--src/threadinterrupt.h2
-rw-r--r--src/torcontrol.cpp18
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/util/readwritefile.h2
-rw-r--r--src/util/strencodings.cpp51
-rw-r--r--src/util/strencodings.h34
-rw-r--r--src/util/string.h2
-rw-r--r--src/util/syscall_sandbox.cpp3
-rw-r--r--src/util/trace.h2
-rw-r--r--src/validation.cpp3
-rw-r--r--src/wallet/init.cpp4
-rw-r--r--src/wallet/rpcdump.cpp12
-rw-r--r--src/wallet/rpcwallet.cpp6
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/scriptpubkeyman.cpp18
-rw-r--r--src/wallet/scriptpubkeyman.h7
-rw-r--r--src/wallet/test/fuzz/notifications.cpp3
-rw-r--r--src/wallet/wallet.cpp17
-rw-r--r--src/wallet/wallet.h2
-rw-r--r--src/wallet/wallettool.cpp2
-rw-r--r--src/warnings.h2
-rw-r--r--src/zmq/zmqrpc.h2
89 files changed, 1337 insertions, 446 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 35119f391a..b61df320cd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -167,7 +167,6 @@ BITCOIN_CORE_H = \
memusage.h \
merkleblock.h \
miner.h \
- minisketchwrapper.h \
net.h \
net_permissions.h \
net_processing.h \
@@ -179,6 +178,7 @@ BITCOIN_CORE_H = \
node/coin.h \
node/coinstats.h \
node/context.h \
+ node/minisketchwrapper.h \
node/psbt.h \
node/transaction.h \
node/ui_interface.h \
@@ -335,7 +335,6 @@ libbitcoin_server_a_SOURCES = \
init.cpp \
mapport.cpp \
miner.cpp \
- minisketchwrapper.cpp \
net.cpp \
net_processing.cpp \
node/blockstorage.cpp \
@@ -343,6 +342,7 @@ libbitcoin_server_a_SOURCES = \
node/coinstats.cpp \
node/context.cpp \
node/interfaces.cpp \
+ node/minisketchwrapper.cpp \
node/psbt.cpp \
node/transaction.cpp \
node/ui_interface.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 402cf188c4..715c5bb11c 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -51,6 +51,7 @@ FUZZ_SUITE_LD_COMMON = \
$(BOOST_LIBS) \
$(LIBMEMENV) \
$(LIBSECP256K1) \
+ $(MINISKETCH_LIBS) \
$(EVENT_LIBS) \
$(EVENT_PTHREADS_LIBS)
@@ -64,11 +65,10 @@ endif
# test_bitcoin binary #
BITCOIN_TESTS =\
- test/arith_uint256_tests.cpp \
- test/scriptnum10.h \
test/addrman_tests.cpp \
- test/amount_tests.cpp \
test/allocator_tests.cpp \
+ test/amount_tests.cpp \
+ test/arith_uint256_tests.cpp \
test/base32_tests.cpp \
test/base58_tests.cpp \
test/base64_tests.cpp \
@@ -76,8 +76,8 @@ BITCOIN_TESTS =\
test/bip32_tests.cpp \
test/blockchain_tests.cpp \
test/blockencodings_tests.cpp \
- test/blockfilter_tests.cpp \
test/blockfilter_index_tests.cpp \
+ test/blockfilter_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
@@ -87,6 +87,7 @@ BITCOIN_TESTS =\
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/cuckoocache_tests.cpp \
+ test/dbwrapper_tests.cpp \
test/denialofservice_tests.cpp \
test/descriptor_tests.cpp \
test/flatfile_tests.cpp \
@@ -98,13 +99,11 @@ BITCOIN_TESTS =\
test/key_io_tests.cpp \
test/key_tests.cpp \
test/logging_tests.cpp \
- test/dbwrapper_tests.cpp \
- test/validation_tests.cpp \
test/mempool_tests.cpp \
test/merkle_tests.cpp \
test/merkleblock_tests.cpp \
- test/minisketch_tests.cpp \
test/miner_tests.cpp \
+ test/minisketch_tests.cpp \
test/multisig_tests.cpp \
test/net_peer_eviction_tests.cpp \
test/net_tests.cpp \
@@ -124,6 +123,7 @@ BITCOIN_TESTS =\
test/script_parse_tests.cpp \
test/script_standard_tests.cpp \
test/script_tests.cpp \
+ test/scriptnum10.h \
test/scriptnum_tests.cpp \
test/serfloat_tests.cpp \
test/serialize_tests.cpp \
@@ -135,21 +135,22 @@ BITCOIN_TESTS =\
test/streams_tests.cpp \
test/sync_tests.cpp \
test/system_tests.cpp \
- test/util_threadnames_tests.cpp \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/txindex_tests.cpp \
- test/txrequest_tests.cpp \
test/txpackage_tests.cpp \
+ test/txrequest_tests.cpp \
test/txvalidation_tests.cpp \
test/txvalidationcache_tests.cpp \
test/uint256_tests.cpp \
test/util_tests.cpp \
+ test/util_threadnames_tests.cpp \
test/validation_block_tests.cpp \
test/validation_chainstate_tests.cpp \
test/validation_chainstatemanager_tests.cpp \
test/validation_flush_tests.cpp \
+ test/validation_tests.cpp \
test/validationinterface_tests.cpp \
test/versionbits_tests.cpp
@@ -259,6 +260,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/locale.cpp \
test/fuzz/merkleblock.cpp \
test/fuzz/message.cpp \
+ test/fuzz/minisketch.cpp \
test/fuzz/muhash.cpp \
test/fuzz/multiplication_overflow.cpp \
test/fuzz/net.cpp \
diff --git a/src/banman.h b/src/banman.h
index f495dab49d..6cb6304744 100644
--- a/src/banman.h
+++ b/src/banman.h
@@ -95,4 +95,4 @@ private:
CRollingBloomFilter m_discouraged GUARDED_BY(m_cs_banned) {50000, 0.000001};
};
-#endif
+#endif // BITCOIN_BANMAN_H
diff --git a/src/bech32.cpp b/src/bech32.cpp
index 9da2488ef2..ea44480a6c 100644
--- a/src/bech32.cpp
+++ b/src/bech32.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2017, 2021 Pieter Wuille
+// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -30,6 +31,183 @@ const int8_t CHARSET_REV[128] = {
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
+// We work with the finite field GF(1024) defined as a degree 2 extension of the base field GF(32)
+// The defining polynomial of the extension is x^2 + 9x + 23
+// Let (e) be a primitive element of GF(1024), that is, a generator of the field.
+// Every non-zero element of the field can then be represented as (e)^k for some power k.
+// The array GF1024_EXP contains all these powers of (e) - GF1024_EXP[k] = (e)^k in GF(1024).
+// Conversely, GF1024_LOG contains the discrete logarithms of these powers, so
+// GF1024_LOG[GF1024_EXP[k]] == k
+// Each element v of GF(1024) is encoded as a 10 bit integer in the following way:
+// v = v1 || v0 where v0, v1 are 5-bit integers (elements of GF(32)).
+//
+// The element (e) is encoded as 9 || 15. Given (v), we compute (e)*(v) by multiplying in the following way:
+// v0' = 27*v1 + 15*v0
+// v1' = 6*v1 + 9*v0
+// e*v = v1' || v0'
+//
+// The following sage code can be used to reproduce both _EXP and _LOG arrays
+// GF1024_LOG = [-1] + [0] * 1023
+// GF1024_EXP = [1] * 1024
+// v = 1
+// for i in range(1, 1023):
+// v0 = v & 31
+// v1 = v >> 5
+// v0n = F.fetch_int(27)*F.fetch_int(v1) + F.fetch_int(15)*F.fetch_int(v0)
+// v1n = F.fetch_int(6)*F.fetch_int(v1) + F.fetch_int(9)*F.fetch_int(v0)
+// v = v1n.integer_representation() << 5 | v0n.integer_representation()
+// GF1024_EXP[i] = v
+// GF1024_LOG[v] = i
+
+const int16_t GF1024_EXP[] = {
+ 1, 303, 635, 446, 997, 640, 121, 142, 959, 420, 350, 438, 166, 39, 543,
+ 335, 831, 691, 117, 632, 719, 97, 107, 374, 558, 797, 54, 150, 858, 877,
+ 724, 1013, 294, 23, 354, 61, 164, 633, 992, 538, 469, 659, 174, 868, 184,
+ 809, 766, 563, 866, 851, 257, 520, 45, 770, 535, 524, 408, 213, 436, 760,
+ 472, 330, 933, 799, 616, 361, 15, 391, 756, 814, 58, 608, 554, 680, 993,
+ 821, 942, 813, 843, 484, 193, 935, 321, 919, 572, 741, 423, 559, 562,
+ 589, 296, 191, 493, 685, 891, 665, 435, 60, 395, 2, 606, 511, 853, 746,
+ 32, 219, 284, 631, 840, 661, 837, 332, 78, 311, 670, 887, 111, 195, 505,
+ 190, 194, 214, 709, 380, 819, 69, 261, 957, 1018, 161, 739, 588, 7, 708,
+ 83, 328, 507, 736, 317, 899, 47, 348, 1000, 345, 882, 245, 367, 996, 943,
+ 514, 304, 90, 804, 295, 312, 793, 387, 833, 249, 921, 660, 618, 823, 496,
+ 722, 30, 782, 225, 892, 93, 480, 372, 112, 738, 867, 636, 890, 950, 968,
+ 386, 622, 642, 551, 369, 234, 846, 382, 365, 442, 592, 343, 986, 122,
+ 1023, 59, 847, 81, 790, 4, 437, 983, 931, 244, 64, 415, 529, 487, 944,
+ 35, 938, 664, 156, 583, 53, 999, 222, 390, 987, 341, 388, 389, 170, 721,
+ 879, 138, 522, 627, 765, 322, 230, 440, 14, 168, 143, 656, 991, 224, 595,
+ 550, 94, 657, 752, 667, 1005, 451, 734, 744, 638, 292, 585, 157, 872,
+ 590, 601, 827, 774, 930, 475, 571, 33, 500, 871, 969, 173, 21, 828, 450,
+ 1009, 147, 960, 705, 201, 228, 998, 497, 1021, 613, 688, 772, 508, 36,
+ 366, 715, 468, 956, 725, 730, 861, 425, 647, 701, 221, 759, 95, 958, 139,
+ 805, 8, 835, 679, 614, 449, 128, 791, 299, 974, 617, 70, 628, 57, 273,
+ 430, 67, 750, 405, 780, 703, 643, 776, 778, 340, 171, 1022, 276, 308,
+ 495, 243, 644, 460, 857, 28, 336, 286, 41, 695, 448, 431, 364, 149, 43,
+ 233, 63, 762, 902, 181, 240, 501, 584, 434, 275, 1008, 444, 443, 895,
+ 812, 612, 927, 383, 66, 961, 1006, 690, 346, 3, 881, 900, 747, 271, 672,
+ 162, 402, 456, 748, 971, 755, 490, 105, 808, 977, 72, 732, 182, 897, 625,
+ 163, 189, 947, 850, 46, 115, 403, 231, 151, 629, 278, 874, 16, 934, 110,
+ 492, 898, 256, 807, 598, 700, 498, 140, 481, 91, 523, 860, 134, 252, 771,
+ 824, 119, 38, 816, 820, 641, 342, 757, 513, 577, 990, 463, 40, 920, 955,
+ 17, 649, 533, 82, 103, 896, 862, 728, 259, 86, 466, 87, 253, 556, 323,
+ 457, 963, 432, 845, 527, 745, 849, 863, 1015, 888, 488, 567, 727, 132,
+ 674, 764, 109, 669, 6, 1003, 552, 246, 542, 96, 324, 781, 912, 248, 694,
+ 239, 980, 210, 880, 683, 144, 177, 325, 546, 491, 326, 339, 623, 941, 92,
+ 207, 783, 462, 263, 483, 517, 1012, 9, 620, 220, 984, 548, 512, 878, 421,
+ 113, 973, 280, 962, 159, 310, 945, 268, 465, 806, 889, 199, 76, 873, 865,
+ 34, 645, 227, 290, 418, 693, 926, 80, 569, 639, 11, 50, 291, 141, 206,
+ 544, 949, 185, 518, 133, 909, 135, 467, 376, 646, 914, 678, 841, 954,
+ 318, 242, 939, 951, 743, 1017, 976, 359, 167, 264, 100, 241, 218, 51, 12,
+ 758, 368, 453, 309, 192, 648, 826, 553, 473, 101, 478, 673, 397, 1001,
+ 118, 265, 331, 650, 356, 982, 652, 655, 510, 634, 145, 414, 830, 924,
+ 526, 966, 298, 737, 18, 504, 401, 697, 360, 288, 1020, 842, 203, 698,
+ 537, 676, 279, 581, 619, 536, 907, 876, 1019, 398, 152, 1010, 994, 68,
+ 42, 454, 580, 836, 99, 565, 137, 379, 503, 22, 77, 582, 282, 412, 352,
+ 611, 347, 300, 266, 570, 270, 911, 729, 44, 557, 108, 946, 637, 597, 461,
+ 630, 615, 238, 763, 681, 718, 334, 528, 200, 459, 413, 79, 24, 229, 713,
+ 906, 579, 384, 48, 893, 370, 923, 202, 917, 98, 794, 754, 197, 530, 662,
+ 52, 712, 677, 56, 62, 981, 509, 267, 789, 885, 561, 316, 684, 596, 226,
+ 13, 985, 779, 123, 720, 576, 753, 948, 406, 125, 315, 104, 519, 426, 502,
+ 313, 566, 1016, 767, 796, 281, 749, 740, 136, 84, 908, 424, 936, 198,
+ 355, 274, 735, 967, 5, 154, 428, 541, 785, 704, 486, 671, 600, 532, 381,
+ 540, 574, 187, 88, 378, 216, 621, 499, 419, 922, 485, 494, 476, 255, 114,
+ 188, 668, 297, 400, 918, 787, 158, 25, 458, 178, 564, 422, 768, 73, 1011,
+ 717, 575, 404, 547, 196, 829, 237, 394, 301, 37, 65, 176, 106, 89, 85,
+ 675, 979, 534, 803, 995, 363, 593, 120, 417, 452, 26, 699, 822, 223, 169,
+ 416, 235, 609, 773, 211, 607, 208, 302, 852, 965, 603, 357, 761, 247,
+ 817, 539, 250, 232, 272, 129, 568, 848, 624, 396, 710, 525, 183, 686, 10,
+ 285, 856, 307, 811, 160, 972, 55, 441, 289, 723, 305, 373, 351, 153, 733,
+ 409, 506, 975, 838, 573, 970, 988, 913, 471, 205, 337, 49, 594, 777, 549,
+ 815, 277, 27, 916, 333, 353, 844, 800, 146, 751, 186, 375, 769, 358, 392,
+ 883, 474, 788, 602, 74, 130, 329, 212, 155, 131, 102, 687, 293, 870, 742,
+ 726, 427, 217, 834, 904, 29, 127, 869, 407, 338, 832, 470, 482, 810, 399,
+ 439, 393, 604, 929, 682, 447, 714, 251, 455, 875, 319, 477, 464, 521,
+ 258, 377, 937, 489, 792, 172, 314, 327, 124, 20, 531, 953, 591, 886, 320,
+ 696, 71, 859, 578, 175, 587, 707, 663, 283, 179, 795, 989, 702, 940, 371,
+ 692, 689, 555, 903, 410, 651, 75, 429, 818, 362, 894, 515, 31, 545, 666,
+ 706, 952, 864, 269, 254, 349, 711, 802, 716, 784, 1007, 925, 801, 445,
+ 148, 260, 658, 385, 287, 262, 204, 126, 586, 1004, 236, 165, 854, 411,
+ 932, 560, 19, 215, 1002, 775, 653, 928, 901, 964, 884, 798, 839, 786,
+ 433, 610, 116, 855, 180, 479, 910, 1014, 599, 915, 905, 306, 516, 731,
+ 626, 978, 825, 344, 605, 654, 209
+};
+// As above, GF1024_EXP contains all elements of GF(1024) except 0
+static_assert(std::size(GF1024_EXP) == 1023, "GF1024_EXP length should be 1023");
+
+const int16_t GF1024_LOG[] = {
+ -1, 0, 99, 363, 198, 726, 462, 132, 297, 495, 825, 528, 561, 693, 231,
+ 66, 396, 429, 594, 990, 924, 264, 627, 33, 660, 759, 792, 858, 330, 891,
+ 165, 957, 104, 259, 518, 208, 280, 776, 416, 13, 426, 333, 618, 339, 641,
+ 52, 388, 140, 666, 852, 529, 560, 678, 213, 26, 832, 681, 309, 70, 194,
+ 97, 35, 682, 341, 203, 777, 358, 312, 617, 125, 307, 931, 379, 765, 875,
+ 951, 515, 628, 112, 659, 525, 196, 432, 134, 717, 781, 438, 440, 740,
+ 780, 151, 408, 487, 169, 239, 293, 467, 21, 672, 622, 557, 571, 881, 433,
+ 704, 376, 779, 22, 643, 460, 398, 116, 172, 503, 751, 389, 1004, 18, 576,
+ 415, 789, 6, 192, 696, 923, 702, 981, 892, 302, 816, 876, 880, 457, 537,
+ 411, 539, 716, 624, 224, 295, 406, 531, 7, 233, 478, 586, 864, 268, 974,
+ 338, 27, 392, 614, 839, 727, 879, 211, 250, 758, 507, 830, 129, 369, 384,
+ 36, 985, 12, 555, 232, 796, 221, 321, 920, 263, 42, 934, 778, 479, 761,
+ 939, 1006, 344, 381, 823, 44, 535, 866, 739, 752, 385, 119, 91, 566, 80,
+ 120, 117, 771, 675, 721, 514, 656, 271, 670, 602, 980, 850, 532, 488,
+ 803, 1022, 475, 801, 878, 57, 121, 991, 742, 888, 559, 105, 497, 291,
+ 215, 795, 236, 167, 692, 520, 272, 661, 229, 391, 814, 340, 184, 798,
+ 984, 773, 650, 473, 345, 558, 548, 326, 202, 145, 465, 810, 471, 158,
+ 813, 908, 412, 441, 964, 750, 401, 50, 915, 437, 975, 126, 979, 491, 556,
+ 577, 636, 685, 510, 963, 638, 367, 815, 310, 723, 349, 323, 857, 394,
+ 606, 505, 713, 630, 938, 106, 826, 332, 978, 599, 834, 521, 530, 248,
+ 883, 32, 153, 90, 754, 592, 304, 635, 775, 804, 1, 150, 836, 1013, 828,
+ 324, 565, 508, 113, 154, 708, 921, 703, 689, 138, 547, 911, 929, 82, 228,
+ 443, 468, 480, 483, 922, 135, 877, 61, 578, 111, 860, 654, 15, 331, 851,
+ 895, 484, 320, 218, 420, 190, 1019, 143, 362, 634, 141, 965, 10, 838,
+ 632, 861, 34, 722, 580, 808, 869, 554, 598, 65, 954, 787, 337, 187, 281,
+ 146, 563, 183, 668, 944, 171, 837, 23, 867, 541, 916, 741, 625, 123, 736,
+ 186, 357, 665, 977, 179, 156, 219, 220, 216, 67, 870, 902, 774, 98, 820,
+ 574, 613, 900, 755, 596, 370, 390, 769, 314, 701, 894, 56, 841, 949, 987,
+ 631, 658, 587, 204, 797, 790, 522, 745, 9, 502, 763, 86, 719, 288, 706,
+ 887, 728, 952, 311, 336, 446, 1002, 348, 96, 58, 199, 11, 901, 230, 833,
+ 188, 352, 351, 973, 3, 906, 335, 301, 266, 244, 791, 564, 619, 909, 371,
+ 444, 760, 657, 328, 647, 490, 425, 913, 511, 439, 540, 283, 40, 897, 849,
+ 60, 570, 872, 257, 749, 912, 572, 1007, 170, 407, 898, 492, 79, 747, 732,
+ 206, 454, 918, 375, 482, 399, 92, 748, 325, 163, 274, 405, 744, 260, 346,
+ 707, 626, 595, 118, 842, 136, 279, 684, 584, 101, 500, 422, 149, 956,
+ 1014, 493, 536, 705, 51, 914, 225, 409, 55, 822, 590, 448, 655, 205, 676,
+ 925, 735, 431, 784, 54, 609, 604, 39, 812, 737, 729, 466, 14, 533, 958,
+ 481, 770, 499, 855, 238, 182, 464, 569, 72, 947, 442, 642, 24, 87, 989,
+ 688, 88, 47, 762, 623, 709, 455, 817, 526, 637, 258, 84, 845, 738, 768,
+ 698, 423, 933, 664, 620, 607, 629, 212, 347, 249, 982, 935, 131, 89, 252,
+ 927, 189, 788, 853, 237, 691, 646, 403, 1010, 734, 253, 874, 807, 903,
+ 1020, 100, 802, 71, 799, 1003, 633, 355, 276, 300, 649, 64, 306, 161,
+ 608, 496, 743, 180, 485, 819, 383, 1016, 226, 308, 393, 648, 107, 19, 37,
+ 585, 2, 175, 645, 247, 527, 5, 419, 181, 317, 327, 519, 542, 289, 567,
+ 430, 579, 950, 582, 994, 1021, 583, 234, 240, 976, 41, 160, 109, 677,
+ 937, 210, 95, 959, 242, 753, 461, 114, 733, 368, 573, 458, 782, 605, 680,
+ 544, 299, 73, 652, 905, 477, 690, 93, 824, 882, 277, 946, 361, 17, 945,
+ 523, 472, 334, 930, 597, 603, 793, 404, 290, 942, 316, 731, 270, 960,
+ 936, 133, 122, 821, 966, 679, 662, 907, 282, 968, 767, 653, 20, 697, 222,
+ 164, 835, 30, 285, 886, 456, 436, 640, 286, 1015, 380, 840, 245, 724,
+ 137, 593, 173, 130, 715, 85, 885, 551, 246, 449, 103, 366, 372, 714, 313,
+ 865, 241, 699, 674, 374, 68, 421, 562, 292, 59, 809, 342, 651, 459, 227,
+ 46, 711, 764, 868, 53, 413, 278, 800, 255, 993, 318, 854, 319, 695, 315,
+ 469, 166, 489, 969, 730, 1001, 757, 873, 686, 197, 303, 919, 155, 673,
+ 940, 712, 25, 999, 63, 863, 972, 967, 785, 152, 296, 512, 402, 377, 45,
+ 899, 829, 354, 77, 69, 856, 417, 811, 953, 124, 418, 75, 794, 162, 414,
+ 1018, 568, 254, 265, 772, 588, 16, 896, 157, 889, 298, 621, 110, 844,
+ 1000, 108, 545, 601, 78, 862, 447, 185, 195, 818, 450, 387, 49, 805, 102,
+ 986, 1005, 827, 329, 28, 932, 410, 287, 435, 451, 962, 517, 48, 174, 43,
+ 893, 884, 261, 251, 516, 395, 910, 611, 29, 501, 223, 476, 364, 144, 871,
+ 998, 687, 928, 115, 453, 513, 176, 94, 168, 667, 955, 353, 434, 382, 400,
+ 139, 365, 996, 343, 948, 890, 1012, 663, 610, 718, 538, 1008, 639, 470,
+ 848, 543, 1011, 859, 671, 756, 83, 427, 159, 746, 669, 589, 971, 524,
+ 356, 995, 904, 256, 201, 988, 62, 397, 81, 720, 917, 209, 549, 943, 486,
+ 76, 148, 207, 509, 644, 386, 700, 534, 177, 550, 961, 926, 546, 428, 284,
+ 127, 294, 8, 269, 359, 506, 445, 997, 806, 591, 725, 178, 262, 846, 373,
+ 831, 504, 305, 843, 553, 378, 1017, 783, 474, 683, 581, 200, 498, 694,
+ 191, 217, 847, 941, 424, 235, 38, 74, 616, 786, 147, 4, 273, 214, 142,
+ 575, 992, 463, 983, 243, 360, 970, 350, 267, 615, 766, 494, 31, 1009,
+ 452, 710, 552, 128, 612, 600, 275, 322, 193
+};
+static_assert(std::size(GF1024_LOG) == 1024, "GF1024_EXP length should be 1024");
+
/* Determine the final constant to use for the specified encoding. */
uint32_t EncodingConstant(Encoding encoding) {
assert(encoding == Encoding::BECH32 || encoding == Encoding::BECH32M);
@@ -127,12 +305,116 @@ uint32_t PolyMod(const data& v)
return c;
}
+/** Syndrome computes the values s_j = R(e^j) for j in [997, 998, 999]. As described above, the
+ * generator polynomial G is the LCM of the minimal polynomials of (e)^997, (e)^998, and (e)^999.
+ *
+ * Consider a codeword with errors, of the form R(x) = C(x) + E(x). The residue is the bit-packed
+ * result of computing R(x) mod G(X), where G is the generator of the code. Because C(x) is a valid
+ * codeword, it is a multiple of G(X), so the residue is in fact just E(x) mod G(x). Note that all
+ * of the (e)^j are roots of G(x) by definition, so R((e)^j) = E((e)^j).
+ *
+ * Syndrome returns the three values packed into a 30-bit integer, where each 10 bits is one value.
+ */
+uint32_t Syndrome(const uint32_t residue) {
+ // Let R(x) = r1*x^5 + r2*x^4 + r3*x^3 + r4*x^2 + r5*x + r6
+ // low is the first 5 bits, corresponding to the r6 in the residue
+ // (the constant term of the polynomial).
+
+ uint32_t low = residue & 0x1f;
+
+ // Recall that XOR corresponds to addition in a characteristic 2 field.
+ //
+ // To compute R((e)^j), we are really computing:
+ // r1*(e)^(j*5) + r2*(e)^(j*4) + r3*(e)^(j*3) + r4*(e)^(j*2) + r5*(e)^j + r6
+ // Now note that all of the (e)^(j*i) for i in [5..0] are constants and can be precomputed
+ // for efficiency. But even more than that, we can consider each coefficient as a bit-string.
+ // For example, take r5 = (b_5, b_4, b_3, b_2, b_1) written out as 5 bits. Then:
+ // r5*(e)^j = b_1*(e)^j + b_2*(2*(e)^j) + b_3*(4*(e)^j) + b_4*(8*(e)^j) + b_5*(16*(e)^j)
+ // where all the (2^i*(e)^j) are constants and can be precomputed. Then we just add each
+ // of these corresponding constants to our final value based on the bit values b_i.
+ // This is exactly what is done below. Note that all three values of s_j for j in (997, 998,
+ // 999) are computed simultaneously.
+ //
+ // We begin by setting s_j = low = r6 for all three values of j, because these are unconditional.
+ // Then for each following bit, we add the corresponding precomputed constant if the bit is 1.
+ // For example, 0x31edd3c4 is 1100011110 1101110100 1111000100 when unpacked in groups of 10
+ // bits, corresponding exactly to a^999 || a^998 || a^997 (matching the corresponding values in
+ // GF1024_EXP above).
+ //
+ // The following sage code reproduces these constants:
+ // for k in range(1, 6):
+ // for b in [1,2,4,8,16]:
+ // c0 = GF1024_EXP[(997*k + GF1024_LOG[b]) % 1023]
+ // c1 = GF1024_EXP[(998*k + GF1024_LOG[b]) % 1023]
+ // c2 = GF1024_EXP[(999*k + GF1024_LOG[b]) % 1023]
+ // c = c2 << 20 | c1 << 10 | c0
+ // print("0x%x" % c)
+
+ return low ^ (low << 10) ^ (low << 20) ^
+ ((residue >> 5) & 1 ? 0x31edd3c4 : 0) ^
+ ((residue >> 6) & 1 ? 0x335f86a8 : 0) ^
+ ((residue >> 7) & 1 ? 0x363b8870 : 0) ^
+ ((residue >> 8) & 1 ? 0x3e6390c9 : 0) ^
+ ((residue >> 9) & 1 ? 0x2ec72192 : 0) ^
+ ((residue >> 10) & 1 ? 0x1046f79d : 0) ^
+ ((residue >> 11) & 1 ? 0x208d4e33 : 0) ^
+ ((residue >> 12) & 1 ? 0x130ebd6f : 0) ^
+ ((residue >> 13) & 1 ? 0x2499fade : 0) ^
+ ((residue >> 14) & 1 ? 0x1b27d4b5 : 0) ^
+ ((residue >> 15) & 1 ? 0x04be1eb4 : 0) ^
+ ((residue >> 16) & 1 ? 0x0968b861 : 0) ^
+ ((residue >> 17) & 1 ? 0x1055f0c2 : 0) ^
+ ((residue >> 18) & 1 ? 0x20ab4584 : 0) ^
+ ((residue >> 19) & 1 ? 0x1342af08 : 0) ^
+ ((residue >> 20) & 1 ? 0x24f1f318 : 0) ^
+ ((residue >> 21) & 1 ? 0x1be34739 : 0) ^
+ ((residue >> 22) & 1 ? 0x35562f7b : 0) ^
+ ((residue >> 23) & 1 ? 0x3a3c5bff : 0) ^
+ ((residue >> 24) & 1 ? 0x266c96f7 : 0) ^
+ ((residue >> 25) & 1 ? 0x25c78b65 : 0) ^
+ ((residue >> 26) & 1 ? 0x1b1f13ea : 0) ^
+ ((residue >> 27) & 1 ? 0x34baa2f4 : 0) ^
+ ((residue >> 28) & 1 ? 0x3b61c0e1 : 0) ^
+ ((residue >> 29) & 1 ? 0x265325c2 : 0);
+}
+
/** Convert to lower case. */
inline unsigned char LowerCase(unsigned char c)
{
return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c;
}
+void push_range(int from, int to, std::vector<int>& vec)
+{
+ for (int i = from; i < to; i++) {
+ vec.push_back(i);
+ }
+}
+
+/** Return index of first invalid character in a Bech32 string. */
+bool CheckCharacters(const std::string& str, std::vector<int>& errors) {
+ bool lower = false, upper = false;
+ for (size_t i = 0; i < str.size(); ++i) {
+ unsigned char c = str[i];
+ if (c >= 'a' && c <= 'z') {
+ if (upper) {
+ errors.push_back(i);
+ } else {
+ lower = true;
+ }
+ } else if (c >= 'A' && c <= 'Z') {
+ if (lower) {
+ errors.push_back(i);
+ } else {
+ upper = true;
+ }
+ } else if (c < 33 || c > 126) {
+ errors.push_back(i);
+ }
+ }
+ return errors.empty();
+}
+
/** Expand a HRP for use in checksum computation. */
data ExpandHRP(const std::string& hrp)
{
@@ -196,14 +478,8 @@ std::string Encode(Encoding encoding, const std::string& hrp, const data& values
/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str) {
- bool lower = false, upper = false;
- for (size_t i = 0; i < str.size(); ++i) {
- unsigned char c = str[i];
- if (c >= 'a' && c <= 'z') lower = true;
- else if (c >= 'A' && c <= 'Z') upper = true;
- else if (c < 33 || c > 126) return {};
- }
- if (lower && upper) return {};
+ std::vector<int> errors;
+ if (!CheckCharacters(str, errors)) return {};
size_t pos = str.rfind('1');
if (str.size() > 90 || pos == str.npos || pos == 0 || pos + 7 > str.size()) {
return {};
@@ -227,4 +503,163 @@ DecodeResult Decode(const std::string& str) {
return {result, std::move(hrp), data(values.begin(), values.end() - 6)};
}
+/** Find index of an incorrect character in a Bech32 string. */
+std::string LocateErrors(const std::string& str, std::vector<int>& error_locations) {
+ if (str.size() > 90) {
+ push_range(90, str.size(), error_locations);
+ return "Bech32 string too long";
+ }
+ if (!CheckCharacters(str, error_locations)){
+ return "Invalid character or mixed case";
+ }
+ size_t pos = str.rfind('1');
+ if (pos == str.npos) {
+ return "Missing separator";
+ }
+ if (pos == 0 || pos + 7 > str.size()) {
+ error_locations.push_back(pos);
+ return "Invalid separator position";
+ }
+ std::string hrp;
+ for (size_t i = 0; i < pos; ++i) {
+ hrp += LowerCase(str[i]);
+ }
+
+ size_t length = str.size() - 1 - pos; // length of data part
+ data values(length);
+ for (size_t i = pos + 1; i < str.size(); ++i) {
+ unsigned char c = str[i];
+ int8_t rev = CHARSET_REV[c];
+ if (rev == -1) {
+ error_locations.push_back(i);
+ return "Invalid Base 32 character";
+ }
+ values[i - pos - 1] = rev;
+ }
+
+ // We attempt error detection with both bech32 and bech32m, and choose the one with the fewest errors
+ // We can't simply use the segwit version, because that may be one of the errors
+ for (Encoding encoding : {Encoding::BECH32, Encoding::BECH32M}) {
+ std::vector<int> possible_errors;
+ // Recall that (ExpandHRP(hrp) ++ values) is interpreted as a list of coefficients of a polynomial
+ // over GF(32). PolyMod computes the "remainder" of this polynomial modulo the generator G(x).
+ uint32_t residue = PolyMod(Cat(ExpandHRP(hrp), values)) ^ EncodingConstant(encoding);
+
+ // All valid codewords should be multiples of G(x), so this remainder (after XORing with the encoding
+ // constant) should be 0 - hence 0 indicates there are no errors present.
+ if (residue != 0) {
+ // If errors are present, our polynomial must be of the form C(x) + E(x) where C is the valid
+ // codeword (a multiple of G(x)), and E encodes the errors.
+ uint32_t syn = Syndrome(residue);
+
+ // Unpack the three 10-bit syndrome values
+ int s0 = syn & 0x3FF;
+ int s1 = (syn >> 10) & 0x3FF;
+ int s2 = syn >> 20;
+
+ // Get the discrete logs of these values in GF1024 for more efficient computation
+ int l_s0 = GF1024_LOG[s0];
+ int l_s1 = GF1024_LOG[s1];
+ int l_s2 = GF1024_LOG[s2];
+
+ // First, suppose there is only a single error. Then E(x) = e1*x^p1 for some position p1
+ // Then s0 = E((e)^997) = e1*(e)^(997*p1) and s1 = E((e)^998) = e1*(e)^(998*p1)
+ // Therefore s1/s0 = (e)^p1, and by the same logic, s2/s1 = (e)^p1 too.
+ // Hence, s1^2 == s0*s2, which is exactly the condition we check first:
+ if (l_s0 != -1 && l_s1 != -1 && l_s2 != -1 && (2 * l_s1 - l_s2 - l_s0 + 2046) % 1023 == 0) {
+ // Compute the error position p1 as l_s1 - l_s0 = p1 (mod 1023)
+ size_t p1 = (l_s1 - l_s0 + 1023) % 1023; // the +1023 ensures it is positive
+ // Now because s0 = e1*(e)^(997*p1), we get e1 = s0/((e)^(997*p1)). Remember that (e)^1023 = 1,
+ // so 1/((e)^997) = (e)^(1023-997).
+ int l_e1 = l_s0 + (1023 - 997) * p1;
+ // Finally, some sanity checks on the result:
+ // - The error position should be within the length of the data
+ // - e1 should be in GF(32), which implies that e1 = (e)^(33k) for some k (the 31 non-zero elements
+ // of GF(32) form an index 33 subgroup of the 1023 non-zero elements of GF(1024)).
+ if (p1 < length && !(l_e1 % 33)) {
+ // Polynomials run from highest power to lowest, so the index p1 is from the right.
+ // We don't return e1 because it is dangerous to suggest corrections to the user,
+ // the user should check the address themselves.
+ possible_errors.push_back(str.size() - p1 - 1);
+ }
+ // Otherwise, suppose there are two errors. Then E(x) = e1*x^p1 + e2*x^p2.
+ } else {
+ // For all possible first error positions p1
+ for (size_t p1 = 0; p1 < length; ++p1) {
+ // We have guessed p1, and want to solve for p2. Recall that E(x) = e1*x^p1 + e2*x^p2, so
+ // s0 = E((e)^997) = e1*(e)^(997^p1) + e2*(e)^(997*p2), and similar for s1 and s2.
+ //
+ // Consider s2 + s1*(e)^p1
+ // = 2e1*(e)^(999^p1) + e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1
+ // = e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1
+ // (Because we are working in characteristic 2.)
+ // = e2*(e)^(998*p2) ((e)^p2 + (e)^p1)
+ //
+ int s2_s1p1 = s2 ^ (s1 == 0 ? 0 : GF1024_EXP[(l_s1 + p1) % 1023]);
+ if (s2_s1p1 == 0) continue;
+ int l_s2_s1p1 = GF1024_LOG[s2_s1p1];
+
+ // Similarly, s1 + s0*(e)^p1
+ // = e2*(e)^(997*p2) ((e)^p2 + (e)^p1)
+ int s1_s0p1 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p1) % 1023]);
+ if (s1_s0p1 == 0) continue;
+ int l_s1_s0p1 = GF1024_LOG[s1_s0p1];
+
+ // So, putting these together, we can compute the second error position as
+ // (e)^p2 = (s2 + s1^p1)/(s1 + s0^p1)
+ // p2 = log((e)^p2)
+ size_t p2 = (l_s2_s1p1 - l_s1_s0p1 + 1023) % 1023;
+
+ // Sanity checks that p2 is a valid position and not the same as p1
+ if (p2 >= length || p1 == p2) continue;
+
+ // Now we want to compute the error values e1 and e2.
+ // Similar to above, we compute s1 + s0*(e)^p2
+ // = e1*(e)^(997*p1) ((e)^p1 + (e)^p2)
+ int s1_s0p2 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p2) % 1023]);
+ if (s1_s0p2 == 0) continue;
+ int l_s1_s0p2 = GF1024_LOG[s1_s0p2];
+
+ // And compute (the log of) 1/((e)^p1 + (e)^p2))
+ int inv_p1_p2 = 1023 - GF1024_LOG[GF1024_EXP[p1] ^ GF1024_EXP[p2]];
+
+ // Then (s1 + s0*(e)^p1) * (1/((e)^p1 + (e)^p2)))
+ // = e2*(e)^(997*p2)
+ // Then recover e2 by dividing by (e)^(997*p2)
+ int l_e2 = l_s1_s0p1 + inv_p1_p2 + (1023 - 997) * p2;
+ // Check that e2 is in GF(32)
+ if (l_e2 % 33) continue;
+
+ // In the same way, (s1 + s0*(e)^p2) * (1/((e)^p1 + (e)^p2)))
+ // = e1*(e)^(997*p1)
+ // So recover e1 by dividing by (e)^(997*p1)
+ int l_e1 = l_s1_s0p2 + inv_p1_p2 + (1023 - 997) * p1;
+ // Check that e1 is in GF(32)
+ if (l_e1 % 33) continue;
+
+ // Again, we do not return e1 or e2 for safety.
+ // Order the error positions from the left of the string and return them
+ if (p1 > p2) {
+ possible_errors.push_back(str.size() - p1 - 1);
+ possible_errors.push_back(str.size() - p2 - 1);
+ } else {
+ possible_errors.push_back(str.size() - p2 - 1);
+ possible_errors.push_back(str.size() - p1 - 1);
+ }
+ break;
+ }
+ }
+ } else {
+ // No errors
+ error_locations.clear();
+ return "";
+ }
+
+ if (error_locations.empty() || (!possible_errors.empty() && possible_errors.size() < error_locations.size())) {
+ error_locations = std::move(possible_errors);
+ }
+ }
+ return "Invalid checksum";
+}
+
} // namespace bech32
diff --git a/src/bech32.h b/src/bech32.h
index e9450ccc2b..7e92d5d23a 100644
--- a/src/bech32.h
+++ b/src/bech32.h
@@ -1,4 +1,5 @@
// Copyright (c) 2017, 2021 Pieter Wuille
+// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -44,6 +45,9 @@ struct DecodeResult
/** Decode a Bech32 or Bech32m string. */
DecodeResult Decode(const std::string& str);
+/** Return the positions of errors in a Bech32 string. */
+std::string LocateErrors(const std::string& str, std::vector<int>& error_locations);
+
} // namespace bech32
#endif // BITCOIN_BECH32_H
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index d5275b0b76..dae3a47cd7 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -45,7 +45,7 @@ static void CCoinsCaching(benchmark::Bench& bench)
// Benchmark.
const CTransaction tx_1(t1);
bench.run([&] {
- bool success = AreInputsStandard(tx_1, coins, false);
+ bool success{AreInputsStandard(tx_1, coins)};
assert(success);
});
ECC_Stop();
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
index f1eeef8885..67c827d0d3 100644
--- a/src/bench/rpc_mempool.cpp
+++ b/src/bench/rpc_mempool.cpp
@@ -12,7 +12,7 @@
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
{
LockPoints lp;
- pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
+ pool.addUnchecked(CTxMemPoolEntry(tx, fee, /*time=*/0, /*entry_height=*/1, /*spends_coinbase=*/false, /*sigops_cost=*/4, lp));
}
static void RpcMempool(benchmark::Bench& bench)
diff --git a/src/consensus/amount.h b/src/consensus/amount.h
index 96566ea13f..59b8e3417a 100644
--- a/src/consensus/amount.h
+++ b/src/consensus/amount.h
@@ -26,4 +26,4 @@ static constexpr CAmount COIN = 100000000;
static constexpr CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
-#endif // BITCOIN_CONSENSUS_AMOUNT_H
+#endif // BITCOIN_CONSENSUS_AMOUNT_H
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 2fdc54464a..dbae2c45f2 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -136,6 +136,10 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo
TryCreateDirectories(path);
LogPrintf("Opening LevelDB in %s\n", fs::PathToString(path));
}
+ // PathToString() return value is safe to pass to leveldb open function,
+ // because on POSIX leveldb passes the byte string directly to ::open(), and
+ // on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
+ // (see env_posix.cc and env_windows.cc).
leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(path), &pdb);
dbwrapper_private::HandleError(status);
LogPrintf("Opened LevelDB successfully\n");
diff --git a/src/fs.h b/src/fs.h
index 4a0bf39e95..3cf4371fb4 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -94,31 +94,34 @@ static inline path operator+(path p1, path p2)
/**
* Convert path object to byte string. On POSIX, paths natively are byte
- * strings so this is trivial. On Windows, paths natively are Unicode, so an
- * encoding step is necessary.
+ * strings, so this is trivial. On Windows, paths natively are Unicode, so an
+ * encoding step is necessary. The inverse of \ref PathToString is \ref
+ * PathFromString. The strings returned and parsed by these functions can be
+ * used to call POSIX APIs, and for roundtrip conversion, logging, and
+ * debugging.
*
- * The inverse of \ref PathToString is \ref PathFromString. The strings
- * returned and parsed by these functions can be used to call POSIX APIs, and
- * for roundtrip conversion, logging, and debugging. But they are not
- * guaranteed to be valid UTF-8, and are generally meant to be used internally,
- * not externally. When communicating with external programs and libraries that
- * require UTF-8, fs::path::u8string() and fs::u8path() methods can be used.
- * For other applications, if support for non UTF-8 paths is required, or if
- * higher-level JSON or XML or URI or C-style escapes are preferred, it may be
- * also be appropriate to use different path encoding functions.
- *
- * Implementation note: On Windows, the std::filesystem::path(string)
- * constructor and std::filesystem::path::string() method are not safe to use
- * here, because these methods encode the path using C++'s narrow multibyte
- * encoding, which on Windows corresponds to the current "code page", which is
- * unpredictable and typically not able to represent all valid paths. So
- * std::filesystem::path::u8string() and std::filesystem::u8path() functions
- * are used instead on Windows. On POSIX, u8string/u8path functions are not
- * safe to use because paths are not always valid UTF-8, so plain string
- * methods which do not transform the path there are used.
+ * Because \ref PathToString and \ref PathFromString functions don't specify an
+ * encoding, they are meant to be used internally, not externally. They are not
+ * appropriate to use in applications requiring UTF-8, where
+ * fs::path::u8string() and fs::u8path() methods should be used instead. Other
+ * applications could require still different encodings. For example, JSON, XML,
+ * or URI applications might prefer to use higher level escapes (\uXXXX or
+ * &XXXX; or %XX) instead of multibyte encoding. Rust, Python, Java applications
+ * may require encoding paths with their respective UTF-8 derivatives WTF-8,
+ * PEP-383, and CESU-8 (see https://en.wikipedia.org/wiki/UTF-8#Derivatives).
*/
static inline std::string PathToString(const path& path)
{
+ // Implementation note: On Windows, the std::filesystem::path(string)
+ // constructor and std::filesystem::path::string() method are not safe to
+ // use here, because these methods encode the path using C++'s narrow
+ // multibyte encoding, which on Windows corresponds to the current "code
+ // page", which is unpredictable and typically not able to represent all
+ // valid paths. So std::filesystem::path::u8string() and
+ // std::filesystem::u8path() functions are used instead on Windows. On
+ // POSIX, u8string/u8path functions are not safe to use because paths are
+ // not always valid UTF-8, so plain string methods which do not transform
+ // the path there are used.
#ifdef WIN32
return path.u8string();
#else
diff --git a/src/httprpc.h b/src/httprpc.h
index 5a3b990646..6daf7d28f5 100644
--- a/src/httprpc.h
+++ b/src/httprpc.h
@@ -31,4 +31,4 @@ void InterruptREST();
*/
void StopREST();
-#endif
+#endif // BITCOIN_HTTPRPC_H
diff --git a/src/i2p.h b/src/i2p.h
index cb2efedba8..86643de637 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -267,4 +267,4 @@ private:
} // namespace sam
} // namespace i2p
-#endif /* BITCOIN_I2P_H */
+#endif // BITCOIN_I2P_H
diff --git a/src/init.cpp b/src/init.cpp
index f659de3a02..a2060daf45 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -59,6 +59,7 @@
#include <util/asmap.h>
#include <util/check.h>
#include <util/moneystr.h>
+#include <util/strencodings.h>
#include <util/string.h>
#include <util/syscall_sandbox.h>
#include <util/system.h>
@@ -436,7 +437,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-maxreceivebuffer=<n>", strprintf("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXRECEIVEBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxsendbuffer=<n>", strprintf("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)", DEFAULT_MAXSENDBUFFER), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target per 24h. Limit does not apply to peers with 'download' permission or blocks created within past week. 0 = no limit (default: %s). Optional suffix units [k|K|m|M|g|G|t|T] (default: M). Lowercase is 1000 base while uppercase is 1024 base", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-i2psam=<ip:port>", "I2P SAM proxy to reach I2P peers and accept I2P connections (default: none)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-i2pacceptincoming", "If set and -i2psam is also set then incoming I2P connections are accepted via the SAM proxy. If this is not set but -i2psam is set then only outgoing connections will be made to the I2P network. Ignored if -i2psam is not set. Listening for incoming I2P connections is done through the SAM proxy, not by binding to a local address and port (default: 1)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -1109,6 +1110,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
{
const ArgsManager& args = *Assert(node.args);
const CChainParams& chainparams = Params();
+
+ auto opt_max_upload = ParseByteUnits(args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET), ByteUnit::M);
+ if (!opt_max_upload) {
+ return InitError(strprintf(_("Unable to parse -maxuploadtarget: '%s' (possible integer overflow?)"), args.GetArg("-maxuploadtarget", "")));
+ }
+
// ********************************************************* Step 4a: application initialization
if (!CreatePidFile(args)) {
// Detailed error printed inside CreatePidFile().
@@ -1760,8 +1767,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
connOptions.nSendBufferMaxSize = 1000 * args.GetIntArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000 * args.GetIntArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
connOptions.m_added_nodes = args.GetArgs("-addnode");
-
- connOptions.nMaxOutboundLimit = 1024 * 1024 * args.GetIntArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET);
+ connOptions.nMaxOutboundLimit = *opt_max_upload;
connOptions.m_peer_connect_timeout = peer_connect_timeout;
for (const std::string& bind_arg : args.GetArgs("-bind")) {
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index d4ceb517dd..38004ce95d 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -287,9 +287,6 @@ public:
//! to be prepared to handle this by ignoring notifications about unknown
//! removed transactions and already added new transactions.
virtual void requestMempoolTransactions(Notifications& notifications) = 0;
-
- //! Check if Taproot has activated
- virtual bool isTaprootActive() = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index ea1cb5ed72..974156e6e1 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -30,6 +30,7 @@ class RPCTimerInterface;
class UniValue;
class proxyType;
enum class SynchronizationState;
+enum class TransactionError;
struct CNodeStateStats;
struct NodeContext;
struct bilingual_str;
@@ -183,6 +184,9 @@ public:
//! Get unspent outputs associated with a transaction.
virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
+ //! Broadcast transaction.
+ virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0;
+
//! Get wallet client.
virtual WalletClient& walletClient() = 0;
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 615f4c9312..6908c5ea52 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -76,12 +76,16 @@ public:
std::string operator()(const CNoDestination& no) const { return {}; }
};
-CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations)
{
std::vector<unsigned char> data;
uint160 hash;
error_str = "";
- if (DecodeBase58Check(str, data, 21)) {
+
+ // Note this will be false if it is a valid Bech32 address for a different network
+ bool is_bech32 = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP());
+
+ if (!is_bech32 && DecodeBase58Check(str, data, 21)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
@@ -98,15 +102,27 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return ScriptHash(hash);
}
- // Set potential error message.
- // This message may be changed if the address can also be interpreted as a Bech32 address.
- error_str = "Invalid prefix for Base58-encoded address";
+ if (!std::equal(script_prefix.begin(), script_prefix.end(), data.begin()) &&
+ !std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
+ error_str = "Invalid prefix for Base58-encoded address";
+ } else {
+ error_str = "Invalid length for Base58 address";
+ }
+ return CNoDestination();
+ } else if (!is_bech32) {
+ // Try Base58 decoding without the checksum, using a much larger max length
+ if (!DecodeBase58(str, data, 100)) {
+ error_str = "Invalid HRP or Base58 character in address";
+ } else {
+ error_str = "Invalid checksum or length of Base58 address";
+ }
+ return CNoDestination();
}
+
data.clear();
const auto dec = bech32::Decode(str);
if ((dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) && dec.data.size() > 0) {
// Bech32 decoding
- error_str = "";
if (dec.hrp != params.Bech32HRP()) {
error_str = "Invalid prefix for Bech32 address";
return CNoDestination();
@@ -168,8 +184,13 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
}
}
- // Set error message if address can't be interpreted as Base58 or Bech32.
- if (error_str.empty()) error_str = "Invalid address format";
+ // Perform Bech32 error location
+ if (!error_locations) {
+ std::vector<int> dummy_errors;
+ error_str = bech32::LocateErrors(str, dummy_errors);
+ } else {
+ error_str = bech32::LocateErrors(str, *error_locations);
+ }
return CNoDestination();
}
@@ -258,9 +279,9 @@ std::string EncodeDestination(const CTxDestination& dest)
return std::visit(DestinationEncoder(Params()), dest);
}
-CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations)
{
- return DecodeDestination(str, Params(), error_msg);
+ return DecodeDestination(str, Params(), error_msg, error_locations);
}
CTxDestination DecodeDestination(const std::string& str)
@@ -272,7 +293,7 @@ CTxDestination DecodeDestination(const std::string& str)
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
std::string error_msg;
- return IsValidDestination(DecodeDestination(str, params, error_msg));
+ return IsValidDestination(DecodeDestination(str, params, error_msg, nullptr));
}
bool IsValidDestinationString(const std::string& str)
diff --git a/src/key_io.h b/src/key_io.h
index bd81f7847e..2062bb4c44 100644
--- a/src/key_io.h
+++ b/src/key_io.h
@@ -23,7 +23,7 @@ std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
-CTxDestination DecodeDestination(const std::string& str, std::string& error_msg);
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations = nullptr);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
diff --git a/src/net.cpp b/src/net.cpp
index 82e55d4189..db496c2185 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -326,8 +326,8 @@ bool IsLocal(const CService& addr)
CNode* CConnman::FindNode(const CNetAddr& ip)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (static_cast<CNetAddr>(pnode->addr) == ip) {
return pnode;
}
@@ -337,8 +337,8 @@ CNode* CConnman::FindNode(const CNetAddr& ip)
CNode* CConnman::FindNode(const CSubNet& subNet)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (subNet.Match(static_cast<CNetAddr>(pnode->addr))) {
return pnode;
}
@@ -348,8 +348,8 @@ CNode* CConnman::FindNode(const CSubNet& subNet)
CNode* CConnman::FindNode(const std::string& addrName)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (pnode->m_addr_name == addrName) {
return pnode;
}
@@ -359,8 +359,8 @@ CNode* CConnman::FindNode(const std::string& addrName)
CNode* CConnman::FindNode(const CService& addr)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (static_cast<CService>(pnode->addr) == addr) {
return pnode;
}
@@ -375,8 +375,8 @@ bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
bool CConnman::CheckIncomingNonce(uint64_t nonce)
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn() && pnode->GetLocalNonce() == nonce)
return false;
}
@@ -435,7 +435,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created.
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
if (pnode) {
LogPrintf("Failed to open new connection, already connected\n");
@@ -1056,8 +1056,8 @@ bool CConnman::AttemptToEvictConnection()
std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
- LOCK(cs_vNodes);
- for (const CNode* node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* node : m_nodes) {
if (node->HasPermission(NetPermissionFlags::NoBan))
continue;
if (!node->IsInboundConn())
@@ -1084,8 +1084,8 @@ bool CConnman::AttemptToEvictConnection()
if (!node_id_to_evict) {
return false;
}
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (pnode->GetId() == *node_id_to_evict) {
LogPrint(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId());
pnode->fDisconnect = true;
@@ -1141,8 +1141,8 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
}
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->IsInboundConn()) nInbound++;
}
}
@@ -1210,8 +1210,8 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket,
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
{
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ LOCK(m_nodes_mutex);
+ m_nodes.push_back(pnode);
}
// We received a new connection, harvest entropy from the time (and our peer count)
@@ -1238,8 +1238,8 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
} // no default case, so the compiler can warn about missing cases
// Count existing connections
- int existing_connections = WITH_LOCK(cs_vNodes,
- return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
+ int existing_connections = WITH_LOCK(m_nodes_mutex,
+ return std::count_if(m_nodes.begin(), m_nodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
// Max connections of specified type already exist
if (max_connections != std::nullopt && existing_connections >= max_connections) return false;
@@ -1255,11 +1255,11 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
void CConnman::DisconnectNodes()
{
{
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
if (!fNetworkActive) {
// Disconnect any connected nodes
- for (CNode* pnode : vNodes) {
+ for (CNode* pnode : m_nodes) {
if (!pnode->fDisconnect) {
LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId());
pnode->fDisconnect = true;
@@ -1268,13 +1268,13 @@ void CConnman::DisconnectNodes()
}
// Disconnect unused nodes
- std::vector<CNode*> vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy)
+ std::vector<CNode*> nodes_copy = m_nodes;
+ for (CNode* pnode : nodes_copy)
{
if (pnode->fDisconnect)
{
- // remove from vNodes
- vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
+ // remove from m_nodes
+ m_nodes.erase(remove(m_nodes.begin(), m_nodes.end(), pnode), m_nodes.end());
// release outbound grant (if any)
pnode->grantOutbound.Release();
@@ -1284,18 +1284,18 @@ void CConnman::DisconnectNodes()
// hold in disconnected pool until all refs are released
pnode->Release();
- vNodesDisconnected.push_back(pnode);
+ m_nodes_disconnected.push_back(pnode);
}
}
}
{
// Delete disconnected nodes
- std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
- for (CNode* pnode : vNodesDisconnectedCopy)
+ std::list<CNode*> nodes_disconnected_copy = m_nodes_disconnected;
+ for (CNode* pnode : nodes_disconnected_copy)
{
// Destroy the object only after other threads have stopped using it.
if (pnode->GetRefCount() <= 0) {
- vNodesDisconnected.remove(pnode);
+ m_nodes_disconnected.remove(pnode);
DeleteNode(pnode);
}
}
@@ -1304,15 +1304,15 @@ void CConnman::DisconnectNodes()
void CConnman::NotifyNumConnectionsChanged()
{
- size_t vNodesSize;
+ size_t nodes_size;
{
- LOCK(cs_vNodes);
- vNodesSize = vNodes.size();
+ LOCK(m_nodes_mutex);
+ nodes_size = m_nodes.size();
}
- if(vNodesSize != nPrevNodeCount) {
- nPrevNodeCount = vNodesSize;
+ if(nodes_size != nPrevNodeCount) {
+ nPrevNodeCount = nodes_size;
if (m_client_interface) {
- m_client_interface->NotifyNumConnectionsChanged(vNodesSize);
+ m_client_interface->NotifyNumConnectionsChanged(nodes_size);
}
}
}
@@ -1353,46 +1353,45 @@ bool CConnman::InactivityCheck(const CNode& node) const
return false;
}
-bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set)
{
for (const ListenSocket& hListenSocket : vhListenSocket) {
recv_set.insert(hListenSocket.socket);
}
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
+ for (CNode* pnode : nodes) {
+ // Implement the following logic:
+ // * If there is data to send, select() for sending data. As this only
+ // happens when optimistic write failed, we choose to first drain the
+ // write buffer in this case before receiving more. This avoids
+ // needlessly queueing received data, if the remote peer is not themselves
+ // receiving data. This means properly utilizing TCP flow control signalling.
+ // * Otherwise, if there is space left in the receive buffer, select() for
+ // receiving data.
+ // * Hand off all complete messages to the processor, to be handled without
+ // blocking here.
+
+ bool select_recv = !pnode->fPauseRecv;
+ bool select_send;
{
- // Implement the following logic:
- // * If there is data to send, select() for sending data. As this only
- // happens when optimistic write failed, we choose to first drain the
- // write buffer in this case before receiving more. This avoids
- // needlessly queueing received data, if the remote peer is not themselves
- // receiving data. This means properly utilizing TCP flow control signalling.
- // * Otherwise, if there is space left in the receive buffer, select() for
- // receiving data.
- // * Hand off all complete messages to the processor, to be handled without
- // blocking here.
-
- bool select_recv = !pnode->fPauseRecv;
- bool select_send;
- {
- LOCK(pnode->cs_vSend);
- select_send = !pnode->vSendMsg.empty();
- }
+ LOCK(pnode->cs_vSend);
+ select_send = !pnode->vSendMsg.empty();
+ }
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
- error_set.insert(pnode->hSocket);
- if (select_send) {
- send_set.insert(pnode->hSocket);
- continue;
- }
- if (select_recv) {
- recv_set.insert(pnode->hSocket);
- }
+ error_set.insert(pnode->hSocket);
+ if (select_send) {
+ send_set.insert(pnode->hSocket);
+ continue;
+ }
+ if (select_recv) {
+ recv_set.insert(pnode->hSocket);
}
}
@@ -1400,10 +1399,13 @@ bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &s
}
#ifdef USE_POLL
-void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set)
{
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
- if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
+ if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
return;
}
@@ -1442,10 +1444,13 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
}
}
#else
-void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
+void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set)
{
std::set<SOCKET> recv_select_set, send_select_set, error_select_set;
- if (!GenerateSelectSet(recv_select_set, send_select_set, error_select_set)) {
+ if (!GenerateSelectSet(nodes, recv_select_set, send_select_set, error_select_set)) {
interruptNet.sleep_for(std::chrono::milliseconds(SELECT_TIMEOUT_MILLISECONDS));
return;
}
@@ -1519,34 +1524,33 @@ void CConnman::SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_s
void CConnman::SocketHandler()
{
- std::set<SOCKET> recv_set, send_set, error_set;
- SocketEvents(recv_set, send_set, error_set);
-
- if (interruptNet) return;
+ std::set<SOCKET> recv_set;
+ std::set<SOCKET> send_set;
+ std::set<SOCKET> error_set;
- //
- // Accept new connections
- //
- for (const ListenSocket& hListenSocket : vhListenSocket)
{
- if (hListenSocket.socket != INVALID_SOCKET && recv_set.count(hListenSocket.socket) > 0)
- {
- AcceptConnection(hListenSocket);
- }
- }
+ const NodesSnapshot snap{*this, /*shuffle=*/false};
- //
- // Service each socket
- //
- std::vector<CNode*> vNodesCopy;
- {
- LOCK(cs_vNodes);
- vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy)
- pnode->AddRef();
+ // Check for the readiness of the already connected sockets and the
+ // listening sockets in one call ("readiness" as in poll(2) or
+ // select(2)). If none are ready, wait for a short while and return
+ // empty sets.
+ SocketEvents(snap.Nodes(), recv_set, send_set, error_set);
+
+ // Service (send/receive) each of the already connected nodes.
+ SocketHandlerConnected(snap.Nodes(), recv_set, send_set, error_set);
}
- for (CNode* pnode : vNodesCopy)
- {
+
+ // Accept new connections from listening sockets.
+ SocketHandlerListening(recv_set);
+}
+
+void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
+ const std::set<SOCKET>& recv_set,
+ const std::set<SOCKET>& send_set,
+ const std::set<SOCKET>& error_set)
+{
+ for (CNode* pnode : nodes) {
if (interruptNet)
return;
@@ -1628,10 +1632,17 @@ void CConnman::SocketHandler()
if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
}
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodesCopy)
- pnode->Release();
+}
+
+void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
+{
+ for (const ListenSocket& listen_socket : vhListenSocket) {
+ if (interruptNet) {
+ return;
+ }
+ if (listen_socket.socket != INVALID_SOCKET && recv_set.count(listen_socket.socket) > 0) {
+ AcceptConnection(listen_socket);
+ }
}
}
@@ -1705,8 +1716,8 @@ void CConnman::ThreadDNSAddressSeed()
int nRelevant = 0;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;
}
}
@@ -1814,8 +1825,8 @@ int CConnman::GetExtraFullOutboundCount() const
{
int full_outbound_peers = 0;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsFullOutboundConn()) {
++full_outbound_peers;
}
@@ -1828,8 +1839,8 @@ int CConnman::GetExtraBlockRelayCount() const
{
int block_relay_peers = 0;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) {
++block_relay_peers;
}
@@ -1900,8 +1911,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// Checking !dnsseed is cheaper before locking 2 mutexes.
if (!add_fixed_seeds_now && !dnsseed) {
- LOCK2(m_addr_fetches_mutex, cs_vAddedNodes);
- if (m_addr_fetches.empty() && vAddedNodes.empty()) {
+ LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex);
+ if (m_addr_fetches.empty() && m_added_nodes.empty()) {
add_fixed_seeds_now = true;
LogPrintf("Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n");
}
@@ -1926,8 +1937,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
std::set<std::vector<unsigned char> > setConnected;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
@@ -2115,8 +2126,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
{
std::vector<CAddress> ret;
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->IsBlockOnlyConn()) {
ret.push_back(pnode->addr);
}
@@ -2131,9 +2142,9 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
std::list<std::string> lAddresses(0);
{
- LOCK(cs_vAddedNodes);
- ret.reserve(vAddedNodes.size());
- std::copy(vAddedNodes.cbegin(), vAddedNodes.cend(), std::back_inserter(lAddresses));
+ LOCK(m_added_nodes_mutex);
+ ret.reserve(m_added_nodes.size());
+ std::copy(m_added_nodes.cbegin(), m_added_nodes.cend(), std::back_inserter(lAddresses));
}
@@ -2141,8 +2152,8 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
std::map<CService, bool> mapConnected;
std::map<std::string, std::pair<bool, CService>> mapConnectedByName;
{
- LOCK(cs_vNodes);
- for (const CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (const CNode* pnode : m_nodes) {
if (pnode->addr.IsValid()) {
mapConnected[pnode->addr] = pnode->IsInboundConn();
}
@@ -2238,57 +2249,42 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
m_msgproc->InitializeNode(pnode);
{
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
+ LOCK(m_nodes_mutex);
+ m_nodes.push_back(pnode);
}
}
void CConnman::ThreadMessageHandler()
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::MESSAGE_HANDLER);
- FastRandomContext rng;
while (!flagInterruptMsgProc)
{
- std::vector<CNode*> vNodesCopy;
- {
- LOCK(cs_vNodes);
- vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy) {
- pnode->AddRef();
- }
- }
-
bool fMoreWork = false;
- // Randomize the order in which we process messages from/to our peers.
- // This prevents attacks in which an attacker exploits having multiple
- // consecutive connections in the vNodes list.
- Shuffle(vNodesCopy.begin(), vNodesCopy.end(), rng);
-
- for (CNode* pnode : vNodesCopy)
{
- if (pnode->fDisconnect)
- continue;
+ // Randomize the order in which we process messages from/to our peers.
+ // This prevents attacks in which an attacker exploits having multiple
+ // consecutive connections in the m_nodes list.
+ const NodesSnapshot snap{*this, /*shuffle=*/true};
- // Receive messages
- bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
- fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
- if (flagInterruptMsgProc)
- return;
- // Send messages
- {
- LOCK(pnode->cs_sendProcessing);
- m_msgproc->SendMessages(pnode);
- }
+ for (CNode* pnode : snap.Nodes()) {
+ if (pnode->fDisconnect)
+ continue;
- if (flagInterruptMsgProc)
- return;
- }
+ // Receive messages
+ bool fMoreNodeWork = m_msgproc->ProcessMessages(pnode, flagInterruptMsgProc);
+ fMoreWork |= (fMoreNodeWork && !pnode->fPauseSend);
+ if (flagInterruptMsgProc)
+ return;
+ // Send messages
+ {
+ LOCK(pnode->cs_sendProcessing);
+ m_msgproc->SendMessages(pnode);
+ }
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodesCopy)
- pnode->Release();
+ if (flagInterruptMsgProc)
+ return;
+ }
}
WAIT_LOCK(mutexMsgProc, lock);
@@ -2698,7 +2694,7 @@ void CConnman::StopNodes()
// Delete peer connections.
std::vector<CNode*> nodes;
- WITH_LOCK(cs_vNodes, nodes.swap(vNodes));
+ WITH_LOCK(m_nodes_mutex, nodes.swap(m_nodes));
for (CNode* pnode : nodes) {
pnode->CloseSocketDisconnect();
DeleteNode(pnode);
@@ -2713,10 +2709,10 @@ void CConnman::StopNodes()
}
}
- for (CNode* pnode : vNodesDisconnected) {
+ for (CNode* pnode : m_nodes_disconnected) {
DeleteNode(pnode);
}
- vNodesDisconnected.clear();
+ m_nodes_disconnected.clear();
vhListenSocket.clear();
semOutbound.reset();
semAddnode.reset();
@@ -2789,21 +2785,21 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
bool CConnman::AddNode(const std::string& strNode)
{
- LOCK(cs_vAddedNodes);
- for (const std::string& it : vAddedNodes) {
+ LOCK(m_added_nodes_mutex);
+ for (const std::string& it : m_added_nodes) {
if (strNode == it) return false;
}
- vAddedNodes.push_back(strNode);
+ m_added_nodes.push_back(strNode);
return true;
}
bool CConnman::RemoveAddedNode(const std::string& strNode)
{
- LOCK(cs_vAddedNodes);
- for(std::vector<std::string>::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
+ LOCK(m_added_nodes_mutex);
+ for(std::vector<std::string>::iterator it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) {
if (strNode == *it) {
- vAddedNodes.erase(it);
+ m_added_nodes.erase(it);
return true;
}
}
@@ -2812,12 +2808,12 @@ bool CConnman::RemoveAddedNode(const std::string& strNode)
size_t CConnman::GetNodeCount(ConnectionDirection flags) const
{
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
if (flags == ConnectionDirection::Both) // Shortcut if we want total
- return vNodes.size();
+ return m_nodes.size();
int nNum = 0;
- for (const auto& pnode : vNodes) {
+ for (const auto& pnode : m_nodes) {
if (flags & (pnode->IsInboundConn() ? ConnectionDirection::In : ConnectionDirection::Out)) {
nNum++;
}
@@ -2829,9 +2825,9 @@ size_t CConnman::GetNodeCount(ConnectionDirection flags) const
void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
{
vstats.clear();
- LOCK(cs_vNodes);
- vstats.reserve(vNodes.size());
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ vstats.reserve(m_nodes.size());
+ for (CNode* pnode : m_nodes) {
vstats.emplace_back();
pnode->CopyStats(vstats.back());
vstats.back().m_mapped_as = pnode->addr.GetMappedAS(addrman.GetAsmap());
@@ -2840,7 +2836,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
bool CConnman::DisconnectNode(const std::string& strNode)
{
- LOCK(cs_vNodes);
+ LOCK(m_nodes_mutex);
if (CNode* pnode = FindNode(strNode)) {
LogPrint(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId());
pnode->fDisconnect = true;
@@ -2852,8 +2848,8 @@ bool CConnman::DisconnectNode(const std::string& strNode)
bool CConnman::DisconnectNode(const CSubNet& subnet)
{
bool disconnected = false;
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* pnode : m_nodes) {
if (subnet.Match(pnode->addr)) {
LogPrint(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId());
pnode->fDisconnect = true;
@@ -2870,8 +2866,8 @@ bool CConnman::DisconnectNode(const CNetAddr& addr)
bool CConnman::DisconnectNode(NodeId id)
{
- LOCK(cs_vNodes);
- for(CNode* pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for(CNode* pnode : m_nodes) {
if (id == pnode->GetId()) {
LogPrint(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId());
pnode->fDisconnect = true;
@@ -2883,7 +2879,6 @@ bool CConnman::DisconnectNode(NodeId id)
void CConnman::RecordBytesRecv(uint64_t bytes)
{
- LOCK(cs_totalBytesRecv);
nTotalBytesRecv += bytes;
}
@@ -2960,7 +2955,6 @@ uint64_t CConnman::GetOutboundTargetBytesLeft() const
uint64_t CConnman::GetTotalBytesRecv() const
{
- LOCK(cs_totalBytesRecv);
return nTotalBytesRecv;
}
@@ -3024,7 +3018,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
size_t nMessageSize = msg.data.size();
LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
if (gArgs.GetBoolArg("-capturemessages", false)) {
- CaptureMessage(pnode->addr, msg.m_type, msg.data, /* incoming */ false);
+ CaptureMessage(pnode->addr, msg.m_type, msg.data, /*is_incoming=*/false);
}
TRACE6(net, outbound_message,
@@ -3063,8 +3057,8 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
{
CNode* found = nullptr;
- LOCK(cs_vNodes);
- for (auto&& pnode : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (auto&& pnode : m_nodes) {
if(pnode->GetId() == id) {
found = pnode;
break;
diff --git a/src/net.h b/src/net.h
index 878f10cd42..dd5cc66a04 100644
--- a/src/net.h
+++ b/src/net.h
@@ -70,7 +70,7 @@ static const bool DEFAULT_LISTEN = true;
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
-static constexpr uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
+static const std::string DEFAULT_MAX_UPLOAD_TARGET{"0M"};
/** Default for blocks only*/
static const bool DEFAULT_BLOCKSONLY = false;
/** -peertimeout default */
@@ -791,8 +791,8 @@ public:
}
vWhitelistedRange = connOptions.vWhitelistedRange;
{
- LOCK(cs_vAddedNodes);
- vAddedNodes = connOptions.m_added_nodes;
+ LOCK(m_added_nodes_mutex);
+ m_added_nodes = connOptions.m_added_nodes;
}
m_onion_binds = connOptions.onion_binds;
}
@@ -823,8 +823,8 @@ public:
using NodeFn = std::function<void(CNode*)>;
void ForEachNode(const NodeFn& func)
{
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (auto&& node : m_nodes) {
if (NodeFullyConnected(node))
func(node);
}
@@ -832,8 +832,8 @@ public:
void ForEachNode(const NodeFn& func) const
{
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (auto&& node : m_nodes) {
if (NodeFullyConnected(node))
func(node);
}
@@ -968,7 +968,7 @@ private:
/**
* Create a `CNode` object from a socket that has just been accepted and add the node to
- * the `vNodes` member.
+ * the `m_nodes` member.
* @param[in] hSocket Connected socket to communicate with the peer.
* @param[in] permissionFlags The peer's permissions.
* @param[in] addr_bind The address and port at our side of the connection.
@@ -983,9 +983,57 @@ private:
void NotifyNumConnectionsChanged();
/** Return true if the peer is inactive and should be disconnected. */
bool InactivityCheck(const CNode& node) const;
- bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
- void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
+
+ /**
+ * Generate a collection of sockets to check for IO readiness.
+ * @param[in] nodes Select from these nodes' sockets.
+ * @param[out] recv_set Sockets to check for read readiness.
+ * @param[out] send_set Sockets to check for write readiness.
+ * @param[out] error_set Sockets to check for errors.
+ * @return true if at least one socket is to be checked (the returned set is not empty)
+ */
+ bool GenerateSelectSet(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set);
+
+ /**
+ * Check which sockets are ready for IO.
+ * @param[in] nodes Select from these nodes' sockets.
+ * @param[out] recv_set Sockets which are ready for read.
+ * @param[out] send_set Sockets which are ready for write.
+ * @param[out] error_set Sockets which have errors.
+ * This calls `GenerateSelectSet()` to gather a list of sockets to check.
+ */
+ void SocketEvents(const std::vector<CNode*>& nodes,
+ std::set<SOCKET>& recv_set,
+ std::set<SOCKET>& send_set,
+ std::set<SOCKET>& error_set);
+
+ /**
+ * Check connected and listening sockets for IO readiness and process them accordingly.
+ */
void SocketHandler();
+
+ /**
+ * Do the read/write for connected sockets that are ready for IO.
+ * @param[in] nodes Nodes to process. The socket of each node is checked against
+ * `recv_set`, `send_set` and `error_set`.
+ * @param[in] recv_set Sockets that are ready for read.
+ * @param[in] send_set Sockets that are ready for send.
+ * @param[in] error_set Sockets that have an exceptional condition (error).
+ */
+ void SocketHandlerConnected(const std::vector<CNode*>& nodes,
+ const std::set<SOCKET>& recv_set,
+ const std::set<SOCKET>& send_set,
+ const std::set<SOCKET>& error_set);
+
+ /**
+ * Accept incoming connections, one from each read-ready listening socket.
+ * @param[in] recv_set Sockets that are ready for read.
+ */
+ void SocketHandlerListening(const std::set<SOCKET>& recv_set);
+
void ThreadSocketHandler();
void ThreadDNSAddressSeed();
@@ -1026,9 +1074,8 @@ private:
static bool NodeFullyConnected(const CNode* pnode);
// Network usage totals
- mutable RecursiveMutex cs_totalBytesRecv;
mutable RecursiveMutex cs_totalBytesSent;
- uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0};
+ std::atomic<uint64_t> nTotalBytesRecv{0};
uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
// outbound limit & stats
@@ -1051,12 +1098,12 @@ private:
bool fAddressesInitialized{false};
AddrMan& addrman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
- RecursiveMutex m_addr_fetches_mutex;
- std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
- mutable RecursiveMutex cs_vAddedNodes;
- std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
- std::list<CNode*> vNodesDisconnected;
- mutable RecursiveMutex cs_vNodes;
+ Mutex m_addr_fetches_mutex;
+ std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
+ mutable Mutex m_added_nodes_mutex;
+ std::vector<CNode*> m_nodes GUARDED_BY(m_nodes_mutex);
+ std::list<CNode*> m_nodes_disconnected;
+ mutable RecursiveMutex m_nodes_mutex;
std::atomic<NodeId> nLastNodeId{0};
unsigned int nPrevNodeCount{0};
@@ -1177,6 +1224,43 @@ private:
*/
std::vector<CService> m_onion_binds;
+ /**
+ * RAII helper to atomically create a copy of `m_nodes` and add a reference
+ * to each of the nodes. The nodes are released when this object is destroyed.
+ */
+ class NodesSnapshot
+ {
+ public:
+ explicit NodesSnapshot(const CConnman& connman, bool shuffle)
+ {
+ {
+ LOCK(connman.m_nodes_mutex);
+ m_nodes_copy = connman.m_nodes;
+ for (auto& node : m_nodes_copy) {
+ node->AddRef();
+ }
+ }
+ if (shuffle) {
+ Shuffle(m_nodes_copy.begin(), m_nodes_copy.end(), FastRandomContext{});
+ }
+ }
+
+ ~NodesSnapshot()
+ {
+ for (auto& node : m_nodes_copy) {
+ node->Release();
+ }
+ }
+
+ const std::vector<CNode*>& Nodes() const
+ {
+ return m_nodes_copy;
+ }
+
+ private:
+ std::vector<CNode*> m_nodes_copy;
+ };
+
friend struct CConnmanTest;
friend struct ConnmanTestMsg;
};
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 2185ccc700..a896bb76ae 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -4105,7 +4105,7 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt
);
if (gArgs.GetBoolArg("-capturemessages", false)) {
- CaptureMessage(pfrom->addr, msg.m_command, MakeUCharSpan(msg.m_recv), /* incoming */ true);
+ CaptureMessage(pfrom->addr, msg.m_command, MakeUCharSpan(msg.m_recv), /*is_incoming=*/true);
}
msg.SetVersion(pfrom->GetCommonVersion());
diff --git a/src/netaddress.h b/src/netaddress.h
index b0b1c5ca9e..a5b74eb35b 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -385,6 +385,12 @@ private:
/**
* Unserialize from a pre-ADDRv2/BIP155 format from an array.
+ *
+ * This function is only called from UnserializeV1Stream() and is a wrapper
+ * for SetLegacyIPv6(); however, we keep it for symmetry with
+ * SerializeV1Array() to have pairs of ser/unser functions and to make clear
+ * that if one is altered, a corresponding reverse modification should be
+ * applied to the other.
*/
void UnserializeV1Array(uint8_t (&arr)[V1_SERIALIZATION_SIZE])
{
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 9f457570fa..e5f2753123 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -276,6 +276,10 @@ public:
LOCK(::cs_main);
return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
}
+ TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
+ {
+ return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
+ }
WalletClient& walletClient() override
{
return *Assert(m_context->wallet_client);
@@ -536,8 +540,11 @@ public:
const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving
- // output uninitialized.
- return FillBlock(ancestor, ancestor_out, lock, active) & FillBlock(block1, block1_out, lock, active) & FillBlock(block2, block2_out, lock, active);
+ // output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
+ // compiler warnings.
+ return int{FillBlock(ancestor, ancestor_out, lock, active)} &
+ int{FillBlock(block1, block1_out, lock, active)} &
+ int{FillBlock(block2, block2_out, lock, active)};
}
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
double guessVerificationProgress(const uint256& block_hash) override
@@ -717,12 +724,6 @@ public:
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
}
}
- bool isTaprootActive() override
- {
- LOCK(::cs_main);
- const CBlockIndex* tip = Assert(m_node.chainman)->ActiveChain().Tip();
- return DeploymentActiveAfter(tip, Params().GetConsensus(), Consensus::DEPLOYMENT_TAPROOT);
- }
NodeContext& m_node;
};
} // namespace
diff --git a/src/minisketchwrapper.cpp b/src/node/minisketchwrapper.cpp
index fb176fb153..572df63463 100644
--- a/src/minisketchwrapper.cpp
+++ b/src/node/minisketchwrapper.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <minisketchwrapper.h>
+#include <node/minisketchwrapper.h>
#include <logging.h>
#include <util/time.h>
diff --git a/src/minisketchwrapper.h b/src/node/minisketchwrapper.h
index 409221de79..a8aef68d01 100644
--- a/src/minisketchwrapper.h
+++ b/src/node/minisketchwrapper.h
@@ -2,10 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_MINISKETCHWRAPPER_H
-#define BITCOIN_MINISKETCHWRAPPER_H
+#ifndef BITCOIN_NODE_MINISKETCHWRAPPER_H
+#define BITCOIN_NODE_MINISKETCHWRAPPER_H
#include <minisketch.h>
+
#include <cstddef>
#include <cstdint>
@@ -14,4 +15,4 @@ Minisketch MakeMinisketch32(size_t capacity);
/** Wrapper around Minisketch::CreateFP. */
Minisketch MakeMinisketch32FP(size_t max_elements, uint32_t fpbits);
-#endif // BITCOIN_DBWRAPPER_H
+#endif // BITCOIN_NODE_MINISKETCHWRAPPER_H
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 8ba896bb01..13c7ec2002 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -67,4 +67,4 @@ public:
SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
};
-#endif // BITCOIN_POLICY_FEERATE_H
+#endif // BITCOIN_POLICY_FEERATE_H
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index fced397e51..2c30b20d5b 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -161,13 +161,13 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
*
* Note that only the non-witness portion of the transaction is checked here.
*/
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
- if (tx.IsCoinBase())
+ if (tx.IsCoinBase()) {
return true; // Coinbases don't use vin normally
+ }
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
@@ -189,9 +189,6 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs,
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
return false;
}
- } else if (whichType == TxoutType::WITNESS_V1_TAPROOT) {
- // Don't allow Taproot spends unless Taproot is active.
- if (!taproot_active) return false;
}
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index f2a3f35546..f6ac6500f6 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -105,10 +105,9 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
-* @param[in] taproot_active Whether or taproot consensus rules are active (used to decide whether spends of them are permitted)
* @return True if all inputs (scriptSigs) use only standard transaction forms
*/
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active);
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
/**
* Check if the transaction is over standard P2WSH resources limit:
* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 5445bc8aa1..b3d8e052bc 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -223,7 +223,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio
// Construct a would-be spend of this output, to update sigdata with.
// Note that ProduceSignature is used to fill in metadata (not actual signatures),
// so provider does not need to provide any private keys (it can be a HidingSigningProvider).
- MutableTransactionSignatureCreator creator(&tx, /* index */ 0, out.nValue, SIGHASH_ALL);
+ MutableTransactionSignatureCreator creator(&tx, /*input_idx=*/0, out.nValue, SIGHASH_ALL);
ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
// Put redeem_script, witness_script, key paths, into PSBTOutput.
diff --git a/src/pubkey.h b/src/pubkey.h
index f174ad8d85..ae6356c246 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -141,7 +141,7 @@ public:
template <typename Stream>
void Unserialize(Stream& s)
{
- unsigned int len = ::ReadCompactSize(s);
+ const unsigned int len(::ReadCompactSize(s));
if (len <= SIZE) {
s.read((char*)vch, len);
if (len != size()) {
@@ -149,9 +149,7 @@ public:
}
} else {
// invalid pubkey, skip available data
- char dummy;
- while (len--)
- s.read(&dummy, 1);
+ s.ignore(len);
Invalidate();
}
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index b68ce39b53..81a1d88d20 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -870,7 +870,7 @@ void BitcoinGUI::showHelpMessageClicked()
#ifdef ENABLE_WALLET
void BitcoinGUI::openClicked()
{
- OpenURIDialog dlg(this);
+ OpenURIDialog dlg(platformStyle, this);
if(dlg.exec())
{
Q_EMIT receivedURI(dlg.getURI());
diff --git a/src/qt/forms/openuridialog.ui b/src/qt/forms/openuridialog.ui
index 1b7291ab9d..97399e59a2 100644
--- a/src/qt/forms/openuridialog.ui
+++ b/src/qt/forms/openuridialog.ui
@@ -30,6 +30,27 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="pasteButton">
+ <property name="toolTip">
+ <string extracomment="Tooltip text for button that allows you to paste an address that is in your clipboard.">Paste address from clipboard</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/editpaste</normaloff>:/icons/editpaste
+ </iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>22</width>
+ <height>22</height>
+ </size>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 1c22124616..6b3a4630a3 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -33,7 +33,7 @@
<string>Automatically start %1 after logging in to the system.</string>
</property>
<property name="text">
- <string>Start %1 on system &amp;login</string>
+ <string>&amp;Start %1 on system login</string>
</property>
</widget>
</item>
@@ -192,7 +192,7 @@
<string extracomment="Tooltip text for Options window setting that enables the RPC server.">This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</string>
</property>
<property name="text">
- <string extracomment="An Options window setting to enable the RPC server.">Enable RPC &amp;server</string>
+ <string extracomment="An Options window setting to enable the RPC server.">Enable R&amp;PC server</string>
</property>
</widget>
</item>
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 10bf82d532..a68eee718e 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -6,15 +6,20 @@
#include <qt/forms/ui_openuridialog.h>
#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
#include <qt/sendcoinsrecipient.h>
+#include <QAbstractButton>
+#include <QLineEdit>
#include <QUrl>
-OpenURIDialog::OpenURIDialog(QWidget *parent) :
- QDialog(parent, GUIUtil::dialog_flags),
- ui(new Ui::OpenURIDialog)
+OpenURIDialog::OpenURIDialog(const PlatformStyle* platformStyle, QWidget* parent) : QDialog(parent, GUIUtil::dialog_flags),
+ ui(new Ui::OpenURIDialog),
+ m_platform_style(platformStyle)
{
ui->setupUi(this);
+ ui->pasteButton->setIcon(m_platform_style->SingleColorIcon(":/icons/editpaste"));
+ QObject::connect(ui->pasteButton, &QAbstractButton::clicked, ui->uriEdit, &QLineEdit::paste);
GUIUtil::handleCloseWindowShortcut(this);
}
@@ -32,11 +37,19 @@ QString OpenURIDialog::getURI()
void OpenURIDialog::accept()
{
SendCoinsRecipient rcp;
- if(GUIUtil::parseBitcoinURI(getURI(), &rcp))
- {
+ if (GUIUtil::parseBitcoinURI(getURI(), &rcp)) {
/* Only accept value URIs */
QDialog::accept();
} else {
ui->uriEdit->setValid(false);
}
}
+
+void OpenURIDialog::changeEvent(QEvent* e)
+{
+ if (e->type() == QEvent::PaletteChange) {
+ ui->pasteButton->setIcon(m_platform_style->SingleColorIcon(":/icons/editpaste"));
+ }
+
+ QDialog::changeEvent(e);
+}
diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h
index efe4b86f37..f3a8b0ba22 100644
--- a/src/qt/openuridialog.h
+++ b/src/qt/openuridialog.h
@@ -7,6 +7,8 @@
#include <QDialog>
+class PlatformStyle;
+
namespace Ui {
class OpenURIDialog;
}
@@ -16,16 +18,19 @@ class OpenURIDialog : public QDialog
Q_OBJECT
public:
- explicit OpenURIDialog(QWidget *parent);
+ explicit OpenURIDialog(const PlatformStyle* platformStyle, QWidget* parent);
~OpenURIDialog();
QString getURI();
protected Q_SLOTS:
void accept() override;
+ void changeEvent(QEvent* e) override;
private:
- Ui::OpenURIDialog *ui;
+ Ui::OpenURIDialog* ui;
+
+ const PlatformStyle* m_platform_style;
};
#endif // BITCOIN_QT_OPENURIDIALOG_H
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 34d56e5506..3e598bfab9 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -110,8 +110,8 @@ void PSBTOperationsDialog::broadcastTransaction()
CTransactionRef tx = MakeTransactionRef(mtx);
std::string err_string;
- TransactionError error = BroadcastTransaction(
- *m_client_model->node().context(), tx, err_string, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true, /* await_callback */ false);
+ TransactionError error =
+ m_client_model->node().broadcastTransaction(tx, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), err_string);
if (error == TransactionError::OK) {
showStatus(tr("Transaction broadcast successfully! Transaction ID: %1")
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 0c3332ab76..6bcdcc4c29 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -866,7 +866,11 @@ void RPCConsole::clear(bool keep_prompt)
}
// Set default style sheet
+#ifdef Q_OS_MAC
+ QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont(/*use_embedded_font=*/true));
+#else
QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
+#endif
ui->messagesWidget->document()->setDefaultStyleSheet(
QString(
"table { }"
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index b26cddf4ae..e7a3d724bb 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -69,7 +69,7 @@ int main(int argc, char* argv[])
#if defined(WIN32)
if (getenv("QT_QPA_PLATFORM") == nullptr) _putenv_s("QT_QPA_PLATFORM", "minimal");
#else
- setenv("QT_QPA_PLATFORM", "minimal", /* overwrite */ 0);
+ setenv("QT_QPA_PLATFORM", "minimal", 0 /* overwrite */);
#endif
// Don't remove this, it's needed to access
diff --git a/src/randomenv.h b/src/randomenv.h
index 46cea6f6f2..746516b79b 100644
--- a/src/randomenv.h
+++ b/src/randomenv.h
@@ -14,4 +14,4 @@ void RandAddDynamicEnv(CSHA512& hasher);
/** Gather non-cryptographic environment data that does not change over time. */
void RandAddStaticEnv(CSHA512& hasher);
-#endif
+#endif // BITCOIN_RANDOMENV_H
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index d9c6761f47..65f6b1429e 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -67,4 +67,4 @@ CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context);
*/
UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFile& afile);
-#endif
+#endif // BITCOIN_RPC_BLOCKCHAIN_H
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 518c41d12a..9e2b1ab07e 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1010,7 +1010,7 @@ static RPCHelpMan submitblock()
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
- bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
+ bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /*force_processing=*/true, /*new_block=*/&new_block);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 39bd9c6091..2bd8a6b050 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -52,6 +52,10 @@ static RPCHelpMan validateaddress()
{RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
{RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
{RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
+ {RPCResult::Type::ARR, "error_locations", "Indices of likely error locations in address, if known (e.g. Bech32 errors)",
+ {
+ {RPCResult::Type::NUM, "index", "index of a potential error"},
+ }},
}
},
RPCExamples{
@@ -61,7 +65,8 @@ static RPCHelpMan validateaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::string error_msg;
- CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
+ std::vector<int> error_locations;
+ CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg, &error_locations);
const bool isValid = IsValidDestination(dest);
CHECK_NONFATAL(isValid == error_msg.empty());
@@ -77,6 +82,9 @@ static RPCHelpMan validateaddress()
UniValue detail = DescribeAddress(dest);
ret.pushKVs(detail);
} else {
+ UniValue error_indices(UniValue::VARR);
+ for (int i : error_locations) error_indices.push_back(i);
+ ret.pushKV("error_locations", error_indices);
ret.pushKV("error", error_msg);
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 89f2309cb7..2dd121c6f6 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1619,7 +1619,7 @@ static RPCHelpMan utxoupdatepsbt()
}
}
// We don't actually need private keys further on; hide them as a precaution.
- HidingSigningProvider public_provider(&provider, /* nosign */ true, /* nobip32derivs */ false);
+ HidingSigningProvider public_provider(&provider, /*hide_secret=*/true, /*hide_origin=*/false);
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
@@ -1658,7 +1658,7 @@ static RPCHelpMan utxoupdatepsbt()
// Update script/keypath information using descriptor data.
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
// we don't actually care about those here, in fact.
- SignPSBTInput(public_provider, psbtx, i, &txdata, /* sighash_type */ 1);
+ SignPSBTInput(public_provider, psbtx, i, &txdata, /*sighash=*/1);
}
// Update script/keypath information using descriptor data.
diff --git a/src/scheduler.h b/src/scheduler.h
index 9eec8c0fa0..be878661db 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -146,4 +146,4 @@ public:
size_t CallbacksPending();
};
-#endif
+#endif // BITCOIN_SCHEDULER_H
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 621a1b9fd6..c3b4d1ddaa 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -851,6 +851,7 @@ protected:
builder.Finalize(xpk);
WitnessV1Taproot output = builder.GetOutput();
out.tr_spenddata[output].Merge(builder.GetSpendData());
+ out.pubkeys.emplace(keys[0].GetID(), keys[0]);
return Vector(GetScriptForDestination(output));
}
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index b282f39e6d..8e044b1e00 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -17,16 +17,16 @@
typedef std::vector<unsigned char> valtype;
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn)
- : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn, MissingDataBehavior::FAIL),
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, int hash_type)
+ : txTo{tx}, nIn{input_idx}, nHashType{hash_type}, amount{amount}, checker{txTo, nIn, amount, MissingDataBehavior::FAIL},
m_txdata(nullptr)
{
}
-MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn)
- : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn),
- checker(txdata ? MutableTransactionSignatureChecker(txTo, nIn, amount, *txdata, MissingDataBehavior::FAIL) :
- MutableTransactionSignatureChecker(txTo, nIn, amount, MissingDataBehavior::FAIL)),
+MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, const PrecomputedTransactionData* txdata, int hash_type)
+ : txTo{tx}, nIn{input_idx}, nHashType{hash_type}, amount{amount},
+ checker{txdata ? MutableTransactionSignatureChecker{txTo, nIn, amount, *txdata, MissingDataBehavior::FAIL} :
+ MutableTransactionSignatureChecker{txTo, nIn, amount, MissingDataBehavior::FAIL}},
m_txdata(txdata)
{
}
diff --git a/src/script/sign.h b/src/script/sign.h
index 6d3479c143..62335b644a 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -45,8 +45,8 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator {
const PrecomputedTransactionData* m_txdata;
public:
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn);
- MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn);
+ MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, int hash_type);
+ MutableTransactionSignatureCreator(const CMutableTransaction* tx, unsigned int input_idx, const CAmount& amount, const PrecomputedTransactionData* txdata, int hash_type);
const BaseSignatureChecker& Checker() const override { return checker; }
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const override;
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index b80fbe22ce..17f97fa30c 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -190,8 +190,8 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{
- // Only supports destinations which map to single public keys, i.e. P2PKH,
- // P2WPKH, and P2SH-P2WPKH.
+ // Only supports destinations which map to single public keys:
+ // P2PKH, P2WPKH, P2SH-P2WPKH, P2TR
if (auto id = std::get_if<PKHash>(&dest)) {
return ToKeyID(*id);
}
@@ -208,5 +208,15 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
}
}
}
+ if (auto output_key = std::get_if<WitnessV1Taproot>(&dest)) {
+ TaprootSpendData spenddata;
+ CPubKey pub;
+ if (store.GetTaprootSpendData(*output_key, spenddata)
+ && !spenddata.internal_key.IsNull()
+ && spenddata.merkle_root.IsNull()
+ && store.GetPubKeyByXOnly(spenddata.internal_key, pub)) {
+ return pub.GetID();
+ }
+ }
return CKeyID();
}
diff --git a/src/shutdown.h b/src/shutdown.h
index ff56c6bd87..9df601d478 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -32,4 +32,4 @@ bool ShutdownRequested();
*/
void WaitForShutdown();
-#endif
+#endif // BITCOIN_SHUTDOWN_H
diff --git a/src/span.h b/src/span.h
index 830164514b..746e41f2f4 100644
--- a/src/span.h
+++ b/src/span.h
@@ -30,7 +30,11 @@
/** A Span is an object that can refer to a contiguous sequence of objects.
*
- * It implements a subset of C++20's std::span.
+ * This file implements a subset of C++20's std::span. It can be considered
+ * temporary compatibility code until C++20 and is designed to be a
+ * self-contained abstraction without depending on other project files. For this
+ * reason, Clang lifetimebound is defined here instead of including
+ * <attributes.h>, which also defines it.
*
* Things to be aware of when writing code that deals with Spans:
*
@@ -60,7 +64,7 @@
* types that expose a data() and size() member function), functions that
* accept a Span as input parameter can be called with any compatible
* range-like object. For example, this works:
-*
+ *
* void Foo(Span<const int> arg);
*
* Foo(std::vector<int>{1, 2, 3}); // Works
@@ -180,6 +184,7 @@ public:
return m_data[m_size - 1];
}
constexpr std::size_t size() const noexcept { return m_size; }
+ constexpr std::size_t size_bytes() const noexcept { return sizeof(C) * m_size; }
constexpr bool empty() const noexcept { return size() == 0; }
CONSTEXPR_IF_NOT_DEBUG C& operator[](std::size_t pos) const noexcept
{
@@ -236,11 +241,35 @@ T& SpanPopBack(Span<T>& span)
return back;
}
+// From C++20 as_bytes and as_writeable_bytes
+template <typename T>
+Span<const std::byte> AsBytes(Span<T> s) noexcept
+{
+ return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
+}
+template <typename T>
+Span<std::byte> AsWritableBytes(Span<T> s) noexcept
+{
+ return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
+}
+
+template <typename V>
+Span<const std::byte> MakeByteSpan(V&& v) noexcept
+{
+ return AsBytes(MakeSpan(std::forward<V>(v)));
+}
+template <typename V>
+Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
+{
+ return AsWritableBytes(MakeSpan(std::forward<V>(v)));
+}
+
// Helper functions to safely cast to unsigned char pointers.
inline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }
inline unsigned char* UCharCast(unsigned char* c) { return c; }
inline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }
inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
+inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }
// Helper function to safely convert a Span to a Span<[const] unsigned char>.
template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }
@@ -248,4 +277,4 @@ template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename s
/** Like MakeSpan, but for (const) unsigned char member types only. Only works for (un)signed char containers. */
template <typename V> constexpr auto MakeUCharSpan(V&& v) -> decltype(UCharSpanCast(MakeSpan(std::forward<V>(v)))) { return UCharSpanCast(MakeSpan(std::forward<V>(v))); }
-#endif
+#endif // BITCOIN_SPAN_H
diff --git a/src/streams.h b/src/streams.h
index 31407287ae..9e8f379cd2 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -226,7 +226,7 @@ public:
: nType{nTypeIn},
nVersion{nVersionIn} {}
- explicit CDataStream(Span<const uint8_t> sp, int nTypeIn, int nVersionIn)
+ explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn)
: vch(sp.data(), sp.data() + sp.size()),
nType{nTypeIn},
nVersion{nVersionIn} {}
@@ -254,17 +254,17 @@ public:
iterator end() { return vch.end(); }
size_type size() const { return vch.size() - nReadPos; }
bool empty() const { return vch.size() == nReadPos; }
- void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); }
+ void resize(size_type n, value_type c = value_type{}) { vch.resize(n + nReadPos, c); }
void reserve(size_type n) { vch.reserve(n + nReadPos); }
const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; }
reference operator[](size_type pos) { return vch[pos + nReadPos]; }
void clear() { vch.clear(); nReadPos = 0; }
- iterator insert(iterator it, const uint8_t x) { return vch.insert(it, x); }
- void insert(iterator it, size_type n, const uint8_t x) { vch.insert(it, n, x); }
+ iterator insert(iterator it, const value_type x) { return vch.insert(it, x); }
+ void insert(iterator it, size_type n, const value_type x) { vch.insert(it, n, x); }
value_type* data() { return vch.data() + nReadPos; }
const value_type* data() const { return vch.data() + nReadPos; }
- void insert(iterator it, std::vector<uint8_t>::const_iterator first, std::vector<uint8_t>::const_iterator last)
+ void insert(iterator it, std::vector<value_type>::const_iterator first, std::vector<value_type>::const_iterator last)
{
if (last == first) return;
assert(last - first > 0);
@@ -278,7 +278,7 @@ public:
vch.insert(it, first, last);
}
- void insert(iterator it, const char* first, const char* last)
+ void insert(iterator it, const value_type* first, const value_type* last)
{
if (last == first) return;
assert(last - first > 0);
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index 9d1dfd46f1..c5fce7bec0 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -23,6 +23,16 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}
+ {
+ const std::vector<uint8_t> in_u{0xff, 0x01, 0xff};
+ const std::vector<std::byte> in_b{std::byte{0xff}, std::byte{0x01}, std::byte{0xff}};
+ const std::string in_s{"\xff\x01\xff"};
+ const std::string out_exp{"/wH/"};
+ BOOST_CHECK_EQUAL(EncodeBase64(in_u), out_exp);
+ BOOST_CHECK_EQUAL(EncodeBase64(in_b), out_exp);
+ BOOST_CHECK_EQUAL(EncodeBase64(in_s), out_exp);
+ }
+
// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase64("invalid\0"s, &failure);
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
index c0344b3cbb..8eed959228 100644
--- a/src/test/bech32_tests.cpp
+++ b/src/test/bech32_tests.cpp
@@ -1,4 +1,5 @@
// Copyright (c) 2017 Pieter Wuille
+// Copyright (c) 2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -68,10 +69,36 @@ BOOST_AUTO_TEST_CASE(bech32_testvectors_invalid)
"1qzzfhee",
"a12UEL5L",
"A12uEL5L",
+ "abcdef1qpzrz9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
};
+ static const std::pair<std::string, int> ERRORS[] = {
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Bech32 string too long", 90},
+ {"Missing separator", -1},
+ {"Invalid separator position", 0},
+ {"Invalid Base 32 character", 2},
+ {"Invalid separator position", 2},
+ {"Invalid character or mixed case", 8},
+ {"Invalid checksum", -1}, // The checksum is calculated using the uppercase form so the entire string is invalid, not just a few characters
+ {"Invalid separator position", 0},
+ {"Invalid separator position", 0},
+ {"Invalid character or mixed case", 3},
+ {"Invalid character or mixed case", 3},
+ {"Invalid checksum", 11}
+ };
+ int i = 0;
for (const std::string& str : CASES) {
+ const auto& err = ERRORS[i];
const auto dec = bech32::Decode(str);
BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
+ std::vector<int> error_locations;
+ std::string error = bech32::LocateErrors(str, error_locations);
+ BOOST_CHECK_EQUAL(err.first, error);
+ if (err.second == -1) BOOST_CHECK(error_locations.empty());
+ else BOOST_CHECK_EQUAL(err.second, error_locations[0]);
+ i++;
}
}
@@ -91,11 +118,37 @@ BOOST_AUTO_TEST_CASE(bech32m_testvectors_invalid)
"au1s5cgom",
"M1VUXWEZ",
"16plkw9",
- "1p2gdwpf"
+ "1p2gdwpf",
+ "abcdef1l7aum6echk45nj2s0wdvt2fg8x9yrzpqzd3ryx",
+ };
+ static const std::pair<std::string, int> ERRORS[] = {
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Invalid character or mixed case", 0},
+ {"Bech32 string too long", 90},
+ {"Missing separator", -1},
+ {"Invalid separator position", 0},
+ {"Invalid Base 32 character", 2},
+ {"Invalid Base 32 character", 3},
+ {"Invalid separator position", 2},
+ {"Invalid Base 32 character", 8},
+ {"Invalid Base 32 character", 7},
+ {"Invalid checksum", -1},
+ {"Invalid separator position", 0},
+ {"Invalid separator position", 0},
+ {"Invalid checksum", 21},
};
+ int i = 0;
for (const std::string& str : CASES) {
+ const auto& err = ERRORS[i];
const auto dec = bech32::Decode(str);
BOOST_CHECK(dec.encoding == bech32::Encoding::INVALID);
+ std::vector<int> error_locations;
+ std::string error = bech32::LocateErrors(str, error_locations);
+ BOOST_CHECK_EQUAL(err.first, error);
+ if (err.second == -1) BOOST_CHECK(error_locations.empty());
+ else BOOST_CHECK_EQUAL(err.second, error_locations[0]);
+ i++;
}
}
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 668ff150ee..765663e0ef 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress(), /* pszDest */ "", ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false);
+ CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false);
dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1);
@@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
static void AddRandomOutboundPeer(std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman)
{
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
- vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 0, /* nLocalHostNonceIn */ 0, CAddress(), /* pszDest */ "", ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false));
+ vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false));
CNode &node = *vNodes.back();
node.SetCommonVersion(PROTOCOL_VERSION);
@@ -212,9 +212,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
std::array<CNode*, 3> nodes;
banman->ClearBanned();
- nodes[0] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[0], /* nKeyedNetGroupIn */ 0,
- /* nLocalHostNonceIn */ 0, CAddress(), /* pszDest */ "",
- ConnectionType::INBOUND, /* inbound_onion */ false};
+ nodes[0] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[0], /*nKeyedNetGroupIn=*/0,
+ /*nLocalHostNonceIn */ 0, CAddress(), /*addrNameIn=*/"",
+ ConnectionType::INBOUND, /*inbound_onion=*/false};
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(nodes[0]);
nodes[0]->fSuccessfullyConnected = true;
@@ -228,9 +228,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_CHECK(nodes[0]->fDisconnect);
BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
- nodes[1] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[1], /* nKeyedNetGroupIn */ 1,
- /* nLocalHostNonceIn */ 1, CAddress(), /* pszDest */ "",
- ConnectionType::INBOUND, /* inbound_onion */ false};
+ nodes[1] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[1], /*nKeyedNetGroupIn=*/1,
+ /*nLocalHostNonceIn */ 1, CAddress(), /*addrNameIn=*/"",
+ ConnectionType::INBOUND, /*inbound_onion=*/false};
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(nodes[1]);
nodes[1]->fSuccessfullyConnected = true;
@@ -259,9 +259,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
// Make sure non-IP peers are discouraged and disconnected properly.
- nodes[2] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[2], /* nKeyedNetGroupIn */ 1,
- /* nLocalHostNonceIn */ 1, CAddress(), /* pszDest */ "",
- ConnectionType::OUTBOUND_FULL_RELAY, /* inbound_onion */ false};
+ nodes[2] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[2], /*nKeyedNetGroupIn=*/1,
+ /*nLocalHostNonceIn */ 1, CAddress(), /*addrNameIn=*/"",
+ ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false};
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(nodes[2]);
nodes[2]->fSuccessfullyConnected = true;
@@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, /* nKeyedNetGroupIn */ 4, /* nLocalHostNonceIn */ 4, CAddress(), /* pszDest */ "", ConnectionType::INBOUND, /* inbound_onion */ false);
+ CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/4, /*nLocalHostNonceIn=*/4, CAddress(), /*addrNameIn=*/"", ConnectionType::INBOUND, /*inbound_onion=*/false);
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode);
dummyNode.fSuccessfullyConnected = true;
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 325a9a170e..2f33598348 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -221,8 +221,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
assert(expected_code_path);
},
[&] {
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
+ (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
},
[&] {
TxValidationState state;
diff --git a/src/test/fuzz/minisketch.cpp b/src/test/fuzz/minisketch.cpp
new file mode 100644
index 0000000000..93954bd3cf
--- /dev/null
+++ b/src/test/fuzz/minisketch.cpp
@@ -0,0 +1,64 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <minisketch.h>
+#include <node/minisketchwrapper.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <util/check.h>
+
+#include <map>
+#include <numeric>
+
+FUZZ_TARGET(minisketch)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const auto capacity{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 200)};
+ Minisketch sketch_a{Assert(MakeMinisketch32(capacity))};
+ Minisketch sketch_b{Assert(MakeMinisketch32(capacity))};
+
+ // Fill two sets and keep the difference in a map
+ std::map<uint32_t, bool> diff;
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
+ {
+ const auto entry{fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, std::numeric_limits<uint32_t>::max() - 1)};
+ const auto KeepDiff{[&] {
+ bool& mut{diff[entry]};
+ mut = !mut;
+ }};
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ sketch_a.Add(entry);
+ KeepDiff();
+ },
+ [&] {
+ sketch_b.Add(entry);
+ KeepDiff();
+ },
+ [&] {
+ sketch_a.Add(entry);
+ sketch_b.Add(entry);
+ });
+ }
+ const auto num_diff{std::accumulate(diff.begin(), diff.end(), size_t{0}, [](auto n, const auto& e) { return n + e.second; })};
+
+ Minisketch sketch_ar{MakeMinisketch32(capacity)};
+ Minisketch sketch_br{MakeMinisketch32(capacity)};
+ sketch_ar.Deserialize(sketch_a.Serialize());
+ sketch_br.Deserialize(sketch_b.Serialize());
+
+ Minisketch sketch_diff{std::move(fuzzed_data_provider.ConsumeBool() ? sketch_a : sketch_ar)};
+ sketch_diff.Merge(fuzzed_data_provider.ConsumeBool() ? sketch_b : sketch_br);
+
+ if (capacity >= num_diff) {
+ const auto max_elements{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(num_diff, capacity)};
+ const auto dec{*Assert(sketch_diff.Decode(max_elements))};
+ Assert(dec.size() == num_diff);
+ for (auto d : dec) {
+ Assert(diff.at(d));
+ }
+ }
+}
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index a21e5cea0c..ba6c500543 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -98,8 +98,7 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
CCoinsView coins_view;
const CCoinsViewCache coins_view_cache(&coins_view);
- (void)AreInputsStandard(tx, coins_view_cache, false);
- (void)AreInputsStandard(tx, coins_view_cache, true);
+ (void)AreInputsStandard(tx, coins_view_cache);
(void)IsWitnessStandard(tx, coins_view_cache);
UniValue u(UniValue::VOBJ);
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 17b5ef88b9..752e882608 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -93,7 +93,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CCh
const auto info_all = tx_pool.infoAll();
if (!info_all.empty()) {
const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
- WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
+ WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, MemPoolRemovalReason::BLOCK /* dummy */));
std::vector<uint256> all_txids;
tx_pool.queryHashes(all_txids);
assert(all_txids.size() < info_all.size());
diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp
index 6798331936..f7dd18923b 100644
--- a/src/test/minisketch_tests.cpp
+++ b/src/test/minisketch_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <minisketch.h>
-#include <minisketchwrapper.h>
+#include <node/minisketchwrapper.h>
#include <random.h>
#include <test/util/setup_common.h>
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index d8a44a65dd..17b3359624 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end());
txTo.vin[4].scriptSig << std::vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end());
- BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins, false));
+ BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins));
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txTo), coins), 22U);
@@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd1.vin[0].scriptSig << std::vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end());
- BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins, false));
+ BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd1), coins), 16U);
CMutableTransaction txToNonStd2;
@@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd2.vin[0].scriptSig << std::vector<unsigned char>(twentySigops.begin(), twentySigops.end());
- BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins, false));
+ BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd2), coins), 20U);
}
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
index 352797f18d..3937366f01 100644
--- a/src/test/scriptnum10.h
+++ b/src/test/scriptnum10.h
@@ -179,4 +179,4 @@ private:
};
-#endif // BITCOIN_TEST_BIGNUM_H
+#endif // BITCOIN_TEST_SCRIPTNUM10_H
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 54f04d2e67..b8d76c9608 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
- std::string(ds.begin(), ds.end()));
+ ds.str());
in.push_back('\x0f');
in.push_back('\xf0');
@@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
- std::string(ds.begin(), ds.end()));
+ ds.str());
// Multi character key
@@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
ds.Xor(key);
BOOST_CHECK_EQUAL(
std::string(expected_xor.begin(), expected_xor.end()),
- std::string(ds.begin(), ds.end()));
+ ds.str());
}
BOOST_AUTO_TEST_CASE(streams_buffered_file)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 252a85c282..e05781a6f0 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1;
- BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins, false));
+ BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins));
}
static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index 537a6ccea1..8d92bee221 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -73,19 +73,19 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
CKey parent_key;
parent_key.MakeNewKey(true);
CScript parent_locking_script = GetScriptForDestination(PKHash(parent_key.GetPubKey()));
- auto mtx_parent = CreateValidMempoolTransaction(/* input_transaction */ m_coinbase_txns[0], /* vout */ 0,
- /* input_height */ 0, /* input_signing_key */ coinbaseKey,
- /* output_destination */ parent_locking_script,
- /* output_amount */ CAmount(49 * COIN), /* submit */ false);
+ auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/ m_coinbase_txns[0], /*input_vout=*/0,
+ /*input_height=*/ 0, /*input_signing_key=*/coinbaseKey,
+ /*output_destination=*/ parent_locking_script,
+ /*output_amount=*/ CAmount(49 * COIN), /*submit=*/false);
CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
CKey child_key;
child_key.MakeNewKey(true);
CScript child_locking_script = GetScriptForDestination(PKHash(child_key.GetPubKey()));
- auto mtx_child = CreateValidMempoolTransaction(/* input_transaction */ tx_parent, /* vout */ 0,
- /* input_height */ 101, /* input_signing_key */ parent_key,
- /* output_destination */ child_locking_script,
- /* output_amount */ CAmount(48 * COIN), /* submit */ false);
+ auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/ tx_parent, /*input_vout=*/0,
+ /*input_height=*/ 101, /*input_signing_key=*/parent_key,
+ /*output_destination */ child_locking_script,
+ /*output_amount=*/ CAmount(48 * COIN), /*submit=*/false);
CTransactionRef tx_child = MakeTransactionRef(mtx_child);
const auto result_parent_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {tx_parent, tx_child}, /* test_accept */ true);
BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(),
diff --git a/src/test/util/net.h b/src/test/util/net.h
index d89fc34b75..2de6e712a2 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -25,16 +25,16 @@ struct ConnmanTestMsg : public CConnman {
void AddTestNode(CNode& node)
{
- LOCK(cs_vNodes);
- vNodes.push_back(&node);
+ LOCK(m_nodes_mutex);
+ m_nodes.push_back(&node);
}
void ClearTestNodes()
{
- LOCK(cs_vNodes);
- for (CNode* node : vNodes) {
+ LOCK(m_nodes_mutex);
+ for (CNode* node : m_nodes) {
delete node;
}
- vNodes.clear();
+ m_nodes.clear();
}
void ProcessMessagesOnce(CNode& node) { m_msgproc->ProcessMessages(&node, flagInterruptMsgProc); }
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 7518cdb042..eb7bc071e5 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -227,4 +227,4 @@ private:
const std::string m_reason;
};
-#endif
+#endif // BITCOIN_TEST_UTIL_SETUP_COMMON_H
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b1300d06ba..76a690fd28 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -151,12 +151,25 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
HexStr(Span<const unsigned char>(ParseHex_expected, ParseHex_expected)),
"");
- std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
+ {
+ const std::vector<char> in_s{ParseHex_expected, ParseHex_expected + 5};
+ const Span<const uint8_t> in_u{MakeUCharSpan(in_s)};
+ const Span<const std::byte> in_b{MakeByteSpan(in_s)};
+ const std::string out_exp{"04678afdb0"};
+
+ BOOST_CHECK_EQUAL(HexStr(in_u), out_exp);
+ BOOST_CHECK_EQUAL(HexStr(in_s), out_exp);
+ BOOST_CHECK_EQUAL(HexStr(in_b), out_exp);
+ }
+}
- BOOST_CHECK_EQUAL(
- HexStr(ParseHex_vec),
- "04678afdb0"
- );
+BOOST_AUTO_TEST_CASE(span_write_bytes)
+{
+ std::array mut_arr{uint8_t{0xaa}, uint8_t{0xbb}};
+ const auto mut_bytes{MakeWritableByteSpan(mut_arr)};
+ mut_bytes[1] = std::byte{0x11};
+ BOOST_CHECK_EQUAL(mut_arr.at(0), 0xaa);
+ BOOST_CHECK_EQUAL(mut_arr.at(1), 0x11);
}
BOOST_AUTO_TEST_CASE(util_Join)
@@ -2456,4 +2469,52 @@ BOOST_AUTO_TEST_CASE(remove_prefix)
BOOST_CHECK_EQUAL(RemovePrefix("", ""), "");
}
+BOOST_AUTO_TEST_CASE(util_ParseByteUnits)
+{
+ auto noop = ByteUnit::NOOP;
+
+ // no multiplier
+ BOOST_CHECK_EQUAL(ParseByteUnits("1", noop).value(), 1);
+ BOOST_CHECK_EQUAL(ParseByteUnits("0", noop).value(), 0);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("1k", noop).value(), 1000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("1K", noop).value(), 1ULL << 10);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("2m", noop).value(), 2'000'000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("2M", noop).value(), 2ULL << 20);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("3g", noop).value(), 3'000'000'000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("3G", noop).value(), 3ULL << 30);
+
+ BOOST_CHECK_EQUAL(ParseByteUnits("4t", noop).value(), 4'000'000'000'000ULL);
+ BOOST_CHECK_EQUAL(ParseByteUnits("4T", noop).value(), 4ULL << 40);
+
+ // check default multiplier
+ BOOST_CHECK_EQUAL(ParseByteUnits("5", ByteUnit::K).value(), 5ULL << 10);
+
+ // NaN
+ BOOST_CHECK(!ParseByteUnits("", noop));
+ BOOST_CHECK(!ParseByteUnits("foo", noop));
+
+ // whitespace
+ BOOST_CHECK(!ParseByteUnits("123m ", noop));
+ BOOST_CHECK(!ParseByteUnits(" 123m", noop));
+
+ // no +-
+ BOOST_CHECK(!ParseByteUnits("-123m", noop));
+ BOOST_CHECK(!ParseByteUnits("+123m", noop));
+
+ // zero padding
+ BOOST_CHECK_EQUAL(ParseByteUnits("020M", noop).value(), 20ULL << 20);
+
+ // fractions not allowed
+ BOOST_CHECK(!ParseByteUnits("0.5T", noop));
+
+ // overflow
+ BOOST_CHECK(!ParseByteUnits("18446744073709551615g", noop));
+
+ // invalid unit
+ BOOST_CHECK(!ParseByteUnits("1x", noop));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 8a48d539f8..54873ce6fa 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
{
bool ignored;
auto ProcessBlock = [&](std::shared_ptr<const CBlock> block) -> bool {
- return Assert(m_node.chainman)->ProcessNewBlock(Params(), block, /* fForceProcessing */ true, /* fNewBlock */ &ignored);
+ return Assert(m_node.chainman)->ProcessNewBlock(Params(), block, /*force_processing=*/true, /*new_block=*/&ignored);
};
// Process all mined blocks
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
index 2665f8a5be..42470c70ee 100644
--- a/src/threadinterrupt.h
+++ b/src/threadinterrupt.h
@@ -33,4 +33,4 @@ private:
std::atomic<bool> flag;
};
-#endif //BITCOIN_THREADINTERRUPT_H
+#endif // BITCOIN_THREADINTERRUPT_H
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 55618a5c57..776981b7f7 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -22,19 +22,17 @@
#include <deque>
#include <functional>
#include <set>
-#include <stdlib.h>
#include <vector>
-#include <boost/signals2/signal.hpp>
-#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/split.hpp>
-#include <event2/bufferevent.h>
#include <event2/buffer.h>
-#include <event2/util.h>
+#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/thread.h>
+#include <event2/util.h>
/** Default control port */
const std::string DEFAULT_TOR_CONTROL = "127.0.0.1:9051";
@@ -277,9 +275,15 @@ std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
if (j == 3 && value[i] > '3') {
j--;
}
- escaped_value.push_back(strtol(value.substr(i, j).c_str(), nullptr, 8));
+ const auto end{i + j};
+ uint8_t val{0};
+ while (i < end) {
+ val *= 8;
+ val += value[i++] - '0';
+ }
+ escaped_value.push_back(char(val));
// Account for automatic incrementing at loop end
- i += j - 1;
+ --i;
} else {
escaped_value.push_back(value[i]);
}
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 7258f27cb6..8fc852f843 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -157,4 +157,4 @@ public:
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
};
-#endif /* BITCOIN_TORCONTROL_H */
+#endif // BITCOIN_TORCONTROL_H
diff --git a/src/util/readwritefile.h b/src/util/readwritefile.h
index 1dab874b38..a59d0be131 100644
--- a/src/util/readwritefile.h
+++ b/src/util/readwritefile.h
@@ -25,4 +25,4 @@ std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size_t maxs
*/
bool WriteBinaryFile(const fs::path &filename, const std::string &data);
-#endif /* BITCOIN_UTIL_READWRITEFILE_H */
+#endif // BITCOIN_UTIL_READWRITEFILE_H
diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp
index 15bd07b374..430f1963ea 100644
--- a/src/util/strencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -11,6 +11,7 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
+#include <limits>
#include <optional>
static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -138,11 +139,6 @@ std::string EncodeBase64(Span<const unsigned char> input)
return str;
}
-std::string EncodeBase64(const std::string& str)
-{
- return EncodeBase64(MakeUCharSpan(str));
-}
-
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
{
static const int decode64_table[256] =
@@ -526,3 +522,48 @@ std::string HexStr(const Span<const uint8_t> s)
assert(it == rv.end());
return rv;
}
+
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier)
+{
+ if (str.empty()) {
+ return std::nullopt;
+ }
+ auto multiplier = default_multiplier;
+ char unit = str.back();
+ switch (unit) {
+ case 'k':
+ multiplier = ByteUnit::k;
+ break;
+ case 'K':
+ multiplier = ByteUnit::K;
+ break;
+ case 'm':
+ multiplier = ByteUnit::m;
+ break;
+ case 'M':
+ multiplier = ByteUnit::M;
+ break;
+ case 'g':
+ multiplier = ByteUnit::g;
+ break;
+ case 'G':
+ multiplier = ByteUnit::G;
+ break;
+ case 't':
+ multiplier = ByteUnit::t;
+ break;
+ case 'T':
+ multiplier = ByteUnit::T;
+ break;
+ default:
+ unit = 0;
+ break;
+ }
+
+ uint64_t unit_amount = static_cast<uint64_t>(multiplier);
+ auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
+ if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
+ return std::nullopt;
+ }
+ return *parsed_num * unit_amount;
+}
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index eedb5ec2f8..08a5465de1 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -30,6 +30,23 @@ enum SafeChars
};
/**
+ * Used by ParseByteUnits()
+ * Lowercase base 1000
+ * Uppercase base 1024
+*/
+enum class ByteUnit : uint64_t {
+ NOOP = 1ULL,
+ k = 1000ULL,
+ K = 1024ULL,
+ m = 1'000'000ULL,
+ M = 1ULL << 20,
+ g = 1'000'000'000ULL,
+ G = 1ULL << 30,
+ t = 1'000'000'000'000ULL,
+ T = 1ULL << 40,
+};
+
+/**
* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
* addresses, but avoid anything even possibly remotely dangerous like & or >
* @param[in] str The string to sanitize
@@ -50,7 +67,8 @@ bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
std::string EncodeBase64(Span<const unsigned char> input);
-std::string EncodeBase64(const std::string& str);
+inline std::string EncodeBase64(Span<const std::byte> input) { return EncodeBase64(MakeUCharSpan(input)); }
+inline std::string EncodeBase64(const std::string& str) { return EncodeBase64(MakeUCharSpan(str)); }
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);
@@ -189,6 +207,7 @@ std::optional<T> ToIntegral(const std::string& str)
*/
std::string HexStr(const Span<const uint8_t> s);
inline std::string HexStr(const Span<const char> s) { return HexStr(MakeUCharSpan(s)); }
+inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCharSpan(s)); }
/**
* Format a paragraph of text to a fixed width, adding spaces for
@@ -305,4 +324,17 @@ std::string ToUpper(const std::string& str);
*/
std::string Capitalize(std::string str);
+/**
+ * Parse a string with suffix unit [k|K|m|M|g|G|t|T].
+ * Must be a whole integer, fractions not allowed (0.5t), no whitespace or +-
+ * Lowercase units are 1000 base. Uppercase units are 1024 base.
+ * Examples: 2m,27M,19g,41T
+ *
+ * @param[in] str the string to convert into bytes
+ * @param[in] default_multiplier if no unit is found in str use this unit
+ * @returns optional uint64_t bytes from str or nullopt
+ * if ToIntegral is false, str is empty, trailing whitespace or overflow
+ */
+std::optional<uint64_t> ParseByteUnits(const std::string& str, ByteUnit default_multiplier);
+
#endif // BITCOIN_UTIL_STRENCODINGS_H
diff --git a/src/util/string.h b/src/util/string.h
index 5617e4acc1..07c87cfcda 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -103,4 +103,4 @@ template <typename T1, size_t PREFIX_LEN>
std::equal(std::begin(prefix), std::end(prefix), std::begin(obj));
}
-#endif // BITCOIN_UTIL_STRENCODINGS_H
+#endif // BITCOIN_UTIL_STRING_H
diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp
index bc69df44f4..6e1cc9b457 100644
--- a/src/util/syscall_sandbox.cpp
+++ b/src/util/syscall_sandbox.cpp
@@ -581,7 +581,7 @@ public:
allowed_syscalls.insert(__NR_fdatasync); // synchronize a file's in-core state with storage device
allowed_syscalls.insert(__NR_flock); // apply or remove an advisory lock on an open file
allowed_syscalls.insert(__NR_fstat); // get file status
- allowed_syscalls.insert(__NR_newfstatat); // get file status
+ allowed_syscalls.insert(__NR_fstatfs); // get file system status
allowed_syscalls.insert(__NR_fsync); // synchronize a file's in-core state with storage device
allowed_syscalls.insert(__NR_ftruncate); // truncate a file to a specified length
allowed_syscalls.insert(__NR_getcwd); // get current working directory
@@ -589,6 +589,7 @@ public:
allowed_syscalls.insert(__NR_getdents64); // get directory entries
allowed_syscalls.insert(__NR_lstat); // get file status
allowed_syscalls.insert(__NR_mkdir); // create a directory
+ allowed_syscalls.insert(__NR_newfstatat); // get file status
allowed_syscalls.insert(__NR_open); // open and possibly create a file
allowed_syscalls.insert(__NR_openat); // open and possibly create a file
allowed_syscalls.insert(__NR_readlink); // read value of a symbolic link
diff --git a/src/util/trace.h b/src/util/trace.h
index 9c92cb10e7..bb901e05da 100644
--- a/src/util/trace.h
+++ b/src/util/trace.h
@@ -42,4 +42,4 @@
#endif
-#endif /* BITCOIN_UTIL_TRACE_H */
+#endif // BITCOIN_UTIL_TRACE_H
diff --git a/src/validation.cpp b/src/validation.cpp
index f163130a18..881b0abc74 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -723,8 +723,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
}
// Check for non-standard pay-to-script-hash in inputs
- const bool taproot_active = DeploymentActiveAfter(m_active_chainstate.m_chain.Tip(), args.m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_TAPROOT);
- if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_active)) {
+ if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
}
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 7a5526a4cb..4ff049170e 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -43,9 +43,9 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions(ArgsManager& argsman) const
{
- argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting many (possibly all) or none, instead of selecting on a per-output basis. Privacy is improved as addresses are mostly swept with fewer transactions and outputs are aggregated in clean change addresses. It may result in higher fees due to less optimal coin selection caused by this added limitation and possibly a larger-than-necessary number of inputs being used. Always enabled for wallets with \"avoid_reuse\" enabled, otherwise default: %u.", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
- argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
+ argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-consolidatefeerate=<amt>", strprintf("The maximum feerate (in %s/kvB) at which transaction building may use more inputs than strictly necessary so that the wallet's UTXO pool can be reduced (default: %s).", CURRENCY_UNIT, FormatMoney(DEFAULT_CONSOLIDATE_FEERATE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 403c978680..e0c5eef96b 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1548,18 +1548,6 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
}
}
- // Taproot descriptors cannot be imported if Taproot is not yet active.
- // Check if this is a Taproot descriptor
- CTxDestination dest;
- ExtractDestination(scripts[0], dest);
- if (std::holds_alternative<WitnessV1Taproot>(dest)) {
- // Check if Taproot is active
- if (!wallet.chain().isTaprootActive()) {
- // Taproot is not active, raise an error
- throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import tr() descriptor when Taproot is not active");
- }
- }
-
// If private keys are enabled, check some things.
if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (keys.keys.empty()) {
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index babb61b03a..e24d1111c7 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2522,7 +2522,6 @@ static RPCHelpMan getwalletinfo()
size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
const auto bal = GetBalance(*pwallet);
- int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
obj.pushKV("walletname", pwallet->GetName());
obj.pushKV("walletversion", pwallet->GetVersion());
obj.pushKV("format", pwallet->GetDatabase().Format());
@@ -2530,8 +2529,9 @@ static RPCHelpMan getwalletinfo()
obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
obj.pushKV("txcount", (int)pwallet->mapWallet.size());
- if (kp_oldest > 0) {
- obj.pushKV("keypoololdest", kp_oldest);
+ const auto kp_oldest = pwallet->GetOldestKeyPoolTime();
+ if (kp_oldest.has_value()) {
+ obj.pushKV("keypoololdest", kp_oldest.value());
}
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 3a85fc0c64..40eb49cf87 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -38,4 +38,4 @@ const LegacyScriptPubKeyMan& EnsureConstLegacyScriptPubKeyMan(const CWallet& wal
RPCHelpMan getaddressinfo();
RPCHelpMan signrawtransactionwithwallet();
-#endif //BITCOIN_WALLET_RPCWALLET_H
+#endif // BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 9173c790d4..0b4632bd99 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -528,7 +528,7 @@ static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, Walle
return keypool.nTime;
}
-int64_t LegacyScriptPubKeyMan::GetOldestKeyPoolTime() const
+std::optional<int64_t> LegacyScriptPubKeyMan::GetOldestKeyPoolTime() const
{
LOCK(cs_KeyStore);
@@ -1876,12 +1876,6 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal)
{
- if (addr_type == OutputType::BECH32M) {
- // Don't allow setting up taproot descriptors yet
- // TODO: Allow setting up taproot descriptors
- return false;
- }
-
LOCK(cs_desc_man);
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
@@ -1911,7 +1905,10 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
desc_prefix = "wpkh(" + xpub + "/84'";
break;
}
- case OutputType::BECH32M: assert(false); // TODO: Setup taproot descriptor
+ case OutputType::BECH32M: {
+ desc_prefix = "tr(" + xpub + "/86'";
+ break;
+ }
} // no default case, so the compiler can warn about missing cases
assert(!desc_prefix.empty());
@@ -1970,11 +1967,10 @@ bool DescriptorScriptPubKeyMan::HavePrivateKeys() const
return m_map_keys.size() > 0 || m_map_crypted_keys.size() > 0;
}
-int64_t DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const
+std::optional<int64_t> DescriptorScriptPubKeyMan::GetOldestKeyPoolTime() const
{
// This is only used for getwalletinfo output and isn't relevant to descriptor wallets.
- // The magic number 0 indicates that it shouldn't be displayed so that's what we return.
- return 0;
+ return std::nullopt;
}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index ef74638751..2d447f1d67 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -19,6 +19,7 @@
#include <boost/signals2/signal.hpp>
+#include <optional>
#include <unordered_map>
enum class OutputType;
@@ -203,7 +204,7 @@ public:
//! The action to do when the DB needs rewrite
virtual void RewriteDB() {}
- virtual int64_t GetOldestKeyPoolTime() const { return GetTime(); }
+ virtual std::optional<int64_t> GetOldestKeyPoolTime() const { return GetTime(); }
virtual unsigned int GetKeyPoolSize() const { return 0; }
@@ -371,7 +372,7 @@ public:
void RewriteDB() override;
- int64_t GetOldestKeyPoolTime() const override;
+ std::optional<int64_t> GetOldestKeyPoolTime() const override;
size_t KeypoolCountExternalKeys() const;
unsigned int GetKeyPoolSize() const override;
@@ -577,7 +578,7 @@ public:
bool HavePrivateKeys() const override;
- int64_t GetOldestKeyPoolTime() const override;
+ std::optional<int64_t> GetOldestKeyPoolTime() const override;
unsigned int GetKeyPoolSize() const override;
int64_t GetTimeFirstKey() const override;
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index e8b49f1220..0601c492cd 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -68,9 +68,6 @@ struct FuzzedWallet {
CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
{
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
- if (type == OutputType::BECH32M) {
- type = OutputType::BECH32; // TODO: Setup taproot descriptor and remove this line
- }
CTxDestination dest;
bilingual_str error;
if (fuzzed_data_provider.ConsumeBool()) {
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 7f60dd6906..155c27cfb6 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2169,14 +2169,18 @@ bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& des
return true;
}
-int64_t CWallet::GetOldestKeyPoolTime() const
+std::optional<int64_t> CWallet::GetOldestKeyPoolTime() const
{
LOCK(cs_wallet);
- int64_t oldestKey = std::numeric_limits<int64_t>::max();
+ if (m_spk_managers.empty()) {
+ return std::nullopt;
+ }
+
+ std::optional<int64_t> oldest_key{std::numeric_limits<int64_t>::max()};
for (const auto& spk_man_pair : m_spk_managers) {
- oldestKey = std::min(oldestKey, spk_man_pair.second->GetOldestKeyPoolTime());
+ oldest_key = std::min(oldest_key, spk_man_pair.second->GetOldestKeyPoolTime());
}
- return oldestKey;
+ return oldest_key;
}
void CWallet::MarkDestinationsDirty(const std::set<CTxDestination>& destinations) {
@@ -3164,11 +3168,6 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- if (t == OutputType::BECH32M) {
- // Skip taproot (bech32m) for now
- // TODO: Setup taproot (bech32m) descriptors by default
- continue;
- }
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
if (IsCrypted()) {
if (IsLocked()) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3855ad821d..bab8314c76 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -632,7 +632,7 @@ public:
size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0);
- int64_t GetOldestKeyPoolTime() const;
+ std::optional<int64_t> GetOldestKeyPoolTime() const;
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index b609ba6881..d6717ebbca 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -26,7 +26,7 @@ static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flag
{
LOCK(wallet_instance->cs_wallet);
- wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
+ wallet_instance->SetMinVersion(FEATURE_LATEST);
wallet_instance->AddWalletFlags(wallet_creation_flags);
if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
diff --git a/src/warnings.h b/src/warnings.h
index c38edb4570..7ab0a93e3f 100644
--- a/src/warnings.h
+++ b/src/warnings.h
@@ -20,4 +20,4 @@ void SetfLargeWorkInvalidChainFound(bool flag);
*/
bilingual_str GetWarnings(bool verbose);
-#endif // BITCOIN_WARNINGS_H
+#endif // BITCOIN_WARNINGS_H
diff --git a/src/zmq/zmqrpc.h b/src/zmq/zmqrpc.h
index 5a810a16fb..8538adf9d3 100644
--- a/src/zmq/zmqrpc.h
+++ b/src/zmq/zmqrpc.h
@@ -9,4 +9,4 @@ class CRPCTable;
void RegisterZMQRPCCommands(CRPCTable& t);
-#endif // BITCOIN_ZMQ_ZMRRPC_H
+#endif // BITCOIN_ZMQ_ZMQRPC_H