diff options
Diffstat (limited to 'test')
86 files changed, 861 insertions, 1048 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3a5998697d..f1d05371ee 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,7 +16,6 @@ function(create_test_config) endmacro() set_configure_variable(ENABLE_WALLET ENABLE_WALLET) - set_configure_variable(WITH_SQLITE USE_SQLITE) set_configure_variable(WITH_BDB USE_BDB) set_configure_variable(BUILD_CLI BUILD_BITCOIN_CLI) set_configure_variable(BUILD_UTIL BUILD_BITCOIN_UTIL) diff --git a/test/config.ini.in b/test/config.ini.in index 3bf79ef25d..cdd13a9d8c 100644 --- a/test/config.ini.in +++ b/test/config.ini.in @@ -16,7 +16,6 @@ RPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py [components] # Which components are enabled. These are commented out by `configure` if they were disabled when running config. @ENABLE_WALLET_TRUE@ENABLE_WALLET=true -@USE_SQLITE_TRUE@USE_SQLITE=true @USE_BDB_TRUE@USE_BDB=true @BUILD_BITCOIN_CLI_TRUE@ENABLE_CLI=true @BUILD_BITCOIN_UTIL_TRUE@ENABLE_BITCOIN_UTIL=true diff --git a/test/functional/README.md b/test/functional/README.md index a34bf1827c..cf0f2fd0e3 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -183,7 +183,7 @@ way is the use the `profile_with_perf` context manager, e.g. with node.profile_with_perf("send-big-msgs"): # Perform activity on the node you're interested in profiling, e.g.: for _ in range(10000): - node.p2ps[0].send_message(some_large_message) + node.p2ps[0].send_without_ping(some_large_message) ``` To see useful textual output, run diff --git a/test/functional/data/README.md b/test/functional/data/README.md index eb217d6071..bb03422f95 100644 --- a/test/functional/data/README.md +++ b/test/functional/data/README.md @@ -32,7 +32,7 @@ pkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg It uses `pkh()` because `tr()` outputs at low heights are not spendable (`unexpected-witness`). -This makes each block determinisic except for its timestamp and nonce, which +This makes each block deterministic except for its timestamp and nonce, which are stored in `mainnet_alt.json` and used to reconstruct the chain without having to redo the proof-of-work. diff --git a/test/functional/data/blockheader_testnet3.hex b/test/functional/data/blockheader_testnet3.hex deleted file mode 100644 index 882133aa2b..0000000000 --- a/test/functional/data/blockheader_testnet3.hex +++ /dev/null @@ -1,548 +0,0 @@ -fork:0000002043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea3309000000000943e54375082c03172552ae841bab31ebf2463484574f6ce6fe9c3723e3defb719a485dffff001db8b63209 -fork:00000020da2809ab72cf2502ecb29137dbe63e51fb82fb5babe6c9530dd86dea000000005dfcdc47012c19a2708b53e820c71b529f616a45529d48bad484948c84685d572d9c485dffff001dd3530a08 -0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b672 -0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d23534 -0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b6 -0100000010befdc16d281e40ecec65b7c9976ddc8fd9bc9752da5827276e898b000000004c976d5776dda2da30d96ee810cd97d23ba852414990d64c4c720f977e651f2daae7494dffff001d02a97640 -01000000dde5b648f594fdd2ec1c4083762dd13b197bb1381e74b1fff90a5d8b00000000b3c6c6c1118c3b6abaa17c5aa74ee279089ad34dc3cec3640522737541cb016818e8494dffff001d02da84c0 -01000000a1213bd4754a6606444b97b5e8c46e9b7832773ff434bd5f87ac45bc00000000d1e7026986a9cd247b5b85a3f30ecbabb6d61840d0abb81f905c411d5fc145e831e8494dffff001d004138f9 -010000007b0a09f26fdde2c432167d8349681c7801d0128f4dfae4dc5e68336600000000c1d71f59ce4419c793eb829380a41dc1ad48c19fcb0083b8f67094d5cae263ad81e8494dffff001d004ddad5 -01000000a62bc0c08afc1d12e6c6a7eb4a464c848190ac0e44123d5fa63a9ee2000000000214335cde9edeb6aa0195f68c08e5e46b07043e24aeff51fd9a3ff992ce6976a0e8494dffff001d02f33927 -01000000f9e2142a93185496f7b21314d8b6fa736d0a30fa3a6d339ab3a1ba9c0000000061974472615d348df6de106dbaaa08cf4dec65e39cefc62af6097b967b9bea52fde8494dffff001d00ca48a2 -010000001e93aa99c8ff9749037d74a2207f299502fa81d56a4ea2ad5330ff50000000002ec2266c3249ce2e079059e0aec01a2d8d8306a468ad3f18f06051f2c3b1645435e9494dffff001d008918cf -010000002e9afd58b91f15c3ec9eb0f01ed9d503134da1918b6bb416a9920e700000000029fb495afdb58f3a26d1c90fafec93aed840e2fa37ad6173ba1e7fadb7121ee57de9494dffff001d02e7f318 -0100000027e0ca29a9802c0a2390ecfa90a9bd814fecc54446510e155652dead000000007e8d5344557575c8f018cc62a32e8e0bd80638643b4ec34945ec4662fcab138142ea494dffff001d04acbc3c -01000000001f3ada9b561378e324e80ee68facd5d232f72f773b86328393054700000000eaf3be35e3f0ace8b6abdeb5509d72999eae2329657238b53fa437e319c8e96b99ea494dffff001d027801a8 -01000000781bc7847e15c3b936a6a6a178e38fa29ee6e4916a8a62e10795c69200000000d44c3443fa8bd88bf32b94b9257f09ce6fb6ec0d5420504d631568f8685200dfa1ea494dffff001d01f781d0 -01000000133991a938b505ee8f6f347f313c3372d82a9d8b42b08b0dd0fc086400000000a0ef58c239e0197a65aa248c2cf52c437d8c8ea30d1b835e630a87c941f7d4e9adea494dffff001d030ef2e0 -0100000028d34cdb13e555032e4bec55fcce3d0fef8212803fb1bab851e1259400000000542c71544b9f28bd5a6fec95ecd509ae49d0b04f8718c685d0751f71d38285d0c3ea494dffff001d056b3115 -010000006b00cf1ce31b33fe1e2c4648a0834dedd972ffb2a2f341f75ad7cbc400000000adebf7afcbf176f765aec16b74d92896f55c3d65e14dd1a8becee0871000291751eb494dffff001d006f85e8 -0100000043a78ddf30a2d28a42cc66f90d13cb8211ee0fca9dbf8a4cce8c19fe000000004edbd2b89cb6d6fd69b575a62bd4e3103b1e0ce19e31bccf9a093ad8ccd753cf7deb494dffff001d0591a0b3 -01000000489ac81592595a4004e14331cb096ffef12b1daf709f6378e9c3558d00000000c757bebd6f2c2c071a3cf739a4cf98b27441809790a5cf40652b46df8a98a473b0eb494dffff001d011aedb6 -01000000a9c570a45d959023551f9a694ace9c12206174f21383f30949ca3b9b00000000eaf93dbbfb3551a1ff8b6bd5ba4cea7508e790c23cd07b9d9e791936a79d5fd4b3eb494dffff001d0385a7dd -01000000d35d5fa860dc70c8bdaf12f18e16d8b4cc29d141c28d59cc317fe5ed00000000507dae091a9657b6c073863ca71ba6989a2cf4417fb81e940668568a35d34a7119ec494dffff001d00effec3 -0100000073379e3ff3dffd006e0090e52ac571a9a309490a23e64d15f8af291a0000000051f1c5b2b7c8f980e7715b4d3ce0180f99c44a16fc9c00ede2f5984b8d7cc22d16ed494dffff001d0082467f -01000000869845a3343adddfa5b1f534b507d9b67c3685b0f1d89d526cdbd34200000000823623e8c6fe2c449065d2c0ae57aeb4bfd8e9687126a6c99d1ce916e2fca63f4ded494dffff001d034f940c -010000005da49f64cf0025ab1111651d94748b00bdb00b780744b88b42f962c200000000fee9e254a5a74c858297e89ebcd2305ad2707a8acc131ad07f6abc0d8e38def969ee494dffff001d05c512e2 -010000006a65bc120bf3e6dfadc3b9543e48f8876cb826aed0d8f809bc34bb220000000090f489f48c88442aa7d9250f743b386558ba1fa2e7e240e5d32195d56cf1c34ffff0494dffff001d014394ce -01000000e3f21ff9cc51ef282bf6bebc90e6f96968a36a704452192724c839bd00000000b6d553c98016b66fcb4856ffedc13a2de720288d4c2e8fed86206981259791a23af1494dffff001d017f7044 -01000000e16daff1b16a81a3058d982e79550c9c9ba84a207a8b84ae092eb4b300000000f2f34dd423f99930aee95815b2885906f9cdeaba04a9bb076c1f359c2031732059f1494dffff001d01b322bb -0100000059ebd22dc26158414c60868355e78ab4b6891345fd97602f6c106d9c00000000e6c5bea3888e891bc5f9f8fcd166d332071d3b434e933763fb20db50e47dad3f5ef1494dffff001d0067a0e5 -0100000015ddbe82f202b27febceb00547dc19653604ef434f080848f22e3b0900000000e26e8971a53396413f0f39b88a697f593993999c8d07fa2dde608111fb2ccbd3daf1494dffff001d04362f37 -01000000a76595e37692f85d5de0438da8e75b5f611fd7b7071816b9ace8ba2b000000004cfb6d8faca8e8e77a71359d2cf0d12d2e52f266591f5fb807aa737c90869d2a81f2494dffff001d040e87a6 -01000000a774311853f32f32d87081529bb0506d5e4e90f7e455bb640081215f00000000228b387354daa9e5d38201811fe746591ab08a66bb3c4fc796a45535acb8c61baaf2494dffff001d01ebfd80 -01000000d0efaa4f6924659f1e0221f910e99f6fae76b36b759b212852d1343a000000005e40d3b65982e929433ee02037a60f05b62e70e6d51f608974fb1f2926169398bff2494dffff001d05c41c3a -010000004c600547d8ed4b9dc946bb455f64917131dd98974bf2dfda05afc3a800000000e5b01ac4a611211847b0777b9ba9e396b0b7348ac401041e4fb6168ed091691ccef2494dffff001d037a60b7 -01000000f571553e5aa32b8374bd5a0f3c58834a46e05727b64dbe62a942376600000000a91cac1e92c7c597af565594565f5b54e658fd2e022e4fc35eb92aa165d9aa4fd3f2494dffff001d02687811 -01000000d8273e218df68e333782ab3b79929a8609404bd85bc225b46debba3700000000e91f9128f70a0502d338221316a0a3a1f4181821f9d2220c3fce7b5cf8e305d514f3494dffff001d01f22226 -01000000ad615025da247d14a4f092f21c4fddc6d1a84e0b4b0929f9ccf81c180000000069cabd55fc74596566ed1548b6b4ac23943d33e817028d8bc8695a7bba82256e6df3494dffff001d00e066e2 -01000000e7da808f2e62c3ec1b443e2979c972f5f69f32146cb4385bcb6fdca2000000002f4092fa4879ecc1a39471c41f8fae20f10ad2204bcda34e79ac37cbbda973757df3494dffff001d0316a8a6 -01000000928b86c36f27d22c7d2baf27f31b50bbec7754d33d12aa37342723db00000000ece3fdbc63b66327abb251165ac0e19b1a02fb79295c9b6eb8b38b68c1c59107dff4494dffff001d05bcddf0 -0100000088c96b45d3e252cdc38780843e3679d74e858a1d218f9e3e0866335e00000000432cba2143d62f6349faf4f7956f7354733518c22a309284d96236a9d8c9616e0ef5494dffff001d026ebb97 -01000000885d76fd42926155ff9ebb1d3c41a517d7beb70564b98c3608719f740000000011a3bb257acf328a5bf1258bbb653b88a40b2d2a66db695a1ff1aa9d31d5186590f5494dffff001d02bcabdb -0100000093f416076c9b2eb0d147e8ce3bac03aa0784e44a6de6fc6f61183a2800000000be46ca90dd31022ee15f74c221208eadf1840e208a6adcaf127a60cc61d959c4d2f6494dffff001d02d68fd2 -01000000f9da861df4a86158e751c062e0a82d3c90e9038330f6447df4aee3d000000000972534907cdd1bc56f21adde0850dd17d988711a5c36ff81ec84610b4f762e9ae3f6494dffff001d00e96635 -01000000303a04a9f551e93a8ca88ceaba1c1d28892323564988ab7f99a9c0d70000000087a11f1aa5769968461b251ca9229f59acad999284e29976331cc13da46432364ff7494dffff001d012c54d2 -010000006b82062aabb19e4cc89addeded5c65ec28684cb54d30d463719f094800000000a98137fab92249e632091c38e3fe4c7fd8bba11bc956fe83c41357e217929e1e8ff7494dffff001d01edcd15 -01000000f7332e78d21adde6e52aa20362c71c1fd7bc745b3edff6e72497067500000000d521571198d3d2c4124b8bd9ba7842716b3bdd93236a92ca6af7c0a7adf9633c2df8494dffff001d031b1c13 -01000000c9ebcb8ea6f7e6a611117d0268639625cee28155c88708b4c09d4aea000000002d4c50f85979f0d2491d015206d867b273b353c253a173abf18dfbc5d96d088e50fa494dffff001d0397f4fc -01000000562c889f95c49db05f6a33277aae9bfe68e92f00a5d6f67ac8c366a100000000b7b0896c4a53b6aab15282cf53e1119676d89be0eda11064cadc40dc8ec194dc66fa494dffff001d01f0369e -01000000d41cef71d625aa5380f6cdc6452c67951e7e4f5b27b7904b4c2da413000000001c1e1096ab473aba614651fb98f47a375c03ec470daccff39a2d2d65bfd881b47bfa494dffff001d02454a15 -0100000095359a35957b89dd268576d562f49db7939baeda6de4855426ab5d9c000000006f68039da08fc314bcc71631be6f4b2ef5e0a2f9491fc078b11fad3dd49ac287a0fb494dffff001d02fbc213 -010000007d505f65addb5a3b50eb33cc5cd3bcafe03ee597c4027166aad2d2630000000090d221539ba3dabdcf0eacfa9d63f272c59dcc07e5e193271a24f4c11caf2c24d9fb494dffff001d05542cd6 -0100000013d5bb77b9235002acc75014e0c061c79de1752d3edc6859b4c0df7a000000000d17f332abe46c092877537ae764aa99e9b25d6bdd94f4007eac43f4861cf4675cfc494dffff001d02f62def -01000000612ec5ae40cb2a58e18d3124fd70664a4fcb9329f7d268d4bcaefacb00000000f7bc31a9984831440cfae529df94ba1680fa15b4490454454920ea8947af4a3765fc494dffff001d01c6c1af -01000000f13ce1836e92f0d12e4892eb229cbf6d50b9b2080af16b01f00b25de000000003f8f64092fddae84dad92736fb7d350e25bda6118bb1c660b06a4a5730fd352815fd494dffff001d055e65b0 -01000000ee24ae636bd70cadac603bf8cc631369bafbdfa8ac8effbc7dcb0fa5000000006faf8082545aef971aa4f92bd411947929c4949362300cd1302ec8bf74091fbe35fd494dffff001d0139a790 -010000006350a3cd2181f0eb75fa8c4022634ad85b6b9e1f9b7346a2eef5517900000000a09d738f407e2dcc888e8ecbde93458d8599720e0359a380d503ee56c688ef72f9fd494dffff001d02661caa -01000000a29d92b014057dbff2775280b8bae8b3877fa9a345f4972034c0711b00000000447bae5734b6c67dc36ae088869c18740a836d7a9feff0b349efdd7373a21358fdfd494dffff001d01b13c06 -01000000dcbf4a9455bf33482c2e17640cb89711468c0def1ba9f6e26e5a4aed00000000b555247649a364adb88b07afac3aa2f9ddf5c379154cb17d22f69fd74c84a2e24afe494dffff001d03144aac -010000000429b2aa02abcb8275705dc6482230dcb7c8678388fe7d75022c1ed800000000d5efd425dce6deb5750306ce8a0e5d045e0a607ee0b530866833e956dbeea0575ffe494dffff001d026ba2bb -01000000871d8a30b3b39373d71fb9c5c7d8d7a3c005ad688d9c8ca974cd330e000000005ec14d2b9adfccae05f78556b12fe2ca03cddd8bd67896fa5c6b6fb090e90177a3fe494dffff001d0147b26b -0100000019fd8a4e03a52e43322506693b696af00b828361e2a0968898708e43000000003853a270a7d9e6ad80fbf911146428c7ed63b2a1154df748f5a980fe20e9e8e2b3fe494dffff001d04538437 -01000000d250d67bd2679caba305e5e13698c7880098a1a4383c2f464fe9006d00000000d793e7c2c9416eae3d8d81046985db5f3d1df7922e869fda6ec5b22181ee46f725ff494dffff001d02391748 -010000009d83b8dbaae3dee980529b6dbd307df153a22b5b0fc35ea694a1faad000000003cfd458875824fadce673ca8c3125fd12c36b7230035b5f056a12d4e0d6b7e6b7eff494dffff001d0448653d -01000000a7d1ff0415c1d1be8a11c7dc20557e001d2fd96c0f396f52969e330d00000000ca20885f915b1d3c5e614cf76067fcf8d9894204db63664d512806ceab58ea27d2ff494dffff001d0327cc00 -01000000d98a10f08f4a7aa698ba8564a85bf821b747c7a44f656fb2e3b9335f00000000dad4bbd7663a69c07ff9579434972bb203d0d78d07858ddc7ca32513101c964e3d004a4dffff001d04df7568 -0100000031965a378dbb0d024df444b3ebf894f370d28df8abdd54565b598b9e000000007ad93f6eed4656fa7c0a606c08b067be35dfa5392eda5d77f133dabdfd08739794004a4dffff001d04facfab -0100000004cc9e4dad8b5d2166fb175e7bfe13ad56018dc81255d335336b8b38000000002d011ec2248c2899ca72a01673535807e2cd0fbcd4465ebafe2a002f3f6c9ec1a3004a4dffff001d04d4b0a1 -010000002093e7853950d588f1a36601643a97b7e187f6b7b274ae43d82410a6000000008ea10bf2d0d535c64d9db748aec8723566b270e0becacdb07438273654e59feea8004a4dffff001d04d4db49 -01000000eff17d4b5360e16151019597f732fc8f6e3b19ecf0c88e2ab1a2bd3a000000005d9b9c1d04856052c8f01497c9ce05d01c4c80c1c4296b15549ace3e04e2cc24e2004a4dffff001d02358897 -01000000bf5ea56c32a49508f0987cf0b18513d285edbe987b0dad25ceef3f1b00000000ba933ef648e2544227c7db41de45f0cf39aa612478c126e5ce5393668e230f1213014a4dffff001d044c6575 -0100000091ff63e6ab577bdc347fc87265fc316d53303bf28d0294a24791143300000000a97e4a6f79bb595fe0239f31549d5b06e13e7d5062e3707ebab0f38f0df5d1832e014a4dffff001d0083c449 -01000000bc749fb377c9a937702bd4ff35d376b43f5bc56726029a93a38e8232000000002bad8475b38ccd82eb98377132453c72706ae9626de3f913e8da2cca6795481166014a4dffff001d0594c61b -01000000a02349924ea393906e7fe3ffc2b9d152fdf55bcc1bace5251517168100000000448e52c8902abd28f82f3ff5eec8c97ab16b71b61674713cbc4f9a896f733b5ba5014a4dffff001d05c09af9 -0100000011f5cea7297afda99c9a141c4d438ff7708f451b571b4aa57b4b69f00000000087550789e53e3c66c4ce24d145f615c95f593d7557fa3ae2eee2a1f985549f9bfc014a4dffff001d00e035ee -010000004ba4c615f54d1557c5f691cb614cecb9edbad0011ebbd3b94fd458ee00000000c9782c5584bbe7c3a51f048dbf1e428e0b0e092607ea6514c401f13a45afd2b6cd024a4dffff001d049ecd2a -01000000718886f10113146ac974a449c8b5bb205e0307f42d1b81990cf1991e00000000b88f0b4d80b631a24a15d7c640ecc15ee82188bb16d692be42467e21b3971c1421044a4dffff001d03e07f40 -0100000081fbffbf5c27e4e908c14bc8f303a4d91bb71ae05445e839c531ec81000000002aefeed1a7378f70e1f434bde89af706e1777993d25d9a95f5b4f4a0d83bcda8d8044a4dffff001d02cda9e0 -010000006d7f371b437cc054548511f0f9ec50b6e04bb4f3a4915a099c3bad36000000005b72bacbca2f6bb848d4753733f6427849b1aa4805b244e2751c38ff8d3e339c41054a4dffff001d0018ffae -01000000b82c2d751368b79004a8e15e5b9f1bc7f620d5de2d6105d83d8ec2f6000000000cdfbd9bd57b78356abb0d07551b0c5c20d5258091604be05674d4d19455df2fb8054a4dffff001d003c4d86 -010000006efef1bc9d35256bbe500ee9c92230e0f987296e373e20ee7f3da4710000000030a2d3961a799e229a81337790254ebaefa055bb85ec7f03e5c8e9c3250eb35ad7054a4dffff001d0514a76d -01000000e789ed685960b594652b9b83a28ded0995725d6ad82b2f358058cbe80000000035b73fb2084e2e8faa28334b17c12668004b7cc8965831aaba65b38b7c54ba97ff064a4dffff001d055247e5 -010000000606ede205a1002e0995f8d009de821d488e22fb37167bcc9120afbe00000000f6f0d5c7f8204a7142f2e37a7cb406e0a57fd7c9784c12111c55a1cde5418ed11a074a4dffff001d01a5f8d1 -010000006da3e0f7fa132425557519508e4e97cbec301a33e25d4b65ac054a0d00000000d657340c13f9f8accfc3af62529a25d3d9e656caf2993fd3166f73850f397c228e074a4dffff001d0309686d -01000000cb9c32345bb264b3b2a6e96c8843f65c9598e4948737c569c0a00073000000000894a15ed694c745d87d2135f90eb9dcf8b454937b48c82132d52405e0d4c4689f074a4dffff001d02d5845a -0100000095349f59ed0c0ce5ab0de43b9d55fbc7b8afac7eb6dacebeaaf290f100000000df9bf22064b03cf08e658257b5d19662fdbe3d7acd27894cef0d3f9ff5a657bbbc074a4dffff001d00a13d79 -010000000be1a15c8ae486da44f0585514eea60780091e52e35f838cd1572bf50000000077333896bed3021acee751bf0c073d95bbdc99125f4298c052db8998bf7c3270f9084a4dffff001d008f86bf -01000000c0b7b630de7b1bd92c4be9d32e19faeadd68f60316ec97db96eaec0f000000005e3c98a964d941f4abd129531d0ee81cd5e7dc098179c3188ba36ccd1e5f9fff7e094a4dffff001d03d8a118 -01000000ae3c51439dc8f2bdd807e1d88c25a5a0b1a3005bcbb50bbb4e48493f00000000ac719d460d514cc4489597ac78e995276865ac07d7606a313c12b16e769b9294f50a4a4dffff001d04735f73 -01000000ce12350c698e84085e7b62c039249c63cb6a6cc9404776c9cc7fba8800000000ca128b2e74fafb345ad249d61c538f75a2a230bbf2266d470d47986555894deb370b4a4dffff001d001c0a17 -010000003dcca8252a636d4c0b8bc4ed9285b749434aaebc29965fc691a635ea00000000baebe5ae323c2bc5c316f6a8f1947b4666c7707c9ae127a03e6429fea7624ae53b0b4a4dffff001d00b4a44c -01000000f6cd7f4cec06d5c6aea54e64b45f049640680e4cb8249cf18587b314000000004a1b2b51da86ee82eadce5d3b852aa8f9b3e63106d877e129c5cf450b47f5c02480c4a4dffff001d02552721 -01000000c64e139bfae4adcd96860bbef3969b84851dc4d4fd8d06f16cd03698000000005e4b195fd24b314f69f7bb5b0139861b0f07a1286b8f6f42dbb6c82524bfdb93890c4a4dffff001d033b3297 -01000000a3e811a098612235feb5e1acb407cd98132a9d5f4dd99aa8d8b576ea0000000025a13ad0cce0eeae69ddb545bda3b490230e68dbf0687af3ddfa132caebadd7cb30c4a4dffff001d04a39aa9 -01000000ab5ab86fe14c9c765d8cdfd67f9bd5d41505f9f9f67e4da1851f099700000000beb6740250c060fa7b472f4daea18186d47e266dfafc88f088d7efe3ca5a2ac1060d4a4dffff001d0511eae4 -010000006ee9f67721369cabaf6e3e9045b2efb70bc1344256dda634a92eec5200000000d5b0833f82460e5ea635a31c60314eec20bb317f2cdaf354023ed4225e31f264380e4a4dffff001d03a74f10 -01000000b3ef61423747695daed4acef8980b5ef4c8feaaa908b3fdc6fbecdab000000004fd416b35e12b775e2899ba509a06822ed8b6627311364f5195d32ca6a314dbb3d0e4a4dffff001d0255ab96 -010000001c75c30c7bb6391ec7d94f6d52bd2aeb0b8f5224907b0106791ccdd70000000016f86bf97a3dda131f108ab4ab456d5ed3cc5e67eec631d8fa044b95c19f3449410e4a4dffff001d048e1c98 -01000000a8bb0604235d5310973b23a5c797442a1ae8c07b96d8cd33c191b45300000000322948a4806acfeca2b32248d0e183c8eb09d5e5ef48adf33777307635414cc05b0e4a4dffff001d00edcc80 -010000004d37f2af0c42371bb77b52cfe7f539e550e126631dbae6056e54dec80000000014238140ff083fe67f0d5c0627857c4330c4c96187964f42b680ec460ad0ccd6620e4a4dffff001d048185d3 -0100000087e774423a88647a4567d3a15e7099b7f271d8d846066af9776ef4ca000000000d90cd436a707875c28222178146cb93f6b048dc4e7555cf37b96757e3b90a5b740e4a4dffff001d030ccab4 -010000002f3be6a1d59b7786d8601330a47f030fcdf2354275fbafa8f4c129490000000098a23359c17ca2678e2039c8ff9081b18c4913749c9a081ac3f62958f09fa472e10e4a4dffff001d00c7fe6b -0100000050ac3cacdb94018a26258b82299da1307ccf3e2bf62a8f4acc19e02c00000000e09f513a024d3e13473d7a65f79073b36a90cc228613672d2a47812368ff42d1df0f4a4dffff001d007f726d -010000000e044393202d6b239c902d3f634e3dfdfa31ae439d339238ab1688e30000000055b5d3d496e196d624a471b818ba0b1778417ae335a544033536654fdda3eef6e80f4a4dffff001d03ed4240 -010000006396e6ba5ef4924d42f4f3114ec7507b81bce51e9e2eb51ca9c53c420000000049af9208af7b7a06d65ce1cfcab6ad9123a8dd7538fb0aca332c63429ff48d59ee0f4a4dffff001d056528d3 -01000000497b15826573b28c3e83a5d0c5ed30cf48b97dd6bd797849144ea2400000000018b50db063333a3261b9b41e887b4aa5b69becdc9967550507c120e22a76496710104a4dffff001d0408eda5 -01000000f5ddc74872eb899f5113e002f642e7b507f871d99a9900edba304aa0000000008f6546b850a14744afc3fe55f76f3959f40799bf4dcefe01ae4dba5903cf2fb553104a4dffff001d018f658e -01000000918a758ed54c9f495edb24ef3fe0f4432ede25853c324fc0f33a458f000000007a8e49b22114f17b5933fc7a8005421ff8370b8c48fa04c24323e91bd02d701492104a4dffff001d053e6e0f -0100000035893f7cdeb0e9af7d9fbda1584ef6d5219dfbb141b07b31257a1658000000008b9b3abfbe24d0e375deebb5f41e74949203c00772a678ba69c1126156c5489bfa104a4dffff001d012a69fb -01000000b6f8c48e94ca346b12373281acbaa08fa54d1cfdcd9c01e020cdda9f00000000be5b4753c6062e3eaed75f5412e43d6dce8d242c5816b436689f795f90536f28cf114a4dffff001d01b6887f -010000006006db00d70ce04a9940c203dc865b3c5d070f8c2d1295498ccd6c32000000008bc41e410a44b764dacb38c1138a3ff2c038a188a063509c6fed4aacaae72ee67b124a4dffff001d009531e5 -010000005e0dc170558d7b2872ddc85f481531dd823dffa66cc620c065adef7700000000e82e91ade6f25c8c6f4c053aa62d94926324ced07ba2f3aae072b13a2c5dc5f89e124a4dffff001d05ae2281 -0100000056320cab20bc1daf4fe3cf0115f2436523e44c40ebcf8c18e6b5822f00000000ce415eab9cba354ae042c22ac9f06c1a69d7a5dba67136fabef93d82f374dd3e01134a4dffff001d05a0d736 -01000000ccb063ab7d74a4030fd155615f046f95c8068078557568ce6b8092fc00000000ff33b27214141ef3d183b1d2499666c8635a57943ef5f515f4e60515f9ea0064c1134a4dffff001d021fa95a -010000007f6d7a61bd46dd27be404b8c883b812c2899095462591dcd75a96f1e0000000091777c00b7168a888d7a7db4b5f78758129e79ef909f92a84110b9f33f9c4c5505144a4dffff001d03526c4d -010000006be8cfe3e176d34d1a46f68b7d20a01ad3f9e2aa6f7540ef6a32573c00000000a870da2f87071c1366a22e77c829a6b85d745ab2279e0333872518d58b8dc0181a144a4dffff001d042c5db7 -010000009cb87223258aba43742de401d0157ee2b4057da95b23e1665880725700000000d54d368cd4243da3793fe3ba2af1570dd44a905d77ecd1a5cbd07cb8f72ad80f30144a4dffff001d048f280c -0100000052b771a3a85c26bc796ae0841ae894c6ad4527b062c94812d98b9c5800000000eeed0f4d975db8f66788f809ecf8c351d19ff5805276ef31983bc5682548342d52144a4dffff001d01aa3be1 -010000007ca07eb5637ef7696d7bf985b9114de19317a9abdfbe4ee79d8bcb1a00000000d7172956946d5547bd98c6a7040d353c3cb6285fbad096a1780f3b7503539adf3b154a4dffff001d0333fec4 -01000000326f947390bf03abdda16f673d26326d4b159e0b7f732a67286ba8e40000000085701296d47b03f388fd85431c2a9fc817afc9b24870a9a7da850d3a43a8154b71154a4dffff001d0164b7d2 -01000000a45af68df42f6f23ecc47e1cd0f41d47c1e5a26e8343951f9881e51400000000b7c1565d19d406d8c56448571d7e7da2ac559bf9b43887e16e4f416276ccb99b8e164a4dffff001d02ec606d -010000007eaec4cfdb152a8ecf8ec155b7343e2cc04750be00b96c61a477e57c00000000096a9263a5008a48e1c2b527b922a81cfc269fd401ce429976c587a951ff00798b174a4dffff001d015bd123 -01000000db36ec19328691975cb8c6666866be64b5be79ae42bee9fce3b5db5800000000b5e73d7d102476db3ca2379bdd891b311140b49626ef42937356ccdb8fed589103184a4dffff001d032d07eb -01000000d8f8a6686ecdeac529caa3ab9ecfa84a5fb62b06849ee09b8331d89e0000000038b408676c2a78fc63ddc1807804d17e8ad9433387cc3cc0edd68c07e4a714b610184a4dffff001d0437e51c -01000000c54675276e0401706aa93db6494dd7d1058b19424f23c8d7c01076da000000001c4375c8056b0ded0fa3d7fc1b5511eaf53216aed72ea95e1b5d19eccbe855f91a184a4dffff001d0336a226 -01000000bca72b7ccb44f1f0dd803f2c321143c9dda7f5a2a6ed87c76aac918a000000004266985f02f11bdffa559a233f5600c95c04bd70340e75673cadaf3ef6ac72b448194a4dffff001d035c84d8 -01000000769d6d6e4672a620669baa56dd39d066523e461762ad3610fb2055b400000000c50652340352ad79b799b870e3fa2c80804d0fc54063b413e0e2d6dc66ca3f9a55194a4dffff001d022510a4 -01000000e846583e9bd64108b3b89ad3883bec7731ddf1688a4cc8f79530fed800000000d2954cb816c87a9572bf822138dc84b5f6847fb502cce3d6073f9ffe40588571a1194a4dffff001d045d675b -010000001d72012c553d72f1f75863310ac0450e53a9e9026b9bf9556ca024ee000000001b7142acd57304290a2ade0e2c96d4fbd3ec924a02a5a0cd30c04f0e96265423ef194a4dffff001d041600b6 -01000000d2c5dfbfa04c7b67457c58f55a8d190dc5f8ec5ab94af969dfb748ba0000000069492041bb66f32c9bd69b74e7ba9bff6d4122e931eacf9c89b45eca2c35eb25211a4a4dffff001d03bca431 -01000000880be932720bbf22f1b14da0e6d16c2773f83699935d390e8621533f000000000f5d2500bce42137fe905225ed9a7380eceb7445c89011bfcc740cf2e9985a034e1a4a4dffff001d03d30924 -0100000000b0b174d61c08a92313345717ca7776a75cb67b77662c04ea7d3e2b00000000c8ac0a2fb1c01e0e0a5339d296eb072b2b9f9cb1d410a1fdd69a2c797094dda56c1a4a4dffff001d05225e37 -0100000089535760639df16a512f9caed73be0edf8c9b5466fcea14336f4a1bc000000001527b6224d45722c8ee351976c69c8fca59c11d3daef7abf1d189aab0e959f7ba71b4a4dffff001d0551b67c -01000000a61d5d887f8fd4c86f7111c2c5a4d0d593665b527cdf84dac7a0d57d0000000069b7df87a13603be78ccb048370aa1d2da0969f3b1822791d24aa921f8e268ffc51b4a4dffff001d055313f2 -010000007f678f2bbdae181d396123431faacd0b956633c30a55a9595ae6657f0000000085daad94e57797b9340c299e483531dfcd0f3c6996da98ffb2ab31bbe34e346a001c4a4dffff001d03ef37a0 -0100000054112b758ce49f1fd22d613250599ffe92c48202b6a477b9289f3d7900000000006302548e973a0d5764711fe84e1900dccedad0de9f054fbaaed3735b70ed62391c4a4dffff001d057c8c98 -01000000bb142886ff32916975d060c649c9119aca0b47e3f169acd3b7f1b9dd00000000ff166532d3f30299c5a82856e3411957dbe35fe7e17c4f58b92b2ef12c399dd7d41c4a4dffff001d04a2a121 -0100000029a936f51d08ad1f1353890300131fb7c04e20606eb48197dc863eb200000000c7bffe64778d6b4815226c6aab915985d8937fb0d3aaaa983bb513c69305caade61c4a4dffff001d0514cd03 -010000007d16758418920cd6d81283aa30108f20f37dc7114076e23025bb881800000000bda8c051f6e99590cbea0919b7a4189e4d3620ff3f46caa4b797fd52e204ff1fcc1d4a4dffff001d047ea807 -0100000087a6243ae1dc858cf91caf8a1f92dc473bdb14203c573b9d9bc134cb000000004caa084ebef276e6c454dff401271b39e55da21a8cd5a3afdf2d0e0f94b94a2dda1d4a4dffff001d039d9a6d -010000002d0a1a0b18f1f74ee797beef1bd4766a050a3480b5d7457303b5c54e00000000955ec547d5ff2bcbb3c9f108828e431a674576e1de0b8da794bfa3a70b794281ef1d4a4dffff001d0019c619 -0100000060500ea2003736b74596d4a507f5cf001daa55e7c93b53c77d32a32e00000000c545bbc6ae68433be1fbbf0ebf59f22751af853d0a6fd6c944458aa73ec7a014f71d4a4dffff001d03d8b5ea -01000000cc3d1b428029cae46634a9b96857475b2bc59619b8408e615f65b7b9000000003563548d04e24c89e7706a3f4ad681bebb3017133e87f7434d824db4e51f479b891e4a4dffff001d038a2031 -0100000073da9ccb3fdbdb4a9e3723a4bd5270c70ef3e78f448fad7e77a8eda0000000001f0a3749af61eeb59aff1499892c6641d1a464a26c156608d02cb74c264786ccfe1e4a4dffff001d0284512b -01000000ef5a98df2a193c1f8a5c271dc4d45de465b7122dfeefe96fedad105100000000cf330295467623ec1378dc6fa312103ad8a210b3e1351f2f4b6a57ac43fcd472071f4a4dffff001d050ac986 -0100000048256cc5b9ec6e7a12c378c93c1dd2ada859c9a9997adca75166c935000000008e3430573cfde2f3e1eece8aefe661dd841bcb665d35832415bab4f7526785229a1f4a4dffff001d02ae4b52 -01000000eb5d7c4b706d8891ddae3ba5bb57fcf509689fbc196f3ef73837f27b00000000226e90ccf96f41e04f011e69a86e18e96c09df6fbba19416132247f1d2a6e4073b204a4dffff001d0488c17c -01000000e5214de98aa5cdf1766c5129649895816f49ec82e93c4bbda787897f000000000abd68f73823585582e65529a8739e90bd943fc4e214ac00a20ca0369b70d45d7d204a4dffff001d041786ab -01000000fd4fc04cdc29aaa117b16b2420aadb9bb92fd19ef2a7aec3c40f71250000000078e5266df52051011f39eb29939c8782564563c20b3856f7aaafa6dc52921359e8204a4dffff001d0205fe6e -010000007252c67173d343874ecfab4d5f57ab5936f2d87f173047c99c20e73500000000d2b61f338da6ac531884c623db2804c0d7eeb84263b501524cbab6d5edfdf56f00214a4dffff001d0027a318 -010000005a7746eb6d1d19cdb24466e0a87a23b6ba8c2e461ba8928edb84253b00000000f1b03cf0680b9ef33fd311f6bbc6db3f1c164f9341f48a02df1905cec4ce241b2e214a4dffff001d03246ebd -01000000e93f1fd6ddca6d8fdc3ef50fe0f31769200f8fde592a0d5d6f8e1d290000000078966e9f0a2d4452ab2418249fa6fb1a325a04f039d015899141a82aa5a6c05c92224a4dffff001d01d8361e -01000000dd5f3ae3d2c2876ffbfe0956b914fe72750b160b667b5bef5aaee61400000000434d2b0f298874c3f6d8467c07dea6883a650de00d48298cd6fb48e8322e1058b4234a4dffff001d0161f3ff -01000000f814899e7f50c4494806f75523c9d8ea6c0198d13f1f14431fb541ff000000005b1015187325285e42c022e0c8388c0bd00a7efb0b28cd0828a5e9575bc040011d244a4dffff001d0579aa5d -010000000f72c6372c87d91f2df95b0c9e91cafab596f29270cb01cc67186040000000001fe6898ac074a680fe7458ff87a03956db73a880d2ace6539efcc43002bd97ed87244a4dffff001d0434b3b7 -010000007cb39114d2372ca1d5dbcc3a1137cf9314a666349dd79b268be1f15100000000b17cb4572964d7c6d671e7cc67b04b9fb1b68b31e52e6b4f956f3a0b72ccc4ccc5244a4dffff001d057875e3 -01000000f8d8634fa1aab0666f63fbebfd61e0ffc1dcc647e218414c528e17dd0000000073a2c54d536c19f0d09156efbad18ca6f96b1e9f3bc8490342958f24ed8fc32d28254a4dffff001d0130c923 -01000000943aae5118b0abf4ff55e050b234c21d223871e815e9fae6fdaf693c000000006fd85c0213cfe9863573596a4d5f1509ac41a91b572e6c1bdafe46d9249a5fa4e9254a4dffff001d05878bcb -010000006c6040618ce7a449cc26ad0578a7c897b4464ee32260014fc5ce6bf20000000096567fa4ac682f9bec7e646452d3bd69088000b19bf7a90eaccc197b632fa79bf3254a4dffff001d02a22cd0 -01000000c067deb4fa218c0f26a247766a969af8a475e5c88c004c300c1c69b100000000ec5a827a707edd70451f070665bf6a9e6f4dd8f815b0265296790f24024142b181264a4dffff001d00e76cbc -010000005cba08b87cefedceed1e60297564a3eb9e9e2bf942bf63f74fdd7f3300000000e3082dfad468d5c0c8e2f8857a999f898081c8cf59e48857997152445a57218095264a4dffff001d05a30a7d -010000001dcc225203fab8d972215ad2311203570fe49707799e6871908e37d900000000cea1cec6febbeb980af51f052dc20065b95b2d65520205616a95284480a4219abf264a4dffff001d01b05d9b -01000000644fa81c1f8c64f08712b41b616a24d3e8af833a4f370c188068133a0000000069f2096bbede7015fee2fb307f7d7dd084641b7f4af5c3074dc7b2b6df03277c80274a4dffff001d01dcf233 -01000000ba750a8cc870173cd7f17dff4c23c228282d9aebc2bbd5ebd9449c7b00000000b28b51c3a1a322c8e29c2b6808ded7981dc085cd7fb529184eff6ce556e09ccefc274a4dffff001d02c039a8 -01000000e0f40d912882e77044fee84e325fdfffbb3aa0fb1fe6ba864d5be65d000000006141e05ebe4e62fc76d0c9f1e61a4d17e6509209309f6fdbaab476fa227f1f4fc9284a4dffff001d0306d223 -0100000003e8e5f89f6d5ee55c6e8ee0d4c1e88d8e4a3a5f05f0c9ec32d580e5000000004e2b02e05fea22c5067327060d3c00482569021252423d372cad30746408d0fcea284a4dffff001d0410f81a -01000000f389178af7b0ea88a83ae251392f7eb336771c8d7ae666d1219f2455000000005f98a8017e8458e6081be384b89f4ed68a6aaee5ac41cc0ad2331929e657deb27b294a4dffff001d04c90ab8 -01000000d8cec9c7b6dd3093ad29b64c234258bce36693f87a4167d6234342cb00000000d5cfb9095ceb210b374686dfc11fb8d8c7932c30b4a3916c7fa4fa7b760a0831122a4a4dffff001d01708f58 -01000000d850850454d9b392ab01e886bacb717a5615f8f70b6a4ef9bf788df50000000075f11e157a482aa640ea8dc7e038ffcbff0e9aa758ff092222fabc325b9c1a56152a4a4dffff001d021f806d -010000003cf1b7fbfa5978d5ce1cae5a5f454d41f840cebb72ad3d600f551901000000004503bb32aa7568d6abb1df7a05b80be6ffad47e5a55886488736b5c344a41d431f2a4a4dffff001d048df744 -010000002d7f6a8f2dec6f914a7a63052facc546567fbb02742dddb150427ab10000000031ea5d7ad7f128ec4daa2855b7944503da503818a75f049dd6980e636aaf59af242a4a4dffff001d017a6543 -010000008976cdb2c5a16c0929b45f29784ad52cf3db3035f112e562ed42447700000000bee2958fb6624ca2382e4a6a1bd7aedc2c58edcb7266a106c76d4504fd39eb89682a4a4dffff001d04d4a620 -01000000d6d7f91896014f1f4419628791a5bc39263704165d3e14e23895f57b000000001ae0ce43e200fa010ca331ee891ce9ee93d468c602703a23ca2eeb693c1e05e1862a4a4dffff001d025a8bf1 -010000002be250378c6001da52d435aaa1240522ccb14a94880ff0e0d1eee82a0000000046297804a9aabf1d08096b034a84364055573c45d09be862c33ae30beb3b5ab5ae2a4a4dffff001d01a34339 -01000000064ac21081e5a5c6509f634ffae17551bd322e46d3396ac49b8d68b300000000d15854d1e5ba349daf72089f470b24557a2be25105b7831a3f18a62fb8bab677342c4a4dffff001d050c273a -01000000ad1cbb656f4799fd8e9de9acb70a47d589ef5311dadade94c494ff60000000007546bbac9ae1c8980da6e8c154b368eb4df305b6f3f27ff38f195a13c9ee0484922c4a4dffff001d059b5c46 -010000009f0d835251ab6812b04939a5889a36d50f4d7486ef98a7f61e45f062000000008dab4ee487e33f872140c04372bbdb6c573b7e9e4ec31cb5d8dff36da17bd8f20d2d4a4dffff001d016572b5 -01000000d1105edb3d0105e862f3bc95a034c0d0815a79505b4b68fdcce9083e0000000061573706774bc7a579a7968281e10612b4551195e16c8051381cdd3a6f93f479292d4a4dffff001d039dfead -01000000d1e7c872bf92ed9d9007926fbe72d976079ae35efd6f81ba4101a98600000000b4bbecee818dd986e5ab82f36dbd5ccc29ab134614e304c0a397e14082fe7bb73e2d4a4dffff001d00b8c45f -010000009287b073f80a1a91caa1f664b8c9c578837f878e6ff04108db28d9c8000000007dc81aba2560e72756db13b1e427c9fb4bdec85486c65da8aca5bf968a5bf51e412d4a4dffff001d03a98277 -01000000a3f00f008ca15686450bda91266f8d01a99f345c7846e9e5bfcc2628000000005ac244c2a763cbc311a245df0d6f98a29e187165048a9da449d29edddf6b1923d42d4a4dffff001d02df0172 -0100000012ced3b143532ef3999faae421b6bd79c8ad62a4dc8db862cb05bbf70000000060e6e42fad3fdc3d353a22f1699b5ead453eb11343a0e603ffd8c77cdc773be2892e4a4dffff001d04945d60 -01000000f0c39624b690456af00d742f323762471854e1db5c96099adad5e53d00000000a2367f2d2214ef900583269eb812ed05d4a8aba11d40081eef999ef16af1d5ebd72e4a4dffff001d02d98796 -01000000294a2e12b2716816a62d761c624248fcc10ae22cc1a80290432c85cb00000000fc4f1ed498c5f31fe90b10389f12566a3350a5080db1dba1f01f8834e5813ca9e42e4a4dffff001d054ad0b6 -01000000774ed03a366b9909cb163ca0178cc6b42847461c4a672a537fb7aee600000000225666176205fe41ad268ba6f5d15633a5381c18fbb6cd2f83700ef928c58fd7362f4a4dffff001d04928537 -0100000083900a5d5ac952d05976df43ee7e280faf6105038a4afa75c4d8a2a50000000091cd49f33c9f5b51fc61790d25539d2e896e87c8c195cf305b499bdf42e029a0d82f4a4dffff001d03994aeb -0100000010336b8cdbaaa1bd6ba9b1e41e85e17bec5b68bc8ff043e5731ed09200000000fc5eecfa90d46aeeda36bb1a2f2da61e4f9be81253033ae55625d00acb13ef35f92f4a4dffff001d049e0a22 -01000000ec5b52a76675e3b1de2e75ad45d6498684a0e81092c5ee36e7fbf60b00000000474d71b72f905a8084842ce4202c2ab9795f3abcf51aa7c458349d21eb6e310498304a4dffff001d015d80bc -010000007af7e899b49494f77c351fe434981ad8b6352ad62527ed9d6d23a8a700000000bcc43ee02af281701574077d6916c07d6bd15cb96c623f6f304de260f616bd57ec304a4dffff001d03a0956e -01000000f22be93799f6fd1527bfa224601261300d38571dddedd804c0c7b94e00000000ca1cb89732eb51c0ace08a564445a2ee762a2cc819209886cd0a09993951544ffb314a4dffff001d03b10c74 -0100000099146a7924d99cd7a2c1e17ce7206712a8349399b34ec98eb706d3b3000000002c4fb29a89bfe568586dd52c4db39c3daed014bce2d94f66d79dadb82bd8300024324a4dffff001d04edf452 -01000000e5139dd4cf7511d9eddccb69d2c7aa0917cbe49eb660fe9293667aa80000000068e91b23282bef6f06f22e479587d03f6e1a2e4891b5d644541f1e10275e52e142324a4dffff001d03ef54c9 -0100000052a5c0e3a6cc34383a58d939053af3261acf266ba6cfd3165435bb2f00000000a32d9b10b7b75323db98d486828a5ea4f9e7a2609b76e496f6d86e0ab13a31587c324a4dffff001d0031025a -010000002ed6742b063239cad1841ce6bcf676a59c66e65eb4a0ccf68ac4eceb00000000efbe4df65aa1137ba3efae5236178fe6646d6eb96a177d5394bba48066a87448a7324a4dffff001d053cfc69 -010000004d4a3f638bb32808c3667937b3a0847eb780a3b3fe70875027adac3e000000000ecc7b73d8cd5d377d74d836bb6e3473478554a923154286ddaf6985948fd9d3f9324a4dffff001d05bead3d -010000007b86d803ae4a477ebf754711cab10b1b7799dcd50fdd6f25cec45e1c0000000033c06971fe80386570f8daafda6e4ab7e72a18624e211481e7b96633c625a52b3a334a4dffff001d01146b3f -0100000034231ba96cab51515ffaa9831930a46d1a8df9bb83d343690edd9ca000000000848736034ba62c9f4f3410b11d2a5ec921592f40b2ad6b1d442ecb3188049e27f5334a4dffff001d00a7bc36 -010000009427d53219ae3be5d968cd3dbe9f52232b0b32f662bbf74b4c2cab8f00000000755e1e0417036010faf0520d2524c806dda1e3fce2ea99dd4e70a42efe44f64011344a4dffff001d02c03350 -01000000db9740f3109d4450584d3223ec605be1f62457d8af2c22671b93b260000000009e93a056a6515e7916fc049578708d188c2146d3c12638acac92e0b72e076edd72344a4dffff001d037e783f -01000000de444daddd51d48d32e2119e59629110ecb69dda27ba85d7e85d40e00000000069b02fd420c2e86a575941a89e46d174a4e0fbc1379dbd6f6d88f3ee58613e5087344a4dffff001d001d016a -01000000a173420cdd0ccf0695a0a341d4f8cd0dc7cd8fd3aa3d01b68066561400000000cf0fb8b5f6fe33f698450ec147ef896ad953e677b4033e50400ec15454d3067fde344a4dffff001d03475525 -01000000343f2b87a053dfebef86bf7108c93e449c6e289e71a75489fe6125130000000088d412c44abb44236383afd182862dde877813143d21d92a3cc373d4bd4017455c354a4dffff001d02b22dbe -010000004375b71a891e69ba37f9c0cc54373be6796f43ba90b16b12564414a400000000e3abf5981a1bd6457ec0cdcab76cc2a176dc0d7e16f6d3781aebc684f13cc4fd81354a4dffff001d00caa9dc -01000000f7b2f9d9a6f44012728b6e09c48750838780f1e1cac9cbaa09e011420000000014bdd0dbddd8e6c917324a49df6459de897031f514b77999c8476d287e47f23b84354a4dffff001d026719b9 -01000000a688cd51d1d4a0cf1b438ae4347bd2e0b07fef348ddeb6a4168f71e000000000e7da7a46f5efaf4fc835468b21620987dbdf8b5f66daa0ffefcca5b0cae2e533a8354a4dffff001d0017ef75 -0100000010f5b842b85241ab32f795ad605ee899389c64c77126503e8eba7f4d00000000df686a7f31c2c1de6a608553b26d6336434719fa45428eb3df59bbef75ce9e7ecf354a4dffff001d02e94089 -01000000ee47f9bf0d5d6d59bafc6ade45ae6da0702b2ae98b792f7a6b95d13f000000009c13741588ce9e729f1b29b82823a97da91a3c6bb89d03c9b33c6cda9d71f0aedc354a4dffff001d00ab6a3b -01000000a0396d99b1042613554a8fe19f38a485daa2eb5b65f5347f3375a838000000008985dce081d487c7eb8f8b871738869922dd73120c75242333c45895bb91e64638364a4dffff001d04d09fc0 -010000000787ce301e6110773cfffc92ae93a3e017ce136ac2fbe2004bfd06ad0000000069ed55457af8174da637b03acdfcaaaa36cf822ec6e72145526cbfc03a6a83f546364a4dffff001d02fc547b -01000000ae76485a78a7a225541cf8025578b9085d39b45d7c2f68669f05eb7c000000005ebf1334d253dd7a7ee381625bc200973e7af65a8a022de034d6955e37823c628b364a4dffff001d06e25145 -0100000057ccd09f8dfb8ff31d4ec9e743ce56ed5c5c501046d709f49c356f08000000003f818cdbb02b1a468aa23e9795f7518ca5a92276559fc40bca459a79e010bee2f7364a4dffff001d04a53656 -0100000042284cac669ab917936f5b96469048d55214c074eee3c7aec95a07f200000000334a4de0559a4db974ee451fe484a0376a44470a1495797992b9a6a0ec7b24cea5374a4dffff001d03a8bda4 -010000005d820c5c53908a13f372a860b57050b9c60ac3360a7bc865fec2029200000000d29036af962f1d725133c89721cc7dea6d3cffda3a529c82e39397027aad7efbce374a4dffff001d02146600 -010000003c3b2d4120567d650494757e86595b7e9c70223af627fa1857ae9cd000000000a4f56464ac27919b3cf8c9ae4390e679cbb2f878dd7098057431c0d92171fb29d7374a4dffff001d01dfdf26 -010000007e74fa0f82027865fdf1aa434e494c2a60e6a9e1b70d2f7c4fc21ae5000000008a360dec0defc12a33c3d959a7ed168aff8e34547db15b516e1b8cca754c0de543384a4dffff001d0568ea46 -010000004960b70d04579667192055ae5e019eae175dd65050e58be04d10b7f5000000002eb73ccd1a64ddd448405955586fe5c95bc54928eb34679f74bfb4c9da8e1b92aa384a4dffff001d00cfcabe -010000008954c37766bb7293e105c476cf2b320cf9932b9543b1398823757c0400000000f85f4ed98adf68f14127aea968a338f2109597b484a808dfc8638112ad0623428f394a4dffff001d036b2da4 -0100000052d3ed4b6951d3d5db9100bf46b7dbfb177917539341431898a0aa5700000000d226fea91b99c5a31a034d340f647b722e50950c96a876eb96569efaeaf3b227a13a4a4dffff001d0051797f -010000002d54616f93e70461538548ac861c860a8bb9077c3452be5b4c00d4c5000000003f88cda74f26fa4ceb0a97161e771a8b1f6caff1069f7b53ab49386916f3820b213b4a4dffff001d024510e3 -01000000e226b7f57fe7d32fc6166057172a4c2931bd4bc3b619a036df08c95a000000005b7df01117c335ca3e8a802376e171e537f090dbe2e3bd1fc291e45e219a8717323b4a4dffff001d05d6def5 -010000005412ebec87fb8c61287f1d2fa1c52617ded826adec22368b84c42bb5000000007992420cd0f0f24840c8d92a4a865e6c906e473c23f1cbe3c183de70c2b2bf42453b4a4dffff001d02a246ad -01000000ba24ca40c17418d7bab5a3cac3c0bf00b9d3a0c09ec5771d0b14015c00000000a30e3f1429bf2a8ed14ca6ec9f3396b8593b8bb6ac1e4d35bd435f05058094ea983b4a4dffff001d02c75930 -010000006e823e852756b7106a0ba02b1b51045d87582001c006a2e8807cd612000000003c11b146d43fd62ec36b733942a52ba0c352c95a3f078808a38d080898cb8330dd3b4a4dffff001d053f9e6a -010000003f03adc125b43a2c8cf9d47ac43dc81fddbcf12ffccc11ebb226520300000000b17c3beacfe667f4014c9da9057fdb6252978fa76dc4dc2d9ddef0562d293d39333c4a4dffff001d0467b375 -010000002bdffedf5912eb0e14baefa637c22cd523c8eb4147bb111db143ce9c00000000e24fd45c98a5b07ef9b236be48aaa1085b1bdf993a1c0db1dc04766895b8a2fb813c4a4dffff001d01c464fc -0100000011c1b397772463dcb8430f661d548b3c55c61d415918681d6c4d4180000000008c32f04b4b70f43c849a8f424c3a82352cc0bc6bb25b2c2ec4a039964ea563c4893c4a4dffff001d05292e68 -01000000a0e705a21be059d1f8780cdcea04e7008b7497cfe8faa0fb59a666600000000059f060dbd892c1499758c7ce9bf8779d8e4dc298484ceeeca6467c17769fad5ccf3c4a4dffff001d013a65ce -01000000492c5c9b8543822db5ad8694cce758fa2019bd5b6f12db4160bee95b00000000f640c60ea438dc020048599869836f5323ef47477ee17caddf076ed428898f71da3c4a4dffff001d0065ac66 -0100000095e3a7f3bdbcfd7a40901eefd95edb7d6d60562f6a427f7986d0861e0000000059ac3c37adfa89b9a907ef9d485c57262e9283e1eb96069c2de04369ef1b3c76e23c4a4dffff001d046e85da -010000000a3f0effcb7af394aacaaa6e2383ec478034ae4ec4d488e47153d21000000000e25e353605728130ebf943b1f468937fc489589975c13765fd677e5050b487df2f3d4a4dffff001d00fe3805 -01000000a1f0d96d647241f42d4a3e02ea933690a4cc33542ed89de511c914c600000000153aef1fb8837f74a82054a0d9df9c566ea9d50df292ff62288082f311dd4212333d4a4dffff001d03d34187 -01000000f78b3189170c0de482943849707aa16247e5d62772953eb54bcc4d9a000000002183968b34446981f960895ed3713dd60fede3a9eeba1d40389123c6c409d3ba6a3e4a4dffff001d03d38a89 -0100000059835cec3351179502bdf8f4b0a0542d3ad336e22549c2a78f1af97d00000000f7f8e1a8f0b4bc0337d67fa4a2fceac7e83adda354d6fa3ba18dcf7e6fa2f2b2c43e4a4dffff001d01558b25 -01000000c6a2e4d395a1899b4be7d915c8dc660efc1298a34b66263044f5a5bf00000000e64b9c2a409a4a1310fb4b4f59559f79b15dc85e686eefc07b0b0a6b7fb6ee5bf03e4a4dffff001d05113e7f -0100000067e62d9c29833a10aa99f00514ec678c06a234e05f5a1de4412988ce00000000e4a12fde56c03eea1acb5eb1b57d35ab1da6e55d544e8212c47ce277416b1b3e0e3f4a4dffff001d00652740 -01000000d468ac8c936b469fdbc0510d88d031ad3d22c3858abb8f89184f0b84000000000fa35a88c8fd0bf5897b921ac75fac304760f6d60ed2355cca82e689ebc0cd53513f4a4dffff001d0405baa5 -01000000d69dcd4cfb5a9ecda166293b3c0bd72e21a804b3a565c8ec4783f8e900000000b3ec99d78bf68d284104779999ff447ab7bc73a783e9fab814c6741e71849cf0d63f4a4dffff001d0355fe58 -01000000a4ee15d19e3a355d221af4e4d6b69a84510a60857ead0af7e3b086c1000000001c25b8c364fd6f8417d45b9501384908824493931b544baabf2299e25277305540404a4dffff001d052500d7 -01000000deea32ce4f7ba1bee123958ad36ad37df8d53372f518a88761d14ff600000000aaeef85b297622ecf311dc5d29669fd4e3863454c6feea361ece4f547ba52e6a96404a4dffff001d03a82644 -01000000b8751c32196c89a35575c5ea97c6395e6dde705aa771287c867b909200000000cad183a8636b222a8ab775d34658b1de92ed57818e26203ee43ffbd4d8bef95b28414a4dffff001d0587f431 -0100000035a68fc6ca182ccb6663ee8b7e44556b950a8351bf2c64cd75dc2d0400000000d59d2a49b1883c6f7ac68a9d2649dc0dde3f0205e19d8fdaf8065381f9ba61cccf414a4dffff001d0592553d -010000002e5b592b34f37b1ae9fe17aa093d2d9c815aaafc5ce3dfb8b91e33d200000000a2990b3a24b766c99702c1d157925089bcd0d377cb70cacd30be33a3c90bd067e0414a4dffff001d03c217d4 -01000000773bd09b330364f704d0b3fa46d8431c5572a100faf117958fc15a3f00000000e739176d62b588566afa47f5fbbc0ec01aa3f058c036ca0ee8f3cd13e4223e01ed414a4dffff001d056b45a8 -01000000e9aa44db469453b2c657b1e4f3e29aba0532b1ba7ce4a8bd8dd00c4a00000000fa5f2cec2dd5e7122182c8e4b2f10a1cff77ce7972ceb53308b827aed06751fbf1424a4dffff001d00523f0e -01000000337df8fe8603beee390360abeed7e956a280fda2dd5aa238e110de090000000071f85d3e358a18a3a3465a1bc93f17e7725549a9507d1b218dfe6d1dc349641e9d434a4dffff001d0042c372 -0100000048bb0f9a7dc5c4fc15e8a4c5ce0adefc49c10db0a582e0476c1498ea00000000640a330a8e9f920e7684276e987d7f5a682838ef8510fbfdc9de08474ed3e74ac5434a4dffff001d01a51ad1 -0100000098349ad38c19d6e481627c6523d9d4f52c031525b8660ed55c215679000000008c06f072a655daa64b9910b1894ca250077f930333c0281c843a1198a6a0924629444a4dffff001d02e40f45 -010000003ad363a33fab1606f7a32896d093b06b84a7d6e9784047cf8b9bc953000000003093ae1fa781fb09af9fe147aa05ed26e90f6e7312a448e934afcb4554d74c11b2444a4dffff001d0029912b -010000006b8abc2fe01dc3a118f4d18c4f0b36b640fc85987db55437099aad3600000000f2e0926ac96d0c8010e095b34c5089f549f2fc8fa626e20b2f0b68dd46a72c2c06454a4dffff001d00149193 -01000000665559872e38dd76cd839459a94b0f6efeaded839d785b2c43c0be1900000000c305ed4fdbd3a11585c8805863472f53be7fb65b7b4404a688c070e8197bf40edc454a4dffff001d01b3084a -010000008fc81523766707ea9cdc7926f5771527eb6a5e6810f86a836ec81d5900000000408efc695c947acb1c0239a9b011d77e55b702fe9c2f6082571ca3bd9ad46bccfb454a4dffff001d05bb7361 -01000000efcd6d1c267d0b764044e85d112b6a32cabb8698bd13b4e947c178ed00000000fc53d40de77f595e1419b205c2dbda50be0a5595c45e001f8dfeaa8d3f19d90f1e464a4dffff001d01fe7935 -01000000339acd071c0a09f678896b302b2c79833152e048f4536994737db5f5000000003c651e6ebe94d51b8d1d1542f3b43f0c26298e4e5c8fb3d275e4e13062800f6c9b464a4dffff001d05eb40cd -01000000ce3f890a2580af6e15d0305dbf50d1fdce03678b626ef2c6f7be3c7a0000000092b0e20be269413c7f519a5e7fc316074aa24e930b8a3edb8a618077567aa832ee464a4dffff001d03713885 -0100000006f4241b0703e90950c5ec74c3e033c39e7b0c7b9b877d5515a6ef9600000000eceece737cbc2bfaba21cd1cd8515d614c2a39ea26d9b41b7daa77a17dd5ea5121474a4dffff001d0326e2f6 -01000000e65e080e4f1df42a905b85fd5d0f0b2d70f3e987e0fbba97cb41111900000000812ce3ea678b31aafecb99db5b0ca6718f9fb3474e0baed35aa6aa7290f5a40972474a4dffff001d043e313c -01000000ef823ae34b33e5aaba6945f46e6c2bea1df86769d877ac0b8ddb0811000000001962162ca36701e79b5ee44367d46a8ad8421b1f80aad651a02022a7b9e1e0a3a2484a4dffff001d0259a126 -01000000c65b1537a27f39bbe1a2884f77807c958faa56f3819aa5e4d49472bf00000000ba78186dcdbed13712e6c29812a54fa620fca9ccf297b8219f7ca736e36e46b7df484a4dffff001d036752dc -01000000d48b9919f537d161b9ba4404e9ba71bda419efe7173ec3569243364a00000000501790f1566c93f0edd817937da1e287147de7bd62629b65b395935017fdc80758494a4dffff001d023a2b4b -0100000083aa1f8934efdf864a78a3594d5c16f7fc8303fa38c01cff7c0c94ec000000005f8a10b8f3b9a4f159bb071ed05f349849e16774cfd79990af242f0ff6a60ea5314a4a4dffff001d04ad807d -01000000f699462ec6c1179023d1504bd5b9510cad887286984b783c943a33610000000074895c719bedafb41d7e5833189d876220fc5cdca55c6ad4b94a971a8e96a259374a4a4dffff001d002f84a0 -0100000077393e4b34076f0a6b6aa9350c799c7b32756a200eb1a7619e1b036f000000004c6b88dde02bd09335ea8bfb6db1e0094a58bdcb59d5ab78303034ff972b8538484a4a4dffff001d013ccb67 -010000004828e19e639deeb00d55f748421f46dc94eebd75e376104740535adf0000000014da74d7e2da39b2b2d676b957e3edc3619f4999922f3fa66c95b64be8fd92a34b4a4a4dffff001d0260001e -0100000092f7a9432462b827705bf9b31224972d61cc9fa8d478939e015ce3540000000076cf4d344b2c5db45b55ea38207cc477342c74b993c401b753378509761729637c4a4a4dffff001d03396962 -01000000b87a944ec8bbd6a73f5a6054efcea696124dcfacb88876995bcff95d000000002dc8a455f4bd8723a5d58a675c5a5e833ee411490a443f6d47f08a6fbf7594a2024b4a4dffff001d03699294 -01000000bc2c1291105e0c6209906934c0f1fe57c4ad13dd74e43830b293c6ee00000000070ef89563a7d8b1c7232b9e391813476ce93c9160051ed55bd396c6747618ee364b4a4dffff001d03bbea80 -0100000062db800da374d1b83b1b460566da0a35d277bdec5a6ef743132b2499000000004af49eb22a467e87048f4625dc9021249c16561d372366a21e8c20cad2c65aaea44b4a4dffff001d0142e34c -01000000e09e577320f539aef8178a3ec09dc306b301acf52e135839fb3fc55300000000734d92340bc4c287b0ef2b88001bac1f41bf5c6d3c725e0fc39e7c593d6ebd4f9f4d4a4dffff001d00bd8009 -01000000389998eeb4bc9b68abc63e8ed99218d00b857dcc5591966d46af4eb500000000752857853f92f5ca863f3254bf18ec5e3c62e1223c3f7968894048d40413daf3e64d4a4dffff001d00cc8cd4 -010000005faf1cf2ae1e1231a1b5aab191614ffeeec0ca86d86e105233c681230000000026dc493ba668f17fde5156a19662ca1a5bfd93b2376edf51ef9e3d623e4ef4a0f64d4a4dffff001d0183b4ab -0100000005bf42fd63d8189e37f471cd3e8a411bf81b4ff8e65532897b755caf00000000e53a837e9e3c05a4b635531c91c39c3c45565dc75e413228dc93d0c764327f86154e4a4dffff001d036f8a98 -01000000dd081cffd3a2812f5c770b8e79aea5e63d67b972ebb5d9dfe8cea3a9000000000803c135f2c72cbd06b77cc2a2a13a3c063028bf4b188b4760bafa112e71e579f74e4a4dffff001d05fe4d4d -01000000a9496d62f029c4b765548666b71a84adeeb9dd5674148b708b7aa70e00000000ad1924dbb0711c96b12ad1376816374008b98ffc43677b0990bca7973432f814334f4a4dffff001d0190dbb1 -01000000ffcc01d81e891bb248fda71e6338614dbea2d46b8e5f71460e6ae2aa000000005510b8c188460a26868d9bb3fc9bca7fca4d9b20f573e182466398f793d5ea8e44504a4dffff001d004f08f5 -010000004300ed388b39e36268421a7b15d337598edb40c8c290166b4376f2490000000054d4f73e569ddc7e67130ea0a43a352064bf3ded26f80877536b0e7277237a7857504a4dffff001d0268c158 -01000000d7e1a7d5fb8d460e90f62666eb9891f9fab06cc2c220899498cb01ec000000006a6a5be5a31aa8a7ced02f8ece18f44261e96ee9176b772fe654f1764cf6a4fd89504a4dffff001d02c96f9d -0100000049599a3ddafecc620c9ad61cc4520a0c70fae3d34dec595669587d260000000018073767fa7a1ef0c4a570f373492a822b5fad5fe3092dde239bcd8081fd3e8c8d504a4dffff001d000e0681 -01000000eed0b252aae103849e6805f28147abd17f294fe55c5c2d966d8850a500000000e15a0907e27914f317962823d82981df6f2dbd256738860027c740ac3f842bcba6504a4dffff001d05ebd48f -0100000031b485a9bc2b16f2ae5108ec786708f3f14447551e7f0f0a8575c75a00000000f6dc88e1c894cf88e930d30adcab0380af8fe00c3ebce9969c0e43242ca422b372514a4dffff001d0103697c -01000000ed18faa5febd8be98c42fe2a1a5dc9e8ddb6a618d0a05d924c522b4500000000811cb2e938cc88f159a82f1e160d80f4c6b429ef51c63ac9f2724810ff7694880b524a4dffff001d0097c6fa -010000008738d8fc729ed970f5223d77d8e776d5e0569ef2385a33596dcbc77e000000000bff98f2293caadd5f7fa74a7c5b3e2399268c171e5adb490d8e1dde1d4926d7a0524a4dffff001d02132278 -010000007ff2786f280df6f5039bfcdc1d2d18eab08e4120a5f67c769b8b464a0000000077b5007a1d08cd2a6abe2cb56a279ee4167092775aabf4245a55723455f7297059534a4dffff001d03c30540 -0100000002ddd5983c40e70e36643ebbe8567a8c115dd7a21262b8c61d693acd00000000504305d5fc375c8303ca009ce2bb783798b303208c8744fce95d0656375b682ab0544a4dffff001d0483c2bf -01000000bc5ffef87baf263ab01ed870a064c46731fdb99beb941bb6ab73fb05000000001679c9d394f4c959d3fa9e054a4e89af624f9206a777368a00d1cb6b175ac5f7ce544a4dffff001d02c1d1b7 -01000000a0fa21e1683774f057767d4545610a63a4c0ffdb774a6577224116cb0000000025db6d92e12ad8376e7e37c12b541faf358404c4b5617b9b287a43c2db4a067b6f554a4dffff001d04cfae4f -010000003abf3b8f61bdfc588bb0440b0f61cc8894cee1291298996712b3e3c8000000009160b7843ed42d0b5ba734634abb2dbb231e68bc37a1d508b2f27ad88d040e3e5a564a4dffff001d00028074 -01000000f23f3229508a7b80a755b69ab0dabb405f5eb566419eb60e2cc1ce780000000015819a3494e7b49042529989b007e8f89a6f69f6d22acd6f0132c270923a192eb9564a4dffff001d05ecd17d -010000005fc1bed214932ceb26a0a81a4dcc6fe290e5b7fbcdbc490f89c310e900000000c6fe4434b767859a8b403df5f195e223e622058ea98abcb0517bec7c5a734fd4c4564a4dffff001d030425fe -01000000390b6d99e31e1f64e6c16a94e7fed310d80bcccf9c7f9e82fd8bb1120000000012d6f8906065837ccd176ea73171077e73a29257d7e0309377e710ebb5629009fe564a4dffff001d0391c3f4 -01000000005ca35550b9d7bb3026a8a9e5c512e0c4714f11e3066f99be7323100000000045ab4575f33ef6bfc4b1c9fce77ea21cb9b606acf2b9a0331b8f9f931169fbbc64584a4dffff001d03f6a4c3 -010000007f0ab1ef14e058aa9823bc23ecaefb694cabcc7de8ca93966dc1cdd300000000272ef40d0354ece93dda9c8370dbaf29c6a2894fecd84a063c5d3de0ba90a088de584a4dffff001d049fcb9e -01000000f6707f93948703990287c88f79c47c2171dbfa2890d69c742ca6dca5000000001f75bdfb31993e02ff9de178dd3f1d765fd7bfb4dc87280c40f21270d7384df6fc584a4dffff001d00b0d294 -01000000096d0d56aa45bfdc9561a804aebf045d86dbe4538ba8abfc483800a9000000007a22463cae54d2b07238b58272c2f47c7bbc3bfc92a15d836f014d34160dc3c10f594a4dffff001d03465905 -01000000edc840e0c2f736161507190b975b87e70ee7842a0449b1bc785975070000000073998e2bd1d6f08ceccde03077d9d86adda70cd56234563c8d37e275767765de74594a4dffff001d03c9895c -01000000fa8f5340eb43544d2562339f1854add2ca2336be9ef3f1659cd2b3c300000000048d698b6d1dbdaecb6b5fa3cdf3c0b06346e43c2aa592606736404a17c7080af85a4a4dffff001d02cc3a19 -01000000683e618822053eeeb0d0a85cb955b3eff25df82e41beb94adae2e81600000000ef84f5c1c80ce84101f205ed007bef67688a709a1638b20bdec8e2d5404820f6cd5b4a4dffff001d0004d110 -010000001a4ac80ae8fba6ec44d500b823515af90fc24eae8aed36d88f73b39100000000d20b7be0fb4d88ad841c2d111b49b33e7d3b786ab431f3b32e6a75d2cb8299bfcf5c4a4dffff001d02b5e1c6 -010000005d8227de291d61223a71e9c11f27298dfda9b82538dc67ecfbbae9b800000000f75f109d50bb4674cee3023c0780403b4998067852cdb56881e69c4412c445b2485d4a4dffff001d00bd7afd -01000000140bf311410ecb5324301a67d5303bf817dc0401cb674e1c9d2b05e600000000cfd1b67825492351322e5e64da5db259d9eb1fa2b309a9917c921685232c9435775d4a4dffff001d03dbbfd3 -01000000a51f6b0e1785a625b71505e4c9ffe60acbae34d5a8e463376b0dd37100000000124c2dfbc87a28fbf04646cef5ecc103f568b8d28ab19661327995a7389d7325c05d4a4dffff001d003facb6 -0100000017b0e14d03cd3cfd82a7e8d54fdf338b7679ffc731ee9eece8d10b3500000000c96f851c0cf08646a15dfc49640c994343795b9609e87350e83f7c69fed804eecb5d4a4dffff001d0180f4c6 -010000007efda66c68e131be2f78ac7331d1d50f0203205a1532e96bebf3c3a10000000075eebc78e8a107eeb04c122618d963c038a00c956a67fe0c4933351c92f68def235e4a4dffff001d03a98d25 -01000000528b90ace50435d962ef0e1457a28b1c140e887060f6b277b37211de00000000739c079a15781e97e60a15e05212ca04c97d6c7509737d5daacdcc61982672e8355e4a4dffff001d053ea865 -010000005533106eb5b75af3ca4e3fb1196fa4c0d4e22413617c385e4ae0984d00000000a6b546b2b262c57c6691555d6f2720383c481ad64f7525c0c266669014632fa2ab5e4a4dffff001d01af78b0 -01000000c6d164638ea706719ccf9a75c7b1cba7a4ab982815490ddc3b2567fb00000000ba99c12105363f09230c6331157d8cd67336745aa9e0ecc46494634e26f875439e604a4dffff001d012bdbc1 -01000000364f362c384a75bde3177d475a8c85340d4fd4ab0ed0b30f17c3317400000000df6d00f0aa27587fab36da531d0c21a27e8b9ba3e7be77a780dc8277fdadad078e614a4dffff001d04ab300f -010000006fe6f7e2e0d1df2b6d71c090c4fa296a2d7d175c9b7853851d0fb03500000000610e56ccf020380fa1918b77eae3eab93231c4bb8d741efdae7c5256d7f01604d9614a4dffff001d032e0df9 -010000009f469645bedab4134a07b9bf6108960de1a2ddac68d59eef58b493a400000000faff99059c41eaf7d7ebdd38efd9b0e5a3ceb2ecdbf2df4b266f4bab573363371a624a4dffff001d024ad9f7 -01000000d4767418fc518c1dad34cddcdbaf06e38a73f680556295a88bae600100000000be0a584aa45ca81a0ec8e4943b91a7e3cd4b33fa67da59db3a15979326eb5e0973634a4dffff001d05e4339e -010000000bcd63dc71092a95a3cfa24deb7a99c097b5f74ee21389f4cf2cec0600000000c590cf15019323e3eef49355d341374d4eb747c85118d2af7ccf749bd6322d81c6634a4dffff001d0453fbbc -01000000e244d491df952155b701e23db092c318752154d0c94b7f1918c139b800000000a7f1371e40c1c7479a0182184e7858b9fc654b553014683443fba375927f9d4f36654a4dffff001d03e0298c -0100000028836ee71421916bfbb216200b5943426946b65d28ead2f6f6b639f3000000000494ca74bd3ac3a44c3e8d2bad9337945f89e45eb63fee5b9860d46a7d4c9d893b654a4dffff001d00ef98f7 -0100000017116f1db86d264512d1e919a74da904290965abc0492169532572230000000060081ea832d5c3e9f675736cf23993c36e8eecdde049a44fcf955ea24e7e9366c0654a4dffff001d034412fb -01000000e79cb282d213491706610e7fc8b02ea62a98e437829b076db087e081000000006fd1b2d70cc93f628dc0f1ec50b4fa820007225cf827e3f94aa581c30f5ae51528684a4dffff001d02c8f506 -010000009539a568fa254f13b10401a64dbf10d2709111822efb587824955f8a00000000a4cc887854ee5ae17aee01ff839bc7cf869aaea30fef9c8782eecf239da4e83f30684a4dffff001d03f4d7dc -01000000b021d8608d5c1517ed201830c7ab24f957ae2d71794ff149c7d11af300000000e58177c0a9f4858d209aa9008b6fae86b6b436c84c906e5faae402e0b14093cb39684a4dffff001d01e43108 -01000000b9d79c9f24321d231a894313febb7c5c264796a1bf60815a0cbcc96a00000000951b66c72f193f3b8374fcf39baa8183795f647fa69a5b2e21ee6505ca3ffe2ba2684a4dffff001d016977c7 -0100000083cbbadd846fd2fca57ab49a7f4b5ad6b1b64889b046ecc00424fe15000000002e26a89403d2d4d2c0cd13b959f9b86c6b6baee4ad0d99e6d04ce21995039981ad684a4dffff001d05ba9aa4 -01000000e435195dc29f89337100e0c2e80944137d2ca37e8e00256fad8b3bf200000000a644a58880e151d73b166f2ee7264025292968dfc2ac6b19516b9fea051a001b3d694a4dffff001d00a59466 -01000000fc27d9c3e7632342b188f423df64d41d8b8ca4c75b7d8a47fadfb13400000000f092bd85e17e84ee69919ffaa3a1936fa24ced5b3d0d0ca073398a256c5293dd4c694a4dffff001d004914dc -010000001dc0cbac620aa5469e889e5709b5ffd3dde92cce25715e084d2265d000000000bb549c5ad4bbfcde450dd1998da568ba168ce940479f92d795235e95ffaff538c4694a4dffff001d01cf90a7 -01000000403be502a01dc5d45288d1f305acdc9e15cdad638ad918392738320300000000cb513c7878b4d2c2376dd1a8d91aafcbfce7fb3ebe6bf419ad69e7408d8e620cf2694a4dffff001d0000764d -01000000919b3148b047d8639e8b46bcc4845d91654c03c6249ea4c443e9b99d0000000061a3e0d8305112ea97d9a2c29b258bd047cf7169c70b4136ba66feffee680f03b56a4a4dffff001d03c843b3 -01000000f90755f869f150d7c4a7191ffb3f74cc1752d0e1c8fa6ea51ed182cc00000000cbdf8c487a3679669f416aa49e20d8665e75ad2895d1256589b996a7f57fdfc6f76a4a4dffff001d003cdf61 -0100000047b42b4f634f26c6344841cba855c2cd7ad377cb35a8774e5e7f58d000000000cf16ae92ffab695258610ee3db7e1681447afcfe60c28ab3ae30e3ecc06de718036c4a4dffff001d036703df -010000009c57f3083374e7552e56d053b0f07fe93a47f6a30430fd36eb40b5250000000017eec598976bfbc55ab4c5d48e00162f31b6aca31bc42ab7084f1f139049b2c60d6c4a4dffff001d03b92cbe -0100000087de9b5ae134e6f3c94361941a079bc41b84ccd02a3416e43369ebeb00000000a0fed8fa4afb32368c57427cc0d9b44869fe8faee44f71910e9408636b82f3b2166c4a4dffff001d02379365 -010000000d544d94180289b766a4cf81e3ce5299f938c7ca3f6956424558ea700000000016164d5a284a0b308928c567c1db87c566e87d1f4810489c8256edb290b21512776c4a4dffff001d003abad2 -01000000555e499668283fc21cbbf2d5d911334ef50c6a58264fe4a9f1c7406b0000000042bf33d98dc089614e3ce83d39736949489ae64bdd1fc477f451c2b6b523c8b88e6c4a4dffff001d0210c9fa -01000000fba43e3e3dda545e1f21d1743123d5b717b0ca9c3b6bab06ee978fc6000000007b3e06d1951308c10625b2c7eeb400f1d9de694922b34bc48bc31cc57945ed609f6c4a4dffff001d0256b7c5 -0100000046b8f387b47ed742c035e8619551c1ed480d111d4e8d8fb231265fb400000000ebe3b715280fa9cb3a6de1d7ed2b27c7f769fa8db53956a443bf9fb8051c96502c6d4a4dffff001d0587e243 -010000009987e9a48351803b25ab0eb6b84ef62d92e33a73b2133687e126c09d000000001460afd3c98403c75ab5858f765e6bdc9a91a9a7377d64f262b0c4d4764fea93936d4a4dffff001d04816e32 -01000000f38c31b10930176f539d4c5c54f22a4e65bdf568ca89ca65518207d300000000ca13d344cf8d51261573a71698c8fe10b7e5d9f7134ae4e60682ff793b1b0278cd6d4a4dffff001d028a436a -01000000f0cc611660dbbddda4cc05700f1ceaa209e1d9e166117e5a4c2748670000000014f341b19c7417fc5b4231ae70027556174a78af7e554174541c36e2e1af9265e96d4a4dffff001d00d47799 -010000003f732830a72d4d1043e43e627abb770e9586c38b530c03331655c0b400000000a28bc5d7b507b81bd9208b9e304460a400dab435a53afd843782a9f9e7ef0b076e6e4a4dffff001d006eba5c -010000001c219fb9bf6eab86c72b3d3bc789b446d5f214222d91c752c4cfdbdb00000000a62967c97b01f47d3a252fd612e772eba117edc1f6033fafae4fa66eabcefcc7096f4a4dffff001d019c3e0f -0100000006de9b309fdeb6361b60029f1c7d6de6c99ff2819609a8c236d9feb300000000cbac2ac965c6b2ea471a630cc99ffa835915fd914c107b2db2dae5050b2ea9f36b6f4a4dffff001d05df3994 -010000002b59084f6b07d1210181294223741d72117914a497e7a07d0c730d4000000000b3ff096b0e79008a55e1816779ba4811e3ff6f3a064b6cf84bb4b1dcc433890cbf6f4a4dffff001d04090899 -010000007001e49d2d872afdb4cc1836b2d91ea483fc7aca9abed6e2e78a8438000000007444e881fd0c51e363543a35b27effae3cff02aa828a8de3c37bdc2db2b090bcc46f4a4dffff001d016b52c7 -01000000d5c3785332c02c192281491fb6b1af615bee7e2a2fcbbc124ba72e8700000000787f53156727d75d5b5a8d88aa93400ca4d53b9d90ac33da81545750405cedd3dc6f4a4dffff001d034694bb -010000009309d876716d2ead60108db4f93782659182759f0b351cd92ba9644900000000fd05849b870af4a38ba121721850a8cd344ca95c3aef88c1ccf25288776264d0b6704a4dffff001d00d1727e -01000000e9206fbdca986700b3747c62ab8169e60181ffdd3f5ca43923ffe8b900000000e08afbe6f2f42beeb5891d78d6774548971dcc9b3b7d3407821e3df29fa1aa0fc1704a4dffff001d045d66ba -01000000bc31e83685c5e76b127e81f12e8867ab8342c02ca51f137a6abed1b3000000001e6e383300d86f0ab1c84d68a38e3a64f94eda07cb5d7b6b20072cd5a610cdaa42714a4dffff001d00cd948d -01000000048a5ab82d24f3dd8bcf472d9081d4aaf4f16a16113821e0ec9d244000000000c1f04bbd361fc5125d1721c032aa88337bfdd16267b16498a8f80f00e2d3ab23cd724a4dffff001d02989202 -01000000e891684a9cdf9608002bb1861338f42e0a42ab96d9656f9f40edd3280000000055248a96fb577bd5c2c929f6b0c5757284ebdd13d09200fd4c342604ea3e5ccb7e734a4dffff001d031094b0 -01000000904984b520e8c777654412655520279fad1f546529d4b255136e42430000000035c50c2c01355804c412bece60540459c86d4a93f336396a664e88acd642347600744a4dffff001d017ae930 -01000000a31367e28327fdcc4b9c28664e5aceff0c6439f86378f8d88a42017200000000c26f017904f09d6c5cdd1b33194d0505a594a6b37ce0a7635ba56ad35e63183f14744a4dffff001d023e46b9 -01000000e78b13a567fa3b7f4329ea4a3700acba52539ea92128bd929e05853000000000980fb406fb9cd2562abbcbd3d2a9698da8aeb255af37c1237a552dbdddabc17d39744a4dffff001d057ca591 -0100000085f94fc42a95c9958bc3e963daf2c1550d97ca945988180a9fa276d100000000931a84625efbff3f1fa30974dc3b58d89a3a6c8c71b673e6a9b84e659fd657d3dc744a4dffff001d05acf2dd -01000000877bc8f841c9fc5f943d51655b089a4d7f545cf233f7b3289d6b113600000000d9df6431534132d6fa686d7496a4825304f8aca55654260c56d4edeaa4ee7bbae2744a4dffff001d05c15bd3 -010000006730e2f111da5208e30dc182cc59c9318675812c24b596e3e5398a4d0000000092c49fe9e2c4008f430cb72949871a174abca604b3e4731d51dc02337cda177ea2754a4dffff001d059577de -01000000a924ed313100b3de054fcb9e9748a12692e0f66d375cc05e01f163760000000039cbb3487e69c00c58056f6cbb3d5a3c136effa76d0d9f0df9fa8963ac0a197bd0754a4dffff001d050295f7 -010000009d977cb94b7caab58fbe8bfb6339a7bc09dc50a8aed9dec7a624e25000000000a1275135d09b38392ea718c862397f389bd358fc242242072db18a35a211ca93fb754a4dffff001d025f7654 -01000000f03542a950904c6e1ff7e8ddcd6c53a9438000df6d3846300afe005a00000000ba9ebb9774f0bacb321c7960e0e13443d58270ddc5493313d96c7784c47f1ae4ff754a4dffff001d042989ea -0100000092f5763855630332ff4790e27b1a8a37975899d435190bb50f8448d800000000c0e15d72865802279f4f5cd13fc86749ce27aac9fd4ba5a8b57c973a82d04a017d764a4dffff001d03bc04b5 -01000000b2dd87c5ae6f6368f5c00991d7d900c14441b315e0fe3cce598cf0a8000000003e0462da7bb4bbbf44948d8cb4af46d7fb0017f598329f2139f52c76a433ff819a764a4dffff001d01486ffc -010000009369370b1d364678e42fbb797a4ee0121fbc3916e5cffbfc5a8e1a620000000031774efc0e33444c762baf022787fbede880fdf466dfd754e3e457f4afe839b32a774a4dffff001d043d36f6 -01000000514da16d5dd2a4f82d4e52941092e8508c4cb7339e4895eb255cd87d00000000b6b3d4911dd13b8bb3d06b75eefd834250ee263cec3e94d9b4c93f600e1de90f5f774a4dffff001d01e3c40d -01000000f3a31ef7b1009ab512e3f3f03860dec8a09c3e7ec246e75163708bd80000000035f2a99aa12f8fa65fa0ec244ebc42cb7161e80bfcbfb1bf3bd89c3585368fe504784a4dffff001d01275ec4 -010000003526d4c92a0e4a1ef78043d2832b94108ae0d3dd21f7738e2033f3c700000000a5ce8a4c43d3b59b6fdc38416eff39c2d1068817022c79a4426b071b85a30cfdb9784a4dffff001d0052c6fc -01000000875794831d6f2c236759cca424704c18b8d89ef9f39347aa4b4fe46800000000dd4ed8001a3ef95027770fea474b5e63fefb27ec2f6b8648865f15e69308ff8734794a4dffff001d004298dc -01000000fb0922edf49601327afef737beb3d683f98b19d128f1ae64725b5abb00000000bf3d088f283f962487807e618960923be192a236beef35f4392d7ecfeb6832ed38794a4dffff001d049e4ba7 -01000000046dac6511ee9b24b34cc63cd704497d6383d1794cc058b28badd5d300000000e885af2ab2be11c610d75db7eb1bd6eaea463efae811fec483ffa41aa7e83f8b687b4a4dffff001d04f872ed -01000000a658975dbe7c08a66b40f3a2e2f0ef98a255d60a79ba975b89a06204000000001e7d0335d1b38ddfa9aa6303ef27c0c6929af97154ab2062f3934a8a29b78a58137c4a4dffff001d04ecec44 -010000008c36b480e7358039d56678918d633d9e92a8f3bca09cfff8286e3fa60000000013ac254600fca551cfb3665dc3beaf8114aec034861d36308d5e6b213f7c01c5a57c4a4dffff001d0061a279 -01000000169009ccd47ab6783ed3657ecb5c962b3b3d3d0edad231df0c9f193700000000623d61fe4724621efeddafcda266ef8edb29c8f2ae051f4c6cf6eb2edd214e5ca87c4a4dffff001d045f755f -010000000b89ccf6b22dc7ff1668cd3de5d6a812f1e5ef46b512cc9e352f3f3b000000007c644560629caa21e1a3fb2bc113deb42f78541283833c4a3abbe6a6fb6d877dd17c4a4dffff001d0588650d -010000003f9e8ff2fbb3e04c36c9683dd534a2d4fee5607825e10a2b4885e8e90000000034dbb7fb145e4c0ef8b98d4a03758ad3e9fde5016b147095494046dade14e834df7c4a4dffff001d0320c105 -010000004ee7497463e160c70196b1412a2ccbd2cc41062a773c4a3202b7b047000000007cd53c97e3e7d4f9f8e172a6168aee8539dcf2f4aa98caefe37be637000aaff9fc7c4a4dffff001d04b19e89 -01000000999ad8365c277b20b05558240e3c383ebea0d478faa53122dfa506b50000000088b03731e11466e46268a2473feb0bfb996a77f1d39d1ad9a23d27aa158ef8719b7d4a4dffff001d041a251c -01000000864569f3105e048d65a9151047f0ca03a5c3311c39dfd84c35bc279b00000000b0c3d72e0b5e89d3cdd7b5d44396e6a4ef92f4a2e7e198a6ee583768d86c839fd47d4a4dffff001d0348f715 -01000000783b15ae83eabb19aac502a6fbae8c6b4b2d8dff30a1c3cb2af0b318000000005e2072b31fecdf48b38a60a1613a73f8c370cb4a857c74844ae17ae30adc9677ca7e4a4dffff001d05a98d10 -010000009b974d3c625f7fcd4e18d7b8e5d53ec6db57b0987f7ceef46e9175c20000000005c8b8ec09654909eb66cb5d6f22c7ba56afafbd3e6486fe8885c7f0ef53b77bd27e4a4dffff001d03cabe9d -01000000d04963c151d6298a97a6ad4c762ccbacec3dabe179b3c39ab96eafed0000000004aa8cff9a7ef9a2029c8f3d45561888c3c50d9d7e9610de7c7976f159bd0d55ff7e4a4dffff001d02e2bf3e -0100000032b6290c64c98539ce9570e69dec2e354bce3909fb62badb2c6dbbdc0000000027cb02841e5e22c93f1e2b61c1cb40553e97205e0956a3b01777c137d3264cdb107f4a4dffff001d03e0d16d -01000000b96ea7181758239d2d12e3c43cb81c47110526fe397595956ec24e1800000000e89deade7ce10d96cd17b1371d1bd50a16e04c997331c3a49baa0ba0cf84e6c5de7f4a4dffff001d02ea02c6 -01000000c80ecafc4bca833c5f2b956f4acd585becd120bc9712517eca873bd5000000003c4a3ed10ee0ff614113e34850ec14018c7286ba1868f4eb541ba0c68a0db05def7f4a4dffff001d05c8b8b2 -01000000c451a1fcaa893e25e72b921e74bbbe82e4489aaeff82806bae8e2ff3000000004d8c8758514bb308bd043ba7c6ab04555831f523ef439b44b6c2d26755a110b86e804a4dffff001d01868381 -01000000b8d4747b5c3a2d6c8e50e389fc938ef7b8c04eb4104c17a2e2694f6000000000aed381b06d2dfe28d0ce14b4f43f5c167dcfbc80d44e37054a014a828a2c8c7236814a4dffff001d05517119 -01000000d0a1893dfc1470c05078598f83a28af1e44df83621ef6a34319f1f79000000008c68d3c55f59e4264a26c2cd1a6a3ed4d45c98eefd14bbfb9a26cf55ba30611d2b824a4dffff001d038d2dc8 -01000000d892825bf696f9c10eead1e3e97dfd043618e0123b72dd058988f92a000000007b921b39ee758310c934e9fc074942513e85716327fa08526e089895530fe6bbca824a4dffff001d0276d82a -0100000062f08100a53cfee15d6960d2915fecda72ac40a116600d176bd6eb5a000000007d4eefd21df4c8472009c501a9c023613b9b67c27231f130cfa72d97978ae996d2824a4dffff001d04f2f222 -01000000c5b9489065fa7e1ac4facc51a5a0ccc2111911609f43386ebe7ca1d200000000a0db3bbb22a2a8441d84dbe335c24959ea3d3d6e91bf67e66bbcb0d7e0a9c4836a834a4dffff001d04181366 -010000007c967c39b155d44a57d37c46bcb47506c0b00a7987d9debe642c4c1a000000009969fab4c50985190c20867d5eb2622f8994a72c05fb9c91ab057be79a80526d94834a4dffff001d0391a66f -0100000015276dffb7a0360993a5a83751944fc88a2d3f13f8e9363e5f3cdce300000000cdaef86e7120eb9f7e0e9c1b3009b4581d1133e5e2371f0da2a0b7d314465f8dd8834a4dffff001d04184062 -01000000d9e737d6b012027382d48297bfa52d08eac8ff7aac62810a3bc6798900000000be2b0f66f65fd65f4d4e387b96041ee0aeadeb736b467f8b64e12663a7f8b92971844a4dffff001d016cbc40 -010000002059d85f0b361f764b21d2254602420fbd84fff571daed5304862a42000000000c0bdb3ed18e03a8b3b92ee43926dfcab9a2bc048c98afa86c1f24e1f7f1ab7e23894a4dffff001d03dc41a4 -01000000c34c5ce16980a5ee4c66a17ca4d8619600a15f7e0dff5edec12209ae00000000e7be4fb74031df2ddaab02750360d6b806cfb54cfb9519ee517c20fd9c636b2332894a4dffff001d05c8f18a -0100000071f7cdf7526fe514f6a17de62bfd240d2eb1fd5f8e406da3833394490000000025156dd8c9381fef3564ec230644a84f35524ee664c3643ccec644088b95d86f7c8a4a4dffff001d054f7dff -010000005b09986f4fe70f0f864a258266fc73e908e170c29b3cfcac9ca9fbe800000000e0f8760379c70b7d7904b5a50c59bc16afc4529114d9b9ac1de43e698debefdba18b4a4dffff001d04457234 -0100000067391d93a161d82b8f968b7041a48507ace6bb30d4dfcc789e0b6f7b00000000a035032fecaa07e192fa2c97f683fc201a50f90c7ce4abcc33ee37aa528503e60b8c4a4dffff001d02bc415c -01000000ddb642656ce71cdf2052b12984eb8c297eed7803ebf000dc63a262ce00000000b9bb4103d0d93289e9f9448ed7e63a8ac751ceaa41d1cc9627d2bca7d7c28a16598c4a4dffff001d02242de7 -010000005705c3df459247a82aaa9c3d836ee2661cfe00c826faa3f2a8462222000000002204f4022b778f21a952719904fcddbefad0afb48be8305e89ddaac4ec8b133c8f8c4a4dffff001d01ef8ecc -01000000560f99e148e5e82dc838535b9cbb5a6116eae26b586531fc2e2a8315000000007760f7a3f07d88e8c7361e1223ea4a9e4fc5f9d8c421037578ac06d921f11095528f4a4dffff001d0392d460 -01000000cb6dafa616960c0d1b87c67ce99dd7238f3891d280444d7a15099f710000000090adecefcdd85452dce9b830a3ceb9240da10806a62404f8b7048c2d85ea0f7d818f4a4dffff001d0331ed48 -010000008f7e1c2ed57b82e56977639379c6cc7eaccdfde5f181fa381b0495610000000023130ef1dba152270b2153aefbb5d4e29c22be3e79b2041ca20620c1b381e099ce8f4a4dffff001d05e4da4e -0100000005b132a4f74a8799a57a4202d0eeb09612cc08d295401f007c4530dd0000000073340035d03933e01bff3c47f14a5b0a8ceae33be12a8dd521315628ebf42eb3f98f4a4dffff001d003a7958 -010000004e6790a025117e8aa81fd453c7c6c236da838f3dacb169abe51897d500000000091aa6ac0aa796201482553ebe24961fdb79bcb2c1b0902f2ecd2c9e7c705d830e934a4dffff001d001badf1 -01000000ef72b16c3d1e58804b715c8ca9d02f2158524171a8a4742d0a07974900000000ecb21277a56d483af3a7ea1615a8a6d0566bf87ef230146ed4a8cc8fbae417b2fc934a4dffff001d0370ca3b -010000004fca0bc6408f652b0d9f79713e880890605c993fe954bb73808f2cba00000000a70a8a17b106c669acb346ac08ca99344b307121658cb8cab8d00eba9adf7c9138944a4dffff001d0328fe63 -01000000077ee2849664864a66985199aa49b030f66c79f8022116c979e234b30000000087be9e1e4f0bda5f90e3c1db350737e4f390064d8aec43d6e00ea92a27c2957ee4944a4dffff001d03af3fb8 -010000008b0d4a2ecef90647f9d1a923020adf2bc138626877f0f855fde5000a00000000ecaa67add6b1f10ff91e5df491b59ab1594c357b39ba9f1f06022b078844375e99944a4dffff001d0037c556 -010000000bafbf706c6cdcd91f5fd082255862927a4d3a0457f7d7fcc6ff3e7600000000087028b6299590346eafb168c13132979b89b4912750975d9bac131a7d4c68c3e2964a4dffff001d0525ab4d -0100000025d15b892b9a091f18e865d579f536c655f18a4994e960b06227a643000000005a2a640ca55a1660daf5363b670daa00560628bc3c39a6dc88d7d59cf2dcb669d0974a4dffff001d0226a908 -010000006843e8fc9750cbf5174a0a778ae5a6a63186683d1296a8514359770d00000000c5eb73e7834883d87b8c0ceef4ba9b850fe503039eee9b28bad767afdf0d0416d7984a4dffff001d05d4fe47 -01000000e3756d4e486befea24a302f095aa87c984f583a66687fae68d92ed1c00000000549848fd7d128b20aae864145aa351ba58eee3feffd7a8089c7adf4445b8de874b994a4dffff001d0496907a -01000000cb8461389ac8693f9f277f037cec93d37eb8b6a6558cbe10bdacd1c3000000008aa6ad7fa12e8ce311c1c659166e587c880e3a6fcdae871eed1bb350d713f25113994a4dffff001d04744479 -010000005573c2792f3790bb99c05da5d71c9a24bce92ffeec84093243a1aeae000000005945dda5801905c0a507e521331b06a9263279c4761dfcdaef431c0a76698688b4994a4dffff001d0546400c -01000000afbc89759982446b305b9f48cdb547f3c95760014fe738ec3e32dc8e00000000fea6f2fb7688cb32351b15857d3f250e581af5b20d9379070b5542a00c42ca70699a4a4dffff001d00ac7c0f -01000000e17f97a9d791f0724271f652f057075f27d96aeb365838d8ab17191500000000a91c00538ff6917dce0bf745e5a040479862ef7134de60320297eb029f7bc07f469a4a4dffff001d03b1cae3 -0100000050e436836fe519456bd7faabec5d522aa80bca6a53af3f9d57457c4f00000000c66962dac9d02aab13c8501636c123f672ab771c8e088e1b24275b105d222c7e569a4a4dffff001d02c1415f -01000000dd654b9a8a51371c852e448ca417a3fb05413a70672783ecb1346f640000000044fae19fa72a7abcbf78d966a5097415b961a316322184bce818191677a3f129fc9a4a4dffff001d01c6aeea -010000004386a29fd8c55a0c47b8e97c6d04e1267549de89abb6db75a577d6ee00000000fa993f2f31763c2969af7e8c181a32cb663e07bd210ec14e29fff768621d4b58459a4a4dffff001d03c6039f -01000000c5cb299e1b345b77d730c527034828c846f23bd3630ff74355c2d9ed0000000056ad317661356b368d8589f343000fb68353f92172d8c7f68a9c9792cc94ca5c779a4a4dffff001d0485feb1 -0100000028fd73f5c4415839b41e887ecd606661462ad914da28c2140afdedd100000000af9d78520fff7f6212f88c7c98521e2c9a8d2a23740ed2068e1b2a55e0c7aba71d9b4a4dffff001d03a07cff -010000000cb32bab66fb7c93a66f841608c74f61dc36d662cb01f30a8f01efd400000000f8bef1ce0194b9aee865355e8e5b0881092bb9fe8e3842c4f7110f7306caec26629b4a4dffff001d004d55fa -01000000c2a8b9e3677de7a6f7286c8a458cd5f09409c254209d9d8c445e0d24000000006bf3416c661bd39443f16a48fb560e97558e2cdab18da1e598086cd40a2ac6ca379b4a4dffff001d02c8a75b -01000000653dea66e42fd4d1019adec51e1f7493b06f458f960a6b08501d8534000000009ec37ca4395220c81233283dfbe020c1982b43c3cec6b82ff425173ef558a51a5c9b4a4dffff001d05681cfd -01000000443c685dd9cd61dbb1d4c1964e8eef7a1e6c6688b38775c2707b2f2e00000000cfb0c5cc863b3809bb9c642a497ab8eb5a2b0e6cb448fb1a12b08c3d0f3b1e13989c4a4dffff001d04a008e2 -0100000059ded6607bd4ccfeb4348c41b04a13343602879158b8d9aa1f3acc6b00000000af43000d9c2194875f48dbe377b839bfa2157758b941b5020e58b55e2ed04fb5de9b4a4dffff001d05540f10 -01000000d04014b56c58d45f823589d9d36bb755c50ee96359ff44449d71cfc4000000009d6e5c4cadaa256c698491f2c3086ceafc5f73eda5e54d4ebd50ac8ed90eefe0c79c4a4dffff001d015a6219 -0100000098fbe05200b867e000286338ee405f70ce4362f54769db2bc9d919db0000000078b787d3d8da61dce5a9fe4d4a9232e804021e439906e6fd52cf8f041f948b3d919d4a4dffff001d05774a61 -01000000c5f311edc79caeab3404ee358871e5f886712e56005f4c67141dadd7000000005545fe6585b08eceabf29cb4ff68ba07020fb36520301d4d5e7f30dd1489aa6e849d4a4dffff001d0505dfe1 -01000000f24700786a174a784f2d99ad24d4c0165e2f64acdf0893cd4839590a0000000022c09454ffd3a434342bed475ee4e9f7a34b99d26b65f2ab92bcf7418e77f732e69d4a4dffff001d04872d33 -010000009849d7f7915299b00804b04d89a946033b4bac82b431a04781ee1c6a000000006801e653da56cf733fbab3ebb4d3f248ae5066f00b0b879a178ce3522c7e1572cb9e4a4dffff001d01e83192 -010000002cc41fc32ae1712dbf174b8d810498ea52c9908a96100cbca447858e00000000a9eefb8c49a77795e353cef1a18ddf9f75556b599049cc5c326bbedbccc3cc5aac9e4a4dffff001d0559b918 -0100000029bd58b2759e2398dafa0ed714764e7ea87a61e9966b4777837ad0520000000073173503f0ea326597487757ead4a2afaded9c36545e6f94578d3dc6e5d58fbdef9f4a4dffff001d01bb0d51 -010000008d7f3d0a93bb78055f440276924456111c24af5ed639ca3b3a2226d600000000fce8d0f71b20ad1d4797818e77da4739eabd906dafb8baa38bed17cc3f8d723906a04a4dffff001d04416634 -01000000e26e977c4cabd28830a8e1f87983e91ecbac81030dbbd7cea6efd4c40000000029045a4c17ed6ba6bfc40396d8b9d2640a705fd487c3c0271eafa3c503d0f54b9ba04a4dffff001d02477ab9 -01000000f3249f94c4a61be9fe426f496ddc9670874206c5034c68fb03a77edb000000008f1c9da6092af60d73b296ebbc796caf1b8a095f7ed33078bae45cbd2925029961a14a4dffff001d0253c63b -010000006f6cd48debac250a7b42738755888a7571eb9935bae9e94d7cc28b1100000000d42144297dd9954a62226db7fa2de24cba50b4c963ae6226ae5fa652946dd0a7e5a24a4dffff001d003cb819 -010000009ff0cf741383d94f79a6efeff2a317aaf6375ac3d252db55362280e00000000029e2f50ac5d203e020e7b59855380dda3e918c80627117c6249f987b28ac807bd6a24a4dffff001d030ba92c -01000000f61d5499f92cf040f17a16d02b348dcb3dd041b224625bc99acd35a400000000400de7fdd4b27e6d8d358cbe3b329417d75352a9aaff9af70c1f685cf842560675a34a4dffff001d0271c0e5 -010000000d1e2a2e2670286100f862dbae397fef5d8dede11bbcb013c453e8ec0000000043db438150141c0240a7f3f03cca32f4fd0ebbd6bae6daf898a6c7aac99b8a85c9a34a4dffff001d010d4882 -01000000abcc3483c5e1adeec60646454065ae3a116dc60aea65be6d0e66bc7c000000006c0e3cda9dd0367de3a4e1d356c0ad23cd88f26cdff41b412b0ca1de1d9c738cbda34a4dffff001d00b44c37 -01000000e0d79f654270f553820b56d0332b5ec18a4cb5d969c5d67c8adf9b2a00000000f2cf8413e5df690ebfdc8441586639e39ee7d8571d88e07853117ed693bc0b8d35a44a4dffff001d017fc225 -01000000ee4c6ec5ebb31e14991634916e68379e6f08617bd3e2b0816c0605fc00000000203f6062b808d073f0471cc4bad3fe9cc51cb9c732ab53e46a4127fbf0b960fbbfa34a4dffff001d03592dc6 -010000008000bccda2bdbf0a6293178dd1cdce1a368824e9c99587798b7fc1c600000000d29fc4754ff52a23715d3147c6a0ae31ddf06fa70465f4d09d41b4aa08da707bc8a34a4dffff001d05e36843 -01000000386cd6cb2551941a87716c2c618e1e56e9fe7acb49b0a71f414047eb000000007bd7a97b969168050de5f20cd3d0ea212b138f4b43e3c27755f46aa08f98f1ce06a44a4dffff001d019dfd3f -0100000053402e2e9f85db9774e0193414436cfbbc70b658c4e54913c67bcad300000000fbcf82e5b9b5c1aff879c25c172d4db531905915b205187bc3ae1425603e7c764da54a4dffff001d0154db1a -01000000ded3e38a879dcbfde2c9ff5690db8377d0c596e20b8be94dafe611df000000009d8b84155b519e0c1cd97837329fc3505f76944245c1bd686617779dc700c15850a54a4dffff001d00ea1441 -0100000011a98d2176e7952434447a06a9ce9f726651737d3a3e006373183b2400000000a50e90ca36c2cab93fd8acec6eae0755d7d2e710688a26fc16557bb5c038d12c0ca54a4dffff001d044b4279 -010000008cffb590fc8e390cc07b0fc7d7e1f83033a7f09c20ef114f6efd73fc0000000098f65f5151c0fdce2398474d0987d7a531aab1c2659675c07658b07cd954f80b29a64a4dffff001d03e15e65 -010000000a7213bcde17cdc86191ebe8580e3a9e893e3b9a189e2787394c5cac00000000230d4c63ebf11994b50ef9c5f1b75b2b8ce6950f63fad01665fec3ed5ff2bcd243a64a4dffff001d02706123 -010000002c29a0a93ef692c20f7a5d0a917a69be60ec5bd73788f9ae92a2e7f90000000048634496267a248713364570b8c4cc6ad5b1a3f32fb74cc1f11fd22c3b293e88b5a64a4dffff001d010845af -01000000fd50cc2daafbf969480d2675a4cdc41f397d1d815a2aeaf863236bbc0000000086d723685d916a3b3aec61efe9b88a845d96fb903e78760e0759aa2089de4e2e66a74a4dffff001d0389da36 -01000000e897be2520f0c6faad2d0c4be209e0d4cb2edfacb7579a6aa939a10a00000000ae3f02363ed042360b679fece5726b2499e74f27f1bc596c3beaf701463be4465aa84a4dffff001d04ea7f5c -01000000a4f61773f2105205cff43c8ccb188a0ebe56f0811834cc0772a5a1e8000000003b776a5a9f039715342ed278feea0e87f1454ffdd086ec1e3663cc738965e9d536a94a4dffff001d04479ccf -01000000cd182da4f3e6641784b8035ac96d74b182939696dda02368f01889b7000000002fa23a7882a373528b5403d34eeb13a26fbf25d668e7019e7a0403ccb5ded71387a84a4dffff001d033151e9 -01000000913cb00e5db68a01cd2c2c469773d0946e3e1589cd72c56349d0405c00000000e04420559afddb03dcf51c67a8317370080e517e24ea38dbbb5bd529680c1d2c3aa94a4dffff001d01ae2ae9 -01000000f87f4f7f7f99202d77747619865391ed07d87afb9c7c9a48b7f319ab00000000b4e21e67bcdbd54bee76d62b5cfdb6b5cdfc5fd1c6ffe9fd6b1e2f39677aeacd2ea94a4dffff001d03275902 -01000000c7a1220a895e2a83917ab688040dea8a000bbd5f4858e8bda00f3bd100000000fcddd0541ddd056f19fcfac0e637cc8fab7503352757707daf37da8e859434f397a94a4dffff001d02d171f6 -01000000c5711e518c4a53e9a6d684759ecd07d69b5d859e1edffcf4bcd3896800000000e4ce2882f8c5b8e467a080c647ca97b8c11070b7ad10a1eaeef13e1b49d0028cdaaa4a4dffff001d03ac5ea8 -010000000a1bf9a1db633b5c817be9ecef65ea99ed980a58d070cfab68b70d5200000000c9fca844eac0515369a587359fce6a2cec83ebe565dbf46b92928ca831a1abd54ab24a4dffff001d0370f65f -0100000081f9fcc96f7824b23225d5526b65d3d5826bfa8b65c083028e7b287700000000163cdfb6b5d8589c539ef411a96eb96ee49dcf03ef4538d8f752762893db209515b34a4dffff001d0215c77e -01000000a563fe8e23fd9acdbd8ce0db616cb72c1b05fc8610c4e89fcd32b21f0000000074fccc385cc517580daf8966fcbae398b81ce1f077bdc5732c529d6c3502e16183b34a4dffff001d033652b3 -01000000de5ca94254b771527679b5dc4862a7eee044409cc33ab2960cbe3920000000005f20491b7a3093fe2b342e816a5b8d409916c2f11a6cb6743dc528e8c7ac51b7ccb44a4dffff001d00d437a6 -01000000f8d57b05a64cb39a5adff645ba434bb707aa118322851cbce137df2800000000d760a34f6e7b07b3718a8355b71b014f07fadb917707e4bb635cc1277cb8ca7f5ab54a4dffff001d00d8ddeb -01000000a54d55adebdea113e46d6911a15712f7545709577a5ef6684a37974800000000849ecac186963e52f8b855e51f70e9cfc90cd0f7054c23f1bcbc1675206a00bb4db54a4dffff001d01cec36c -01000000f2f0b39c9e0f8ae81ceaf09ad25ee9166e8f3d33addaca1ca1366c5100000000060e3cb266839d6c8155ebef78939c33b659156bb2cbca1cc95b50e58ad5100b2eb74a4dffff001d02e282eb -010000004a016d8b02a6e3c33705715c29754230218f04485693994b29d78a2c000000007286500c919f491aa5a0721558e4b8a64230ec2d1d955c45ac871da0e74c898d3eb74a4dffff001d036714f3 -010000002d24b64aca8efd3a0a948e813c5303891d1971e6295be97c1923e05c00000000eca7286e07ea252409b51cb2124e3fcd6adb8e6fdcf87046de18666e36037511e6b74a4dffff001d037e372e -01000000dc8280b9a38ed7829f3ae49bf8f01642c0b16b90642b2e911c2cb69000000000a10c2661ab1b02ab9f3c5bf928db087c27c06ee7537b04ee66ea4785fb625c6205b84a4dffff001d053fb75f -01000000280fd86185912d306966b6b7bd90a765e659bad17564825f0c997f2d000000006637b339af8cdf579a250267ce7ce41f19de798c7ee6ff7823312076e0950962c7b84a4dffff001d00c1fc82 -01000000993b4428fc00d1eef46e5fb166b32f32ea75e3e49105a04322845d2800000000fbdd76c6562c86af0e63ea9a6c46a91b8d92c4e7df480977ec0d53b7f3c25b9812b94a4dffff001d0099e992 -01000000c3b9d6eb714b91e367d7a44145f498cdde7f579b68c66bc1b9af7886000000005b0df3f16d5bb399b09989beaf8e0665c695ef49b7aa8473ba8690f0b029ce0094b94a4dffff001d036efa36 -01000000a702519acf76d7519ce42d6c0bfff12644be3694621a942a55e4b36900000000f9357358ee5931b907a8c3df01115891a740ce6f4df224eda4586eaf450d8b9f3bb94a4dffff001d02d9d39c -01000000931d5230c5a2b7d43d322cebf9026ca68fe1a70afe0d8c8abed78d320000000005634a2446d5fb785d1f1582e6f35418bc6fbfb6abb9507213b010e58dac1c3ce0b94a4dffff001d02e9d793 -010000009c7bf22857a46add066ce2267450ddd5a6f280943e961b1db4d3be0a000000005eef5906ff42a8baf4a8a2d8119f88112d802484361ea778d22e44300f6ab20c55bb4a4dffff001d0179f4e9 -01000000e2a926d9239573962e534a47311e7875482832ecc6306bfaf1137c0500000000fe6ae11390e7bca224e9937759c658c9aadc8971e8ba384caf2a58de311826e7abbb4a4dffff001d01d2102e -01000000dd3fb5ca9283091e24a2dec99871d9c033f39b1009f5ac592ae2cf190000000086a971609dbe58f45f99ae1a769c07ed6b0575ffe811844b8f6e04edac722bdae9bc4a4dffff001d037251ae -01000000a7f31bcf8d5a86bda0ddaadc3c8b77ec71af748584b3a5eda6b88c4600000000adc6c0ba4cebd8e2b0154e9f876f1e6ea54e293e6505a5200a4a75d394521a7882bd4a4dffff001d02defce7 -010000003846b6ba73428b23c1aea96cb3a4cf8b72ea4f40268ed68fd16ad9bc0000000050a4b5b4d3fb6c72d198506c83d6e2792262134ac07813baf355921ffee7c6579abd4a4dffff001d04687d8c -01000000df7e6b1a5947867dda62ed7a79f75d939d4190f3a575b447c31308f9000000002523ea33f4e43dc2dbdb14116d5d087aa3544a7f886a69693caa154ae0abcfdf05be4a4dffff001d030a6d3c -01000000799f7e9b6d0ef1bcc5d4e6b82936272e3492df8a920b934dc9e1973000000000d0038b40a4b3c20cb7a6b431d6c2edcd235c59dfaca4698dc0f4a057d89eded6ebbd4a4dffff001d01e9924b -010000005dc85295d33956fc24736fe54dfaa12ca98cae2ba02ef7eb9655a12a00000000b7bae6ad3a263adfc01e5e76acfa7dbdc0e60962230af6fc59003d59b437b28d90be4a4dffff001d032ce3c6 -01000000a3b52bc4a8ade1fb7764462099a412272fa13b3d9de508c356a3d7910000000001eef5a3b0e24e946235bdbdaf78601185042a5974a6f9aa7d8deab62b6bc49c18bf4a4dffff001d05a9f6dc -010000000e816fbf3db7c990098f50722e36029dda668e9aa386c23a201e9d8e0000000027d9b4ef4291c5332a05c4a2918b5526b96a117c0bb2bc97cd18f5a6eea15caca7bf4a4dffff001d023f105f -01000000514062fccf6e88a8ad9d0ff0fa2ca4d2716c2b5fcc577f52e4557fab00000000ca12c4c5fa9b8106d21f12f4bb24e1954ee95686b849c643e0504328653198fe1cc04a4dffff001d022e817e -01000000b8631eb7fbe8abdc32f81b54c6f86c96cdb5d7c270cbc8e8026890e80000000032510d84003ef4d4b634cb4bc914de16f8e9b72b6f1ea20dd9eb847f11351641f7bf4a4dffff001d011d83b5 -01000000bf3ce738c0692a474dadc784640fe4e2f06beef2fffed0bfee65cff100000000a463353790f4669516f33c405164df2ee08f7738bc91ded3ca2a025e18143ac967c04a4dffff001d01fcc651 -01000000fd4bb907a2089b41433dde0fcfa70db3ac3a6f075be657f0e15144d1000000004bc439544765cbaef9a184ce7fb26bd62cf1ab32267eed5fb3bc7050a8f0c427b4c04a4dffff001d05d07be8 -01000000d0d3565bbad3a5fd165a7fbd978fb2ff2974dac1fb4ef21ee0c6282200000000e4e9ef647dfd719c086990944594c3892d0deffc18fc90e092d61a3e586e4cf8c6c14a4dffff001d0188a8b7 -01000000d2d5324fd546db69e8c42e6f6c5f2f686cf29a9fae985224d450ca7b00000000b3c4d587370073598ce1a226be2f70e0ccbe446e80f88f0446dc5b179782186b78c34a4dffff001d027bf975 -0100000074b16276f3e902ba74a5a938a86ad7249db7c620b06023385b515109000000001b94a65422bddf5384bb8da9d866fc7a7e5c5abfbd5867efdc8eada3b78b8e3babc34a4dffff001d02d402ae -0100000057f6b87254267089a1d84eeb06f20c3b181177372b88cb9152f356dd00000000c70258c4f96177b1cdd9d6fd5ad0e9a65abb44e7fc3dbe507f45e2984ab830d9c9c34a4dffff001d03cfee0e -0100000078eea9a9282653e1e213c716004ee3c5b7d323c37bdec7a64565831200000000ac37dfa5948ecb63e944a61eb0e83cbf7dff61cd61cf66d21f447d9a97bcbec123c44a4dffff001d05c7a466 -010000006c0d72985fd57581d55754a3dc631a89e6e4e1edbad1696ec271d6c200000000c1d26e829e285126d03a1943bc46d72c7e68f7fe1855393079dcc6406328ebc53ac44a4dffff001d01ec1ff0 -0100000060f628c70ffabdde8c265ff6aa1b49e0f42d250a0645ac0fa2963ffc0000000074f7d49e03dd5ccae2109db1e4ff11507238642d86fc771aaa999ae48b06f3d26fc44a4dffff001d044b6b47 -01000000f2c8d522c94e93a8ff5d947c057e4125a4deb167e5eabed5dfb56736000000005127f86da79df2980cedb16ab9a4b167e6daeadcda0d645f83deb48a3dcc065eb8c44a4dffff001d0561c0ee -01000000e6c388d72c717914e507f11c58a139137fd483dbd746e9c5f2a1eb0f00000000afa8dd6f0e319d4ddedfa1425f6c03e461dfa005d42d3f355a04cae42626c9b121c64a4dffff001d059f05b2 -010000001b354bd6d10f5a24879851bb2aff42548cb66cebda04e7103bc2521900000000622c689b318941bef087640fddab2c5ef6dd6024f133ac28c1ccfaf30e380bfa4dc64a4dffff001d00484506 -010000003e226e00e126f0a4a35b1c6c09509e0d999122428262a5303e563c6000000000d7432b21fd48689d7e79f9b6f7f624aefe8b72503fca13b814d355618b9023cf23c74a4dffff001d0247f874 -01000000fbb3060018eb1f40d734cc64744134d96536c4a331e00d4c05e2cf9b0000000061b34d561ddfd18ea3381d48a8bbe4627727c6ead00a84030e7f76eeb788148a71c74a4dffff001d012e783d -01000000fff008ec46c2d35cf469eded16dfadc77ca6e9a9680cea0b0611661b000000001d1e1087d20d41da1f0b4a5423aeb281ecd48cfc434feb45a4c6c31b6b61398124c84a4dffff001d05928767 -0100000093ebaafdaac804feef3ec352e40cc78be60e7ef1edb167891ccd99cc000000006bf225e961b1f1b8e042c45966c2118f20871551e0996eaf51bb628cd9d49b7a45c84a4dffff001d00381daf -01000000e85fb976eb4817418c0ed2987dba1674c0fd757f70b470f83d01a2d300000000fd6717e5d49bf303d41d861fc50503aa8575eb52243f426de308869a8cd57c57f5c74a4dffff001d033a590f -010000009cf5f976b9ae634b4c867bf78cb602bee8150ea1838d0ef3d06ce94700000000fe6ce75c462d7d09aa8d917fa90a49bd6a4c41f02457ff40ca47ded089021042b0c84a4dffff001d03a5f6aa -010000002eff16b6669f88de6f40810c57349804014f734c692a44ee822b7f1200000000c095ce4ab7e0e02110b75a33012da97d75e26b83de5ae0bd392fc3b8191b77e8e8c84a4dffff001d032c2bf6 -0100000001aa2c494f2d4b7ecf367734c734b931d3592b1572dcff557186ece700000000a10e60b120c06cd1be1d2153abb7901e2d9f1a3f43de9e6642ad269be1cae22e44c94a4dffff001d01f2005b -010000003d04e058642d22428704ad4337f372bb8574cae072c2a4b469b2e1dd00000000bff07e723c3859fe85bb849d860b21a325b1baf1494a3c1e73435dd7992bf8e53dc94a4dffff001d00262757 -01000000272ecd270665dc39e924838516da62f8588270f1e37812aabdb1d48c000000001725d4769aaca3cf86c5b0dd199bf93f2d16dbb13fbd4029633bdd1085283fdd13c94a4dffff001d02f79a8a -01000000705f1bbf68b4976a9ade4ff01ae933030cfe4cd43e8092c9604442a2000000000cb7f30461a3563992f7b02095263fdceb13984123a28ea68d0989601655e84ab8c94a4dffff001d0017e0d9 -0100000082d6e6bf4ed6c5b989705920effd072fe6b7119ea5b8c8fa6d0bf5c70000000071959f90386cdc263655d36033817a6f69cbc2d99fc56cc81f893b9787907a4fcfc94a4dffff001d000f9093 -01000000374e3a88a3a3eef84b4212e90e863754ac2a6999747c22667c0b29e0000000003a0e3693a8455ac94beb574efd98297948c5b5f69eaf0b813e6d5e57426e39e279ca4a4dffff001d042b079c -0100000003f06b3017023d1cbddd4cf169c4e74879754683f0d7670f1d1197f70000000098b12eacd55084fe2807a33dc2c89e6fc25f382aba3c6b4c7ee2f74a6999a6bbfbca4a4dffff001d03ba1eb8 -010000009c0730eadadb66fa486e40dbddd14b635ec7939f788fdfd999e043f2000000006b0a86109aea3d5e4b7dc320da600dff19d81dce7b77dab9596204c20c6125b06eca4a4dffff001d01c88a1c -01000000410f77945e68dba04d76fc931b26ccb571159c9bad438df5f8fc4d190000000004d902fedee34fce75de583a54e1fe7ef26a7946b48b93b9b0834dbf19a0b47f3dcb4a4dffff001d016618bc -0100000025ec91d09a451f18667262004e0cebb2ad66262407ed0a8f4ddbff580000000092f8e1be93272aae6b36766d721df3d80444582edec0143174c5fafad4cef50c79cd4a4dffff001d031ee0cf -01000000d8d0cea1249f726362ee78259d97d98efa17ab0efeb1b9d0a0cf0d880000000035c3dc39e544b855457fb0711697a24123fc3ba6c439123714b193b9d1d9ec7514cd4a4dffff001d0526c906 -010000003e824b7a8cb7bea1dddcaee7bbc4720e8c5d2f53c9c28dbaea4662a90000000061ef7a1ca4f6f61cc594d040490d3cb2f11054639a0a964c67cebc6dbc079e36cacc4a4dffff001d03af40bf -01000000da9201093da940fb6badc420406540a979cd5c06fc2f47db3215130b0000000069577de9d33e6351fb0ac1be26158f94c217d2522c35e9f813e47bf9811fad72dacd4a4dffff001d02f70faa -010000003dca51f6b97f7c05a44f329c1c9f4d7cf03eeb3b16d94bd56e34b50600000000092122ea597797ea0de7841945f09c221578800d0c44de4961cad7ecfb93c47323ce4a4dffff001d03bd9635 -01000000a560b2ead8a3f50df84385c1d5a51654c22a321268e077dfcb9ef90c0000000091db9cfec3e6c44a790d6295a2effcb8dc94f9f1c0fc4f6d867e90e140c1e9f325cf4a4dffff001d03a86875 -0100000056e6a9a6b93f9ad3ad847ee845ee9c366dc9376489516c31d892ed5e00000000bf2f3b6867855fe1058092fec7c5ea89c15cf8a70d0c565c26362d10129221af47cf4a4dffff001d027a9b69 -01000000d123e40889dc9dd8039943b5b1a0de53026e9ce92cfc69d5f8482fbc0000000022b49f0319707490d002d5b2c04adfc7a6433c2931ed04545e9c33f37a12b5bb924bbe4fffff001d00b7fffa -0100000065aa216d118366b22580747fb4d876d80ae3be145e318563984e0b040000000000c2b33efaf934623c6bea64570558d6551524e2f45d022b0fe935387279e6a37b51be4fffff001d0511e593 -01000000eced0b25fadf8818fabbf65b9c16f39874336d7faca51b74698ad55500000000ee49643ded3202eb46b451c55a652c6cf38d82da93de97a2f2bc0e8a28c1be7ba951be4fffff001d01f82bc0 -01000000bc9c266783225bfa273dbba2342f54809dcc2b263e1e6bf3269bda300000000001aa244355f8827bdc7eaaa0defe1a928816cf7d919890781c1fe3ee58d985684d53be4fffff001d01a443c5 -010000001b7467dcebcf2baa4814161dd6c7ab966ba082d670a69eaacc1785910000000050098a241f8df957a6bbea8ecc39473091636a4e55d673ae723edb6a3f50b9835853be4fffff001d013788f6 -01000000f5023ad6b3432b6b2d5afe707cfbfa0a30e94000799c8430a97da151000000007a53e7dbfb43a28ee9d5956be8da4190e5be6f16da4a5636f6139742754ec0cedc54be4fffff001d04474930 -010000002077ea8e53ba9a132d83b91e40fb1f4c724217b8197c4533a5bee9e90000000096a376627bd7b42278fb33609713b83665f195d100316b9e1651638cd4d7d47cfd84bf4fffff001d027c40c5 -010000001936a4ef861f194c15f171e843866f33ec3b3cf09394bc323753beb8000000002e3288941ec156d0fdc90d314d85a71a418d272704e12f2a99576fe3201e2d1b3887bf4fffff001d027aefaf -010000006e5c2e805629d476b92e0a8d74c3ee0dea0c24e9f35ab4afc6ac77b400000000d26cbed9a7c1e51fe657c6b3cdf202926e0b6e371ebf41ccdcbc0909470d56256e88bf4fffff001d05a2db35 -01000000e5f26b5abf56353520e1f9baa35e9cdeb57f257f59ff6a4ee42c3795000000007becb215d446a70b351fdb14659d105b3c258802fa4314b536c4e5249adaab2a9c88bf4fffff001d04e36b51 -010000003cf3550994f31a27c040b1340c7ae9ccd36d554a1bfa797cf46504c00000000005f56011e8d4bf55bca3dd8c9799e0d83304e43ae8b66ee58c688bb9d7f7fefeb088bf4fffff001d0314c7c0 -01000000ad48a4d4922e3834375f8c50e8cb1842688829c8952204f66b89a7e9000000004579dc3ff13abb920007843862e9091b0e142564cd0a75f5fc3272982b816d4ee988bf4fffff001d00becf18 -0100000098eff668afac04d3d8531d9bc31aafcd48f7ba68b080b40641dfddc200000000a91184d97bec523016c15dfc3473e7407278b70638f4fd6c9dc1ba210454f7fb1189bf4fffff001d042a1349 -01000000ed2b2b04575642de5fc665cb8e30f3e39dea66299592405204bf6b5d00000000f3af0d684b2c16f307b6ddf9a02b58b9079e858dd2d093aa29288856b83b82183789bf4fffff001d002cfc38 -01000000a398a8e978de6f1e7b9b84523d45e5f2021feb29f6d39890a2f48afd00000000f4a78ab4703ca95ed478e78e526f1a8198c3cbfb8a9ee6455338d517aa18173f3e89bf4fffff001d008b40b4 -0100000036bef7eedabe3b05e1e049efcf66823190285d64d11ccfd2eccb5e3200000000243f2ed308bd48cd3dd25d4cc649dea0d0518d6e12612e03c8a0888aa284bf2d6189bf4fffff001d0498f47c -010000008d84b4fadc45563b60c0f50797ffaf71046f287482ab9fe629f64e4e000000003ae5c2515afb4117d032de958e0ba535e484575b80ff6d6e2e0a23e6dc95e0ea7889bf4fffff001d0518a2da -0100000020ddc91a15f8c9ec5161bf1709ad7f37c33ecce9809b353dfd3df2a400000000f2b6d372af2c7164d36dc1c369090f4f9179b0870676ab6ec2641b0922b1fd179289bf4fffff001d04bbff73 -010000009701e67638ec4e8b47c547ac3125ac6c1892a98d77a580ab88f069d5000000007c740055656afd61883f9c1c102fec710315e6e4d58904accd184cba85c9f958cd8bbf4fffff001d03f8f01b -01000000fa9f56e3e4fe1352905b3a1f12567caa3f9f4251f0bda94fb07f1684000000009ff7fbae47f6afb47a1723662d196155b5f4bc1c62e882a93f54ba2d9a10913b508cbf4fffff001d02d1c97b -0100000002ae1c66166259ef43d290c6a60cf8eb5783e6c91293a3566946673a00000000846d597237ea76576bc49381badb59bd509cfda3095c2c1ce5c75788b96aa144718cbf4fffff001d0139c1f5 -010000001ed0a06499985c4cfb05371eec681819d8e193b66011f57b66792565000000008980b714aeb09568fd34128f4c7ff84d3e09223dcb2b290c5948816cc636d69fa58cbf4fffff001d0122c5f4 -010000008c045f9e0e200a8eea9c0957b12e045e927dc768a8a5fc2d8fd8d9ad000000009925a3f617c025b95f6329247379b7ef7bd081e52838676671c7360eec07255a098dbf4fffff001d0099c40f -01000000a6adbd81b12cff9948911af583db14484c4c0d30e91b1af2e7fd4d4f00000000a70e4b2057854c71170f8468b799f03d0344905213872216f4210f7bfcf76980198dbf4fffff001d002b7c3a -0100000059e1e5ae6727e02c2acf95bc5f24d8274e42495c790125ba52a581170000000043412a5a9f1749688460eee46b62851641fd9b17f9ed5131b3f50e4f160eadc45cb3bf4fffff001d03a966ba -01000000c704e90a0c4cb992d6973d636a7094ef2790a60231db345a926b6cb6000000006f98c89001a2e89ea35aaf00b85d965af5598b61bc48d9d9847609331995383effb4bf4fffff001d02ee5af9 -010000005468467a64f255415f3ad770f0d5393275f2813fd0e1e915a2b8c28b000000000566f29ed6b8cdf85a4b197dcbb0135dfb7b671f83ca67970bffea903309ab7445b5bf4fffff001d032ac068 -0100000021ad75b801d48a30fa5b4e6b1e43106a294a5e2763307a992fbd5282000000002c20851e58dc1a2ceb7c7771822ed41c7d0994731d01829628c3e938f4155a276eb5bf4fffff001d01a1420f -0100000002954bf32d68d54adac42cb5190efc06f18ead35208dc14a8face6f1000000009002c5c2dfd0259960507e69399c688f0d74bbcd52c810cd2d2507a829133f4941bdbf4fffff001d01724be9 -01000000add5df18f427437ace8b40064b3806583217a3f724672cf72cf8c18300000000bc652800c84513b2de38e0e97be92a582a628e1e49a9fe8d49aea5623251eda54abdbf4fffff001d045ec8ea -010000003b0c953fed585c1ac952df84e4c3953ba551da457c700035f6f3fc0c00000000831c01723b0fa955a6fbd51d9ddc5c77964814868f96f52ea3eaf3b66098e6df9dbdbf4fffff001d00cb77db -01000000f6667e8c4557c28f88b86a6892d03509a5afc9a89088a5bb8638eafa00000000ff61d87fbc86dac7f80962702153a2a6d9a84dac13c265106b883ed7ef68fc91cebdbf4fffff001d00e07f63 -010000002cb99b76cd981a422d02d61684f76bacea92669298e552e412ce41df000000005f2a9977b14cf34078500f956be0cc154291ce5a0e34c00a3dbbae97bed5e930f5bdbf4fffff001d008fd760 diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 39cea2962f..47185cbb9f 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -184,7 +184,7 @@ class ExampleTest(BitcoinTestFramework): block.solve() block_message = msg_block(block) # Send message is used to send a P2P message to the node over our P2PInterface - peer_messaging.send_message(block_message) + peer_messaging.send_without_ping(block_message) self.tip = block.sha256 blocks.append(self.tip) self.block_time += 1 @@ -209,7 +209,7 @@ class ExampleTest(BitcoinTestFramework): getdata_request = msg_getdata() for block in blocks: getdata_request.inv.append(CInv(MSG_BLOCK, block)) - peer_receiving.send_message(getdata_request) + peer_receiving.send_without_ping(getdata_request) # wait_until() will loop until a predicate condition is met. Use it to test properties of the # P2PInterface objects. diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index 2d4e33e5d8..df2fdc9643 100755 --- a/test/functional/feature_assumeutxo.py +++ b/test/functional/feature_assumeutxo.py @@ -9,6 +9,7 @@ to a hash that has been compiled into bitcoind. The assumeutxo value generated and used here is committed to in `CRegTestParams::m_assumeutxo_data` in `src/kernel/chainparams.cpp`. """ +import contextlib from shutil import rmtree from dataclasses import dataclass @@ -16,11 +17,16 @@ from test_framework.blocktools import ( create_block, create_coinbase ) +from test_framework.compressor import ( + compress_amount, +) from test_framework.messages import ( CBlockHeader, from_hex, msg_headers, - tx_from_hex + tx_from_hex, + ser_varint, + MAX_MONEY, ) from test_framework.p2p import ( P2PInterface, @@ -139,7 +145,14 @@ class AssumeutxoTest(BitcoinTestFramework): [b"\x81", 34, "3da966ba9826fb6d2604260e01607b55ba44e1a5de298606b08704bc62570ea8", None], # wrong coin code VARINT [b"\x80", 34, "091e893b3ccb4334378709578025356c8bcb0a623f37c7c4e493133c988648e5", None], # another wrong coin code [b"\x84\x58", 34, None, "Bad snapshot data after deserializing 0 coins"], # wrong coin case with height 364 and coinbase 0 - [b"\xCA\xD2\x8F\x5A", 39, None, "Bad snapshot data after deserializing 0 coins - bad tx out value"], # Amount exceeds MAX_MONEY + [ + # compressed txout value + scriptpubkey + ser_varint(compress_amount(MAX_MONEY + 1)) + ser_varint(0), + # txid + coins per txid + vout + coin height + 32 + 1 + 1 + 2, + None, + "Bad snapshot data after deserializing 0 coins - bad tx out value" + ], # Amount exceeds MAX_MONEY ] for content, offset, wrong_hash, custom_message in cases: @@ -297,7 +310,7 @@ class AssumeutxoTest(BitcoinTestFramework): msg = msg_headers() for block_num in range(1, miner.getblockcount()+1): msg.headers.append(from_hex(CBlockHeader(), miner.getblockheader(miner.getblockhash(block_num), verbose=False))) - headers_provider_conn.send_message(msg) + headers_provider_conn.send_without_ping(msg) # Ensure headers arrived default_value = {'status': ''} # No status @@ -337,6 +350,22 @@ class AssumeutxoTest(BitcoinTestFramework): assert 'NETWORK' not in node_services assert 'NETWORK_LIMITED' in node_services + @contextlib.contextmanager + def assert_disk_cleanup(self, node, assumeutxo_used): + """ + Ensure an assumeutxo node is cleaning up the background chainstate + """ + msg = [] + if assumeutxo_used: + # Check that the snapshot actually existed before restart + assert (node.datadir_path / node.chain / "chainstate_snapshot").exists() + msg = ["cleaning up unneeded background chainstate"] + + with node.assert_debug_log(msg): + yield + + assert not (node.datadir_path / node.chain / "chainstate_snapshot").exists() + def run_test(self): """ Bring up two (disconnected) nodes, mine some new blocks on the first, @@ -644,7 +673,8 @@ class AssumeutxoTest(BitcoinTestFramework): for i in (0, 1): n = self.nodes[i] self.log.info(f"Restarting node {i} to ensure (Check|Load)BlockIndex passes") - self.restart_node(i, extra_args=self.extra_args[i]) + with self.assert_disk_cleanup(n, i == 1): + self.restart_node(i, extra_args=self.extra_args[i]) assert_equal(n.getblockchaininfo()["blocks"], FINAL_HEIGHT) @@ -721,7 +751,8 @@ class AssumeutxoTest(BitcoinTestFramework): for i in (0, 2): n = self.nodes[i] self.log.info(f"Restarting node {i} to ensure (Check|Load)BlockIndex passes") - self.restart_node(i, extra_args=self.extra_args[i]) + with self.assert_disk_cleanup(n, i == 2): + self.restart_node(i, extra_args=self.extra_args[i]) assert_equal(n.getblockchaininfo()["blocks"], FINAL_HEIGHT) diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 32ad3ad271..2f67ef8536 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -58,7 +58,7 @@ class BaseNode(P2PInterface): def send_header_for_blocks(self, new_blocks): headers_message = msg_headers() headers_message.headers = [CBlockHeader(b) for b in new_blocks] - self.send_message(headers_message) + self.send_without_ping(headers_message) class AssumeValidTest(BitcoinTestFramework): @@ -80,7 +80,7 @@ class AssumeValidTest(BitcoinTestFramework): if not p2p_conn.is_connected: break try: - p2p_conn.send_message(msg_block(self.blocks[i])) + p2p_conn.send_without_ping(msg_block(self.blocks[i])) except IOError: assert not p2p_conn.is_connected break @@ -157,7 +157,7 @@ class AssumeValidTest(BitcoinTestFramework): # Send all blocks to node1. All blocks will be accepted. for i in range(2202): - p2p1.send_message(msg_block(self.blocks[i])) + p2p1.send_without_ping(msg_block(self.blocks[i])) # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync. p2p1.sync_with_ping(timeout=960) assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202) diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py index e8fc1aca46..c5e3c33b14 100755 --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -24,6 +24,9 @@ class ConfArgsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 + # Prune to prevent disk space warning on CI systems with limited space, + # when using networks other than regtest. + self.extra_args = [["-prune=550"]] self.supports_cli = False self.wallet_names = [] self.disable_autoconnect = False @@ -471,32 +474,21 @@ class ConfArgsTest(BitcoinTestFramework): self.log.info("Test testnet3 deprecation warning") t3_warning_log = "Warning: Support for testnet3 is deprecated and will be removed in an upcoming release. Consider switching to testnet4." - def warning_msg(node, approx_size): - return f'Warning: Disk space for "{node.datadir_path / node.chain / "blocks" }" may not accommodate the block files. Approximately {approx_size} GB of data will be stored in this directory.' - - # Testnet3 node will log the warning + self.log.debug("Testnet3 node will log the deprecation warning") self.nodes[0].chain = 'testnet3' self.nodes[0].replace_in_config([('regtest=', 'testnet='), ('[regtest]', '[test]')]) with self.nodes[0].assert_debug_log([t3_warning_log]): self.start_node(0) - # Some CI environments will have limited space and some others won't - # so we need to handle both cases as a valid result. - self.nodes[0].stderr.seek(0) - err = self.nodes[0].stdout.read() - self.nodes[0].stderr.seek(0) - self.nodes[0].stderr.truncate() - if err != b'' and err != warning_msg(self.nodes[0], 42): - raise AssertionError("Unexpected stderr after shutdown of Testnet3 node") self.stop_node(0) - # Testnet4 node will not log the warning + self.log.debug("Testnet4 node will not log the deprecation warning") self.nodes[0].chain = 'testnet4' self.nodes[0].replace_in_config([('testnet=', 'testnet4='), ('[test]', '[testnet4]')]) with self.nodes[0].assert_debug_log([], unexpected_msgs=[t3_warning_log]): self.start_node(0) self.stop_node(0) - # Reset to regtest + self.log.debug("Reset to regtest") self.nodes[0].chain = 'regtest' self.nodes[0].replace_in_config([('testnet4=', 'regtest='), ('[testnet4]', '[regtest]')]) diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py index aa4ca4b45a..956c0dbda2 100755 --- a/test/functional/feature_filelock.py +++ b/test/functional/feature_filelock.py @@ -59,8 +59,7 @@ class FilelockTest(BitcoinTestFramework): if self.is_bdb_compiled(): check_wallet_filelock(False) - if self.is_sqlite_compiled(): - check_wallet_filelock(True) + check_wallet_filelock(True) if __name__ == '__main__': FilelockTest(__file__).main() diff --git a/test/functional/feature_framework_unit_tests.py b/test/functional/feature_framework_unit_tests.py index 14d83f8a70..4ee2143ad6 100755 --- a/test/functional/feature_framework_unit_tests.py +++ b/test/functional/feature_framework_unit_tests.py @@ -18,6 +18,7 @@ TEST_FRAMEWORK_MODULES = [ "address", "crypto.bip324_cipher", "blocktools", + "compressor", "crypto.chacha20", "crypto.ellswift", "key", diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index 4a2f7ecf42..8a936fc0a5 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -4,10 +4,13 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Tests related to node initialization.""" from pathlib import Path +import os import platform import shutil +import signal +import subprocess -from test_framework.test_framework import BitcoinTestFramework, SkipTest +from test_framework.test_framework import BitcoinTestFramework from test_framework.test_node import ( BITCOIN_PID_FILENAME_DEFAULT, ErrorMatch, @@ -33,20 +36,17 @@ class InitTest(BitcoinTestFramework): - test terminating initialization after seeing a certain log line. - test removing certain essential files to test startup error paths. """ - # TODO: skip Windows for now since it isn't clear how to SIGTERM. - # - # Windows doesn't support `process.terminate()`. - # and other approaches (like below) don't work: - # - # os.kill(node.process.pid, signal.CTRL_C_EVENT) - if platform.system() == 'Windows': - raise SkipTest("can't SIGTERM on Windows") - self.stop_node(0) node = self.nodes[0] def sigterm_node(): - node.process.terminate() + if platform.system() == 'Windows': + # Don't call Python's terminate() since it calls + # TerminateProcess(), which unlike SIGTERM doesn't allow + # bitcoind to perform any shutdown logic. + os.kill(node.process.pid, signal.CTRL_BREAK_EVENT) + else: + node.process.terminate() node.process.wait() def start_expecting_error(err_fragment): @@ -86,10 +86,16 @@ class InitTest(BitcoinTestFramework): if self.is_wallet_compiled(): lines_to_terminate_after.append(b'Verifying wallet') + args = ['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'] for terminate_line in lines_to_terminate_after: - self.log.info(f"Starting node and will exit after line {terminate_line}") + self.log.info(f"Starting node and will terminate after line {terminate_line}") with node.busy_wait_for_debug_log([terminate_line]): - node.start(extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1']) + if platform.system() == 'Windows': + # CREATE_NEW_PROCESS_GROUP is required in order to be able + # to terminate the child without terminating the test. + node.start(extra_args=args, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) + else: + node.start(extra_args=args) self.log.debug("Terminating node after terminate line was found") sigterm_node() @@ -102,12 +108,22 @@ class InitTest(BitcoinTestFramework): 'blocks/index/*.ldb': 'Error opening block database.', 'chainstate/*.ldb': 'Error opening coins database.', 'blocks/blk*.dat': 'Error loading block database.', + 'indexes/txindex/MANIFEST*': 'LevelDB error: Corruption: CURRENT points to a non-existent file', + # Removing these files does not result in a startup error: + # 'indexes/blockfilter/basic/*.dat', 'indexes/blockfilter/basic/db/*.*', 'indexes/coinstats/db/*.*', + # 'indexes/txindex/*.log', 'indexes/txindex/CURRENT', 'indexes/txindex/LOCK' } files_to_perturb = { 'blocks/index/*.ldb': 'Error loading block database.', 'chainstate/*.ldb': 'Error opening coins database.', 'blocks/blk*.dat': 'Corrupted block database detected.', + 'indexes/blockfilter/basic/db/*.*': 'LevelDB error: Corruption', + 'indexes/coinstats/db/*.*': 'LevelDB error: Corruption', + 'indexes/txindex/*.log': 'LevelDB error: Corruption', + 'indexes/txindex/CURRENT': 'LevelDB error: Corruption', + # Perturbing these files does not result in a startup error: + # 'indexes/blockfilter/basic/*.dat', 'indexes/txindex/MANIFEST*', 'indexes/txindex/LOCK' } for file_patt, err_fragment in files_to_delete.items(): @@ -129,9 +145,10 @@ class InitTest(BitcoinTestFramework): self.stop_node(0) self.log.info("Test startup errors after perturbing certain essential files") + dirs = ["blocks", "chainstate", "indexes"] for file_patt, err_fragment in files_to_perturb.items(): - shutil.copytree(node.chain_path / "blocks", node.chain_path / "blocks_bak") - shutil.copytree(node.chain_path / "chainstate", node.chain_path / "chainstate_bak") + for dir in dirs: + shutil.copytree(node.chain_path / dir, node.chain_path / f"{dir}_bak") target_files = list(node.chain_path.glob(file_patt)) for target_file in target_files: @@ -145,10 +162,9 @@ class InitTest(BitcoinTestFramework): start_expecting_error(err_fragment) - shutil.rmtree(node.chain_path / "blocks") - shutil.rmtree(node.chain_path / "chainstate") - shutil.move(node.chain_path / "blocks_bak", node.chain_path / "blocks") - shutil.move(node.chain_path / "chainstate_bak", node.chain_path / "chainstate") + for dir in dirs: + shutil.rmtree(node.chain_path / dir) + shutil.move(node.chain_path / f"{dir}_bak", node.chain_path / dir) def init_pid_test(self): BITCOIN_PID_FILENAME_CUSTOM = "my_fancy_bitcoin_pid_file.foobar" diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index ad5a7e4831..1d7a7bfc55 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -124,7 +124,7 @@ class MaxUploadTest(BitcoinTestFramework): # the test has been running so far). with self.nodes[0].assert_debug_log(expected_msgs=["historical block serving limit reached, disconnecting peer=0"]): for _ in range(3): - p2p_conns[0].send_message(getdata_request) + p2p_conns[0].send_without_ping(getdata_request) p2p_conns[0].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 2) self.log.info("Peer 0 disconnected after downloading old block too many times") @@ -148,7 +148,7 @@ class MaxUploadTest(BitcoinTestFramework): # But if p2p_conns[1] tries for an old block, it gets disconnected too. getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)] with self.nodes[0].assert_debug_log(expected_msgs=["historical block serving limit reached, disconnecting peer=1"]): - p2p_conns[1].send_message(getdata_request) + p2p_conns[1].send_without_ping(getdata_request) p2p_conns[1].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 1) @@ -198,7 +198,7 @@ class MaxUploadTest(BitcoinTestFramework): self.log.info("Peer gets disconnected for a mempool request after limit is reached") with self.nodes[0].assert_debug_log(expected_msgs=["mempool request with bandwidth limit reached, disconnecting peer=0"]): - peer.send_message(msg_mempool()) + peer.send_without_ping(msg_mempool()) peer.wait_for_disconnect() self.log.info("Test passing an unparsable value to -maxuploadtarget throws an error") diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py index 63091b3ee8..02e37f0fdd 100755 --- a/test/functional/feature_signet.py +++ b/test/functional/feature_signet.py @@ -26,12 +26,14 @@ signet_blocks = [ class SignetParams: def __init__(self, challenge=None): + # Prune to prevent disk space warning on CI systems with limited space, + # when using networks other than regtest. if challenge is None: self.challenge = SIGNET_DEFAULT_CHALLENGE - self.shared_args = [] + self.shared_args = ["-prune=550"] else: self.challenge = challenge - self.shared_args = [f"-signetchallenge={challenge}"] + self.shared_args = ["-prune=550", f"-signetchallenge={challenge}"] class SignetBasicTest(BitcoinTestFramework): def set_test_params(self): diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index dc25ce6c83..af59666222 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -47,7 +47,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): for _ in range(numblocks): block = create_block(tip, create_coinbase(height + 1), block_time, version=version) block.solve() - peer.send_message(msg_block(block)) + peer.send_without_ping(msg_block(block)) block_time += 1 height += 1 tip = block.sha256 diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py index f684848aed..1f4d6d6fbf 100755 --- a/test/functional/interface_usdt_coinselection.py +++ b/test/functional/interface_usdt_coinselection.py @@ -49,10 +49,13 @@ BPF_QUEUE(coin_selection_events, struct event_data, 1024); int trace_selected_coins(struct pt_regs *ctx) { struct event_data data; + void *pwallet_name = NULL, *palgo = NULL; __builtin_memset(&data, 0, sizeof(data)); data.type = 1; - bpf_usdt_readarg_p(1, ctx, &data.wallet_name, WALLET_NAME_LENGTH); - bpf_usdt_readarg_p(2, ctx, &data.algo, ALGO_NAME_LENGTH); + bpf_usdt_readarg(1, ctx, &pwallet_name); + bpf_probe_read_user_str(&data.wallet_name, WALLET_NAME_LENGTH, pwallet_name); + bpf_usdt_readarg(2, ctx, &palgo); + bpf_probe_read_user_str(&data.algo, ALGO_NAME_LENGTH, palgo); bpf_usdt_readarg(3, ctx, &data.target); bpf_usdt_readarg(4, ctx, &data.waste); bpf_usdt_readarg(5, ctx, &data.selected_value); @@ -62,9 +65,11 @@ int trace_selected_coins(struct pt_regs *ctx) { int trace_normal_create_tx(struct pt_regs *ctx) { struct event_data data; + void *pwallet_name = NULL; __builtin_memset(&data, 0, sizeof(data)); data.type = 2; - bpf_usdt_readarg_p(1, ctx, &data.wallet_name, WALLET_NAME_LENGTH); + bpf_usdt_readarg(1, ctx, &pwallet_name); + bpf_probe_read_user_str(&data.wallet_name, WALLET_NAME_LENGTH, pwallet_name); bpf_usdt_readarg(2, ctx, &data.success); bpf_usdt_readarg(3, ctx, &data.fee); bpf_usdt_readarg(4, ctx, &data.change_pos); @@ -74,18 +79,22 @@ int trace_normal_create_tx(struct pt_regs *ctx) { int trace_attempt_aps(struct pt_regs *ctx) { struct event_data data; + void *pwallet_name = NULL; __builtin_memset(&data, 0, sizeof(data)); data.type = 3; - bpf_usdt_readarg_p(1, ctx, &data.wallet_name, WALLET_NAME_LENGTH); + bpf_usdt_readarg(1, ctx, &pwallet_name); + bpf_probe_read_user_str(&data.wallet_name, WALLET_NAME_LENGTH, pwallet_name); coin_selection_events.push(&data, 0); return 0; } int trace_aps_create_tx(struct pt_regs *ctx) { struct event_data data; + void *pwallet_name = NULL; __builtin_memset(&data, 0, sizeof(data)); data.type = 4; - bpf_usdt_readarg_p(1, ctx, &data.wallet_name, WALLET_NAME_LENGTH); + bpf_usdt_readarg(1, ctx, &pwallet_name); + bpf_probe_read_user_str(&data.wallet_name, WALLET_NAME_LENGTH, pwallet_name); bpf_usdt_readarg(2, ctx, &data.use_aps); bpf_usdt_readarg(3, ctx, &data.success); bpf_usdt_readarg(4, ctx, &data.fee); diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py index 44882f642e..7535954172 100755 --- a/test/functional/interface_usdt_mempool.py +++ b/test/functional/interface_usdt_mempool.py @@ -75,8 +75,9 @@ BPF_PERF_OUTPUT(replaced_events); int trace_added(struct pt_regs *ctx) { struct added_event added = {}; - - bpf_usdt_readarg_p(1, ctx, &added.hash, HASH_LENGTH); + void *phash = NULL; + bpf_usdt_readarg(1, ctx, &phash); + bpf_probe_read_user(&added.hash, sizeof(added.hash), phash); bpf_usdt_readarg(2, ctx, &added.vsize); bpf_usdt_readarg(3, ctx, &added.fee); @@ -86,9 +87,11 @@ int trace_added(struct pt_regs *ctx) { int trace_removed(struct pt_regs *ctx) { struct removed_event removed = {}; - - bpf_usdt_readarg_p(1, ctx, &removed.hash, HASH_LENGTH); - bpf_usdt_readarg_p(2, ctx, &removed.reason, MAX_REMOVAL_REASON_LENGTH); + void *phash = NULL, *preason = NULL; + bpf_usdt_readarg(1, ctx, &phash); + bpf_probe_read_user(&removed.hash, sizeof(removed.hash), phash); + bpf_usdt_readarg(2, ctx, &preason); + bpf_probe_read_user_str(&removed.reason, sizeof(removed.reason), preason); bpf_usdt_readarg(3, ctx, &removed.vsize); bpf_usdt_readarg(4, ctx, &removed.fee); bpf_usdt_readarg(5, ctx, &removed.entry_time); @@ -99,22 +102,25 @@ int trace_removed(struct pt_regs *ctx) { int trace_rejected(struct pt_regs *ctx) { struct rejected_event rejected = {}; - - bpf_usdt_readarg_p(1, ctx, &rejected.hash, HASH_LENGTH); - bpf_usdt_readarg_p(2, ctx, &rejected.reason, MAX_REJECT_REASON_LENGTH); - + void *phash = NULL, *preason = NULL; + bpf_usdt_readarg(1, ctx, &phash); + bpf_probe_read_user(&rejected.hash, sizeof(rejected.hash), phash); + bpf_usdt_readarg(2, ctx, &preason); + bpf_probe_read_user_str(&rejected.reason, sizeof(rejected.reason), preason); rejected_events.perf_submit(ctx, &rejected, sizeof(rejected)); return 0; } int trace_replaced(struct pt_regs *ctx) { struct replaced_event replaced = {}; - - bpf_usdt_readarg_p(1, ctx, &replaced.replaced_hash, HASH_LENGTH); + void *preplaced_hash = NULL, *preplacement_hash = NULL; + bpf_usdt_readarg(1, ctx, &preplaced_hash); + bpf_probe_read_user(&replaced.replaced_hash, sizeof(replaced.replaced_hash), preplaced_hash); bpf_usdt_readarg(2, ctx, &replaced.replaced_vsize); bpf_usdt_readarg(3, ctx, &replaced.replaced_fee); bpf_usdt_readarg(4, ctx, &replaced.replaced_entry_time); - bpf_usdt_readarg_p(5, ctx, &replaced.replacement_hash, HASH_LENGTH); + bpf_usdt_readarg(5, ctx, &preplacement_hash); + bpf_probe_read_user(&replaced.replacement_hash, sizeof(replaced.replacement_hash), preplacement_hash); bpf_usdt_readarg(6, ctx, &replaced.replacement_vsize); bpf_usdt_readarg(7, ctx, &replaced.replacement_fee); bpf_usdt_readarg(8, ctx, &replaced.replaced_by_transaction); @@ -314,10 +320,7 @@ class MempoolTracepointTest(BitcoinTestFramework): assert_equal(1, len(events)) event = events[0] assert_equal(bytes(event.hash)[::-1].hex(), tx["tx"].hash) - # The next test is already known to fail, so disable it to avoid - # wasting CPU time and developer time. See - # https://github.com/bitcoin/bitcoin/issues/27380 - #assert_equal(event.reason.decode("UTF-8"), "min relay fee not met") + assert_equal(event.reason.decode("UTF-8"), "min relay fee not met") bpf.cleanup() self.generate(self.wallet, 1) diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py index beb2546153..94baacf3dd 100755 --- a/test/functional/interface_usdt_net.py +++ b/test/functional/interface_usdt_net.py @@ -17,7 +17,7 @@ except ImportError: from test_framework.messages import CBlockHeader, MAX_HEADERS_RESULTS, msg_headers, msg_version from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import assert_equal, assert_greater_than # Tor v3 addresses are 62 chars + 6 chars for the port (':12345'). MAX_PEER_ADDR_LENGTH = 68 @@ -91,12 +91,17 @@ struct MisbehavingConnection BPF_PERF_OUTPUT(inbound_messages); int trace_inbound_message(struct pt_regs *ctx) { struct p2p_message msg = {}; + void *paddr = NULL, *pconn_type = NULL, *pmsg_type = NULL, *pmsg = NULL; bpf_usdt_readarg(1, ctx, &msg.peer_id); - bpf_usdt_readarg_p(2, ctx, &msg.peer_addr, MAX_PEER_ADDR_LENGTH); - bpf_usdt_readarg_p(3, ctx, &msg.peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH); - bpf_usdt_readarg_p(4, ctx, &msg.msg_type, MAX_MSG_TYPE_LENGTH); + bpf_usdt_readarg(2, ctx, &paddr); + bpf_probe_read_user_str(&msg.peer_addr, sizeof(msg.peer_addr), paddr); + bpf_usdt_readarg(3, ctx, &pconn_type); + bpf_probe_read_user_str(&msg.peer_conn_type, sizeof(msg.peer_conn_type), pconn_type); + bpf_usdt_readarg(4, ctx, &pmsg_type); + bpf_probe_read_user_str(&msg.msg_type, sizeof(msg.msg_type), pmsg_type); bpf_usdt_readarg(5, ctx, &msg.msg_size); - bpf_usdt_readarg_p(6, ctx, &msg.msg, _TRACEPOINT_TEST_MIN(msg.msg_size, MAX_MSG_DATA_LENGTH)); + bpf_usdt_readarg(6, ctx, &pmsg); + bpf_probe_read_user(&msg.msg, _TRACEPOINT_TEST_MIN(msg.msg_size, MAX_MSG_DATA_LENGTH), pmsg); inbound_messages.perf_submit(ctx, &msg, sizeof(msg)); return 0; } @@ -104,12 +109,18 @@ int trace_inbound_message(struct pt_regs *ctx) { BPF_PERF_OUTPUT(outbound_messages); int trace_outbound_message(struct pt_regs *ctx) { struct p2p_message msg = {}; + void *paddr = NULL, *pconn_type = NULL, *pmsg_type = NULL, *pmsg = NULL; bpf_usdt_readarg(1, ctx, &msg.peer_id); - bpf_usdt_readarg_p(2, ctx, &msg.peer_addr, MAX_PEER_ADDR_LENGTH); - bpf_usdt_readarg_p(3, ctx, &msg.peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH); - bpf_usdt_readarg_p(4, ctx, &msg.msg_type, MAX_MSG_TYPE_LENGTH); + bpf_usdt_readarg(1, ctx, &msg.peer_id); + bpf_usdt_readarg(2, ctx, &paddr); + bpf_probe_read_user_str(&msg.peer_addr, sizeof(msg.peer_addr), paddr); + bpf_usdt_readarg(3, ctx, &pconn_type); + bpf_probe_read_user_str(&msg.peer_conn_type, sizeof(msg.peer_conn_type), pconn_type); + bpf_usdt_readarg(4, ctx, &pmsg_type); + bpf_probe_read_user_str(&msg.msg_type, sizeof(msg.msg_type), pmsg_type); bpf_usdt_readarg(5, ctx, &msg.msg_size); - bpf_usdt_readarg_p(6, ctx, &msg.msg, _TRACEPOINT_TEST_MIN(msg.msg_size, MAX_MSG_DATA_LENGTH)); + bpf_usdt_readarg(6, ctx, &pmsg); + bpf_probe_read_user(&msg.msg, _TRACEPOINT_TEST_MIN(msg.msg_size, MAX_MSG_DATA_LENGTH), pmsg); outbound_messages.perf_submit(ctx, &msg, sizeof(msg)); return 0; }; @@ -353,8 +364,8 @@ class NetTracepointTest(BitcoinTestFramework): assert_equal(EXPECTED_INBOUND_CONNECTIONS, len(inbound_connections)) for inbound_connection in inbound_connections: - assert inbound_connection.conn.id > 0 - assert inbound_connection.existing > 0 + assert_greater_than(inbound_connection.conn.id, 0) + assert_greater_than(inbound_connection.existing, 0) assert_equal(b'inbound', inbound_connection.conn.conn_type) assert_equal(NETWORK_TYPE_UNROUTABLE, inbound_connection.conn.network) @@ -394,8 +405,8 @@ class NetTracepointTest(BitcoinTestFramework): assert_equal(EXPECTED_OUTBOUND_CONNECTIONS, len(outbound_connections)) for outbound_connection in outbound_connections: - assert outbound_connection.conn.id > 0 - assert outbound_connection.existing > 0 + assert_greater_than(outbound_connection.conn.id, 0) + assert_greater_than(outbound_connection.existing, 0) assert_equal(EXPECTED_CONNECTION_TYPE, outbound_connection.conn.conn_type.decode('utf-8')) assert_equal(NETWORK_TYPE_UNROUTABLE, outbound_connection.conn.network) @@ -431,8 +442,8 @@ class NetTracepointTest(BitcoinTestFramework): assert_equal(EXPECTED_EVICTED_CONNECTIONS, len(evicted_connections)) for evicted_connection in evicted_connections: - assert evicted_connection.conn.id > 0 - assert evicted_connection.time_established > 0 + assert_greater_than(evicted_connection.conn.id, 0) + assert_greater_than(evicted_connection.time_established, 0) assert_equal("inbound", evicted_connection.conn.conn_type.decode('utf-8')) assert_equal(NETWORK_TYPE_UNROUTABLE, evicted_connection.conn.network) @@ -462,15 +473,15 @@ class NetTracepointTest(BitcoinTestFramework): for _ in range(EXPECTED_MISBEHAVING_CONNECTIONS): testnode = P2PInterface() self.nodes[0].add_p2p_connection(testnode) - testnode.send_message(msg) + testnode.send_without_ping(msg) bpf.perf_buffer_poll(timeout=500) testnode.peer_disconnect() assert_equal(EXPECTED_MISBEHAVING_CONNECTIONS, len(misbehaving_connections)) for misbehaving_connection in misbehaving_connections: - assert misbehaving_connection.id > 0 - assert len(misbehaving_connection.message) > 0 - assert misbehaving_connection.message == b"headers message size = 2001" + assert_greater_than(misbehaving_connection.id, 0) + assert_greater_than(len(misbehaving_connection.message), 0) + assert_equal(misbehaving_connection.message, b"headers message size = 2001") bpf.cleanup() @@ -505,10 +516,10 @@ class NetTracepointTest(BitcoinTestFramework): assert_equal(EXPECTED_CLOSED_CONNECTIONS, len(closed_connections)) for closed_connection in closed_connections: - assert closed_connection.conn.id > 0 + assert_greater_than(closed_connection.conn.id, 0) assert_equal("inbound", closed_connection.conn.conn_type.decode('utf-8')) assert_equal(0, closed_connection.conn.network) - assert closed_connection.time_established > 0 + assert_greater_than(closed_connection.time_established, 0) bpf.cleanup() diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py index 1617c580f3..12a11409e0 100755 --- a/test/functional/interface_usdt_utxocache.py +++ b/test/functional/interface_usdt_utxocache.py @@ -35,7 +35,9 @@ struct utxocache_change BPF_PERF_OUTPUT(utxocache_add); int trace_utxocache_add(struct pt_regs *ctx) { struct utxocache_change add = {}; - bpf_usdt_readarg_p(1, ctx, &add.txid, 32); + void *ptxid = NULL; + bpf_usdt_readarg(1, ctx, &ptxid); + bpf_probe_read_user(&add.txid, sizeof(add.txid), ptxid); bpf_usdt_readarg(2, ctx, &add.index); bpf_usdt_readarg(3, ctx, &add.height); bpf_usdt_readarg(4, ctx, &add.value); @@ -47,7 +49,9 @@ int trace_utxocache_add(struct pt_regs *ctx) { BPF_PERF_OUTPUT(utxocache_spent); int trace_utxocache_spent(struct pt_regs *ctx) { struct utxocache_change spent = {}; - bpf_usdt_readarg_p(1, ctx, &spent.txid, 32); + void *ptxid = NULL; + bpf_usdt_readarg(1, ctx, &ptxid); + bpf_probe_read_user(&spent.txid, sizeof(spent.txid), ptxid); bpf_usdt_readarg(2, ctx, &spent.index); bpf_usdt_readarg(3, ctx, &spent.height); bpf_usdt_readarg(4, ctx, &spent.value); @@ -59,7 +63,9 @@ int trace_utxocache_spent(struct pt_regs *ctx) { BPF_PERF_OUTPUT(utxocache_uncache); int trace_utxocache_uncache(struct pt_regs *ctx) { struct utxocache_change uncache = {}; - bpf_usdt_readarg_p(1, ctx, &uncache.txid, 32); + void *ptxid = NULL; + bpf_usdt_readarg(1, ctx, &ptxid); + bpf_probe_read_user(&uncache.txid, sizeof(uncache.txid), ptxid); bpf_usdt_readarg(2, ctx, &uncache.index); bpf_usdt_readarg(3, ctx, &uncache.height); bpf_usdt_readarg(4, ctx, &uncache.value); diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py index 8a98a452de..9b2e708d95 100755 --- a/test/functional/interface_usdt_validation.py +++ b/test/functional/interface_usdt_validation.py @@ -39,7 +39,9 @@ struct connected_block BPF_PERF_OUTPUT(block_connected); int trace_block_connected(struct pt_regs *ctx) { struct connected_block block = {}; - bpf_usdt_readarg_p(1, ctx, &block.hash, 32); + void *phash = NULL; + bpf_usdt_readarg(1, ctx, &phash); + bpf_probe_read_user(&block.hash, sizeof(block.hash), phash); bpf_usdt_readarg(2, ctx, &block.height); bpf_usdt_readarg(3, ctx, &block.transactions); bpf_usdt_readarg(4, ctx, &block.inputs); diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 27ecc3b4a8..9014ab260e 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -45,6 +45,7 @@ from test_framework.util import ( assert_equal, assert_greater_than, assert_raises_rpc_error, + sync_txindex, ) from test_framework.wallet import MiniWallet from test_framework.wallet_util import generate_keypair @@ -270,6 +271,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): self.log.info('A coinbase transaction') # Pick the input of the first tx we created, so it has to be a coinbase tx + sync_txindex(self, node) raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid']) tx = tx_from_hex(raw_tx_coinbase_spent) self.check_mempool_result( diff --git a/test/functional/mempool_ephemeral_dust.py b/test/functional/mempool_ephemeral_dust.py index e614a9e607..004db3656e 100755 --- a/test/functional/mempool_ephemeral_dust.py +++ b/test/functional/mempool_ephemeral_dust.py @@ -233,8 +233,8 @@ class EphemeralDustTest(BitcoinTestFramework): unspent_sweep_tx = self.wallet.create_self_transfer_multi(fee_per_output=2000, utxos_to_spend=[dusty_tx["new_utxos"][0]], version=3) assert_greater_than(unspent_sweep_tx["fee"], sweep_tx["fee"]) res = self.nodes[0].submitpackage([dusty_tx["hex"], unspent_sweep_tx["hex"]]) - assert_equal(res["tx-results"][unspent_sweep_tx["wtxid"]]["error"], f"missing-ephemeral-spends, tx {unspent_sweep_tx['txid']} did not spend parent's ephemeral dust") - assert_raises_rpc_error(-26, f"missing-ephemeral-spends, tx {unspent_sweep_tx['txid']} did not spend parent's ephemeral dust", self.nodes[0].sendrawtransaction, unspent_sweep_tx["hex"]) + assert_equal(res["tx-results"][unspent_sweep_tx["wtxid"]]["error"], f"missing-ephemeral-spends, tx {unspent_sweep_tx['txid']} (wtxid={unspent_sweep_tx['wtxid']}) did not spend parent's ephemeral dust") + assert_raises_rpc_error(-26, f"missing-ephemeral-spends, tx {unspent_sweep_tx['txid']} (wtxid={unspent_sweep_tx['wtxid']}) did not spend parent's ephemeral dust", self.nodes[0].sendrawtransaction, unspent_sweep_tx["hex"]) assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"], sweep_tx["tx"]]) # Spend works with dust spent @@ -405,7 +405,7 @@ class EphemeralDustTest(BitcoinTestFramework): res = self.nodes[0].submitpackage([dusty_tx["hex"] for dusty_tx in dusty_txs] + [insufficient_sweep_tx["hex"]]) assert_equal(res['package_msg'], "transaction failed") - assert_equal(res['tx-results'][insufficient_sweep_tx['wtxid']]['error'], f"missing-ephemeral-spends, tx {insufficient_sweep_tx['txid']} did not spend parent's ephemeral dust") + assert_equal(res['tx-results'][insufficient_sweep_tx['wtxid']]['error'], f"missing-ephemeral-spends, tx {insufficient_sweep_tx['txid']} (wtxid={insufficient_sweep_tx['wtxid']}) did not spend parent's ephemeral dust") # Everything got in except for insufficient spend assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"] for dusty_tx in dusty_txs]) @@ -418,7 +418,7 @@ class EphemeralDustTest(BitcoinTestFramework): res = self.nodes[0].submitpackage([dusty_tx["hex"] for dusty_tx in dusty_txs] + [insufficient_sweep_tx["hex"]]) assert_equal(res['package_msg'], "transaction failed") - assert_equal(res['tx-results'][insufficient_sweep_tx["wtxid"]]["error"], f"missing-ephemeral-spends, tx {insufficient_sweep_tx['txid']} did not spend parent's ephemeral dust") + assert_equal(res['tx-results'][insufficient_sweep_tx["wtxid"]]["error"], f"missing-ephemeral-spends, tx {insufficient_sweep_tx['txid']} (wtxid={insufficient_sweep_tx['wtxid']}) did not spend parent's ephemeral dust") assert_mempool_contents(self, self.nodes[0], expected=[dusty_tx["tx"] for dusty_tx in dusty_txs] + [sweep_all_but_one_tx["tx"]]) # Cycle out the partial sweep to avoid triggering package RBF behavior which limits package to no in-mempool ancestors diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index c64c203e50..bf0a97df0d 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -59,7 +59,7 @@ class MempoolPersistTest(BitcoinTestFramework): def run_test(self): self.mini_wallet = MiniWallet(self.nodes[2]) - if self.is_sqlite_compiled(): + if self.is_wallet_compiled(): self.nodes[2].createwallet( wallet_name="watch", descriptors=True, @@ -73,7 +73,7 @@ class MempoolPersistTest(BitcoinTestFramework): tx_creation_time_lower = int(time.time()) for _ in range(5): last_txid = self.mini_wallet.send_self_transfer(from_node=self.nodes[2])["txid"] - if self.is_sqlite_compiled(): + if self.is_wallet_compiled(): self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet node2_balance = wallet_watch.getbalance() self.sync_all() @@ -137,7 +137,7 @@ class MempoolPersistTest(BitcoinTestFramework): assert_equal(entry_prioritised_before_restart['fees']['base'] + Decimal('0.00009999'), entry_prioritised_before_restart['fees']['modified']) # Verify accounting of mempool transactions after restart is correct - if self.is_sqlite_compiled(): + if self.is_wallet_compiled(): self.nodes[2].loadwallet("watch") wallet_watch = self.nodes[2].get_wallet_rpc("watch") self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 56a9e6a84e..71af7f1e7c 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -76,9 +76,9 @@ class AddrReceiver(P2PInterface): def on_version(self, message): self.send_version() - self.send_message(msg_verack()) + self.send_without_ping(msg_verack()) if (self.send_getaddr): - self.send_message(msg_getaddr()) + self.send_without_ping(msg_getaddr()) def getaddr_received(self): return self.message_count['getaddr'] > 0 @@ -142,7 +142,7 @@ class AddrTest(BitcoinTestFramework): msg = self.setup_addr_msg(1010) with self.nodes[0].assert_debug_log(['addr message size = 1010']): - addr_source.send_message(msg) + addr_source.send_without_ping(msg) addr_source.wait_for_disconnect() self.nodes[0].disconnect_p2ps() diff --git a/test/functional/p2p_addrfetch.py b/test/functional/p2p_addrfetch.py index 69cc106341..1243f951dc 100755 --- a/test/functional/p2p_addrfetch.py +++ b/test/functional/p2p_addrfetch.py @@ -62,7 +62,7 @@ class P2PAddrFetch(BitcoinTestFramework): self.log.info("Check that answering with larger addr messages leads to disconnect") msg.addrs = [ADDR] * 2 - peer.send_message(msg) + peer.send_without_ping(msg) peer.wait_for_disconnect(timeout=5) self.log.info("Check timeout for addr-fetch peer that does not send addrs") diff --git a/test/functional/p2p_addrv2_relay.py b/test/functional/p2p_addrv2_relay.py index 8012137971..3a14d89239 100755 --- a/test/functional/p2p_addrv2_relay.py +++ b/test/functional/p2p_addrv2_relay.py @@ -79,7 +79,7 @@ class AddrTest(BitcoinTestFramework): self.log.info('Check disconnection when sending sendaddrv2 after verack') conn = self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(['sendaddrv2 received after verack, disconnecting peer=0']): - conn.send_message(msg_sendaddrv2()) + conn.send_without_ping(msg_sendaddrv2()) conn.wait_for_disconnect() self.log.info('Create connection that sends addrv2 messages') @@ -104,7 +104,7 @@ class AddrTest(BitcoinTestFramework): self.log.info('Send too-large addrv2 message') msg.addrs = ADDRS * 101 with self.nodes[0].assert_debug_log(['addrv2 message size = 1010']): - addr_source.send_message(msg) + addr_source.send_without_ping(msg) addr_source.wait_for_disconnect() diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index 88d5aa1408..0a4b7f0296 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -212,7 +212,7 @@ class CompactFiltersTest(BitcoinTestFramework): for request in requests: peer_1 = self.nodes[1].add_p2p_connection(P2PInterface()) with self.nodes[1].assert_debug_log(expected_msgs=["requested unsupported block filter type"]): - peer_1.send_message(request) + peer_1.send_without_ping(request) peer_1.wait_for_disconnect() self.log.info("Check that invalid requests result in disconnection.") @@ -259,7 +259,7 @@ class CompactFiltersTest(BitcoinTestFramework): for request, expected_log_msg in requests: peer_0 = self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(expected_msgs=[expected_log_msg]): - peer_0.send_message(request) + peer_0.send_without_ping(request) peer_0.wait_for_disconnect() self.log.info("Test -peerblockfilters without -blockfilterindex raises an error") diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 6737cc687e..fca8e3266c 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -34,7 +34,7 @@ class P2PBlocksOnly(BitcoinTestFramework): self.log.info('Check that tx invs also violate the protocol') self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(['transaction (0000000000000000000000000000000000000000000000000000000000001234) inv sent in violation of protocol, disconnecting peer']): - self.nodes[0].p2ps[0].send_message(msg_inv([CInv(t=MSG_WTX, h=0x1234)])) + self.nodes[0].p2ps[0].send_without_ping(msg_inv([CInv(t=MSG_WTX, h=0x1234)])) self.nodes[0].p2ps[0].wait_for_disconnect() del self.nodes[0].p2ps[0] @@ -68,7 +68,7 @@ class P2PBlocksOnly(BitcoinTestFramework): # But if, for some reason, first_peer decides to relay transactions to us anyway, we should relay them to # second_peer since we gave relay permission to first_peer. # See https://github.com/bitcoin/bitcoin/issues/19943 for details. - first_peer.send_message(msg_tx(tx)) + first_peer.send_without_ping(msg_tx(tx)) self.log.info('Check that the peer with relay-permission is still connected after sending the transaction') assert_equal(first_peer.is_connected, True) second_peer.wait_for_tx(txid) @@ -107,7 +107,7 @@ class P2PBlocksOnly(BitcoinTestFramework): def check_p2p_inv_violation(self, peer): self.log.info("Check that tx-invs from P2P are rejected and result in disconnect") with self.nodes[0].assert_debug_log(["inv sent in violation of protocol, disconnecting peer"]): - peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0x12345)])) + peer.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=0x12345)])) peer.wait_for_disconnect() self.nodes[0].disconnect_p2ps() @@ -116,7 +116,7 @@ class P2PBlocksOnly(BitcoinTestFramework): spendtx = self.miniwallet.create_self_transfer() with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol, disconnecting peer=0']): - self.nodes[0].p2ps[0].send_message(msg_tx(spendtx['tx'])) + self.nodes[0].p2ps[0].send_without_ping(msg_tx(spendtx['tx'])) self.nodes[0].p2ps[0].wait_for_disconnect() assert_equal(self.nodes[0].getmempoolinfo()['size'], 0) self.nodes[0].disconnect_p2ps() diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index ca36b2fbc0..a0bd063663 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -113,12 +113,12 @@ class TestP2PConn(P2PInterface): msg = msg_getheaders() msg.locator.vHave = locator msg.hashstop = hashstop - self.send_message(msg) + self.send_without_ping(msg) def send_header_for_blocks(self, new_blocks): headers_message = msg_headers() headers_message.headers = [CBlockHeader(b) for b in new_blocks] - self.send_message(headers_message) + self.send_without_ping(headers_message) def request_headers_and_sync(self, locator, hashstop=0): self.clear_block_announcement() @@ -138,7 +138,7 @@ class TestP2PConn(P2PInterface): This is used when we want to send a message into the node that we expect will get us disconnected, eg an invalid block.""" - self.send_message(message) + self.send_without_ping(message) self.wait_for_disconnect(timeout=timeout) class CompactBlocksTest(BitcoinTestFramework): @@ -325,7 +325,7 @@ class CompactBlocksTest(BitcoinTestFramework): # Now fetch the compact block using a normal non-announce getdata test_node.clear_block_announcement() inv = CInv(MSG_CMPCT_BLOCK, block_hash) - test_node.send_message(msg_getdata([inv])) + test_node.send_without_ping(msg_getdata([inv])) test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) @@ -386,7 +386,7 @@ class CompactBlocksTest(BitcoinTestFramework): block = self.build_block_on_tip(node) if announce == "inv": - test_node.send_message(msg_inv([CInv(MSG_BLOCK, block.sha256)])) + test_node.send_without_ping(msg_inv([CInv(MSG_BLOCK, block.sha256)])) test_node.wait_for_getheaders(timeout=30) test_node.send_header_for_blocks([block]) else: @@ -497,7 +497,7 @@ class CompactBlocksTest(BitcoinTestFramework): block = self.build_block_with_transactions(node, utxo, 10) self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue]) for tx in block.vtx[1:]: - test_node.send_message(msg_tx(tx)) + test_node.send_without_ping(msg_tx(tx)) test_node.sync_with_ping() # Make sure all transactions were accepted. mempool = node.getrawmempool() @@ -525,7 +525,7 @@ class CompactBlocksTest(BitcoinTestFramework): self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue]) # Relay the first 5 transactions from the block in advance for tx in block.vtx[1:6]: - test_node.send_message(msg_tx(tx)) + test_node.send_without_ping(msg_tx(tx)) test_node.sync_with_ping() # Make sure all transactions were accepted. mempool = node.getrawmempool() @@ -581,7 +581,7 @@ class CompactBlocksTest(BitcoinTestFramework): msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), []) num_to_request = random.randint(1, len(block.vtx)) msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request))) - test_node.send_message(msg) + test_node.send_without_ping(msg) test_node.wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) [tx.calc_sha256() for tx in block.vtx] @@ -616,7 +616,7 @@ class CompactBlocksTest(BitcoinTestFramework): block = from_hex(CBlock(), node.getblock(block_hash, False)) msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [len(block.vtx)]) with node.assert_debug_log(['getblocktxn with out-of-bounds tx indices']): - bad_peer.send_message(msg) + bad_peer.send_without_ping(msg) bad_peer.wait_for_disconnect() def test_low_work_compactblocks(self, test_node): @@ -651,7 +651,7 @@ class CompactBlocksTest(BitcoinTestFramework): test_node.wait_until(test_node.received_block_announcement, timeout=30) test_node.clear_block_announcement() - test_node.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) + test_node.send_without_ping(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) test_node.clear_block_announcement() @@ -660,7 +660,7 @@ class CompactBlocksTest(BitcoinTestFramework): test_node.clear_block_announcement() with p2p_lock: test_node.last_message.pop("block", None) - test_node.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) + test_node.send_without_ping(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) test_node.wait_until(lambda: "block" in test_node.last_message, timeout=30) with p2p_lock: test_node.last_message["block"].block.calc_sha256() @@ -768,7 +768,7 @@ class CompactBlocksTest(BitcoinTestFramework): block, cmpct_block = announce_cmpct_block(node, stalling_peer) for tx in block.vtx[1:]: - delivery_peer.send_message(msg_tx(tx)) + delivery_peer.send_without_ping(msg_tx(tx)) delivery_peer.sync_with_ping() mempool = node.getrawmempool() for tx in block.vtx[1:]: @@ -783,7 +783,7 @@ class CompactBlocksTest(BitcoinTestFramework): block, cmpct_block = announce_cmpct_block(node, stalling_peer) for tx in block.vtx[1:]: - delivery_peer.send_message(msg_tx(tx)) + delivery_peer.send_without_ping(msg_tx(tx)) delivery_peer.sync_with_ping() cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [CTxInWitness()] diff --git a/test/functional/p2p_compactblocks_blocksonly.py b/test/functional/p2p_compactblocks_blocksonly.py index b92efc875c..954175b772 100755 --- a/test/functional/p2p_compactblocks_blocksonly.py +++ b/test/functional/p2p_compactblocks_blocksonly.py @@ -93,19 +93,16 @@ class P2PCompactBlocksBlocksOnly(BitcoinTestFramework): block1 = self.build_block_on_tip() - p2p_conn_blocksonly.send_message(msg_headers(headers=[CBlockHeader(block1)])) - p2p_conn_blocksonly.sync_with_ping() + p2p_conn_blocksonly.send_and_ping(msg_headers(headers=[CBlockHeader(block1)])) assert_equal(p2p_conn_blocksonly.last_message['getdata'].inv, [CInv(MSG_BLOCK | MSG_WITNESS_FLAG, block1.sha256)]) - p2p_conn_high_bw.send_message(msg_headers(headers=[CBlockHeader(block1)])) - p2p_conn_high_bw.sync_with_ping() + p2p_conn_high_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)])) assert_equal(p2p_conn_high_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.sha256)]) self.log.info("Test that getdata(CMPCT) is still sent on BIP152 low bandwidth connections" " when no -blocksonly nodes are involved") p2p_conn_low_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)])) - p2p_conn_low_bw.sync_with_ping() assert_equal(p2p_conn_low_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.sha256)]) self.log.info("Test that -blocksonly nodes still serve compact blocks") @@ -115,7 +112,7 @@ class P2PCompactBlocksBlocksOnly(BitcoinTestFramework): return False return p2p_conn_blocksonly.last_message['cmpctblock'].header_and_shortids.header.rehash() == block.sha256 - p2p_conn_blocksonly.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, block0.sha256)])) + p2p_conn_blocksonly.send_without_ping(msg_getdata([CInv(MSG_CMPCT_BLOCK, block0.sha256)])) p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block0)) # Request BIP152 high bandwidth mode from the -blocksonly node. diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py deleted file mode 100755 index fbb5d716f5..0000000000 --- a/test/functional/p2p_dos_header_tree.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2019-2022 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test that we reject low difficulty headers to prevent our block tree from filling up with useless bloat""" - -from test_framework.messages import ( - CBlockHeader, - from_hex, -) -from test_framework.p2p import ( - P2PInterface, - msg_headers, -) -from test_framework.test_framework import BitcoinTestFramework - -import os - - -class RejectLowDifficultyHeadersTest(BitcoinTestFramework): - def set_test_params(self): - self.setup_clean_chain = True - self.chain = 'testnet3' # Use testnet chain because it has an early checkpoint - self.num_nodes = 2 - self.extra_args = [["-minimumchainwork=0x0", '-prune=550']] * self.num_nodes - - def add_options(self, parser): - parser.add_argument( - '--datafile', - default='data/blockheader_testnet3.hex', - help='Test data file (default: %(default)s)', - ) - - def run_test(self): - self.log.info("Read headers data") - self.headers_file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile) - with open(self.headers_file_path, encoding='utf-8') as headers_data: - h_lines = [l.strip() for l in headers_data.readlines()] - - # The headers data is taken from testnet3 for early blocks from genesis until the first checkpoint. There are - # two headers with valid POW at height 1 and 2, forking off from genesis. They are indicated by the FORK_PREFIX. - FORK_PREFIX = 'fork:' - self.headers = [l for l in h_lines if not l.startswith(FORK_PREFIX)] - self.headers_fork = [l[len(FORK_PREFIX):] for l in h_lines if l.startswith(FORK_PREFIX)] - - self.headers = [from_hex(CBlockHeader(), h) for h in self.headers] - self.headers_fork = [from_hex(CBlockHeader(), h) for h in self.headers_fork] - - self.log.info("Feed all non-fork headers, including and up to the first checkpoint") - peer_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface()) - peer_checkpoint.send_and_ping(msg_headers(self.headers)) - assert { - 'height': 546, - 'hash': '000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70', - 'branchlen': 546, - 'status': 'headers-only', - } in self.nodes[0].getchaintips() - - self.log.info("Feed all fork headers (fails due to checkpoint)") - with self.nodes[0].assert_debug_log(['bad-fork-prior-to-checkpoint']): - peer_checkpoint.send_message(msg_headers(self.headers_fork)) - peer_checkpoint.wait_for_disconnect() - - self.log.info("Feed all fork headers (succeeds without checkpoint)") - # On node 0 it succeeds because checkpoints are disabled - self.restart_node(0, extra_args=['-nocheckpoints', "-minimumchainwork=0x0", '-prune=550']) - peer_no_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface()) - peer_no_checkpoint.send_and_ping(msg_headers(self.headers_fork)) - assert { - "height": 2, - "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", - "branchlen": 2, - "status": "headers-only", - } in self.nodes[0].getchaintips() - - # On node 1 it succeeds because no checkpoint has been reached yet by a chain tip - peer_before_checkpoint = self.nodes[1].add_p2p_connection(P2PInterface()) - peer_before_checkpoint.send_and_ping(msg_headers(self.headers_fork)) - assert { - "height": 2, - "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", - "branchlen": 2, - "status": "headers-only", - } in self.nodes[1].getchaintips() - - -if __name__ == '__main__': - RejectLowDifficultyHeadersTest(__file__).main() diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py index 0d2bdcc429..9809faa682 100755 --- a/test/functional/p2p_eviction.py +++ b/test/functional/p2p_eviction.py @@ -34,13 +34,13 @@ from test_framework.wallet import MiniWallet class SlowP2PDataStore(P2PDataStore): def on_ping(self, message): time.sleep(0.1) - self.send_message(msg_pong(message.nonce)) + self.send_without_ping(msg_pong(message.nonce)) class SlowP2PInterface(P2PInterface): def on_ping(self, message): time.sleep(0.1) - self.send_message(msg_pong(message.nonce)) + self.send_without_ping(msg_pong(message.nonce)) class P2PEvict(BitcoinTestFramework): @@ -82,7 +82,7 @@ class P2PEvict(BitcoinTestFramework): txpeer.sync_with_ping() tx = self.wallet.create_self_transfer()['tx'] - txpeer.send_message(msg_tx(tx)) + txpeer.send_without_ping(msg_tx(tx)) protected_peers.add(current_peer) self.log.info("Create 8 peers and protect them from eviction by having faster pings") diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index e4aaf507cf..e3612f9852 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -62,7 +62,7 @@ class P2PBloomFilter(P2PInterface): else: want.inv.append(i) if len(want.inv): - self.send_message(want) + self.send_without_ping(want) def on_merkleblock(self, message): self._merkleblock_received = True @@ -146,11 +146,11 @@ class FilterTest(BitcoinTestFramework): self.log.info("Send a mempool msg after connecting and check that the relevant tx is announced") self.nodes[0].add_p2p_connection(filter_peer) filter_peer.send_and_ping(filter_peer.watch_filter_init) - filter_peer.send_message(msg_mempool()) + filter_peer.send_without_ping(msg_mempool()) filter_peer.wait_for_tx(rel_txid) self.log.info("Request the irrelevant transaction even though it was not announced") - filter_peer.send_message(msg_getdata([CInv(t=MSG_WTX, h=int(irr_wtxid, 16))])) + filter_peer.send_without_ping(msg_getdata([CInv(t=MSG_WTX, h=int(irr_wtxid, 16))])) self.log.info("We should get it anyway because it was in the mempool on connection to peer") filter_peer.wait_for_tx(irr_txid) @@ -242,7 +242,7 @@ class FilterTest(BitcoinTestFramework): version_without_fRelay.strSubVer = P2P_SUBVERSION version_without_fRelay.nServices = P2P_SERVICES version_without_fRelay.relay = 0 - filter_peer_without_nrelay.send_message(version_without_fRelay) + filter_peer_without_nrelay.send_without_ping(version_without_fRelay) filter_peer_without_nrelay.wait_for_verack() assert not self.nodes[0].getpeerinfo()[0]['relaytxes'] self.test_frelay_false(filter_peer_without_nrelay) diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index f49be62056..412de0149f 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -50,13 +50,13 @@ class P2PFingerprintTest(BitcoinTestFramework): def send_block_request(self, block_hash, node): msg = msg_getdata() msg.inv.append(CInv(MSG_BLOCK, block_hash)) - node.send_message(msg) + node.send_without_ping(msg) # Send a getheaders request for a given single block hash def send_header_request(self, block_hash, node): msg = msg_getheaders() msg.hashstop = block_hash - node.send_message(msg) + node.send_without_ping(msg) # Checks that stale blocks timestamped more than a month ago are not served # by the node while recent stale blocks and old active chain blocks are. @@ -78,7 +78,7 @@ class P2PFingerprintTest(BitcoinTestFramework): new_blocks = self.build_chain(5, block_hash, height, block_time) # Force reorg to a longer chain - node0.send_message(msg_headers(new_blocks)) + node0.send_without_ping(msg_headers(new_blocks)) node0.wait_for_getdata([x.sha256 for x in new_blocks]) for block in new_blocks: node0.send_and_ping(msg_block(block)) diff --git a/test/functional/p2p_ibd_stalling.py b/test/functional/p2p_ibd_stalling.py index 4348bf7ee9..1ae508085d 100755 --- a/test/functional/p2p_ibd_stalling.py +++ b/test/functional/p2p_ibd_stalling.py @@ -38,7 +38,7 @@ class P2PStaller(P2PDataStore): self.getdata_requests.append(inv.hash) if (inv.type & MSG_TYPE_MASK) == MSG_BLOCK: if (inv.hash != self.stall_block): - self.send_message(msg_block(self.block_store[inv.hash])) + self.send_without_ping(msg_block(self.block_store[inv.hash])) def on_getheaders(self, message): pass @@ -78,7 +78,7 @@ class P2PIBDStallingTest(BitcoinTestFramework): for id in range(NUM_PEERS): peers.append(node.add_outbound_p2p_connection(P2PStaller(stall_block), p2p_idx=id, connection_type="outbound-full-relay")) peers[-1].block_store = block_dict - peers[-1].send_message(headers_message) + peers[-1].send_without_ping(headers_message) # Need to wait until 1023 blocks are received - the magic total bytes number is a workaround in lack of an rpc # returning the number of downloaded (but not connected) blocks. @@ -96,7 +96,7 @@ class P2PIBDStallingTest(BitcoinTestFramework): headers_message.headers = [CBlockHeader(b) for b in blocks] with node.assert_debug_log(expected_msgs=['Stall started']): for p in peers: - p.send_message(headers_message) + p.send_without_ping(headers_message) self.all_sync_send_with_ping(peers) self.log.info("Check that the stalling peer is disconnected after 2 seconds") @@ -139,7 +139,7 @@ class P2PIBDStallingTest(BitcoinTestFramework): with node.assert_debug_log(expected_msgs=['Decreased stalling timeout to 2 seconds']): for p in peers: if p.is_connected and (stall_block in p.getdata_requests): - p.send_message(msg_block(block_dict[stall_block])) + p.send_without_ping(msg_block(block_dict[stall_block])) self.log.info("Check that all outstanding blocks get connected") self.wait_until(lambda: node.getblockcount() == NUM_BLOCKS) diff --git a/test/functional/p2p_initial_headers_sync.py b/test/functional/p2p_initial_headers_sync.py index 5c17b75677..595a5202f5 100755 --- a/test/functional/p2p_initial_headers_sync.py +++ b/test/functional/p2p_initial_headers_sync.py @@ -45,7 +45,7 @@ class HeadersSyncTest(BitcoinTestFramework): # An empty reply will clear the outstanding getheaders request, # allowing additional getheaders requests to be sent to this peer in # the future. - peer1.send_message(msg_headers()) + peer1.send_without_ping(msg_headers()) self.log.info("Connecting two more peers to node0") # Connect 2 more peers; they should not receive a getheaders yet @@ -66,7 +66,7 @@ class HeadersSyncTest(BitcoinTestFramework): self.log.info("Check that peer1 receives a getheaders in response") peer1.wait_for_getheaders(block_hash=best_block_hash) - peer1.send_message(msg_headers()) # Send empty response, see above + peer1.send_without_ping(msg_headers()) # Send empty response, see above self.log.info("Check that exactly 1 of {peer2, peer3} received a getheaders in response") count = 0 @@ -76,7 +76,7 @@ class HeadersSyncTest(BitcoinTestFramework): if "getheaders" in p.last_message: count += 1 peer_receiving_getheaders = p - p.send_message(msg_headers()) # Send empty response, see above + p.send_without_ping(msg_headers()) # Send empty response, see above assert_equal(count, 1) diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index bde01d5c95..d36f4c6a02 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -24,14 +24,14 @@ class InvalidLocatorTest(BitcoinTestFramework): self.log.info('Wait for disconnect when sending {} hashes in locator'.format(MAX_LOCATOR_SZ + 1)) exceed_max_peer = node.add_p2p_connection(P2PInterface()) msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ + 1), -1)] - exceed_max_peer.send_message(msg) + exceed_max_peer.send_without_ping(msg) exceed_max_peer.wait_for_disconnect() node.disconnect_p2ps() self.log.info('Wait for response when sending {} hashes in locator'.format(MAX_LOCATOR_SZ)) within_max_peer = node.add_p2p_connection(P2PInterface()) msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ), -1)] - within_max_peer.send_message(msg) + within_max_peer.send_without_ping(msg) if type(msg) is msg_getheaders: within_max_peer.wait_for_header(node.getbestblockhash()) else: diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index 507393fb70..c8228df802 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -261,7 +261,7 @@ class InvalidMessagesTest(BitcoinTestFramework): self.log.info("Test {} message of size {} is logged as misbehaving".format(msg_type, size)) with self.nodes[0].assert_debug_log(['Misbehaving', '{} message size = {}'.format(msg_type, size)]): conn = self.nodes[0].add_p2p_connection(P2PInterface()) - conn.send_message(msg) + conn.send_without_ping(msg) conn.wait_for_disconnect() self.nodes[0].disconnect_p2ps() @@ -304,7 +304,7 @@ class InvalidMessagesTest(BitcoinTestFramework): blockheader.nNonce += 1 blockheader.rehash() with self.nodes[0].assert_debug_log(['Misbehaving', 'header with invalid proof of work']): - peer.send_message(msg_headers([blockheader])) + peer.send_without_ping(msg_headers([blockheader])) peer.wait_for_disconnect() def test_noncontinuous_headers_msg(self): @@ -323,7 +323,7 @@ class InvalidMessagesTest(BitcoinTestFramework): # delete arbitrary block header somewhere in the middle to break link del block_headers[random.randrange(1, len(block_headers)-1)] with self.nodes[0].assert_debug_log(expected_msgs=MISBEHAVING_NONCONTINUOUS_HEADERS_MSGS): - peer.send_message(msg_headers(block_headers)) + peer.send_without_ping(msg_headers(block_headers)) peer.wait_for_disconnect() self.nodes[0].disconnect_p2ps() @@ -338,7 +338,7 @@ class InvalidMessagesTest(BitcoinTestFramework): self.log.info("(a) Send 80 messages, each of maximum valid data size (4MB)") for _ in range(80): - conn.send_message(msg_at_size) + conn.send_without_ping(msg_at_size) # Check that, even though the node is being hammered by nonsense from one # connection, it can still service other peers in a timely way. diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 7848cdaadb..4b74c55ae8 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -84,8 +84,8 @@ class NoVerackIdlePeer(LazyPeer): # list! def on_version(self, message): self.version_received = True - self.send_message(msg_ping()) - self.send_message(msg_getaddr()) + self.send_without_ping(msg_ping()) + self.send_without_ping(msg_getaddr()) class P2PVersionStore(P2PInterface): @@ -121,7 +121,7 @@ class P2PLeakTest(BitcoinTestFramework): # Pre-wtxidRelay peer that sends a version but not a verack and does not support feature negotiation # messages which start at nVersion == 70016 pre_wtxidrelay_peer = self.nodes[0].add_p2p_connection(NoVerackIdlePeer(), send_version=False, wait_for_verack=False) - pre_wtxidrelay_peer.send_message(self.create_old_version(70015)) + pre_wtxidrelay_peer.send_without_ping(self.create_old_version(70015)) # Wait until the peer gets the verack in response to the version. Though, don't wait for the node to receive the # verack, since the peer never sent one @@ -173,7 +173,7 @@ class P2PLeakTest(BitcoinTestFramework): self.log.info('Check that old peers are disconnected') p2p_old_peer = self.nodes[0].add_p2p_connection(P2PInterface(), send_version=False, wait_for_verack=False) with self.nodes[0].assert_debug_log(["using obsolete version 31799, disconnecting peer=5"]): - p2p_old_peer.send_message(self.create_old_version(31799)) + p2p_old_peer.send_without_ping(self.create_old_version(31799)) p2p_old_peer.wait_for_disconnect() diff --git a/test/functional/p2p_mutated_blocks.py b/test/functional/p2p_mutated_blocks.py index 4a790168da..6d909ded05 100755 --- a/test/functional/p2p_mutated_blocks.py +++ b/test/functional/p2p_mutated_blocks.py @@ -60,7 +60,7 @@ class MutatedBlocksTest(BitcoinTestFramework): # Announce the new block via a compact block through the honest relayer cmpctblock = HeaderAndShortIDs() cmpctblock.initialize_from_block(block, use_witness=True) - honest_relayer.send_message(msg_cmpctblock(cmpctblock.to_p2p())) + honest_relayer.send_without_ping(msg_cmpctblock(cmpctblock.to_p2p())) # Wait for a `getblocktxn` that attempts to fetch the self-transfer def self_transfer_requested(): @@ -80,7 +80,7 @@ class MutatedBlocksTest(BitcoinTestFramework): # Attempt to clear the honest relayer's download request by sending the # mutated block (as the attacker). with self.nodes[0].assert_debug_log(expected_msgs=["Block mutated: bad-txnmrklroot, hashMerkleRoot mismatch"]): - attacker.send_message(msg_block(mutated_block)) + attacker.send_without_ping(msg_block(mutated_block)) # Attacker should get disconnected for sending a mutated block attacker.wait_for_disconnect(timeout=5) @@ -107,7 +107,7 @@ class MutatedBlocksTest(BitcoinTestFramework): # Check that non-connecting block causes disconnect assert_equal(len(self.nodes[0].getpeerinfo()), 2) with self.nodes[0].assert_debug_log(expected_msgs=["AcceptBlock FAILED (prev-blk-not-found)"]): - attacker.send_message(msg_block(block_missing_prev)) + attacker.send_without_ping(msg_block(block_missing_prev)) attacker.wait_for_disconnect(timeout=5) diff --git a/test/functional/p2p_nobloomfilter_messages.py b/test/functional/p2p_nobloomfilter_messages.py index dd2dc9ae69..835230fa7e 100755 --- a/test/functional/p2p_nobloomfilter_messages.py +++ b/test/functional/p2p_nobloomfilter_messages.py @@ -26,7 +26,7 @@ class P2PNoBloomFilterMessages(BitcoinTestFramework): def test_message_causes_disconnect(self, message): """Add a p2p connection that sends a message and check that it disconnects.""" peer = self.nodes[0].add_p2p_connection(P2PInterface()) - peer.send_message(message) + peer.send_without_ping(message) peer.wait_for_disconnect() assert_equal(self.nodes[0].getconnectioncount(), 0) diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index 7788be6adb..73f52b0e49 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -40,7 +40,7 @@ class P2PIgnoreInv(P2PInterface): def send_getdata_for_block(self, blockhash): getdata_request = msg_getdata() getdata_request.inv.append(CInv(MSG_BLOCK, int(blockhash, 16))) - self.send_message(getdata_request) + self.send_without_ping(getdata_request) class NodeNetworkLimitedTest(BitcoinTestFramework): def set_test_params(self): diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index 5cf616b3ef..addb5027f3 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -249,7 +249,7 @@ class PackageRelayTest(BitcoinTestFramework): assert tx_orphan_bad_wit.rehash() not in node_mempool # 5. Have the other peer send the tx too, so that tx_orphan_bad_wit package is attempted. - bad_orphan_sender.send_message(msg_tx(low_fee_parent["tx"])) + bad_orphan_sender.send_without_ping(msg_tx(low_fee_parent["tx"])) bad_orphan_sender.wait_for_disconnect() # The peer that didn't provide the orphan should not be disconnected. diff --git a/test/functional/p2p_orphan_handling.py b/test/functional/p2p_orphan_handling.py index 755cb8f3e9..e839b2d987 100755 --- a/test/functional/p2p_orphan_handling.py +++ b/test/functional/p2p_orphan_handling.py @@ -312,7 +312,7 @@ class OrphanHandlingTest(BitcoinTestFramework): # Even though the peer would send a notfound for the "old" confirmed transaction, the node # doesn't give up on the orphan. Once all of the missing parents are received, it should be # submitted to mempool. - peer.send_message(msg_notfound(vec=[CInv(MSG_WITNESS_TX, int(txid_conf_old, 16))])) + peer.send_without_ping(msg_notfound(vec=[CInv(MSG_WITNESS_TX, int(txid_conf_old, 16))])) # Sync with ping to ensure orphans are reconsidered peer.send_and_ping(msg_tx(missing_tx["tx"])) assert_equal(node.getmempoolentry(orphan["txid"])["ancestorcount"], 3) @@ -611,7 +611,7 @@ class OrphanHandlingTest(BitcoinTestFramework): tx_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_1["new_utxo"]) parent_orphans.append(tx_parent_1["tx"]) orphans.append(tx_child_1["tx"]) - peer_1.send_message(msg_tx(tx_child_1["tx"])) + peer_1.send_without_ping(msg_tx(tx_child_1["tx"])) peer_1.sync_with_ping() orphanage = node.getorphantxs() @@ -771,7 +771,7 @@ class OrphanHandlingTest(BitcoinTestFramework): node.bumpmocktime(NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY) peer1.wait_for_getdata([int(parent_missing["txid"], 16)]) - # Replace parent_peekaboo_AB so that is is a newly missing parent. + # Replace parent_peekaboo_AB so that is a newly missing parent. # Then, replace the replacement so that it can be resubmitted. node.sendrawtransaction(tx_replacer_BC["hex"]) assert tx_replacer_BC["txid"] in node.getrawmempool() @@ -788,6 +788,8 @@ class OrphanHandlingTest(BitcoinTestFramework): # Disconnect peer1. peer2 should become the new candidate for orphan resolution. peer1.peer_disconnect() + self.wait_until(lambda: node.num_test_p2p_connections() == 1) + peer2.sync_with_ping() # Sync with the 'net' thread which completes the disconnection fully node.bumpmocktime(TXREQUEST_TIME_SKIP) self.wait_until(lambda: len(node.getorphantxs(verbosity=2)[0]["from"]) == 1) # Both parents should be requested, now that they are both missing. diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 9caf5a19aa..0f04a87707 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -174,9 +174,9 @@ class TestP2PConn(P2PInterface): self.last_message.pop("getdata", None) if use_wtxid: wtxid = tx.calc_sha256(True) - self.send_message(msg_inv(inv=[CInv(MSG_WTX, wtxid)])) + self.send_without_ping(msg_inv(inv=[CInv(MSG_WTX, wtxid)])) else: - self.send_message(msg_inv(inv=[CInv(MSG_TX, tx.sha256)])) + self.send_without_ping(msg_inv(inv=[CInv(MSG_TX, tx.sha256)])) if success: if use_wtxid: @@ -192,17 +192,17 @@ class TestP2PConn(P2PInterface): msg = msg_headers() msg.headers = [CBlockHeader(block)] if use_header: - self.send_message(msg) + self.send_without_ping(msg) else: - self.send_message(msg_inv(inv=[CInv(MSG_BLOCK, block.sha256)])) + self.send_without_ping(msg_inv(inv=[CInv(MSG_BLOCK, block.sha256)])) self.wait_for_getheaders(block_hash=block.hashPrevBlock, timeout=timeout) - self.send_message(msg) + self.send_without_ping(msg) self.wait_for_getdata([block.sha256], timeout=timeout) def request_block(self, blockhash, inv_type, timeout=60): with p2p_lock: self.last_message.pop("block", None) - self.send_message(msg_getdata(inv=[CInv(inv_type, blockhash)])) + self.send_without_ping(msg_getdata(inv=[CInv(inv_type, blockhash)])) self.wait_for_block(blockhash, timeout=timeout) return self.last_message["block"].block @@ -373,7 +373,7 @@ class SegWitTest(BitcoinTestFramework): # Send an empty headers message, to clear out any prior getheaders # messages that our peer may be waiting for us on. - self.test_node.send_message(msg_headers()) + self.test_node.send_without_ping(msg_headers()) self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False) assert self.test_node.last_message["getdata"].inv[0].type == blocktype @@ -444,7 +444,7 @@ class SegWitTest(BitcoinTestFramework): # to announce this block. msg = msg_headers() msg.headers = [CBlockHeader(block4)] - self.old_node.send_message(msg) + self.old_node.send_without_ping(msg) self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0]) assert block4.sha256 not in self.old_node.getdataset diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index db706556d8..7dc91305f3 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -115,28 +115,28 @@ class BaseNode(P2PInterface): msg = msg_getdata() for x in block_hashes: msg.inv.append(CInv(MSG_BLOCK, x)) - self.send_message(msg) + self.send_without_ping(msg) def send_get_headers(self, locator, hashstop): msg = msg_getheaders() msg.locator.vHave = locator msg.hashstop = hashstop - self.send_message(msg) + self.send_without_ping(msg) def send_block_inv(self, blockhash): msg = msg_inv() msg.inv = [CInv(MSG_BLOCK, blockhash)] - self.send_message(msg) + self.send_without_ping(msg) def send_header_for_blocks(self, new_blocks): headers_message = msg_headers() headers_message.headers = [CBlockHeader(b) for b in new_blocks] - self.send_message(headers_message) + self.send_without_ping(headers_message) def send_getblocks(self, locator): getblocks_message = msg_getblocks() getblocks_message.locator.vHave = locator - self.send_message(getblocks_message) + self.send_without_ping(getblocks_message) def wait_for_block_announcement(self, block_hash, timeout=60): test_function = lambda: self.last_blockhash_announced == block_hash @@ -252,7 +252,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.sync_with_ping() assert_equal(test_node.block_announced, False) inv_node.clear_block_announcements() - test_node.send_message(msg_block(block)) + test_node.send_without_ping(msg_block(block)) inv_node.check_last_inv_announcement(inv=[int(block.hash, 16)]) def test_nonnull_locators(self, test_node, inv_node): @@ -298,7 +298,7 @@ class SendHeadersTest(BitcoinTestFramework): # PART 2 # 2. Send a sendheaders message and test that headers announcements # commence and keep working. - test_node.send_message(msg_sendheaders()) + test_node.send_without_ping(msg_sendheaders()) prev_tip = int(self.nodes[0].getbestblockhash(), 16) test_node.send_get_headers(locator=[prev_tip], hashstop=0) test_node.sync_with_ping() @@ -348,7 +348,7 @@ class SendHeadersTest(BitcoinTestFramework): # getdata requests (the check is further down) inv_node.send_header_for_blocks(blocks) inv_node.sync_with_ping() - [test_node.send_message(msg_block(x)) for x in blocks] + [test_node.send_without_ping(msg_block(x)) for x in blocks] test_node.sync_with_ping() inv_node.sync_with_ping() # This block should not be announced to the inv node (since it also @@ -444,7 +444,7 @@ class SendHeadersTest(BitcoinTestFramework): tip = blocks[-1].sha256 block_time += 1 height += 1 - inv_node.send_message(msg_block(blocks[-1])) + inv_node.send_without_ping(msg_block(blocks[-1])) inv_node.sync_with_ping() # Make sure blocks are processed test_node.last_message.pop("getdata", None) @@ -467,7 +467,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.sync_with_ping() test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=DIRECT_FETCH_RESPONSE_TIME) - [test_node.send_message(msg_block(x)) for x in blocks] + [test_node.send_without_ping(msg_block(x)) for x in blocks] test_node.sync_with_ping() @@ -514,7 +514,7 @@ class SendHeadersTest(BitcoinTestFramework): self.log.info("Part 4: success!") # Now deliver all those blocks we announced. - [test_node.send_message(msg_block(x)) for x in blocks] + [test_node.send_without_ping(msg_block(x)) for x in blocks] self.log.info("Part 5: Testing handling of unconnecting headers") # First we test that receipt of an unconnecting header doesn't prevent @@ -537,7 +537,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.wait_for_getheaders(block_hash=expected_hash) test_node.send_header_for_blocks(blocks) test_node.wait_for_getdata([x.sha256 for x in blocks]) - [test_node.send_message(msg_block(x)) for x in blocks] + [test_node.send_without_ping(msg_block(x)) for x in blocks] test_node.sync_with_ping() assert_equal(int(self.nodes[0].getbestblockhash(), 16), blocks[1].sha256) expected_hash = blocks[1].sha256 diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py index 3f1fca5c78..43c171f26f 100755 --- a/test/functional/p2p_sendtxrcncl.py +++ b/test/functional/p2p_sendtxrcncl.py @@ -31,7 +31,7 @@ class PeerNoVerack(P2PInterface): # comment in add_p2p_connection). self.send_version() if message.nVersion >= 70016 and self.wtxidrelay: - self.send_message(msg_wtxidrelay()) + self.send_without_ping(msg_wtxidrelay()) class SendTxrcnclReceiver(P2PInterface): def __init__(self): @@ -92,7 +92,7 @@ class SendTxRcnclTest(BitcoinTestFramework): pre_wtxid_version_msg.strSubVer = P2P_SUBVERSION pre_wtxid_version_msg.nServices = P2P_SERVICES pre_wtxid_version_msg.relay = 1 - peer.send_message(pre_wtxid_version_msg) + peer.send_without_ping(pre_wtxid_version_msg) peer.wait_for_verack() assert not peer.sendtxrcncl_msg_received self.nodes[0].disconnect_p2ps() @@ -104,7 +104,7 @@ class SendTxRcnclTest(BitcoinTestFramework): no_txrelay_version_msg.strSubVer = P2P_SUBVERSION no_txrelay_version_msg.nServices = P2P_SERVICES no_txrelay_version_msg.relay = 0 - peer.send_message(no_txrelay_version_msg) + peer.send_without_ping(no_txrelay_version_msg) peer.wait_for_verack() assert not peer.sendtxrcncl_msg_received self.nodes[0].disconnect_p2ps() @@ -117,7 +117,7 @@ class SendTxRcnclTest(BitcoinTestFramework): no_txrelay_version_msg.strSubVer = P2P_SUBVERSION no_txrelay_version_msg.nServices = P2P_SERVICES no_txrelay_version_msg.relay = 0 - peer.send_message(no_txrelay_version_msg) + peer.send_without_ping(no_txrelay_version_msg) peer.wait_for_verack() assert peer.nServices & NODE_BLOOM != 0 assert not peer.sendtxrcncl_msg_received @@ -166,17 +166,17 @@ class SendTxRcnclTest(BitcoinTestFramework): self.log.info('valid SENDTXRCNCL received') peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) with self.nodes[0].assert_debug_log(["received: sendtxrcncl"]): - peer.send_message(create_sendtxrcncl_msg()) + peer.send_without_ping(create_sendtxrcncl_msg()) self.log.info('second SENDTXRCNCL triggers a disconnect') with self.nodes[0].assert_debug_log(["(sendtxrcncl received from already registered peer), disconnecting peer=0"]): - peer.send_message(create_sendtxrcncl_msg()) + peer.send_without_ping(create_sendtxrcncl_msg()) peer.wait_for_disconnect() self.restart_node(0, []) self.log.info('SENDTXRCNCL if no txreconciliation supported is ignored') peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) with self.nodes[0].assert_debug_log(['ignored, as our node does not have txreconciliation enabled']): - peer.send_message(create_sendtxrcncl_msg()) + peer.send_without_ping(create_sendtxrcncl_msg()) self.nodes[0].disconnect_p2ps() self.restart_node(0, ["-txreconciliation"]) @@ -186,7 +186,7 @@ class SendTxRcnclTest(BitcoinTestFramework): sendtxrcncl_low_version.version = 0 peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) with self.nodes[0].assert_debug_log(["txreconciliation protocol violation"]): - peer.send_message(sendtxrcncl_low_version) + peer.send_without_ping(sendtxrcncl_low_version) peer.wait_for_disconnect() self.log.info('SENDTXRCNCL with version=2 is valid') @@ -194,7 +194,7 @@ class SendTxRcnclTest(BitcoinTestFramework): sendtxrcncl_higher_version.version = 2 peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False) with self.nodes[0].assert_debug_log(['Register peer=1']): - peer.send_message(sendtxrcncl_higher_version) + peer.send_without_ping(sendtxrcncl_higher_version) self.nodes[0].disconnect_p2ps() self.log.info('unexpected SENDTXRCNCL is ignored') @@ -204,22 +204,22 @@ class SendTxRcnclTest(BitcoinTestFramework): old_version_msg.strSubVer = P2P_SUBVERSION old_version_msg.nServices = P2P_SERVICES old_version_msg.relay = 1 - peer.send_message(old_version_msg) + peer.send_without_ping(old_version_msg) with self.nodes[0].assert_debug_log(['Ignore unexpected txreconciliation signal']): - peer.send_message(create_sendtxrcncl_msg()) + peer.send_without_ping(create_sendtxrcncl_msg()) self.nodes[0].disconnect_p2ps() self.log.info('sending SENDTXRCNCL after sending VERACK triggers a disconnect') peer = self.nodes[0].add_p2p_connection(P2PInterface()) with self.nodes[0].assert_debug_log(["sendtxrcncl received after verack"]): - peer.send_message(create_sendtxrcncl_msg()) + peer.send_without_ping(create_sendtxrcncl_msg()) peer.wait_for_disconnect() self.log.info('SENDTXRCNCL without WTXIDRELAY is ignored (recon state is erased after VERACK)') peer = self.nodes[0].add_p2p_connection(PeerNoVerack(wtxidrelay=False), send_version=True, wait_for_verack=False) with self.nodes[0].assert_debug_log(['Forget txreconciliation state of peer']): - peer.send_message(create_sendtxrcncl_msg()) - peer.send_message(msg_verack()) + peer.send_without_ping(create_sendtxrcncl_msg()) + peer.send_without_ping(msg_verack()) self.nodes[0].disconnect_p2ps() # Now, *receiving* from *outbound*. @@ -227,7 +227,7 @@ class SendTxRcnclTest(BitcoinTestFramework): peer = self.nodes[0].add_outbound_p2p_connection( PeerNoVerack(), wait_for_verack=False, p2p_idx=0, connection_type="block-relay-only") with self.nodes[0].assert_debug_log(["we indicated no tx relay, disconnecting peer=5"]): - peer.send_message(create_sendtxrcncl_msg()) + peer.send_without_ping(create_sendtxrcncl_msg()) peer.wait_for_disconnect() diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py index ce01547887..73a6a866e8 100755 --- a/test/functional/p2p_timeouts.py +++ b/test/functional/p2p_timeouts.py @@ -67,10 +67,10 @@ class TimeoutsTest(BitcoinTestFramework): assert no_send_node.is_connected with self.nodes[0].assert_debug_log(['Unsupported message "ping" prior to verack from peer=0']): - no_verack_node.send_message(msg_ping()) + no_verack_node.send_without_ping(msg_ping()) with self.nodes[0].assert_debug_log(['non-version message before version handshake. Message "ping" from peer=1']): - no_version_node.send_message(msg_ping()) + no_version_node.send_without_ping(msg_ping()) self.mock_forward(1) assert "version" in no_verack_node.last_message @@ -79,8 +79,8 @@ class TimeoutsTest(BitcoinTestFramework): assert no_version_node.is_connected assert no_send_node.is_connected - no_verack_node.send_message(msg_ping()) - no_version_node.send_message(msg_ping()) + no_verack_node.send_without_ping(msg_ping()) + no_version_node.send_without_ping(msg_ping()) if self.options.v2transport: expected_timeout_logs = [ diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py index a5e3905990..2b75c1193d 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -143,13 +143,13 @@ class TxDownloadTest(BitcoinTestFramework): mock_time = int(time.time() + 1) self.nodes[0].setmocktime(mock_time) for i in range(MAX_PEER_TX_REQUEST_IN_FLIGHT): - p.send_message(msg_inv([CInv(t=MSG_WTX, h=txids[i])])) + p.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=txids[i])])) p.sync_with_ping() mock_time += NONPREF_PEER_TX_DELAY self.nodes[0].setmocktime(mock_time) p.wait_until(lambda: p.tx_getdata_count >= MAX_PEER_TX_REQUEST_IN_FLIGHT) for i in range(MAX_PEER_TX_REQUEST_IN_FLIGHT, len(txids)): - p.send_message(msg_inv([CInv(t=MSG_WTX, h=txids[i])])) + p.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=txids[i])])) p.sync_with_ping() self.log.info("No more than {} requests should be seen within {} seconds after announcement".format(MAX_PEER_TX_REQUEST_IN_FLIGHT, NONPREF_PEER_TX_DELAY + OVERLOADED_PEER_TX_DELAY - 1)) self.nodes[0].setmocktime(mock_time + NONPREF_PEER_TX_DELAY + OVERLOADED_PEER_TX_DELAY - 1) @@ -166,7 +166,7 @@ class TxDownloadTest(BitcoinTestFramework): peer1 = self.nodes[0].add_p2p_connection(TestP2PConn()) peer2 = self.nodes[0].add_p2p_connection(TestP2PConn()) for p in [peer1, peer2]: - p.send_message(msg_inv([CInv(t=MSG_WTX, h=WTXID)])) + p.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=WTXID)])) # One of the peers is asked for the tx peer2.wait_until(lambda: sum(p.tx_getdata_count for p in [peer1, peer2]) == 1) with p2p_lock: @@ -182,7 +182,7 @@ class TxDownloadTest(BitcoinTestFramework): peer1 = self.nodes[0].add_p2p_connection(TestP2PConn()) peer2 = self.nodes[0].add_p2p_connection(TestP2PConn()) for p in [peer1, peer2]: - p.send_message(msg_inv([CInv(t=MSG_WTX, h=WTXID)])) + p.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=WTXID)])) # One of the peers is asked for the tx peer2.wait_until(lambda: sum(p.tx_getdata_count for p in [peer1, peer2]) == 1) with p2p_lock: @@ -198,7 +198,7 @@ class TxDownloadTest(BitcoinTestFramework): peer1 = self.nodes[0].add_p2p_connection(TestP2PConn()) peer2 = self.nodes[0].add_p2p_connection(TestP2PConn()) for p in [peer1, peer2]: - p.send_message(msg_inv([CInv(t=MSG_WTX, h=WTXID)])) + p.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=WTXID)])) # One of the peers is asked for the tx peer2.wait_until(lambda: sum(p.tx_getdata_count for p in [peer1, peer2]) == 1) with p2p_lock: @@ -229,8 +229,7 @@ class TxDownloadTest(BitcoinTestFramework): else: peer = self.nodes[0].add_p2p_connection(TestP2PConn()) - peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) - peer.sync_with_ping() + peer.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) if connection_type != ConnectionType.INBOUND: peer.wait_until(lambda: peer.tx_getdata_count >= 1, timeout=1) else: @@ -250,8 +249,7 @@ class TxDownloadTest(BitcoinTestFramework): # of which is preferred and one which is not unresponsive_peer = self.nodes[0].add_outbound_p2p_connection( TestP2PConn(), wait_for_verack=True, p2p_idx=0, connection_type="outbound-full-relay") - unresponsive_peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) - unresponsive_peer.sync_with_ping() + unresponsive_peer.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) unresponsive_peer.wait_until(lambda: unresponsive_peer.tx_getdata_count >= 1, timeout=1) # A bunch of incoming (non-preferred) connections that advertise the same tx @@ -259,8 +257,7 @@ class TxDownloadTest(BitcoinTestFramework): NUM_INBOUND = 10 for _ in range(NUM_INBOUND): non_pref_peers.append(self.nodes[0].add_p2p_connection(TestP2PConn())) - non_pref_peers[-1].send_message(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) - non_pref_peers[-1].sync_with_ping() + non_pref_peers[-1].send_and_ping(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) # Check that no request made due to in-flight self.nodes[0].bumpmocktime(NONPREF_PEER_TX_DELAY) @@ -272,8 +269,7 @@ class TxDownloadTest(BitcoinTestFramework): # upon advertisement pref_peer = self.nodes[0].add_outbound_p2p_connection( TestP2PConn(), wait_for_verack=True, p2p_idx=1, connection_type="outbound-full-relay") - pref_peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) - pref_peer.sync_with_ping() + pref_peer.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)])) assert_equal(len(self.nodes[0].getpeerinfo()), NUM_INBOUND + 2) @@ -302,8 +298,7 @@ class TxDownloadTest(BitcoinTestFramework): # Add a second wtxid-relay connection otherwise TXID_RELAY_DELAY is waived in # lack of wtxid-relay peers self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=True)) - peer.send_message(msg_inv([CInv(t=MSG_TX, h=0xff11ff11)])) - peer.sync_with_ping() + peer.send_and_ping(msg_inv([CInv(t=MSG_TX, h=0xff11ff11)])) with p2p_lock: assert_equal(peer.tx_getdata_count, 0 if glob_wtxid else 1) self.nodes[0].setmocktime(mock_time + TXID_RELAY_DELAY) @@ -313,19 +308,19 @@ class TxDownloadTest(BitcoinTestFramework): self.log.info('Test how large inv batches are handled with relay permission') self.restart_node(0, extra_args=['-whitelist=relay@127.0.0.1']) peer = self.nodes[0].add_p2p_connection(TestP2PConn()) - peer.send_message(msg_inv([CInv(t=MSG_WTX, h=wtxid) for wtxid in range(MAX_PEER_TX_ANNOUNCEMENTS + 1)])) + peer.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=wtxid) for wtxid in range(MAX_PEER_TX_ANNOUNCEMENTS + 1)])) peer.wait_until(lambda: peer.tx_getdata_count == MAX_PEER_TX_ANNOUNCEMENTS + 1) self.log.info('Test how large inv batches are handled without relay permission') self.restart_node(0) peer = self.nodes[0].add_p2p_connection(TestP2PConn()) - peer.send_message(msg_inv([CInv(t=MSG_WTX, h=wtxid) for wtxid in range(MAX_PEER_TX_ANNOUNCEMENTS + 1)])) + peer.send_without_ping(msg_inv([CInv(t=MSG_WTX, h=wtxid) for wtxid in range(MAX_PEER_TX_ANNOUNCEMENTS + 1)])) peer.wait_until(lambda: peer.tx_getdata_count == MAX_PEER_TX_ANNOUNCEMENTS) peer.sync_with_ping() def test_spurious_notfound(self): self.log.info('Check that spurious notfound is ignored') - self.nodes[0].p2ps[0].send_message(msg_notfound(vec=[CInv(MSG_TX, 1)])) + self.nodes[0].p2ps[0].send_without_ping(msg_notfound(vec=[CInv(MSG_TX, 1)])) def test_rejects_filter_reset(self): self.log.info('Check that rejected tx is not requested again') diff --git a/test/functional/p2p_tx_privacy.py b/test/functional/p2p_tx_privacy.py index afe9df8a0f..688f27f582 100755 --- a/test/functional/p2p_tx_privacy.py +++ b/test/functional/p2p_tx_privacy.py @@ -39,7 +39,7 @@ class P2PTxSpy(P2PInterface): self.all_invs = [] def on_version(self, message): - self.send_message(msg_wtxidrelay()) + self.send_without_ping(msg_wtxidrelay()) def on_inv(self, message): self.all_invs += message.inv diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 1430131a97..34c2654b9b 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -170,7 +170,7 @@ class AcceptBlockTest(BitcoinTestFramework): tip = next_block # Now send the block at height 5 and check that it wasn't accepted (missing header) - test_node.send_message(msg_block(all_blocks[1])) + test_node.send_without_ping(msg_block(all_blocks[1])) test_node.wait_for_disconnect() assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock, all_blocks[1].hash) assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblockheader, all_blocks[1].hash) @@ -179,13 +179,13 @@ class AcceptBlockTest(BitcoinTestFramework): # The block at height 5 should be accepted if we provide the missing header, though headers_message = msg_headers() headers_message.headers.append(CBlockHeader(all_blocks[0])) - test_node.send_message(headers_message) + test_node.send_without_ping(headers_message) test_node.send_and_ping(msg_block(all_blocks[1])) self.nodes[0].getblock(all_blocks[1].hash) # Now send the blocks in all_blocks for i in range(288): - test_node.send_message(msg_block(all_blocks[i])) + test_node.send_without_ping(msg_block(all_blocks[i])) test_node.sync_with_ping() # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead @@ -215,7 +215,7 @@ class AcceptBlockTest(BitcoinTestFramework): with p2p_lock: # Clear state so we can check the getdata request test_node.last_message.pop("getdata", None) - test_node.send_message(msg_inv([CInv(MSG_BLOCK, block_h3.sha256)])) + test_node.send_without_ping(msg_inv([CInv(MSG_BLOCK, block_h3.sha256)])) test_node.sync_with_ping() with p2p_lock: @@ -262,13 +262,13 @@ class AcceptBlockTest(BitcoinTestFramework): assert tip_entry_found assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", self.nodes[0].getblock, block_292.hash) - test_node.send_message(msg_block(block_289f)) + test_node.send_without_ping(msg_block(block_289f)) test_node.send_and_ping(msg_block(block_290f)) self.nodes[0].getblock(block_289f.hash) self.nodes[0].getblock(block_290f.hash) - test_node.send_message(msg_block(block_291)) + test_node.send_without_ping(msg_block(block_291)) # At this point we've sent an obviously-bogus block, wait for full processing # and assume disconnection @@ -287,7 +287,7 @@ class AcceptBlockTest(BitcoinTestFramework): block_293.solve() headers_message = msg_headers() headers_message.headers.append(CBlockHeader(block_293)) - test_node.send_message(headers_message) + test_node.send_without_ping(headers_message) test_node.wait_for_disconnect() # 9. Connect node1 to node0 and ensure it is able to sync diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py index 4a415d57f5..f4036abdad 100755 --- a/test/functional/rpc_deprecated.py +++ b/test/functional/rpc_deprecated.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2017-2021 The Bitcoin Core developers +# Copyright (c) 2017-2025 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test deprecation of RPC calls.""" @@ -7,23 +7,23 @@ from test_framework.test_framework import BitcoinTestFramework class DeprecatedRpcTest(BitcoinTestFramework): def set_test_params(self): - self.num_nodes = 2 + self.num_nodes = 1 self.setup_clean_chain = True - self.extra_args = [[], ['-deprecatedrpc=bumpfee']] + self.extra_args = [[]] def run_test(self): - # This test should be used to verify correct behaviour of deprecated - # RPC methods with and without the -deprecatedrpc flags. For example: + # This test should be used to verify the errors of the currently + # deprecated RPC methods (without the -deprecatedrpc flag) until + # such RPCs are fully removed. For example: # - # In set_test_params: - # self.extra_args = [[], ["-deprecatedrpc=generate"]] - # - # In run_test: # self.log.info("Test generate RPC") # assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].rpc.generate, 1) - # self.generate(self.nodes[1], 1) + # + # Please ensure that for all the RPC methods tested here, there is + # at least one other functional test that still tests the RPCs + # functionality using the respective -deprecatedrpc flag. - self.log.info("No tested deprecated RPC methods") + self.log.info("Currently no tests for deprecated RPC methods") if __name__ == '__main__': DeprecatedRpcTest(__file__).main() diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py index e4e6d6f0f3..65aa6dd47c 100755 --- a/test/functional/rpc_getdescriptorinfo.py +++ b/test/functional/rpc_getdescriptorinfo.py @@ -11,6 +11,7 @@ from test_framework.util import ( assert_equal, assert_raises_rpc_error, ) +from test_framework.wallet_util import generate_keypair class DescriptorTest(BitcoinTestFramework): @@ -36,6 +37,12 @@ class DescriptorTest(BitcoinTestFramework): assert_raises_rpc_error(-1, 'getdescriptorinfo', self.nodes[0].getdescriptorinfo) assert_raises_rpc_error(-3, 'JSON value of type number is not of expected type string', self.nodes[0].getdescriptorinfo, 1) assert_raises_rpc_error(-5, "'' is not a valid descriptor function", self.nodes[0].getdescriptorinfo, "") + assert_raises_rpc_error(-5, "pk(): Key ' 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, "pk( 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)") + assert_raises_rpc_error(-5, "pk(): Key '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 ' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 )") + assert_raises_rpc_error(-5, "Multi: Key ' 03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, "wsh(multi(2, 03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))") + assert_raises_rpc_error(-5, "Multi: Key ' 03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, "wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7, 03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a))") + priv_key = generate_keypair(wif=True)[0] + assert_raises_rpc_error(-5, f"pk(): Key ' {priv_key}' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, f"pk( {priv_key})") # P2PK output with the specified public key. self.test_desc('pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)', isrange=False, issolvable=True, hasprivatekeys=False) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 8042bdf071..04e68a97af 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -999,7 +999,7 @@ class PSBTTest(BitcoinTestFramework): {'hex': '0200000001dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd0000000000000000000100000000000000000000000000', 'complete': True}) self.log.info("Test we don't crash when making a 0-value funded transaction at 0 fee without forcing an input selection") - assert_raises_rpc_error(-4, "Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input", self.nodes[0].walletcreatefundedpsbt, [], [{"data": "deadbeef"}], 0, {"fee_rate": "0"}) + assert_raises_rpc_error(-4, "Transaction requires one destination of non-zero value, a non-zero feerate, or a pre-selected input", self.nodes[0].walletcreatefundedpsbt, [], [{"data": "deadbeef"}], 0, {"fee_rate": "0"}) self.log.info("Test descriptorprocesspsbt updates and signs a psbt with descriptors") diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 18b1fc1896..3c3eb9fcb6 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -34,6 +34,7 @@ from test_framework.util import ( assert_equal, assert_greater_than, assert_raises_rpc_error, + sync_txindex, ) from test_framework.wallet import ( getnewdestination, @@ -70,7 +71,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.num_nodes = 3 self.extra_args = [ ["-txindex"], - ["-txindex"], + [], ["-fastprune", "-prune=1"], ] # whitelist peers to speed up tx relay / mempool sync @@ -109,6 +110,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex") if n == 0: + sync_txindex(self, self.nodes[n]) # With -txindex. # 1. valid parameters - only supply txid assert_equal(self.nodes[n].getrawtransaction(txId), tx['hex']) diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py index 90572245d6..d430f47f66 100755 --- a/test/functional/rpc_txoutproof.py +++ b/test/functional/rpc_txoutproof.py @@ -12,6 +12,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, + sync_txindex, ) from test_framework.wallet import MiniWallet @@ -77,6 +78,7 @@ class MerkleBlockTest(BitcoinTestFramework): assert_equal(sorted(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid1, txid2]))), sorted(txlist)) assert_equal(sorted(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid2, txid1]))), sorted(txlist)) # We can always get a proof if we have a -txindex + sync_txindex(self, self.nodes[1]) assert_equal(self.nodes[0].verifytxoutproof(self.nodes[1].gettxoutproof([txid_spent])), [txid_spent]) # We can't get a proof if we specify transactions from different blocks assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[0].gettxoutproof, [txid1, txid3]) diff --git a/test/functional/test-shell.md b/test/functional/test-shell.md index d79c4a0ab6..0a05658e2f 100644 --- a/test/functional/test-shell.md +++ b/test/functional/test-shell.md @@ -24,13 +24,16 @@ user inputs. Such environments include the Python3 command line interpreter or ## 2. Importing `TestShell` from the Bitcoin Core repository -We can import the `TestShell` by adding the path of the Bitcoin Core +We can import the `TestShell` by adding the path of the configured Bitcoin Core `test_framework` module to the beginning of the PATH variable, and then -importing the `TestShell` class from the `test_shell` sub-package. +importing the `TestShell` class from the `test_shell` sub-package. Since +the build system creates a copy of the `test_framework` module into a new `build/` +directory along with the required configuration file, the path to the build copy +must be used. ``` >>> import sys ->>> sys.path.insert(0, "/path/to/bitcoin/test/functional") +>>> sys.path.insert(0, "/path/to/bitcoin/build/test/functional") >>> from test_framework.test_shell import TestShell ``` @@ -155,7 +158,7 @@ To prevent the logs from being removed after a shutdown, simply set the The following utility consolidates logs from the bitcoind nodes and the underlying `BitcoinTestFramework`: -* `/path/to/bitcoin/test/functional/combine_logs.py +* `/path/to/bitcoin/build/test/functional/combine_logs.py '/path/to/bitcoin_func_test_XXXXXXX'` ## 6. Custom `TestShell` parameters @@ -170,9 +173,9 @@ can be called after the TestShell is shut down. | Test parameter key | Default Value | Description | |---|---|---| | `bind_to_localhost_only` | `True` | Binds bitcoind P2P services to `127.0.0.1` if set to `True`.| -| `cachedir` | `"/path/to/bitcoin/test/cache"` | Sets the bitcoind datadir directory. | +| `cachedir` | `"/path/to/bitcoin/build/test/cache"` | Sets the bitcoind datadir directory. | | `chain` | `"regtest"` | Sets the chain-type for the underlying test bitcoind processes. | -| `configfile` | `"/path/to/bitcoin/test/config.ini"` | Sets the location of the test framework config file. | +| `configfile` | `"/path/to/bitcoin/build/test/config.ini"` | Sets the location of the test framework config file. | | `coveragedir` | `None` | Records bitcoind RPC test coverage into this directory if set. | | `loglevel` | `INFO` | Logs events at this level and higher. Can be set to `DEBUG`, `INFO`, `WARNING`, `ERROR` or `CRITICAL`. | | `nocleanup` | `False` | Cleans up temporary test directory if set to `True` during `shutdown`. | diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py index 37fd5ae568..e24e5f7312 100644 --- a/test/functional/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py @@ -105,14 +105,19 @@ class AuthServiceProxy(): self.__conn.request(method, path, postdata, headers) return self._get_response() + def _json_dumps(self, obj): + return json.dumps(obj, default=serialization_fallback, ensure_ascii=self.ensure_ascii) + def get_request(self, *args, **argsn): AuthServiceProxy.__id_count += 1 - log.debug("-{}-> {} {}".format( + log.debug("-{}-> {} {} {}".format( AuthServiceProxy.__id_count, self._service_name, - json.dumps(args or argsn, default=serialization_fallback, ensure_ascii=self.ensure_ascii), + self._json_dumps(args), + self._json_dumps(argsn), )) + if args and argsn: params = dict(args=args, **argsn) else: @@ -123,7 +128,7 @@ class AuthServiceProxy(): 'id': AuthServiceProxy.__id_count} def __call__(self, *args, **argsn): - postdata = json.dumps(self.get_request(*args, **argsn), default=serialization_fallback, ensure_ascii=self.ensure_ascii) + postdata = self._json_dumps(self.get_request(*args, **argsn)) response, status = self._request('POST', self.__url.path, postdata.encode('utf-8')) # For backwards compatibility tests, accept JSON RPC 1.1 responses if 'jsonrpc' not in response: @@ -150,7 +155,7 @@ class AuthServiceProxy(): return response['result'] def batch(self, rpc_call_list): - postdata = json.dumps(list(rpc_call_list), default=serialization_fallback, ensure_ascii=self.ensure_ascii) + postdata = self._json_dumps(list(rpc_call_list)) log.debug("--> " + postdata) response, status = self._request('POST', self.__url.path, postdata.encode('utf-8')) if status != HTTPStatus.OK: @@ -197,7 +202,7 @@ class AuthServiceProxy(): response = json.loads(responsedata, parse_float=decimal.Decimal) elapsed = time.time() - req_start_time if "error" in response and response["error"] is None: - log.debug("<-%s- [%.6f] %s" % (response["id"], elapsed, json.dumps(response["result"], default=serialization_fallback, ensure_ascii=self.ensure_ascii))) + log.debug("<-%s- [%.6f] %s" % (response["id"], elapsed, self._json_dumps(response["result"]))) else: log.debug("<-- [%.6f] %s" % (elapsed, responsedata)) return response, http_response.status diff --git a/test/functional/test_framework/compressor.py b/test/functional/test_framework/compressor.py new file mode 100644 index 0000000000..1c30d749df --- /dev/null +++ b/test/functional/test_framework/compressor.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# Copyright (c) 2025-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Routines for compressing transaction output amounts and scripts.""" +import unittest + +from .messages import COIN + + +def compress_amount(n): + if n == 0: + return 0 + e = 0 + while ((n % 10) == 0) and (e < 9): + n //= 10 + e += 1 + if e < 9: + d = n % 10 + assert (d >= 1 and d <= 9) + n //= 10 + return 1 + (n*9 + d - 1)*10 + e + else: + return 1 + (n - 1)*10 + 9 + + +def decompress_amount(x): + if x == 0: + return 0 + x -= 1 + e = x % 10 + x //= 10 + n = 0 + if e < 9: + d = (x % 9) + 1 + x //= 9 + n = x * 10 + d + else: + n = x + 1 + while e > 0: + n *= 10 + e -= 1 + return n + + +class TestFrameworkCompressor(unittest.TestCase): + def test_amount_compress_decompress(self): + def check_amount(amount, expected_compressed): + self.assertEqual(compress_amount(amount), expected_compressed) + self.assertEqual(decompress_amount(expected_compressed), amount) + + # test cases from compress_tests.cpp:compress_amounts + check_amount(0, 0x0) + check_amount(1, 0x1) + check_amount(1000000, 0x7) + check_amount(COIN, 0x9) + check_amount(50*COIN, 0x32) + check_amount(21000000*COIN, 0x1406f40) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 9ebb683a9d..1ba48f9a48 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -120,6 +120,26 @@ def deser_compact_size(f): return nit +def ser_varint(l): + r = b"" + while True: + r = bytes([(l & 0x7f) | (0x80 if len(r) > 0 else 0x00)]) + r + if l <= 0x7f: + return r + l = (l >> 7) - 1 + + +def deser_varint(f): + n = 0 + while True: + dat = f.read(1)[0] + n = (n << 7) | (dat & 0x7f) + if (dat & 0x80) > 0: + n += 1 + else: + return n + + def deser_string(f): nit = deser_compact_size(f) return f.read(nit) @@ -1913,3 +1933,20 @@ class TestFrameworkScript(unittest.TestCase): check_addrv2("2bqghnldu6mcug4pikzprwhtjjnsyederctvci6klcwzepnjd46ikjyd.onion", CAddress.NET_TORV3) check_addrv2("255fhcp6ajvftnyo7bwz3an3t4a4brhopm3bamyh2iu5r3gnr2rq.b32.i2p", CAddress.NET_I2P) check_addrv2("fc32:17ea:e415:c3bf:9808:149d:b5a2:c9aa", CAddress.NET_CJDNS) + + def test_varint_encode_decode(self): + def check_varint(num, expected_encoding_hex): + expected_encoding = bytes.fromhex(expected_encoding_hex) + self.assertEqual(ser_varint(num), expected_encoding) + self.assertEqual(deser_varint(BytesIO(expected_encoding)), num) + + # test cases from serialize_tests.cpp:varint_bitpatterns + check_varint(0, "00") + check_varint(0x7f, "7f") + check_varint(0x80, "8000") + check_varint(0x1234, "a334") + check_varint(0xffff, "82fe7f") + check_varint(0x123456, "c7e756") + check_varint(0x80123456, "86ffc7e756") + check_varint(0xffffffff, "8efefefe7f") + check_varint(0xffffffffffffffff, "80fefefefefefefefe7f") diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index 207d19137b..bac57f3886 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.py @@ -378,11 +378,17 @@ class P2PConnection(asyncio.Protocol): # Socket write methods - def send_message(self, message, is_decoy=False): + def send_without_ping(self, message, is_decoy=False): """Send a P2P message over the socket. This method takes a P2P payload, builds the P2P header and adds - the message to the send buffer to be sent over the socket.""" + the message to the send buffer to be sent over the socket. + + When a message does not lead to a disconnect, send_and_ping is usually + preferred to send a message. This can help to reduce intermittent test + failures due to a missing sync. Also, it includes a call to + sync_with_ping, allowing for concise test code. + """ with self._send_lock: tmsg = self.build_message(message, is_decoy) self._log_message("send", message) @@ -558,10 +564,10 @@ class P2PInterface(P2PConnection): if i.type != 0: want.inv.append(i) if len(want.inv): - self.send_message(want) + self.send_without_ping(want) def on_ping(self, message): - self.send_message(msg_pong(message.nonce)) + self.send_without_ping(msg_pong(message.nonce)) def on_verack(self, message): pass @@ -574,14 +580,14 @@ class P2PInterface(P2PConnection): self.send_version() self.reconnect = False if message.nVersion >= 70016 and self.wtxidrelay: - self.send_message(msg_wtxidrelay()) + self.send_without_ping(msg_wtxidrelay()) if self.support_addrv2: - self.send_message(msg_sendaddrv2()) - self.send_message(msg_verack()) + self.send_without_ping(msg_sendaddrv2()) + self.send_without_ping(msg_verack()) self.nServices = message.nServices self.relay = message.relay if self.p2p_connected_to_node: - self.send_message(msg_getaddr()) + self.send_without_ping(msg_getaddr()) # Connection helper methods @@ -688,11 +694,11 @@ class P2PInterface(P2PConnection): def send_version(self): if self.on_connection_send_msg: - self.send_message(self.on_connection_send_msg) + self.send_without_ping(self.on_connection_send_msg) self.on_connection_send_msg = None # Never used again def send_and_ping(self, message, *, timeout=60): - self.send_message(message) + self.send_without_ping(message) self.sync_with_ping(timeout=timeout) def sync_with_ping(self, *, timeout=60): @@ -700,8 +706,8 @@ class P2PInterface(P2PConnection): # Sending two pings back-to-back, requires that the node calls # `ProcessMessage` twice, and thus ensures `SendMessages` must have # been called at least once - self.send_message(msg_ping(nonce=0)) - self.send_message(msg_ping(nonce=self.ping_counter)) + self.send_without_ping(msg_ping(nonce=0)) + self.send_without_ping(msg_ping(nonce=self.ping_counter)) def test_function(): return self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter @@ -814,9 +820,9 @@ class P2PDataStore(P2PInterface): self.getdata_requests.append(inv.hash) invtype = inv.type & MSG_TYPE_MASK if (invtype == MSG_TX or invtype == MSG_WTX) and inv.hash in self.tx_store.keys(): - self.send_message(msg_tx(self.tx_store[inv.hash])) + self.send_without_ping(msg_tx(self.tx_store[inv.hash])) elif invtype == MSG_BLOCK and inv.hash in self.block_store.keys(): - self.send_message(msg_block(self.block_store[inv.hash])) + self.send_without_ping(msg_block(self.block_store[inv.hash])) else: logger.debug('getdata message type {} received.'.format(hex(inv.type))) @@ -849,7 +855,7 @@ class P2PDataStore(P2PInterface): response = msg_headers(headers_list) if response is not None: - self.send_message(response) + self.send_without_ping(response) def send_blocks_and_test(self, blocks, node, *, success=True, force_send=False, reject_reason=None, expect_disconnect=False, timeout=60, is_decoy=False): """Send blocks to test node and test whether the tip advances. @@ -874,9 +880,9 @@ class P2PDataStore(P2PInterface): force_send = True if force_send: for b in blocks: - self.send_message(msg_block(block=b), is_decoy) + self.send_without_ping(msg_block(block=b), is_decoy) else: - self.send_message(msg_headers([CBlockHeader(block) for block in blocks])) + self.send_without_ping(msg_headers([CBlockHeader(block) for block in blocks])) self.wait_until( lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, @@ -909,7 +915,7 @@ class P2PDataStore(P2PInterface): reject_reason = [reject_reason] if reject_reason else [] with node.assert_debug_log(expected_msgs=reject_reason): for tx in txs: - self.send_message(msg_tx(tx)) + self.send_without_ping(msg_tx(tx)) if expect_disconnect: self.wait_for_disconnect() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 921f12d9fb..c4b10af16c 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -18,6 +18,7 @@ import subprocess import sys import tempfile import time +import types from .address import create_deterministic_address_bcrt1_p2tr_op_true from .authproxy import JSONRPCException @@ -56,6 +57,48 @@ class SkipTest(Exception): self.message = message +class Binaries: + """Helper class to provide information about bitcoin binaries + + Attributes: + paths: Object returned from get_binary_paths() containing information + which binaries and command lines to use from environment variables and + the config file. + bin_dir: An optional string containing a directory path to look for + binaries, which takes precedence over the paths above, if specified. + This is used by tests calling binaries from previous releases. + """ + def __init__(self, paths, bin_dir): + self.paths = paths + self.bin_dir = bin_dir + + def daemon_argv(self): + "Return argv array that should be used to invoke bitcoind" + return self._argv(self.paths.bitcoind) + + def rpc_argv(self): + "Return argv array that should be used to invoke bitcoin-cli" + return self._argv(self.paths.bitcoincli) + + def util_argv(self): + "Return argv array that should be used to invoke bitcoin-util" + return self._argv(self.paths.bitcoinutil) + + def wallet_argv(self): + "Return argv array that should be used to invoke bitcoin-wallet" + return self._argv(self.paths.bitcoinwallet) + + def _argv(self, bin_path): + """Return argv array that should be used to invoke the command. + Normally this will return binary paths directly from the paths object, + but when bin_dir is set (by tests calling binaries from previous + releases) it will return paths relative to bin_dir instead.""" + if self.bin_dir is not None: + return [os.path.join(self.bin_dir, os.path.basename(bin_path))] + else: + return [bin_path] + + class BitcoinTestMetaClass(type): """Metaclass for BitcoinTestFramework. @@ -220,6 +263,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): config = configparser.ConfigParser() config.read_file(open(self.options.configfile)) self.config = config + self.binary_paths = self.get_binary_paths() if self.options.v1transport: self.options.v2transport=False @@ -229,23 +273,20 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): # So set it to None to force -disablewallet, because the wallet is not needed. self.options.descriptors = None elif self.options.descriptors is None: - # Some wallet is either required or optionally used by the test. - # Prefer SQLite unless it isn't available - if self.is_sqlite_compiled(): + if self.is_wallet_compiled(): self.options.descriptors = True - elif self.is_bdb_compiled(): - self.options.descriptors = False else: - # If neither are compiled, tests requiring a wallet will be skipped and the value of self.options.descriptors won't matter + # Tests requiring a wallet will be skipped and the value of self.options.descriptors won't matter # It still needs to exist and be None in order for tests to work however. # So set it to None, which will also set -disablewallet. self.options.descriptors = None PortSeed.n = self.options.port_seed - def set_binary_paths(self): - """Update self.options with the paths of all binaries from environment variables or their default values""" + def get_binary_paths(self): + """Get paths of all binaries from environment variables or their default values""" + paths = types.SimpleNamespace() binaries = { "bitcoind": ("bitcoind", "BITCOIND"), "bitcoin-cli": ("bitcoincli", "BITCOINCLI"), @@ -255,10 +296,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): for binary, [attribute_name, env_variable_name] in binaries.items(): default_filename = os.path.join( self.config["environment"]["BUILDDIR"], - "src", + "bin", binary + self.config["environment"]["EXEEXT"], ) - setattr(self.options, attribute_name, os.getenv(env_variable_name, default=default_filename)) + setattr(paths, attribute_name, os.getenv(env_variable_name, default=default_filename)) + return paths + + def get_binaries(self, bin_dir=None): + return Binaries(self.binary_paths, bin_dir) def setup(self): """Call this method to start up the test framework object with options set.""" @@ -269,11 +314,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): config = self.config - self.set_binary_paths() - os.environ['PATH'] = os.pathsep.join([ - os.path.join(config['environment']['BUILDDIR'], 'src'), - os.path.join(config['environment']['BUILDDIR'], 'src', 'qt'), os.environ['PATH'] + os.path.join(config['environment']['BUILDDIR'], 'bin'), + os.environ['PATH'] ]) # Set up temp directory and start logging @@ -477,14 +520,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): group.add_argument("--legacy-wallet", action='store_const', const=False, **kwargs, help="Run test using legacy wallets", dest='descriptors') - def add_nodes(self, num_nodes: int, extra_args=None, *, rpchost=None, binary=None, binary_cli=None, versions=None): + def add_nodes(self, num_nodes: int, extra_args=None, *, rpchost=None, versions=None): """Instantiate TestNode objects. Should only be called once after the nodes have been specified in set_test_params().""" - def get_bin_from_version(version, bin_name, bin_default): + def bin_dir_from_version(version): if not version: - return bin_default + return None if version > 219999: # Starting at client version 220000 the first two digits represent # the major version, e.g. v22.0 instead of v0.22.0. @@ -502,7 +545,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): ), ), 'bin', - bin_name, ) if self.bind_to_localhost_only: @@ -517,13 +559,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): extra_args[i] = extra_args[i] + ["-whitelist=noban,in,out@127.0.0.1"] if versions is None: versions = [None] * num_nodes - if binary is None: - binary = [get_bin_from_version(v, 'bitcoind', self.options.bitcoind) for v in versions] - if binary_cli is None: - binary_cli = [get_bin_from_version(v, 'bitcoin-cli', self.options.bitcoincli) for v in versions] + bin_dirs = [bin_dir_from_version(v) for v in versions] # Fail test if any of the needed release binaries is missing bins_missing = False - for bin_path in binary + binary_cli: + for bin_path in (argv[0] for bin_dir in bin_dirs + for binaries in (self.get_binaries(bin_dir),) + for argv in (binaries.daemon_argv(), binaries.rpc_argv())): if shutil.which(bin_path) is None: self.log.error(f"Binary not found: {bin_path}") bins_missing = True @@ -533,8 +574,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): assert_equal(len(extra_confs), num_nodes) assert_equal(len(extra_args), num_nodes) assert_equal(len(versions), num_nodes) - assert_equal(len(binary), num_nodes) - assert_equal(len(binary_cli), num_nodes) + assert_equal(len(bin_dirs), num_nodes) for i in range(num_nodes): args = list(extra_args[i]) test_node_i = TestNode( @@ -544,8 +584,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): rpchost=rpchost, timewait=self.rpc_timeout, timeout_factor=self.options.timeout_factor, - bitcoind=binary[i], - bitcoin_cli=binary_cli[i], + binaries=self.get_binaries(bin_dirs[i]), version=versions[i], coverage_dir=self.options.coveragedir, cwd=self.options.tmpdir, @@ -856,8 +895,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): rpchost=None, timewait=self.rpc_timeout, timeout_factor=self.options.timeout_factor, - bitcoind=self.options.bitcoind, - bitcoin_cli=self.options.bitcoincli, + binaries=self.get_binaries(), coverage_dir=None, cwd=self.options.tmpdir, descriptors=self.options.descriptors, @@ -966,16 +1004,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self._requires_wallet = True if not self.is_wallet_compiled(): raise SkipTest("wallet has not been compiled.") - if self.options.descriptors: - self.skip_if_no_sqlite() - else: + if not self.options.descriptors: self.skip_if_no_bdb() - def skip_if_no_sqlite(self): - """Skip the running test if sqlite has not been compiled.""" - if not self.is_sqlite_compiled(): - raise SkipTest("sqlite has not been compiled.") - def skip_if_no_bdb(self): """Skip the running test if BDB has not been compiled.""" if not self.is_bdb_compiled(): @@ -1030,7 +1061,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): """Checks whether wallet support for the specified type (legacy or descriptor wallet) was compiled.""" if self.options.descriptors: - return self.is_sqlite_compiled() + return self.is_wallet_compiled() else: return self.is_bdb_compiled() @@ -1050,10 +1081,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): """Checks whether the USDT tracepoints were compiled.""" return self.config["components"].getboolean("ENABLE_USDT_TRACEPOINTS") - def is_sqlite_compiled(self): - """Checks whether the wallet module was compiled with Sqlite support.""" - return self.config["components"].getboolean("USE_SQLITE") - def is_bdb_compiled(self): """Checks whether the wallet module was compiled with BDB support.""" return self.config["components"].getboolean("USE_BDB") diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index f7d6ba78d2..7ab6dd0f30 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -76,7 +76,7 @@ class TestNode(): To make things easier for the test writer, any unrecognised messages will be dispatched to the RPC connection.""" - def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False, v2transport=False): + def __init__(self, i, datadir_path, *, chain, rpchost, timewait, timeout_factor, binaries, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False, v2transport=False): """ Kwargs: start_perf (bool): If True, begin profiling the node with `perf` as soon as @@ -92,7 +92,7 @@ class TestNode(): self.chain = chain self.rpchost = rpchost self.rpc_timeout = timewait - self.binary = bitcoind + self.binaries = binaries self.coverage_dir = coverage_dir self.cwd = cwd self.descriptors = descriptors @@ -109,8 +109,7 @@ class TestNode(): # Configuration for logging is set as command-line args rather than in the bitcoin.conf file. # This means that starting a bitcoind using the temp dir to debug a failed test won't # spam debug.log. - self.args = [ - self.binary, + self.args = self.binaries.daemon_argv() + [ f"-datadir={self.datadir_path}", "-logtimemicros", "-debug", @@ -149,7 +148,7 @@ class TestNode(): self.args.append("-v2transport=0") # if v2transport is requested via global flag but not supported for node version, ignore it - self.cli = TestNodeCLI(bitcoin_cli, self.datadir_path) + self.cli = TestNodeCLI(binaries, self.datadir_path) self.use_cli = use_cli self.start_perf = start_perf @@ -443,6 +442,11 @@ class TestNode(): kwargs["expected_ret_code"] = 1 if expect_error else 0 # Whether node shutdown return EXIT_FAILURE or EXIT_SUCCESS self.wait_until(lambda: self.is_node_stopped(**kwargs), timeout=timeout) + def kill_process(self): + self.process.kill() + self.wait_until_stopped(expected_ret_code=1 if platform.system() == "Windows" else -9) + assert self.is_node_stopped() + def replace_in_config(self, replacements): """ Perform replacements in the configuration file. @@ -822,7 +826,8 @@ class TestNode(): def disconnect_p2ps(self): """Close all p2p connections to the node. - Use only after each p2p has sent a version message to ensure the wait works.""" + The state of the peers (such as txrequests) may not be fully cleared + yet, even after this method returns.""" for p in self.p2ps: p.peer_disconnect() del self.p2ps[:] @@ -865,16 +870,16 @@ def arg_to_cli(arg): class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" - def __init__(self, binary, datadir): + def __init__(self, binaries, datadir): self.options = [] - self.binary = binary + self.binaries = binaries self.datadir = datadir self.input = None self.log = logging.getLogger('TestFramework.bitcoincli') def __call__(self, *options, input=None): # TestNodeCLI is callable with bitcoin-cli command-line options - cli = TestNodeCLI(self.binary, self.datadir) + cli = TestNodeCLI(self.binaries, self.datadir) cli.options = [str(o) for o in options] cli.input = input return cli @@ -895,7 +900,7 @@ class TestNodeCLI(): """Run bitcoin-cli command. Deserializes returned string as python object.""" pos_args = [arg_to_cli(arg) for arg in args] named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()] - p_args = [self.binary, f"-datadir={self.datadir}"] + self.options + p_args = self.binaries.rpc_argv() + [f"-datadir={self.datadir}"] + self.options if named_args: p_args += ["-named"] if clicommand is not None: @@ -911,7 +916,7 @@ class TestNodeCLI(): code, message = match.groups() raise JSONRPCException(dict(code=int(code), message=message)) # Ignore cli_stdout, raise with cli_stderr - raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr) + raise subprocess.CalledProcessError(returncode, p_args, output=cli_stderr) try: return json.loads(cli_stdout, parse_float=decimal.Decimal) except (json.JSONDecodeError, decimal.InvalidOperation): diff --git a/test/functional/test_framework/test_shell.py b/test/functional/test_framework/test_shell.py index e232430507..3f237c7ea2 100644 --- a/test/functional/test_framework/test_shell.py +++ b/test/functional/test_framework/test_shell.py @@ -61,7 +61,8 @@ class TestShell: print("Shutdown TestShell before resetting!") else: self.num_nodes = None - super().__init__() + dummy_testshell_file = pathlib.Path(__file__).absolute().parent.parent / "testshell_dummy.py" + super().__init__(dummy_testshell_file) instance = None @@ -74,8 +75,8 @@ class TestShell: # cache. Since TestShell is meant for interactive use, there is no concrete # test; passing a dummy name is fine though, as only the containing directory # is relevant for successful initialization. - tests_directory = pathlib.Path(__file__).resolve().parent.parent - TestShell.instance = TestShell.__TestShell(tests_directory / "testshell_dummy.py") + dummy_testshell_file = pathlib.Path(__file__).absolute().parent.parent / "testshell_dummy.py" + TestShell.instance = TestShell.__TestShell(dummy_testshell_file) TestShell.instance.running = False return TestShell.instance diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 14930ef671..ceca0d3b19 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -592,3 +592,10 @@ def find_vout_for_address(node, txid, addr): if addr == tx["vout"][i]["scriptPubKey"]["address"]: return i raise RuntimeError("Vout not found for address: txid=%s, addr=%s" % (txid, addr)) + + +def sync_txindex(test_framework, node): + test_framework.log.debug("Waiting for node txindex to sync") + sync_start = int(time.time()) + test_framework.wait_until(lambda: node.getindexinfo("txindex")["txindex"]["synced"]) + test_framework.log.debug(f"Synced in {time.time() - sync_start} seconds") diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index a332818e5d..4b8c9172b4 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -275,6 +275,7 @@ BASE_SCRIPTS = [ 'mempool_truc.py', 'wallet_txn_doublespend.py --legacy-wallet', 'wallet_multisig_descriptor_psbt.py --descriptors', + 'wallet_miniscript_decaying_multisig_descriptor_psbt.py --descriptors', 'wallet_txn_doublespend.py --descriptors', 'wallet_backwards_compatibility.py --legacy-wallet', 'wallet_backwards_compatibility.py --descriptors', @@ -364,7 +365,6 @@ BASE_SCRIPTS = [ 'feature_filelock.py', 'feature_loadblock.py', 'wallet_assumeutxo.py --descriptors', - 'p2p_dos_header_tree.py', 'p2p_add_connections.py', 'feature_bind_port_discover.py', 'p2p_unrequested_blocks.py', diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py index 0084158554..11b6af4e9d 100755 --- a/test/functional/tool_signet_miner.py +++ b/test/functional/tool_signet_miner.py @@ -5,6 +5,7 @@ """Test signet miner tool""" import os.path +import shlex import subprocess import sys import time @@ -49,13 +50,15 @@ class SignetMinerTest(BitcoinTestFramework): # generate block with signet miner tool base_dir = self.config["environment"]["SRCDIR"] signet_miner_path = os.path.join(base_dir, "contrib", "signet", "miner") + rpc_argv = node.binaries.rpc_argv() + [f"-datadir={node.cli.datadir}"] + util_argv = node.binaries.util_argv() + ["grind"] subprocess.run([ sys.executable, signet_miner_path, - f'--cli={node.cli.binary} -datadir={node.cli.datadir}', + f'--cli={shlex.join(rpc_argv)}', 'generate', f'--address={node.getnewaddress()}', - f'--grind-cmd={self.options.bitcoinutil} grind', + f'--grind-cmd={shlex.join(util_argv)}', f'--nbits={DIFF_1_N_BITS:08x}', f'--set-block-time={int(time.time())}', '--poolnum=99', diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index b0b9adab87..387ba276dd 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -5,7 +5,6 @@ """Test bitcoin-wallet.""" import os -import platform import random import stat import string @@ -49,7 +48,7 @@ class ToolWalletTest(BitcoinTestFramework): if "dump" in args and self.options.bdbro: default_args.append("-withinternalbdb") - return subprocess.Popen([self.options.bitcoinwallet] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + return subprocess.Popen(self.get_binaries().wallet_argv() + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) def assert_raises_tool_error(self, error, *args): p = self.bitcoin_wallet_process(*args) @@ -367,8 +366,7 @@ class ToolWalletTest(BitcoinTestFramework): self.do_tool_createfromdump("load", "wallet.dump") if self.is_bdb_compiled(): self.do_tool_createfromdump("load-bdb", "wallet.dump", "bdb") - if self.is_sqlite_compiled(): - self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite") + self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite") self.log.info('Checking createfromdump handling of magic and versions') bad_ver_wallet_dump = self.nodes[0].datadir_path / "wallet-bad_ver1.dump" @@ -537,9 +535,7 @@ class ToolWalletTest(BitcoinTestFramework): # Next cause a bunch of writes by filling the keypool wallet.keypoolrefill(wallet.getwalletinfo()["keypoolsize"] + 100) # Lastly kill bitcoind so that the LSNs don't get reset - self.nodes[0].process.kill() - self.nodes[0].wait_until_stopped(expected_ret_code=1 if platform.system() == "Windows" else -9) - assert self.nodes[0].is_node_stopped() + self.nodes[0].kill_process() wallet_dump = self.nodes[0].datadir_path / "unclean_lsn.dump" self.assert_raises_tool_error("LSNs are not reset, this database is not completely flushed. Please reopen then close the database with a version that has BDB support", "-wallet=unclean_lsn", f"-dumpfile={wallet_dump}", "dump") diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index ce0f4d099b..2bbfaee3db 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -45,6 +45,10 @@ class AbandonConflictTest(BitcoinTestFramework): txB = alice.sendtoaddress(alice.getnewaddress(), Decimal("10")) txC = alice.sendtoaddress(alice.getnewaddress(), Decimal("10")) self.sync_mempools() + + # Can not abandon transaction in mempool + assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: alice.abandontransaction(txid=txA)) + self.generate(self.nodes[1], 1) # Can not abandon non-wallet transaction diff --git a/test/functional/wallet_avoid_mixing_output_types.py b/test/functional/wallet_avoid_mixing_output_types.py index 146b3df3f4..08584abfbc 100755 --- a/test/functional/wallet_avoid_mixing_output_types.py +++ b/test/functional/wallet_avoid_mixing_output_types.py @@ -117,7 +117,6 @@ class AddressInputTypeGrouping(BitcoinTestFramework): self.extra_args = [ [ "-addresstype=bech32", - "-txindex", ], [ "-addresstype=p2sh-segwit", @@ -127,7 +126,6 @@ class AddressInputTypeGrouping(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() def make_payment(self, A, B, v, addr_type): fee_rate = random.randint(1, 20) diff --git a/test/functional/wallet_crosschain.py b/test/functional/wallet_crosschain.py index 97db84c3e4..a496694d12 100755 --- a/test/functional/wallet_crosschain.py +++ b/test/functional/wallet_crosschain.py @@ -11,7 +11,7 @@ class WalletCrossChain(BitcoinTestFramework): self.add_wallet_options(parser) def set_test_params(self): - self.num_nodes = 3 + self.num_nodes = 2 self.setup_clean_chain = True def skip_test_if_missing_module(self): @@ -20,16 +20,11 @@ class WalletCrossChain(BitcoinTestFramework): def setup_network(self): self.add_nodes(self.num_nodes) - # Switch node 1 to testnet before starting it. - self.nodes[1].chain = 'testnet3' - self.nodes[1].extra_args = ['-maxconnections=0', '-prune=550'] # disable testnet sync - self.nodes[1].replace_in_config([('regtest=', 'testnet='), ('[regtest]', '[test]')]) - - # Switch node 2 to testnet4 before starting it. - self.nodes[2].chain = 'testnet4' - self.nodes[2].extra_args = ['-maxconnections=0', '-prune=550'] # disable testnet4 sync - self.nodes[2].replace_in_config([('regtest=', 'testnet4='), ('[regtest]', '[testnet4]')]) - + # Switch node 1 to any network different from regtest before starting it. + self.nodes[1].chain = 'signet' + # Disable network sync and prevent disk space warning on low resource CI + self.nodes[1].extra_args = ['-maxconnections=0', '-prune=550'] + self.nodes[1].replace_in_config([('regtest=', 'signet='), ('[regtest]', '[signet]')]) self.start_nodes() def run_test(self): @@ -45,40 +40,19 @@ class WalletCrossChain(BitcoinTestFramework): self.nodes[1].createwallet(node1_wallet) self.nodes[1].backupwallet(node1_wallet_backup) self.nodes[1].unloadwallet(node1_wallet) - node2_wallet = self.nodes[2].datadir_path / 'node2_wallet' - node2_wallet_backup = self.nodes[0].datadir_path / 'node2_wallet.bak' - self.nodes[2].createwallet(node2_wallet) - self.nodes[2].backupwallet(node2_wallet_backup) - self.nodes[2].unloadwallet(node2_wallet) self.log.info("Loading/restoring wallets into nodes with a different genesis block") if self.options.descriptors: assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].loadwallet, node1_wallet) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].loadwallet, node2_wallet) assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].loadwallet, node0_wallet) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].loadwallet, node0_wallet) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].loadwallet, node2_wallet) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].loadwallet, node1_wallet) assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].restorewallet, 'w', node1_wallet_backup) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[0].restorewallet, 'w', node2_wallet_backup) assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].restorewallet, 'w', node0_wallet_backup) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].restorewallet, 'w', node0_wallet_backup) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[1].restorewallet, 'w', node2_wallet_backup) - assert_raises_rpc_error(-18, 'Wallet file verification failed.', self.nodes[2].restorewallet, 'w', node1_wallet_backup) else: assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].loadwallet, node1_wallet) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].loadwallet, node2_wallet) assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].loadwallet, node0_wallet) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].loadwallet, node0_wallet) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].loadwallet, node2_wallet) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].loadwallet, node1_wallet) assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].restorewallet, 'w', node1_wallet_backup) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[0].restorewallet, 'w', node2_wallet_backup) assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].restorewallet, 'w', node0_wallet_backup) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].restorewallet, 'w', node0_wallet_backup) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[1].restorewallet, 'w', node2_wallet_backup) - assert_raises_rpc_error(-4, 'Wallet files should not be reused across chains.', self.nodes[2].restorewallet, 'w', node1_wallet_backup) if not self.options.descriptors: self.log.info("Override cross-chain wallet load protection") diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index 5e0ee97892..0071d671c2 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -33,7 +33,6 @@ class WalletDescriptorTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() self.skip_if_no_py_sqlite3() def test_concurrent_writes(self): diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index 5e131405f1..4171951cf8 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -112,7 +112,7 @@ class WalletEncryptionTest(BitcoinTestFramework): def do_wallet_tool(*args): proc = subprocess.Popen( - [self.options.bitcoinwallet, f"-datadir={self.nodes[0].datadir_path}", f"-chain={self.chain}"] + list(args), + self.get_binaries().wallet_argv() + [f"-datadir={self.nodes[0].datadir_path}", f"-chain={self.chain}"] + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, diff --git a/test/functional/wallet_fast_rescan.py b/test/functional/wallet_fast_rescan.py index 6cee0d3660..1a9c319cb1 100755 --- a/test/functional/wallet_fast_rescan.py +++ b/test/functional/wallet_fast_rescan.py @@ -28,7 +28,6 @@ class WalletFastRescanTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() def get_wallet_txids(self, node: TestNode, wallet_name: str) -> list[str]: w = node.get_wallet_rpc(wallet_name) diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py index 03e26465f1..bd50b8cdc0 100755 --- a/test/functional/wallet_importdescriptors.py +++ b/test/functional/wallet_importdescriptors.py @@ -24,7 +24,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.descriptors import descsum_create from test_framework.util import ( assert_equal, - assert_greater_than, assert_raises_rpc_error, ) from test_framework.wallet_util import ( @@ -48,7 +47,6 @@ class ImportDescriptorsTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() def test_importdesc(self, req, success, error_code=None, error_message=None, warnings=None, wallet=None): """Run importdescriptors and assert success""" @@ -130,6 +128,20 @@ class ImportDescriptorsTest(BitcoinTestFramework): assert_equal(info["ismine"], True) assert_equal(info["ischange"], True) + self.log.info("Should not import a descriptor with an invalid public key due to whitespace") + self.test_importdesc({"desc": descsum_create("pkh( " + key.pubkey + ")"), + "timestamp": "now", + "internal": True}, + error_code=-5, + error_message=f"pkh(): Key ' {key.pubkey}' is invalid due to whitespace", + success=False) + self.test_importdesc({"desc": descsum_create("pkh(" + key.pubkey + " )"), + "timestamp": "now", + "internal": True}, + error_code=-5, + error_message=f"pkh(): Key '{key.pubkey} ' is invalid due to whitespace", + success=False) + # # Test importing of a P2SH-P2WPKH descriptor key = get_generate_key() self.log.info("Should not import a p2sh-p2wpkh descriptor without checksum") @@ -706,13 +718,6 @@ class ImportDescriptorsTest(BitcoinTestFramework): except JSONRPCException as e: assert e.error["code"] == -4 and "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before changing the passphrase." in e.error["message"] - wallet_info = self.nodes[0].cli("-rpcwallet=encrypted_wallet").getwalletinfo() - try: - duration = wallet_info["scanning"]["duration"] - assert_greater_than(duration, 0) - except Exception: - assert "scanning" not in wallet_info - assert_equal(importing.result(), [{"success": True}]) assert_equal(temp_wallet.getbalance(), encrypted_wallet.getbalance()) diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py index c9d6c1f190..35be527b32 100755 --- a/test/functional/wallet_listdescriptors.py +++ b/test/functional/wallet_listdescriptors.py @@ -26,7 +26,6 @@ class ListDescriptorsTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() # do not create any wallet by default def init_wallet(self, *, node): diff --git a/test/functional/wallet_miniscript.py b/test/functional/wallet_miniscript.py index 064eac499b..748faf14e2 100755 --- a/test/functional/wallet_miniscript.py +++ b/test/functional/wallet_miniscript.py @@ -212,7 +212,6 @@ class WalletMiniscriptTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() def watchonly_test(self, desc): self.log.info(f"Importing descriptor '{desc}'") diff --git a/test/functional/wallet_miniscript_decaying_multisig_descriptor_psbt.py b/test/functional/wallet_miniscript_decaying_multisig_descriptor_psbt.py new file mode 100755 index 0000000000..1c8c4de492 --- /dev/null +++ b/test/functional/wallet_miniscript_decaying_multisig_descriptor_psbt.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test a miniscript multisig that starts as 4-of-4 and "decays" to 3-of-4, 2-of-4, and finally 1-of-4 at each future halvening block height. + +Spending policy: `thresh(4,pk(key_1),pk(key_2),pk(key_3),pk(key_4),after(t1),after(t2),after(t3))` +This is similar to `test/functional/wallet_multisig_descriptor_psbt.py`. +""" + +import random +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_approx, + assert_equal, + assert_raises_rpc_error, +) + + +class WalletMiniscriptDecayingMultisigDescriptorPSBTTest(BitcoinTestFramework): + def add_options(self, parser): + self.add_wallet_options(parser, legacy=False) + + def set_test_params(self): + self.num_nodes = 1 + self.setup_clean_chain = True + self.wallet_names = [] + self.extra_args = [["-keypool=100"]] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + @staticmethod + def _get_xpub(wallet, internal): + """Extract the wallet's xpubs using `listdescriptors` and pick the one from the `pkh` descriptor since it's least likely to be accidentally reused (legacy addresses).""" + pkh_descriptor = next(filter(lambda d: d["desc"].startswith("pkh(") and d["internal"] == internal, wallet.listdescriptors()["descriptors"])) + # keep all key origin information (master key fingerprint and all derivation steps) for proper support of hardware devices + # see section 'Key origin identification' in 'doc/descriptors.md' for more details... + return pkh_descriptor["desc"].split("pkh(")[1].split(")")[0] + + def create_multisig(self, external_xpubs, internal_xpubs): + """The multisig is created by importing the following descriptors. The resulting wallet is watch-only and every signer can do this.""" + self.node.createwallet(wallet_name=f"{self.name}", blank=True, descriptors=True, disable_private_keys=True) + multisig = self.node.get_wallet_rpc(f"{self.name}") + # spending policy: `thresh(4,pk(key_1),pk(key_2),pk(key_3),pk(key_4),after(t1),after(t2),after(t3))` + # IMPORTANT: when backing up your descriptor, the order of key_1...key_4 must be correct! + external = multisig.getdescriptorinfo(f"wsh(thresh({self.N},pk({'),s:pk('.join(external_xpubs)}),sln:after({'),sln:after('.join(map(str, self.locktimes))})))") + internal = multisig.getdescriptorinfo(f"wsh(thresh({self.N},pk({'),s:pk('.join(internal_xpubs)}),sln:after({'),sln:after('.join(map(str, self.locktimes))})))") + result = multisig.importdescriptors([ + { # receiving addresses (internal: False) + "desc": external["descriptor"], + "active": True, + "internal": False, + "timestamp": "now", + }, + { # change addresses (internal: True) + "desc": internal["descriptor"], + "active": True, + "internal": True, + "timestamp": "now", + }, + ]) + assert all(r["success"] for r in result) + return multisig + + def run_test(self): + self.node = self.nodes[0] + self.M = 4 # starts as 4-of-4 + self.N = 4 + + self.locktimes = [104, 106, 108] + assert_equal(len(self.locktimes), self.N - 1) + + self.name = f"{self.M}_of_{self.N}_decaying_multisig" + self.log.info(f"Testing a miniscript multisig which starts as 4-of-4 and 'decays' to 3-of-4 at block height {self.locktimes[0]}, 2-of-4 at {self.locktimes[1]}, and finally 1-of-4 at {self.locktimes[2]}...") + + self.log.info("Create the signer wallets and get their xpubs...") + signers = [self.node.get_wallet_rpc(self.node.createwallet(wallet_name=f"signer_{i}", descriptors=True)["name"]) for i in range(self.N)] + external_xpubs, internal_xpubs = [[self._get_xpub(signer, internal) for signer in signers] for internal in [False, True]] + + self.log.info("Create the watch-only decaying multisig using signers' xpubs...") + multisig = self.create_multisig(external_xpubs, internal_xpubs) + + self.log.info("Get a mature utxo to send to the multisig...") + coordinator_wallet = self.node.get_wallet_rpc(self.node.createwallet(wallet_name="coordinator", descriptors=True)["name"]) + self.generatetoaddress(self.node, 101, coordinator_wallet.getnewaddress()) + + self.log.info("Send funds to the multisig's receiving address...") + deposit_amount = 6.15 + coordinator_wallet.sendtoaddress(multisig.getnewaddress(), deposit_amount) + self.generate(self.node, 1) + assert_approx(multisig.getbalance(), deposit_amount, vspan=0.001) + + self.log.info("Send transactions from the multisig as required signers decay...") + amount = 1.5 + receiver = signers[0] + sent = 0 + for locktime in [0] + self.locktimes: + self.log.info(f"At block height >= {locktime} this multisig is {self.M}-of-{self.N}") + current_height = self.node.getblock(self.node.getbestblockhash())['height'] + + # in this test each signer signs the same psbt "in series" one after the other. + # Another option is for each signer to sign the original psbt, and then combine + # and finalize these. In some cases this may be more optimal for coordination. + psbt = multisig.walletcreatefundedpsbt(inputs=[], outputs={receiver.getnewaddress(): amount}, feeRate=0.00010, locktime=locktime) + # the random sample asserts that any of the signing keys can sign for the 3-of-4, + # 2-of-4, and 1-of-4. While this is basic behavior of the miniscript thresh primitive, + # it is a critical property of this wallet. + for i, m in enumerate(random.sample(range(self.M), self.M)): + psbt = signers[m].walletprocesspsbt(psbt["psbt"]) + assert_equal(psbt["complete"], i == self.M - 1) + + if self.M < self.N: + self.log.info(f"Check that the time-locked transaction is too immature to spend with {self.M}-of-{self.N} at block height {current_height}...") + assert_equal(current_height >= locktime, False) + assert_raises_rpc_error(-26, "non-final", multisig.sendrawtransaction, psbt["hex"]) + + self.log.info(f"Generate blocks to reach the time-lock block height {locktime} and broadcast the transaction...") + self.generate(self.node, locktime - current_height) + else: + self.log.info("All the signers are required to spend before the first locktime") + + multisig.sendrawtransaction(psbt["hex"]) + sent += amount + + self.log.info("Check that balances are correct after the transaction has been included in a block...") + self.generate(self.node, 1) + assert_approx(multisig.getbalance(), deposit_amount - sent, vspan=0.001) + assert_equal(receiver.getbalance(), sent) + + self.M -= 1 # decay the number of required signers for the next locktime.. + + +if __name__ == "__main__": + WalletMiniscriptDecayingMultisigDescriptorPSBTTest(__file__).main() diff --git a/test/functional/wallet_multisig_descriptor_psbt.py b/test/functional/wallet_multisig_descriptor_psbt.py index a69185b3a5..23a9a4cc75 100755 --- a/test/functional/wallet_multisig_descriptor_psbt.py +++ b/test/functional/wallet_multisig_descriptor_psbt.py @@ -26,7 +26,6 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() @staticmethod def _get_xpub(wallet, internal): diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py index 77cf34898b..9c69c33680 100755 --- a/test/functional/wallet_reorgsrestore.py +++ b/test/functional/wallet_reorgsrestore.py @@ -19,6 +19,8 @@ import shutil from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + assert_greater_than, + assert_raises_rpc_error ) class ReorgsRestoreTest(BitcoinTestFramework): @@ -31,6 +33,113 @@ class ReorgsRestoreTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + def test_coinbase_automatic_abandon_during_startup(self): + ########################################################################################################## + # Verify the wallet marks coinbase transactions, and their descendants, as abandoned during startup when # + # the block is no longer part of the best chain. # + ########################################################################################################## + self.log.info("Test automatic coinbase abandonment during startup") + # Test setup: Sync nodes for the coming test, ensuring both are at the same block, then disconnect them to + # generate two competing chains. After disconnection, verify no other peer connection exists. + self.connect_nodes(1, 0) + self.sync_blocks(self.nodes[:2]) + self.disconnect_nodes(1, 0) + assert all(len(node.getpeerinfo()) == 0 for node in self.nodes[:2]) + + # Create a new block in node0, coinbase going to wallet0 + self.nodes[0].createwallet(wallet_name="w0", load_on_startup=True) + wallet0 = self.nodes[0].get_wallet_rpc("w0") + self.generatetoaddress(self.nodes[0], 1, wallet0.getnewaddress(), sync_fun=self.no_op) + node0_coinbase_tx_hash = wallet0.getblock(wallet0.getbestblockhash(), verbose=1)['tx'][0] + + # Mine 100 blocks on top to mature the coinbase and create a descendant + self.generate(self.nodes[0], 101, sync_fun=self.no_op) + # Make descendant, send-to-self + descendant_tx_id = wallet0.sendtoaddress(wallet0.getnewaddress(), 1) + + # Verify balance + wallet0.syncwithvalidationinterfacequeue() + assert(wallet0.getbalances()['mine']['trusted'] > 0) + + # Now create a fork in node1. This will be used to replace node0's chain later. + self.nodes[1].createwallet(wallet_name="w1", load_on_startup=True) + wallet1 = self.nodes[1].get_wallet_rpc("w1") + self.generatetoaddress(self.nodes[1], 1, wallet1.getnewaddress(), sync_fun=self.no_op) + wallet1.syncwithvalidationinterfacequeue() + + # Verify both nodes are on a different chain + block0_best_hash, block1_best_hash = wallet0.getbestblockhash(), wallet1.getbestblockhash() + assert(block0_best_hash != block1_best_hash) + + # Stop both nodes and replace node0 chain entirely for the node1 chain + self.stop_nodes() + for path in ["chainstate", "blocks"]: + shutil.rmtree(self.nodes[0].chain_path / path) + shutil.copytree(self.nodes[1].chain_path / path, self.nodes[0].chain_path / path) + + # Start node0 and verify that now it has node1 chain and no info about its previous best block + self.start_node(0) + wallet0 = self.nodes[0].get_wallet_rpc("w0") + assert_equal(wallet0.getbestblockhash(), block1_best_hash) + assert_raises_rpc_error(-5, "Block not found", wallet0.getblock, block0_best_hash) + + # Verify the coinbase tx was marked as abandoned and balance correctly computed + tx_info = wallet0.gettransaction(node0_coinbase_tx_hash)['details'][0] + assert_equal(tx_info['abandoned'], True) + assert_equal(tx_info['category'], 'orphan') + assert(wallet0.getbalances()['mine']['trusted'] == 0) + # Verify the coinbase descendant was also marked as abandoned + assert_equal(wallet0.gettransaction(descendant_tx_id)['details'][0]['abandoned'], True) + + def test_reorg_handling_during_unclean_shutdown(self): + self.log.info("Test that wallet doesn't crash due to a duplicate block disconnection event after an unclean shutdown") + node = self.nodes[0] + # Receive coinbase reward on a new wallet + node.createwallet(wallet_name="reorg_crash", load_on_startup=True) + wallet = node.get_wallet_rpc("reorg_crash") + self.generatetoaddress(node, 1, wallet.getnewaddress(), sync_fun=self.no_op) + + # Restart to ensure node and wallet are flushed + self.restart_node(0) + wallet = node.get_wallet_rpc("reorg_crash") + assert_greater_than(wallet.getwalletinfo()['immature_balance'], 0) + + # Disconnect tip and sync wallet state + tip = wallet.getbestblockhash() + wallet.invalidateblock(tip) + wallet.syncwithvalidationinterfacequeue() + + # Tip was disconnected, ensure coinbase has been abandoned + assert_equal(wallet.getwalletinfo()['immature_balance'], 0) + coinbase_tx_id = wallet.getblock(tip, verbose=1)["tx"][0] + assert_equal(wallet.gettransaction(coinbase_tx_id)['details'][0]['abandoned'], True) + + # Abort process abruptly to mimic an unclean shutdown (no chain state flush to disk) + node.kill_process() + + # Restart the node and confirm that it has not persisted the last chain state changes to disk + self.start_node(0) + assert_equal(node.getbestblockhash(), tip) + + # Due to an existing bug, the wallet incorrectly keeps the transaction in an abandoned state, even though that's + # no longer the case (after the unclean shutdown, the node's chain returned to the pre-invalidation tip). + # This issue blocks any future spending and results in an incorrect balance display. + wallet = node.get_wallet_rpc("reorg_crash") + assert_equal(wallet.getwalletinfo()['immature_balance'], 0) # FIXME: #31824. + + # Previously, a bug caused the node to crash if two block disconnection events occurred consecutively. + # Ensure this is no longer the case by simulating a new reorg. + node.invalidateblock(tip) + assert(node.getbestblockhash() != tip) + # Ensure wallet state is consistent now + assert_equal(wallet.gettransaction(coinbase_tx_id)['details'][0]['abandoned'], True) + assert_equal(wallet.getwalletinfo()['immature_balance'], 0) + + # And finally, verify the state if the block ends up being into the best chain again + node.reconsiderblock(tip) + assert_equal(wallet.gettransaction(coinbase_tx_id)['details'][0]['abandoned'], False) + assert_greater_than(wallet.getwalletinfo()['immature_balance'], 0) + def run_test(self): # Send a tx from which to conflict outputs later txid_conflict_from = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) @@ -100,5 +209,12 @@ class ReorgsRestoreTest(BitcoinTestFramework): assert_equal(conflicted_after_reorg["confirmations"], 1) assert conflicting["blockhash"] != conflicted_after_reorg["blockhash"] + # Verify we mark coinbase txs, and their descendants, as abandoned during startup + self.test_coinbase_automatic_abandon_during_startup() + + # Verify reorg behavior during an unclean shutdown + self.test_reorg_handling_during_unclean_shutdown() + + if __name__ == '__main__': ReorgsRestoreTest(__file__).main() diff --git a/test/functional/wallet_rescan_unconfirmed.py b/test/functional/wallet_rescan_unconfirmed.py index 69ad522b5d..23c58b92f4 100755 --- a/test/functional/wallet_rescan_unconfirmed.py +++ b/test/functional/wallet_rescan_unconfirmed.py @@ -24,7 +24,6 @@ class WalletRescanUnconfirmed(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() def run_test(self): self.log.info("Create wallets and mine initial chain") diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py index a88d84f4c6..cc9683fcde 100755 --- a/test/functional/wallet_taproot.py +++ b/test/functional/wallet_taproot.py @@ -198,7 +198,6 @@ class WalletTaprootTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() - self.skip_if_no_sqlite() def setup_network(self): self.setup_nodes() diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index c909336a25..e1bb098ec7 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -343,16 +343,15 @@ class UpgradeWalletTest(BitcoinTestFramework): v16_3_kvs = dump_bdb_kv(v16_3_wallet) assert b'\x0adefaultkey' not in v16_3_kvs - if self.is_sqlite_compiled(): - self.log.info("Checking that descriptor wallets do nothing, successfully") - self.nodes[0].createwallet(wallet_name="desc_upgrade", descriptors=True) - desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade") - self.test_upgradewallet(desc_wallet, previous_version=169900, expected_version=169900) - - self.log.info("Checking that descriptor wallets without privkeys do nothing, successfully") - self.nodes[0].createwallet(wallet_name="desc_upgrade_nopriv", descriptors=True, disable_private_keys=True) - desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade_nopriv") - self.test_upgradewallet(desc_wallet, previous_version=169900, expected_version=169900) + self.log.info("Checking that descriptor wallets do nothing, successfully") + self.nodes[0].createwallet(wallet_name="desc_upgrade", descriptors=True) + desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade") + self.test_upgradewallet(desc_wallet, previous_version=169900, expected_version=169900) + + self.log.info("Checking that descriptor wallets without privkeys do nothing, successfully") + self.nodes[0].createwallet(wallet_name="desc_upgrade_nopriv", descriptors=True, disable_private_keys=True) + desc_wallet = self.nodes[0].get_wallet_rpc("desc_upgrade_nopriv") + self.test_upgradewallet(desc_wallet, previous_version=169900, expected_version=169900) if self.is_bdb_compiled(): self.log.info("Upgrading a wallet with private keys disabled") diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py index e87977edfc..12661b4da5 100755 --- a/test/fuzz/test_runner.py +++ b/test/fuzz/test_runner.py @@ -109,7 +109,7 @@ def main(): logging.error("Must have fuzz executable built") sys.exit(1) - fuzz_bin=os.getenv("BITCOINFUZZ", default=os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz')) + fuzz_bin=os.getenv("BITCOINFUZZ", default=os.path.join(config["environment"]["BUILDDIR"], 'bin', 'fuzz')) # Build list of tests test_list_all = parse_test_list( diff --git a/test/lint/README.md b/test/lint/README.md index 8c1f0fedf0..a1e1a35a67 100644 --- a/test/lint/README.md +++ b/test/lint/README.md @@ -96,7 +96,7 @@ maintained: * for `src/leveldb`: https://github.com/bitcoin-core/leveldb-subtree.git (branch bitcoin-fork) * for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) * for `src/crc32c`: https://github.com/bitcoin-core/crc32c-subtree.git (branch bitcoin-fork) -* for `src/minisketch`: https://github.com/sipa/minisketch.git (branch master) +* for `src/minisketch`: https://github.com/bitcoin-core/minisketch.git (branch master) To do so, add the upstream repository as remote: diff --git a/test/util/test_runner.py b/test/util/test_runner.py index cac184ca30..d6faf18c5c 100755 --- a/test/util/test_runner.py +++ b/test/util/test_runner.py @@ -73,7 +73,7 @@ def bctest(testDir, testObj, buildenv): are not as expected. Error is caught by bctester() and reported. """ # Get the exec names and arguments - execprog = os.path.join(buildenv["BUILDDIR"], "src", testObj["exec"] + buildenv["EXEEXT"]) + execprog = os.path.join(buildenv["BUILDDIR"], "bin", testObj["exec"] + buildenv["EXEEXT"]) if testObj["exec"] == "./bitcoin-util": execprog = os.getenv("BITCOINUTIL", default=execprog) elif testObj["exec"] == "./bitcoin-tx": |