chia-blockchain 2.5.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1042) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +195 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +145 -0
  9. chia/_tests/blockchain/test_blockchain.py +4202 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
  11. chia/_tests/blockchain/test_build_chains.py +59 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
  14. chia/_tests/build-init-files.py +92 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +72 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +149 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +55 -0
  26. chia/_tests/clvm/test_message_conditions.py +184 -0
  27. chia/_tests/clvm/test_program.py +150 -0
  28. chia/_tests/clvm/test_puzzle_compression.py +143 -0
  29. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  30. chia/_tests/clvm/test_puzzles.py +242 -0
  31. chia/_tests/clvm/test_singletons.py +540 -0
  32. chia/_tests/clvm/test_spend_sim.py +181 -0
  33. chia/_tests/cmds/__init__.py +0 -0
  34. chia/_tests/cmds/cmd_test_utils.py +469 -0
  35. chia/_tests/cmds/config.py +3 -0
  36. chia/_tests/cmds/conftest.py +23 -0
  37. chia/_tests/cmds/test_click_types.py +200 -0
  38. chia/_tests/cmds/test_cmd_framework.py +620 -0
  39. chia/_tests/cmds/test_cmds_util.py +97 -0
  40. chia/_tests/cmds/test_daemon.py +92 -0
  41. chia/_tests/cmds/test_dev_gh.py +131 -0
  42. chia/_tests/cmds/test_farm_cmd.py +66 -0
  43. chia/_tests/cmds/test_show.py +116 -0
  44. chia/_tests/cmds/test_sim.py +207 -0
  45. chia/_tests/cmds/test_timelock_args.py +75 -0
  46. chia/_tests/cmds/test_tx_config_args.py +154 -0
  47. chia/_tests/cmds/testing_classes.py +59 -0
  48. chia/_tests/cmds/wallet/__init__.py +0 -0
  49. chia/_tests/cmds/wallet/test_consts.py +47 -0
  50. chia/_tests/cmds/wallet/test_dao.py +565 -0
  51. chia/_tests/cmds/wallet/test_did.py +403 -0
  52. chia/_tests/cmds/wallet/test_nft.py +471 -0
  53. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  54. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  55. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  56. chia/_tests/cmds/wallet/test_vcs.py +400 -0
  57. chia/_tests/cmds/wallet/test_wallet.py +1125 -0
  58. chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
  59. chia/_tests/conftest.py +1419 -0
  60. chia/_tests/connection_utils.py +125 -0
  61. chia/_tests/core/__init__.py +0 -0
  62. chia/_tests/core/cmds/__init__.py +0 -0
  63. chia/_tests/core/cmds/test_beta.py +382 -0
  64. chia/_tests/core/cmds/test_keys.py +1734 -0
  65. chia/_tests/core/cmds/test_wallet.py +126 -0
  66. chia/_tests/core/config.py +3 -0
  67. chia/_tests/core/consensus/__init__.py +0 -0
  68. chia/_tests/core/consensus/test_block_creation.py +54 -0
  69. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  70. chia/_tests/core/custom_types/__init__.py +0 -0
  71. chia/_tests/core/custom_types/test_coin.py +107 -0
  72. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  73. chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
  74. chia/_tests/core/daemon/__init__.py +0 -0
  75. chia/_tests/core/daemon/config.py +4 -0
  76. chia/_tests/core/daemon/test_daemon.py +2128 -0
  77. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  78. chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
  79. chia/_tests/core/data_layer/__init__.py +0 -0
  80. chia/_tests/core/data_layer/config.py +5 -0
  81. chia/_tests/core/data_layer/conftest.py +106 -0
  82. chia/_tests/core/data_layer/test_data_cli.py +56 -0
  83. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  84. chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
  85. chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
  86. chia/_tests/core/data_layer/test_data_store.py +2424 -0
  87. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  88. chia/_tests/core/data_layer/test_plugin.py +91 -0
  89. chia/_tests/core/data_layer/util.py +233 -0
  90. chia/_tests/core/farmer/__init__.py +0 -0
  91. chia/_tests/core/farmer/config.py +3 -0
  92. chia/_tests/core/farmer/test_farmer_api.py +103 -0
  93. chia/_tests/core/full_node/__init__.py +0 -0
  94. chia/_tests/core/full_node/config.py +4 -0
  95. chia/_tests/core/full_node/dos/__init__.py +0 -0
  96. chia/_tests/core/full_node/dos/config.py +3 -0
  97. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  98. chia/_tests/core/full_node/full_sync/config.py +4 -0
  99. chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
  100. chia/_tests/core/full_node/ram_db.py +27 -0
  101. chia/_tests/core/full_node/stores/__init__.py +0 -0
  102. chia/_tests/core/full_node/stores/config.py +4 -0
  103. chia/_tests/core/full_node/stores/test_block_store.py +590 -0
  104. chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
  105. chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
  106. chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
  107. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  108. chia/_tests/core/full_node/test_address_manager.py +588 -0
  109. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  110. chia/_tests/core/full_node/test_conditions.py +556 -0
  111. chia/_tests/core/full_node/test_full_node.py +2700 -0
  112. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  113. chia/_tests/core/full_node/test_hint_management.py +104 -0
  114. chia/_tests/core/full_node/test_node_load.py +34 -0
  115. chia/_tests/core/full_node/test_performance.py +179 -0
  116. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  117. chia/_tests/core/full_node/test_transactions.py +203 -0
  118. chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
  119. chia/_tests/core/large_block.py +2388 -0
  120. chia/_tests/core/make_block_generator.py +70 -0
  121. chia/_tests/core/mempool/__init__.py +0 -0
  122. chia/_tests/core/mempool/config.py +4 -0
  123. chia/_tests/core/mempool/test_mempool.py +3255 -0
  124. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  125. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  126. chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
  127. chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
  128. chia/_tests/core/mempool/test_mempool_performance.py +64 -0
  129. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  130. chia/_tests/core/node_height.py +28 -0
  131. chia/_tests/core/server/__init__.py +0 -0
  132. chia/_tests/core/server/config.py +3 -0
  133. chia/_tests/core/server/flood.py +84 -0
  134. chia/_tests/core/server/serve.py +135 -0
  135. chia/_tests/core/server/test_api_protocol.py +21 -0
  136. chia/_tests/core/server/test_capabilities.py +66 -0
  137. chia/_tests/core/server/test_dos.py +319 -0
  138. chia/_tests/core/server/test_event_loop.py +109 -0
  139. chia/_tests/core/server/test_loop.py +294 -0
  140. chia/_tests/core/server/test_node_discovery.py +73 -0
  141. chia/_tests/core/server/test_rate_limits.py +482 -0
  142. chia/_tests/core/server/test_server.py +226 -0
  143. chia/_tests/core/server/test_upnp.py +8 -0
  144. chia/_tests/core/services/__init__.py +0 -0
  145. chia/_tests/core/services/config.py +3 -0
  146. chia/_tests/core/services/test_services.py +188 -0
  147. chia/_tests/core/ssl/__init__.py +0 -0
  148. chia/_tests/core/ssl/config.py +3 -0
  149. chia/_tests/core/ssl/test_ssl.py +202 -0
  150. chia/_tests/core/test_coins.py +33 -0
  151. chia/_tests/core/test_cost_calculation.py +313 -0
  152. chia/_tests/core/test_crawler.py +175 -0
  153. chia/_tests/core/test_crawler_rpc.py +53 -0
  154. chia/_tests/core/test_daemon_rpc.py +24 -0
  155. chia/_tests/core/test_db_conversion.py +130 -0
  156. chia/_tests/core/test_db_validation.py +162 -0
  157. chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
  158. chia/_tests/core/test_filter.py +35 -0
  159. chia/_tests/core/test_full_node_rpc.py +768 -0
  160. chia/_tests/core/test_merkle_set.py +343 -0
  161. chia/_tests/core/test_program.py +47 -0
  162. chia/_tests/core/test_rpc_util.py +86 -0
  163. chia/_tests/core/test_seeder.py +420 -0
  164. chia/_tests/core/test_setproctitle.py +13 -0
  165. chia/_tests/core/util/__init__.py +0 -0
  166. chia/_tests/core/util/config.py +4 -0
  167. chia/_tests/core/util/test_block_cache.py +44 -0
  168. chia/_tests/core/util/test_cached_bls.py +57 -0
  169. chia/_tests/core/util/test_config.py +337 -0
  170. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  171. chia/_tests/core/util/test_files.py +391 -0
  172. chia/_tests/core/util/test_jsonify.py +146 -0
  173. chia/_tests/core/util/test_keychain.py +522 -0
  174. chia/_tests/core/util/test_keyring_wrapper.py +491 -0
  175. chia/_tests/core/util/test_lockfile.py +380 -0
  176. chia/_tests/core/util/test_log_exceptions.py +187 -0
  177. chia/_tests/core/util/test_lru_cache.py +56 -0
  178. chia/_tests/core/util/test_significant_bits.py +40 -0
  179. chia/_tests/core/util/test_streamable.py +883 -0
  180. chia/_tests/db/__init__.py +0 -0
  181. chia/_tests/db/test_db_wrapper.py +566 -0
  182. chia/_tests/environments/__init__.py +0 -0
  183. chia/_tests/environments/common.py +35 -0
  184. chia/_tests/environments/full_node.py +47 -0
  185. chia/_tests/environments/wallet.py +429 -0
  186. chia/_tests/ether.py +19 -0
  187. chia/_tests/farmer_harvester/__init__.py +0 -0
  188. chia/_tests/farmer_harvester/config.py +3 -0
  189. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  190. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  191. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
  192. chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
  193. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  194. chia/_tests/fee_estimation/__init__.py +0 -0
  195. chia/_tests/fee_estimation/config.py +3 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  197. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  198. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
  199. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  200. chia/_tests/generator/__init__.py +0 -0
  201. chia/_tests/generator/puzzles/__init__.py +0 -0
  202. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  203. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  204. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  205. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  206. chia/_tests/generator/test_compression.py +201 -0
  207. chia/_tests/generator/test_generator_types.py +44 -0
  208. chia/_tests/generator/test_rom.py +180 -0
  209. chia/_tests/plot_sync/__init__.py +0 -0
  210. chia/_tests/plot_sync/config.py +3 -0
  211. chia/_tests/plot_sync/test_delta.py +101 -0
  212. chia/_tests/plot_sync/test_plot_sync.py +618 -0
  213. chia/_tests/plot_sync/test_receiver.py +451 -0
  214. chia/_tests/plot_sync/test_sender.py +116 -0
  215. chia/_tests/plot_sync/test_sync_simulated.py +451 -0
  216. chia/_tests/plot_sync/util.py +68 -0
  217. chia/_tests/plotting/__init__.py +0 -0
  218. chia/_tests/plotting/config.py +3 -0
  219. chia/_tests/plotting/test_plot_manager.py +781 -0
  220. chia/_tests/plotting/util.py +12 -0
  221. chia/_tests/pools/__init__.py +0 -0
  222. chia/_tests/pools/config.py +5 -0
  223. chia/_tests/pools/test_pool_cli_parsing.py +128 -0
  224. chia/_tests/pools/test_pool_cmdline.py +1001 -0
  225. chia/_tests/pools/test_pool_config.py +42 -0
  226. chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
  227. chia/_tests/pools/test_pool_rpc.py +1123 -0
  228. chia/_tests/pools/test_pool_wallet.py +205 -0
  229. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  230. chia/_tests/process_junit.py +348 -0
  231. chia/_tests/rpc/__init__.py +0 -0
  232. chia/_tests/rpc/test_rpc_client.py +138 -0
  233. chia/_tests/rpc/test_rpc_server.py +183 -0
  234. chia/_tests/simulation/__init__.py +0 -0
  235. chia/_tests/simulation/config.py +6 -0
  236. chia/_tests/simulation/test_simulation.py +501 -0
  237. chia/_tests/simulation/test_simulator.py +232 -0
  238. chia/_tests/simulation/test_start_simulator.py +107 -0
  239. chia/_tests/testconfig.py +13 -0
  240. chia/_tests/timelord/__init__.py +0 -0
  241. chia/_tests/timelord/config.py +3 -0
  242. chia/_tests/timelord/test_new_peak.py +437 -0
  243. chia/_tests/timelord/test_timelord.py +11 -0
  244. chia/_tests/tools/1315537.json +170 -0
  245. chia/_tests/tools/1315544.json +160 -0
  246. chia/_tests/tools/1315630.json +150 -0
  247. chia/_tests/tools/300000.json +105 -0
  248. chia/_tests/tools/442734.json +140 -0
  249. chia/_tests/tools/466212.json +130 -0
  250. chia/_tests/tools/__init__.py +0 -0
  251. chia/_tests/tools/config.py +5 -0
  252. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  253. chia/_tests/tools/test_full_sync.py +30 -0
  254. chia/_tests/tools/test_legacy_keyring.py +82 -0
  255. chia/_tests/tools/test_run_block.py +128 -0
  256. chia/_tests/tools/test_virtual_project.py +591 -0
  257. chia/_tests/util/__init__.py +0 -0
  258. chia/_tests/util/benchmark_cost.py +170 -0
  259. chia/_tests/util/benchmarks.py +153 -0
  260. chia/_tests/util/bip39_test_vectors.json +148 -0
  261. chia/_tests/util/blockchain.py +134 -0
  262. chia/_tests/util/blockchain_mock.py +132 -0
  263. chia/_tests/util/build_network_protocol_files.py +302 -0
  264. chia/_tests/util/clvm_generator.bin +0 -0
  265. chia/_tests/util/config.py +3 -0
  266. chia/_tests/util/constants.py +20 -0
  267. chia/_tests/util/db_connection.py +37 -0
  268. chia/_tests/util/full_sync.py +253 -0
  269. chia/_tests/util/gen_ssl_certs.py +114 -0
  270. chia/_tests/util/generator_tools_testing.py +45 -0
  271. chia/_tests/util/get_name_puzzle_conditions.py +52 -0
  272. chia/_tests/util/key_tool.py +36 -0
  273. chia/_tests/util/misc.py +675 -0
  274. chia/_tests/util/network_protocol_data.py +1072 -0
  275. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  276. chia/_tests/util/protocol_messages_json.py +2701 -0
  277. chia/_tests/util/rpc.py +26 -0
  278. chia/_tests/util/run_block.py +163 -0
  279. chia/_tests/util/setup_nodes.py +481 -0
  280. chia/_tests/util/spend_sim.py +492 -0
  281. chia/_tests/util/split_managers.py +102 -0
  282. chia/_tests/util/temp_file.py +14 -0
  283. chia/_tests/util/test_action_scope.py +144 -0
  284. chia/_tests/util/test_async_pool.py +366 -0
  285. chia/_tests/util/test_build_job_matrix.py +42 -0
  286. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  287. chia/_tests/util/test_chia_version.py +50 -0
  288. chia/_tests/util/test_collection.py +11 -0
  289. chia/_tests/util/test_condition_tools.py +229 -0
  290. chia/_tests/util/test_config.py +426 -0
  291. chia/_tests/util/test_dump_keyring.py +60 -0
  292. chia/_tests/util/test_errors.py +10 -0
  293. chia/_tests/util/test_full_block_utils.py +279 -0
  294. chia/_tests/util/test_installed.py +20 -0
  295. chia/_tests/util/test_limited_semaphore.py +53 -0
  296. chia/_tests/util/test_logging_filter.py +42 -0
  297. chia/_tests/util/test_misc.py +445 -0
  298. chia/_tests/util/test_network.py +73 -0
  299. chia/_tests/util/test_network_protocol_files.py +578 -0
  300. chia/_tests/util/test_network_protocol_json.py +267 -0
  301. chia/_tests/util/test_network_protocol_test.py +256 -0
  302. chia/_tests/util/test_paginator.py +71 -0
  303. chia/_tests/util/test_pprint.py +17 -0
  304. chia/_tests/util/test_priority_mutex.py +488 -0
  305. chia/_tests/util/test_recursive_replace.py +116 -0
  306. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  307. chia/_tests/util/test_service_groups.py +15 -0
  308. chia/_tests/util/test_ssl_check.py +31 -0
  309. chia/_tests/util/test_testnet_overrides.py +19 -0
  310. chia/_tests/util/test_tests_misc.py +38 -0
  311. chia/_tests/util/test_timing.py +37 -0
  312. chia/_tests/util/test_trusted_peer.py +51 -0
  313. chia/_tests/util/time_out_assert.py +191 -0
  314. chia/_tests/wallet/__init__.py +0 -0
  315. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  316. chia/_tests/wallet/cat_wallet/config.py +4 -0
  317. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  318. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  319. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
  320. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  321. chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
  322. chia/_tests/wallet/clawback/__init__.py +0 -0
  323. chia/_tests/wallet/clawback/config.py +3 -0
  324. chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
  325. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  326. chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
  327. chia/_tests/wallet/config.py +4 -0
  328. chia/_tests/wallet/conftest.py +278 -0
  329. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  330. chia/_tests/wallet/dao_wallet/config.py +3 -0
  331. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
  332. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  333. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  334. chia/_tests/wallet/db_wallet/config.py +3 -0
  335. chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
  336. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  337. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  338. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  339. chia/_tests/wallet/did_wallet/config.py +4 -0
  340. chia/_tests/wallet/did_wallet/test_did.py +2284 -0
  341. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  342. chia/_tests/wallet/nft_wallet/config.py +4 -0
  343. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
  344. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
  345. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
  346. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  347. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  348. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
  349. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  350. chia/_tests/wallet/rpc/__init__.py +0 -0
  351. chia/_tests/wallet/rpc/config.py +4 -0
  352. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
  353. chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
  354. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  355. chia/_tests/wallet/simple_sync/config.py +3 -0
  356. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
  357. chia/_tests/wallet/sync/__init__.py +0 -0
  358. chia/_tests/wallet/sync/config.py +4 -0
  359. chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
  360. chia/_tests/wallet/test_address_type.py +189 -0
  361. chia/_tests/wallet/test_bech32m.py +45 -0
  362. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  363. chia/_tests/wallet/test_coin_management.py +354 -0
  364. chia/_tests/wallet/test_coin_selection.py +588 -0
  365. chia/_tests/wallet/test_conditions.py +400 -0
  366. chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
  367. chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
  368. chia/_tests/wallet/test_nft_store.py +192 -0
  369. chia/_tests/wallet/test_notifications.py +196 -0
  370. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  371. chia/_tests/wallet/test_puzzle_store.py +132 -0
  372. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  373. chia/_tests/wallet/test_signer_protocol.py +947 -0
  374. chia/_tests/wallet/test_singleton.py +122 -0
  375. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  376. chia/_tests/wallet/test_singleton_store.py +152 -0
  377. chia/_tests/wallet/test_taproot.py +19 -0
  378. chia/_tests/wallet/test_transaction_store.py +945 -0
  379. chia/_tests/wallet/test_util.py +185 -0
  380. chia/_tests/wallet/test_wallet.py +2139 -0
  381. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  382. chia/_tests/wallet/test_wallet_blockchain.py +111 -0
  383. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  384. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  385. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  386. chia/_tests/wallet/test_wallet_node.py +780 -0
  387. chia/_tests/wallet/test_wallet_retry.py +95 -0
  388. chia/_tests/wallet/test_wallet_state_manager.py +259 -0
  389. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  390. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  391. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  392. chia/_tests/wallet/test_wallet_utils.py +156 -0
  393. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  394. chia/_tests/wallet/vc_wallet/config.py +3 -0
  395. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  396. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  397. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
  398. chia/_tests/wallet/wallet_block_tools.py +327 -0
  399. chia/_tests/weight_proof/__init__.py +0 -0
  400. chia/_tests/weight_proof/config.py +3 -0
  401. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  402. chia/apis.py +19 -0
  403. chia/clvm/__init__.py +0 -0
  404. chia/cmds/__init__.py +0 -0
  405. chia/cmds/beta.py +184 -0
  406. chia/cmds/beta_funcs.py +137 -0
  407. chia/cmds/check_wallet_db.py +420 -0
  408. chia/cmds/chia.py +151 -0
  409. chia/cmds/cmd_classes.py +323 -0
  410. chia/cmds/cmd_helpers.py +242 -0
  411. chia/cmds/cmds_util.py +488 -0
  412. chia/cmds/coin_funcs.py +275 -0
  413. chia/cmds/coins.py +182 -0
  414. chia/cmds/completion.py +49 -0
  415. chia/cmds/configure.py +332 -0
  416. chia/cmds/dao.py +1064 -0
  417. chia/cmds/dao_funcs.py +598 -0
  418. chia/cmds/data.py +708 -0
  419. chia/cmds/data_funcs.py +385 -0
  420. chia/cmds/db.py +87 -0
  421. chia/cmds/db_backup_func.py +77 -0
  422. chia/cmds/db_upgrade_func.py +452 -0
  423. chia/cmds/db_validate_func.py +184 -0
  424. chia/cmds/dev.py +18 -0
  425. chia/cmds/farm.py +100 -0
  426. chia/cmds/farm_funcs.py +200 -0
  427. chia/cmds/gh.py +275 -0
  428. chia/cmds/init.py +63 -0
  429. chia/cmds/init_funcs.py +367 -0
  430. chia/cmds/installers.py +131 -0
  431. chia/cmds/keys.py +527 -0
  432. chia/cmds/keys_funcs.py +863 -0
  433. chia/cmds/netspace.py +50 -0
  434. chia/cmds/netspace_funcs.py +54 -0
  435. chia/cmds/options.py +32 -0
  436. chia/cmds/param_types.py +238 -0
  437. chia/cmds/passphrase.py +131 -0
  438. chia/cmds/passphrase_funcs.py +292 -0
  439. chia/cmds/peer.py +51 -0
  440. chia/cmds/peer_funcs.py +129 -0
  441. chia/cmds/plotnft.py +260 -0
  442. chia/cmds/plotnft_funcs.py +405 -0
  443. chia/cmds/plots.py +230 -0
  444. chia/cmds/plotters.py +18 -0
  445. chia/cmds/rpc.py +208 -0
  446. chia/cmds/show.py +72 -0
  447. chia/cmds/show_funcs.py +215 -0
  448. chia/cmds/signer.py +296 -0
  449. chia/cmds/sim.py +225 -0
  450. chia/cmds/sim_funcs.py +509 -0
  451. chia/cmds/start.py +24 -0
  452. chia/cmds/start_funcs.py +109 -0
  453. chia/cmds/stop.py +62 -0
  454. chia/cmds/units.py +9 -0
  455. chia/cmds/wallet.py +1901 -0
  456. chia/cmds/wallet_funcs.py +1874 -0
  457. chia/consensus/__init__.py +0 -0
  458. chia/consensus/block_body_validation.py +562 -0
  459. chia/consensus/block_creation.py +546 -0
  460. chia/consensus/block_header_validation.py +1059 -0
  461. chia/consensus/block_record.py +31 -0
  462. chia/consensus/block_rewards.py +53 -0
  463. chia/consensus/blockchain.py +1087 -0
  464. chia/consensus/blockchain_interface.py +56 -0
  465. chia/consensus/coinbase.py +30 -0
  466. chia/consensus/condition_costs.py +9 -0
  467. chia/consensus/constants.py +49 -0
  468. chia/consensus/cost_calculator.py +15 -0
  469. chia/consensus/default_constants.py +89 -0
  470. chia/consensus/deficit.py +55 -0
  471. chia/consensus/difficulty_adjustment.py +412 -0
  472. chia/consensus/find_fork_point.py +111 -0
  473. chia/consensus/full_block_to_block_record.py +167 -0
  474. chia/consensus/get_block_challenge.py +106 -0
  475. chia/consensus/get_block_generator.py +27 -0
  476. chia/consensus/make_sub_epoch_summary.py +210 -0
  477. chia/consensus/multiprocess_validation.py +268 -0
  478. chia/consensus/pos_quality.py +19 -0
  479. chia/consensus/pot_iterations.py +67 -0
  480. chia/consensus/puzzles/__init__.py +0 -0
  481. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  482. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  483. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  484. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  485. chia/consensus/vdf_info_computation.py +156 -0
  486. chia/daemon/__init__.py +0 -0
  487. chia/daemon/client.py +252 -0
  488. chia/daemon/keychain_proxy.py +502 -0
  489. chia/daemon/keychain_server.py +365 -0
  490. chia/daemon/server.py +1606 -0
  491. chia/daemon/windows_signal.py +56 -0
  492. chia/data_layer/__init__.py +0 -0
  493. chia/data_layer/data_layer.py +1291 -0
  494. chia/data_layer/data_layer_api.py +33 -0
  495. chia/data_layer/data_layer_errors.py +50 -0
  496. chia/data_layer/data_layer_server.py +170 -0
  497. chia/data_layer/data_layer_util.py +985 -0
  498. chia/data_layer/data_layer_wallet.py +1311 -0
  499. chia/data_layer/data_store.py +2267 -0
  500. chia/data_layer/dl_wallet_store.py +407 -0
  501. chia/data_layer/download_data.py +389 -0
  502. chia/data_layer/puzzles/__init__.py +0 -0
  503. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  504. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  505. chia/data_layer/s3_plugin_config.yml +33 -0
  506. chia/data_layer/s3_plugin_service.py +468 -0
  507. chia/data_layer/util/__init__.py +0 -0
  508. chia/data_layer/util/benchmark.py +107 -0
  509. chia/data_layer/util/plugin.py +40 -0
  510. chia/farmer/__init__.py +0 -0
  511. chia/farmer/farmer.py +923 -0
  512. chia/farmer/farmer_api.py +820 -0
  513. chia/full_node/__init__.py +0 -0
  514. chia/full_node/bitcoin_fee_estimator.py +85 -0
  515. chia/full_node/block_height_map.py +271 -0
  516. chia/full_node/block_store.py +576 -0
  517. chia/full_node/bundle_tools.py +19 -0
  518. chia/full_node/coin_store.py +647 -0
  519. chia/full_node/fee_estimate.py +54 -0
  520. chia/full_node/fee_estimate_store.py +24 -0
  521. chia/full_node/fee_estimation.py +92 -0
  522. chia/full_node/fee_estimator.py +90 -0
  523. chia/full_node/fee_estimator_constants.py +38 -0
  524. chia/full_node/fee_estimator_interface.py +42 -0
  525. chia/full_node/fee_history.py +25 -0
  526. chia/full_node/fee_tracker.py +564 -0
  527. chia/full_node/full_node.py +3327 -0
  528. chia/full_node/full_node_api.py +2025 -0
  529. chia/full_node/full_node_store.py +1033 -0
  530. chia/full_node/hint_management.py +56 -0
  531. chia/full_node/hint_store.py +93 -0
  532. chia/full_node/mempool.py +589 -0
  533. chia/full_node/mempool_check_conditions.py +146 -0
  534. chia/full_node/mempool_manager.py +853 -0
  535. chia/full_node/pending_tx_cache.py +112 -0
  536. chia/full_node/puzzles/__init__.py +0 -0
  537. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  538. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  539. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  540. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  541. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  542. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  543. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  544. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  545. chia/full_node/signage_point.py +16 -0
  546. chia/full_node/subscriptions.py +247 -0
  547. chia/full_node/sync_store.py +146 -0
  548. chia/full_node/tx_processing_queue.py +78 -0
  549. chia/full_node/util/__init__.py +0 -0
  550. chia/full_node/weight_proof.py +1720 -0
  551. chia/harvester/__init__.py +0 -0
  552. chia/harvester/harvester.py +272 -0
  553. chia/harvester/harvester_api.py +380 -0
  554. chia/introducer/__init__.py +0 -0
  555. chia/introducer/introducer.py +122 -0
  556. chia/introducer/introducer_api.py +70 -0
  557. chia/legacy/__init__.py +0 -0
  558. chia/legacy/keyring.py +155 -0
  559. chia/plot_sync/__init__.py +0 -0
  560. chia/plot_sync/delta.py +61 -0
  561. chia/plot_sync/exceptions.py +56 -0
  562. chia/plot_sync/receiver.py +386 -0
  563. chia/plot_sync/sender.py +340 -0
  564. chia/plot_sync/util.py +43 -0
  565. chia/plotters/__init__.py +0 -0
  566. chia/plotters/bladebit.py +388 -0
  567. chia/plotters/chiapos.py +63 -0
  568. chia/plotters/madmax.py +224 -0
  569. chia/plotters/plotters.py +577 -0
  570. chia/plotters/plotters_util.py +133 -0
  571. chia/plotting/__init__.py +0 -0
  572. chia/plotting/cache.py +213 -0
  573. chia/plotting/check_plots.py +283 -0
  574. chia/plotting/create_plots.py +278 -0
  575. chia/plotting/manager.py +436 -0
  576. chia/plotting/util.py +336 -0
  577. chia/pools/__init__.py +0 -0
  578. chia/pools/pool_config.py +110 -0
  579. chia/pools/pool_puzzles.py +459 -0
  580. chia/pools/pool_wallet.py +933 -0
  581. chia/pools/pool_wallet_info.py +118 -0
  582. chia/pools/puzzles/__init__.py +0 -0
  583. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  584. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  585. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  586. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  587. chia/protocols/__init__.py +0 -0
  588. chia/protocols/farmer_protocol.py +102 -0
  589. chia/protocols/full_node_protocol.py +219 -0
  590. chia/protocols/harvester_protocol.py +216 -0
  591. chia/protocols/introducer_protocol.py +25 -0
  592. chia/protocols/pool_protocol.py +177 -0
  593. chia/protocols/protocol_message_types.py +139 -0
  594. chia/protocols/protocol_state_machine.py +87 -0
  595. chia/protocols/protocol_timing.py +8 -0
  596. chia/protocols/shared_protocol.py +86 -0
  597. chia/protocols/timelord_protocol.py +93 -0
  598. chia/protocols/wallet_protocol.py +401 -0
  599. chia/py.typed +0 -0
  600. chia/rpc/__init__.py +0 -0
  601. chia/rpc/crawler_rpc_api.py +80 -0
  602. chia/rpc/data_layer_rpc_api.py +644 -0
  603. chia/rpc/data_layer_rpc_client.py +188 -0
  604. chia/rpc/data_layer_rpc_util.py +58 -0
  605. chia/rpc/farmer_rpc_api.py +365 -0
  606. chia/rpc/farmer_rpc_client.py +86 -0
  607. chia/rpc/full_node_rpc_api.py +959 -0
  608. chia/rpc/full_node_rpc_client.py +292 -0
  609. chia/rpc/harvester_rpc_api.py +141 -0
  610. chia/rpc/harvester_rpc_client.py +54 -0
  611. chia/rpc/rpc_client.py +164 -0
  612. chia/rpc/rpc_server.py +521 -0
  613. chia/rpc/timelord_rpc_api.py +32 -0
  614. chia/rpc/util.py +93 -0
  615. chia/rpc/wallet_request_types.py +904 -0
  616. chia/rpc/wallet_rpc_api.py +4943 -0
  617. chia/rpc/wallet_rpc_client.py +1814 -0
  618. chia/seeder/__init__.py +0 -0
  619. chia/seeder/crawl_store.py +425 -0
  620. chia/seeder/crawler.py +410 -0
  621. chia/seeder/crawler_api.py +135 -0
  622. chia/seeder/dns_server.py +593 -0
  623. chia/seeder/peer_record.py +146 -0
  624. chia/seeder/start_crawler.py +92 -0
  625. chia/server/__init__.py +0 -0
  626. chia/server/address_manager.py +658 -0
  627. chia/server/address_manager_store.py +237 -0
  628. chia/server/api_protocol.py +116 -0
  629. chia/server/capabilities.py +24 -0
  630. chia/server/chia_policy.py +346 -0
  631. chia/server/introducer_peers.py +76 -0
  632. chia/server/node_discovery.py +714 -0
  633. chia/server/outbound_message.py +33 -0
  634. chia/server/rate_limit_numbers.py +214 -0
  635. chia/server/rate_limits.py +153 -0
  636. chia/server/server.py +741 -0
  637. chia/server/signal_handlers.py +120 -0
  638. chia/server/ssl_context.py +32 -0
  639. chia/server/start_data_layer.py +151 -0
  640. chia/server/start_farmer.py +98 -0
  641. chia/server/start_full_node.py +112 -0
  642. chia/server/start_harvester.py +93 -0
  643. chia/server/start_introducer.py +81 -0
  644. chia/server/start_service.py +316 -0
  645. chia/server/start_timelord.py +89 -0
  646. chia/server/start_wallet.py +113 -0
  647. chia/server/upnp.py +118 -0
  648. chia/server/ws_connection.py +766 -0
  649. chia/simulator/__init__.py +0 -0
  650. chia/simulator/add_blocks_in_batches.py +54 -0
  651. chia/simulator/block_tools.py +2054 -0
  652. chia/simulator/full_node_simulator.py +794 -0
  653. chia/simulator/keyring.py +128 -0
  654. chia/simulator/setup_services.py +506 -0
  655. chia/simulator/simulator_constants.py +13 -0
  656. chia/simulator/simulator_full_node_rpc_api.py +99 -0
  657. chia/simulator/simulator_full_node_rpc_client.py +60 -0
  658. chia/simulator/simulator_protocol.py +29 -0
  659. chia/simulator/simulator_test_tools.py +164 -0
  660. chia/simulator/socket.py +24 -0
  661. chia/simulator/ssl_certs.py +114 -0
  662. chia/simulator/ssl_certs_1.py +697 -0
  663. chia/simulator/ssl_certs_10.py +697 -0
  664. chia/simulator/ssl_certs_2.py +697 -0
  665. chia/simulator/ssl_certs_3.py +697 -0
  666. chia/simulator/ssl_certs_4.py +697 -0
  667. chia/simulator/ssl_certs_5.py +697 -0
  668. chia/simulator/ssl_certs_6.py +697 -0
  669. chia/simulator/ssl_certs_7.py +697 -0
  670. chia/simulator/ssl_certs_8.py +697 -0
  671. chia/simulator/ssl_certs_9.py +697 -0
  672. chia/simulator/start_simulator.py +143 -0
  673. chia/simulator/wallet_tools.py +246 -0
  674. chia/ssl/__init__.py +0 -0
  675. chia/ssl/chia_ca.crt +19 -0
  676. chia/ssl/chia_ca.key +28 -0
  677. chia/ssl/create_ssl.py +249 -0
  678. chia/ssl/dst_root_ca.pem +20 -0
  679. chia/timelord/__init__.py +0 -0
  680. chia/timelord/iters_from_block.py +50 -0
  681. chia/timelord/timelord.py +1226 -0
  682. chia/timelord/timelord_api.py +138 -0
  683. chia/timelord/timelord_launcher.py +190 -0
  684. chia/timelord/timelord_state.py +244 -0
  685. chia/timelord/types.py +22 -0
  686. chia/types/__init__.py +0 -0
  687. chia/types/aliases.py +35 -0
  688. chia/types/block_protocol.py +20 -0
  689. chia/types/blockchain_format/__init__.py +0 -0
  690. chia/types/blockchain_format/classgroup.py +5 -0
  691. chia/types/blockchain_format/coin.py +28 -0
  692. chia/types/blockchain_format/foliage.py +8 -0
  693. chia/types/blockchain_format/pool_target.py +5 -0
  694. chia/types/blockchain_format/program.py +269 -0
  695. chia/types/blockchain_format/proof_of_space.py +135 -0
  696. chia/types/blockchain_format/reward_chain_block.py +6 -0
  697. chia/types/blockchain_format/serialized_program.py +5 -0
  698. chia/types/blockchain_format/sized_bytes.py +11 -0
  699. chia/types/blockchain_format/slots.py +9 -0
  700. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  701. chia/types/blockchain_format/tree_hash.py +72 -0
  702. chia/types/blockchain_format/vdf.py +86 -0
  703. chia/types/clvm_cost.py +13 -0
  704. chia/types/coin_record.py +43 -0
  705. chia/types/coin_spend.py +115 -0
  706. chia/types/condition_opcodes.py +73 -0
  707. chia/types/condition_with_args.py +16 -0
  708. chia/types/eligible_coin_spends.py +365 -0
  709. chia/types/end_of_slot_bundle.py +5 -0
  710. chia/types/fee_rate.py +38 -0
  711. chia/types/full_block.py +5 -0
  712. chia/types/generator_types.py +13 -0
  713. chia/types/header_block.py +5 -0
  714. chia/types/internal_mempool_item.py +18 -0
  715. chia/types/mempool_inclusion_status.py +9 -0
  716. chia/types/mempool_item.py +85 -0
  717. chia/types/mempool_submission_status.py +30 -0
  718. chia/types/mojos.py +7 -0
  719. chia/types/peer_info.py +64 -0
  720. chia/types/signing_mode.py +29 -0
  721. chia/types/spend_bundle.py +30 -0
  722. chia/types/spend_bundle_conditions.py +7 -0
  723. chia/types/transaction_queue_entry.py +55 -0
  724. chia/types/unfinished_block.py +5 -0
  725. chia/types/unfinished_header_block.py +37 -0
  726. chia/types/validation_state.py +14 -0
  727. chia/types/weight_proof.py +49 -0
  728. chia/util/__init__.py +0 -0
  729. chia/util/action_scope.py +168 -0
  730. chia/util/async_pool.py +226 -0
  731. chia/util/augmented_chain.py +134 -0
  732. chia/util/batches.py +42 -0
  733. chia/util/bech32m.py +126 -0
  734. chia/util/beta_metrics.py +119 -0
  735. chia/util/block_cache.py +56 -0
  736. chia/util/byte_types.py +12 -0
  737. chia/util/check_fork_next_block.py +33 -0
  738. chia/util/chia_logging.py +144 -0
  739. chia/util/chia_version.py +33 -0
  740. chia/util/collection.py +17 -0
  741. chia/util/condition_tools.py +201 -0
  742. chia/util/config.py +367 -0
  743. chia/util/cpu.py +22 -0
  744. chia/util/db_synchronous.py +23 -0
  745. chia/util/db_version.py +32 -0
  746. chia/util/db_wrapper.py +430 -0
  747. chia/util/default_root.py +27 -0
  748. chia/util/dump_keyring.py +93 -0
  749. chia/util/english.txt +2048 -0
  750. chia/util/errors.py +353 -0
  751. chia/util/file_keyring.py +469 -0
  752. chia/util/files.py +97 -0
  753. chia/util/full_block_utils.py +345 -0
  754. chia/util/generator_tools.py +72 -0
  755. chia/util/hash.py +31 -0
  756. chia/util/initial-config.yaml +694 -0
  757. chia/util/inline_executor.py +26 -0
  758. chia/util/ints.py +19 -0
  759. chia/util/ip_address.py +39 -0
  760. chia/util/json_util.py +37 -0
  761. chia/util/keychain.py +676 -0
  762. chia/util/keyring_wrapper.py +327 -0
  763. chia/util/limited_semaphore.py +41 -0
  764. chia/util/lock.py +49 -0
  765. chia/util/log_exceptions.py +32 -0
  766. chia/util/logging.py +36 -0
  767. chia/util/lru_cache.py +31 -0
  768. chia/util/math.py +20 -0
  769. chia/util/network.py +182 -0
  770. chia/util/paginator.py +48 -0
  771. chia/util/path.py +31 -0
  772. chia/util/permissions.py +20 -0
  773. chia/util/prev_transaction_block.py +21 -0
  774. chia/util/priority_mutex.py +95 -0
  775. chia/util/profiler.py +197 -0
  776. chia/util/recursive_replace.py +24 -0
  777. chia/util/safe_cancel_task.py +16 -0
  778. chia/util/service_groups.py +47 -0
  779. chia/util/setproctitle.py +22 -0
  780. chia/util/significant_bits.py +32 -0
  781. chia/util/ssl_check.py +213 -0
  782. chia/util/streamable.py +642 -0
  783. chia/util/task_referencer.py +59 -0
  784. chia/util/task_timing.py +382 -0
  785. chia/util/timing.py +67 -0
  786. chia/util/vdf_prover.py +30 -0
  787. chia/util/virtual_project_analysis.py +540 -0
  788. chia/util/ws_message.py +66 -0
  789. chia/wallet/__init__.py +0 -0
  790. chia/wallet/cat_wallet/__init__.py +0 -0
  791. chia/wallet/cat_wallet/cat_constants.py +75 -0
  792. chia/wallet/cat_wallet/cat_info.py +47 -0
  793. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  794. chia/wallet/cat_wallet/cat_utils.py +164 -0
  795. chia/wallet/cat_wallet/cat_wallet.py +855 -0
  796. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  797. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  798. chia/wallet/cat_wallet/lineage_store.py +74 -0
  799. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  800. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  801. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  802. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  803. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  804. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  805. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  806. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  807. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  808. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  809. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  810. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  811. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  812. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  813. chia/wallet/coin_selection.py +188 -0
  814. chia/wallet/conditions.py +1512 -0
  815. chia/wallet/dao_wallet/__init__.py +0 -0
  816. chia/wallet/dao_wallet/dao_info.py +61 -0
  817. chia/wallet/dao_wallet/dao_utils.py +811 -0
  818. chia/wallet/dao_wallet/dao_wallet.py +2119 -0
  819. chia/wallet/db_wallet/__init__.py +0 -0
  820. chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
  821. chia/wallet/derivation_record.py +30 -0
  822. chia/wallet/derive_keys.py +146 -0
  823. chia/wallet/did_wallet/__init__.py +0 -0
  824. chia/wallet/did_wallet/did_info.py +39 -0
  825. chia/wallet/did_wallet/did_wallet.py +1494 -0
  826. chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
  827. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  828. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  829. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  830. chia/wallet/driver_protocol.py +26 -0
  831. chia/wallet/key_val_store.py +55 -0
  832. chia/wallet/lineage_proof.py +58 -0
  833. chia/wallet/nft_wallet/__init__.py +0 -0
  834. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  835. chia/wallet/nft_wallet/nft_info.py +120 -0
  836. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  837. chia/wallet/nft_wallet/nft_wallet.py +1687 -0
  838. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  839. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  840. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  841. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  842. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  843. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  844. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  845. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  846. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  847. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  848. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  849. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  850. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  851. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  852. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  853. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  854. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  855. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  856. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  857. chia/wallet/notification_manager.py +117 -0
  858. chia/wallet/notification_store.py +178 -0
  859. chia/wallet/outer_puzzles.py +84 -0
  860. chia/wallet/payment.py +33 -0
  861. chia/wallet/puzzle_drivers.py +118 -0
  862. chia/wallet/puzzles/__init__.py +0 -0
  863. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  864. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  865. chia/wallet/puzzles/clawback/__init__.py +0 -0
  866. chia/wallet/puzzles/clawback/drivers.py +188 -0
  867. chia/wallet/puzzles/clawback/metadata.py +38 -0
  868. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  869. chia/wallet/puzzles/condition_codes.clib +77 -0
  870. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  871. chia/wallet/puzzles/curry.clib +135 -0
  872. chia/wallet/puzzles/curry_by_index.clib +16 -0
  873. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  874. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  876. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  877. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  878. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  879. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  880. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  881. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  882. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  883. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  884. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  885. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  886. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  887. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  888. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  889. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  890. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  891. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  892. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  893. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  894. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  895. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  896. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  897. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  898. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  899. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  900. chia/wallet/puzzles/json.clib +25 -0
  901. chia/wallet/puzzles/load_clvm.py +161 -0
  902. chia/wallet/puzzles/merkle_utils.clib +18 -0
  903. chia/wallet/puzzles/notification.clsp +7 -0
  904. chia/wallet/puzzles/notification.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  906. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  907. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  908. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  909. chia/wallet/puzzles/p2_conditions.py +26 -0
  910. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  911. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  912. chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
  913. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  914. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  915. chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
  916. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  917. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
  919. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  920. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  921. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
  922. chia/wallet/puzzles/p2_parent.clsp +19 -0
  923. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  924. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  925. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  926. chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
  927. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  928. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  929. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  930. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  931. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  932. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  933. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  934. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  935. chia/wallet/puzzles/puzzle_utils.py +34 -0
  936. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  937. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  938. chia/wallet/puzzles/sha256tree.clib +11 -0
  939. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  940. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  941. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  942. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  943. chia/wallet/puzzles/singleton_top_layer.py +296 -0
  944. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  945. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  946. chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
  947. chia/wallet/puzzles/singleton_truths.clib +21 -0
  948. chia/wallet/puzzles/tails.py +348 -0
  949. chia/wallet/puzzles/utility_macros.clib +48 -0
  950. chia/wallet/signer_protocol.py +125 -0
  951. chia/wallet/singleton.py +106 -0
  952. chia/wallet/singleton_record.py +30 -0
  953. chia/wallet/trade_manager.py +1102 -0
  954. chia/wallet/trade_record.py +67 -0
  955. chia/wallet/trading/__init__.py +0 -0
  956. chia/wallet/trading/offer.py +702 -0
  957. chia/wallet/trading/trade_status.py +13 -0
  958. chia/wallet/trading/trade_store.py +526 -0
  959. chia/wallet/transaction_record.py +158 -0
  960. chia/wallet/transaction_sorting.py +14 -0
  961. chia/wallet/uncurried_puzzle.py +17 -0
  962. chia/wallet/util/__init__.py +0 -0
  963. chia/wallet/util/address_type.py +55 -0
  964. chia/wallet/util/blind_signer_tl.py +164 -0
  965. chia/wallet/util/clvm_streamable.py +203 -0
  966. chia/wallet/util/compute_hints.py +66 -0
  967. chia/wallet/util/compute_memos.py +43 -0
  968. chia/wallet/util/curry_and_treehash.py +91 -0
  969. chia/wallet/util/debug_spend_bundle.py +232 -0
  970. chia/wallet/util/merkle_tree.py +100 -0
  971. chia/wallet/util/merkle_utils.py +102 -0
  972. chia/wallet/util/new_peak_queue.py +82 -0
  973. chia/wallet/util/notifications.py +12 -0
  974. chia/wallet/util/peer_request_cache.py +174 -0
  975. chia/wallet/util/pprint.py +39 -0
  976. chia/wallet/util/puzzle_compression.py +95 -0
  977. chia/wallet/util/puzzle_decorator.py +100 -0
  978. chia/wallet/util/puzzle_decorator_type.py +7 -0
  979. chia/wallet/util/query_filter.py +59 -0
  980. chia/wallet/util/transaction_type.py +23 -0
  981. chia/wallet/util/tx_config.py +158 -0
  982. chia/wallet/util/wallet_sync_utils.py +351 -0
  983. chia/wallet/util/wallet_types.py +72 -0
  984. chia/wallet/vc_wallet/__init__.py +0 -0
  985. chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
  986. chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
  987. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  988. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  989. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  990. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  992. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  994. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  996. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  997. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  998. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  1002. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  1003. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  1004. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  1005. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  1006. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  1007. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  1008. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  1009. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  1010. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  1011. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  1012. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  1013. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1014. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1015. chia/wallet/vc_wallet/vc_store.py +263 -0
  1016. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1017. chia/wallet/wallet.py +698 -0
  1018. chia/wallet/wallet_action_scope.py +96 -0
  1019. chia/wallet/wallet_blockchain.py +244 -0
  1020. chia/wallet/wallet_coin_record.py +72 -0
  1021. chia/wallet/wallet_coin_store.py +351 -0
  1022. chia/wallet/wallet_info.py +35 -0
  1023. chia/wallet/wallet_interested_store.py +188 -0
  1024. chia/wallet/wallet_nft_store.py +279 -0
  1025. chia/wallet/wallet_node.py +1765 -0
  1026. chia/wallet/wallet_node_api.py +207 -0
  1027. chia/wallet/wallet_pool_store.py +119 -0
  1028. chia/wallet/wallet_protocol.py +90 -0
  1029. chia/wallet/wallet_puzzle_store.py +396 -0
  1030. chia/wallet/wallet_retry_store.py +70 -0
  1031. chia/wallet/wallet_singleton_store.py +259 -0
  1032. chia/wallet/wallet_spend_bundle.py +25 -0
  1033. chia/wallet/wallet_state_manager.py +2819 -0
  1034. chia/wallet/wallet_transaction_store.py +496 -0
  1035. chia/wallet/wallet_user_store.py +110 -0
  1036. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1037. chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
  1038. chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
  1039. chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
  1040. chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
  1041. chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
  1042. mozilla-ca/cacert.pem +3611 -0
@@ -0,0 +1,2700 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import contextlib
5
+ import dataclasses
6
+ import logging
7
+ import random
8
+ import time
9
+ from collections.abc import Awaitable, Coroutine
10
+ from typing import Optional
11
+
12
+ import pytest
13
+ from chia_rs import (
14
+ AugSchemeMPL,
15
+ G2Element,
16
+ PrivateKey,
17
+ SpendBundleConditions,
18
+ additions_and_removals,
19
+ get_flags_for_height_and_constants,
20
+ )
21
+ from clvm.casts import int_to_bytes
22
+ from packaging.version import Version
23
+
24
+ from chia._tests.blockchain.blockchain_test_utils import _validate_and_add_block, _validate_and_add_block_no_error
25
+ from chia._tests.conftest import ConsensusMode
26
+ from chia._tests.connection_utils import add_dummy_connection, connect_and_get_peer
27
+ from chia._tests.core.full_node.stores.test_coin_store import get_future_reward_coins
28
+ from chia._tests.core.make_block_generator import make_spend_bundle
29
+ from chia._tests.core.node_height import node_height_at_least
30
+ from chia._tests.util.misc import wallet_height_at_least
31
+ from chia._tests.util.setup_nodes import SimulatorsAndWalletsServices
32
+ from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_custom_interval, time_out_messages
33
+ from chia.consensus.block_body_validation import ForkInfo
34
+ from chia.consensus.multiprocess_validation import PreValidationResult, pre_validate_block
35
+ from chia.consensus.pot_iterations import is_overflow_block
36
+ from chia.full_node.coin_store import CoinStore
37
+ from chia.full_node.full_node import WalletUpdate
38
+ from chia.full_node.full_node_api import FullNodeAPI
39
+ from chia.full_node.signage_point import SignagePoint
40
+ from chia.full_node.sync_store import Peak
41
+ from chia.protocols import full_node_protocol, timelord_protocol, wallet_protocol
42
+ from chia.protocols import full_node_protocol as fnp
43
+ from chia.protocols.full_node_protocol import RespondTransaction
44
+ from chia.protocols.protocol_message_types import ProtocolMessageTypes
45
+ from chia.protocols.shared_protocol import Capability, default_capabilities
46
+ from chia.protocols.wallet_protocol import SendTransaction, TransactionAck
47
+ from chia.server.address_manager import AddressManager
48
+ from chia.server.outbound_message import Message, NodeType
49
+ from chia.server.server import ChiaServer
50
+ from chia.simulator.add_blocks_in_batches import add_blocks_in_batches
51
+ from chia.simulator.block_tools import (
52
+ BlockTools,
53
+ create_block_tools_async,
54
+ get_signage_point,
55
+ make_unfinished_block,
56
+ test_constants,
57
+ )
58
+ from chia.simulator.full_node_simulator import FullNodeSimulator
59
+ from chia.simulator.keyring import TempKeyring
60
+ from chia.simulator.setup_services import setup_full_node
61
+ from chia.simulator.simulator_protocol import FarmNewBlockProtocol
62
+ from chia.simulator.wallet_tools import WalletTool
63
+ from chia.types.blockchain_format.classgroup import ClassgroupElement
64
+ from chia.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock, TransactionsInfo
65
+ from chia.types.blockchain_format.program import Program
66
+ from chia.types.blockchain_format.proof_of_space import ProofOfSpace, calculate_plot_id_pk, calculate_pos_challenge
67
+ from chia.types.blockchain_format.reward_chain_block import RewardChainBlockUnfinished
68
+ from chia.types.blockchain_format.serialized_program import SerializedProgram
69
+ from chia.types.blockchain_format.sized_bytes import bytes32
70
+ from chia.types.blockchain_format.vdf import CompressibleVDFField, VDFProof
71
+ from chia.types.coin_record import CoinRecord
72
+ from chia.types.coin_spend import make_spend
73
+ from chia.types.condition_opcodes import ConditionOpcode
74
+ from chia.types.condition_with_args import ConditionWithArgs
75
+ from chia.types.full_block import FullBlock
76
+ from chia.types.mempool_inclusion_status import MempoolInclusionStatus
77
+ from chia.types.peer_info import PeerInfo, TimestampedPeerInfo
78
+ from chia.types.spend_bundle import SpendBundle, estimate_fees
79
+ from chia.types.unfinished_block import UnfinishedBlock
80
+ from chia.types.validation_state import ValidationState
81
+ from chia.util.augmented_chain import AugmentedBlockchain
82
+ from chia.util.errors import ConsensusError, Err
83
+ from chia.util.hash import std_hash
84
+ from chia.util.ints import uint8, uint16, uint32, uint64, uint128
85
+ from chia.util.limited_semaphore import LimitedSemaphore
86
+ from chia.util.recursive_replace import recursive_replace
87
+ from chia.util.task_referencer import create_referenced_task
88
+ from chia.util.vdf_prover import get_vdf_info_and_proof
89
+ from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
90
+ from chia.wallet.wallet_spend_bundle import WalletSpendBundle
91
+
92
+
93
+ def test_pre_validation_result() -> None:
94
+ conds = SpendBundleConditions([], 0, 0, 0, None, None, [], 0, 0, 0, True, 0, 0)
95
+ results = PreValidationResult(None, uint64(1), conds, uint32(0))
96
+ assert results.validated_signature is True
97
+
98
+ conds = SpendBundleConditions([], 0, 0, 0, None, None, [], 0, 0, 0, False, 0, 0)
99
+ results = PreValidationResult(None, uint64(1), conds, uint32(0))
100
+ assert results.validated_signature is False
101
+
102
+
103
+ async def new_transaction_not_requested(incoming, new_spend):
104
+ await asyncio.sleep(3)
105
+ while not incoming.empty():
106
+ response = await incoming.get()
107
+ if (
108
+ response is not None
109
+ and isinstance(response, Message)
110
+ and response.type == ProtocolMessageTypes.request_transaction.value
111
+ ):
112
+ request = full_node_protocol.RequestTransaction.from_bytes(response.data)
113
+ if request.transaction_id == new_spend.transaction_id:
114
+ return False
115
+ return True
116
+
117
+
118
+ async def new_transaction_requested(incoming, new_spend):
119
+ await asyncio.sleep(1)
120
+ while not incoming.empty():
121
+ response = await incoming.get()
122
+ if (
123
+ response is not None
124
+ and isinstance(response, Message)
125
+ and response.type == ProtocolMessageTypes.request_transaction.value
126
+ ):
127
+ request = full_node_protocol.RequestTransaction.from_bytes(response.data)
128
+ if request.transaction_id == new_spend.transaction_id:
129
+ return True
130
+ return False
131
+
132
+
133
+ async def get_block_path(full_node: FullNodeAPI):
134
+ blocks_list = [await full_node.full_node.blockchain.get_full_peak()]
135
+ assert blocks_list[0] is not None
136
+ while blocks_list[0].height != 0:
137
+ b = await full_node.full_node.block_store.get_full_block(blocks_list[0].prev_header_hash)
138
+ assert b is not None
139
+ blocks_list.insert(0, b)
140
+ return blocks_list
141
+
142
+
143
+ @pytest.mark.anyio
144
+ async def test_sync_no_farmer(
145
+ setup_two_nodes_and_wallet,
146
+ default_1000_blocks: list[FullBlock],
147
+ self_hostname: str,
148
+ seeded_random: random.Random,
149
+ ):
150
+ nodes, _wallets, _bt = setup_two_nodes_and_wallet
151
+ server_1 = nodes[0].full_node.server
152
+ server_2 = nodes[1].full_node.server
153
+ full_node_1 = nodes[0]
154
+ full_node_2 = nodes[1]
155
+
156
+ blocks = default_1000_blocks
157
+
158
+ # full node 1 has the complete chain
159
+ await add_blocks_in_batches(blocks, full_node_1.full_node)
160
+ target_peak = full_node_1.full_node.blockchain.get_peak()
161
+
162
+ # full node 2 is behind by 800 blocks
163
+ await add_blocks_in_batches(blocks[:-800], full_node_2.full_node)
164
+ # connect the nodes and wait for node 2 to sync up to node 1
165
+ await connect_and_get_peer(server_1, server_2, self_hostname)
166
+
167
+ def check_nodes_in_sync():
168
+ p1 = full_node_2.full_node.blockchain.get_peak()
169
+ p2 = full_node_1.full_node.blockchain.get_peak()
170
+ return p1 == p2
171
+
172
+ await time_out_assert(120, check_nodes_in_sync)
173
+
174
+ assert full_node_1.full_node.blockchain.get_peak() == target_peak
175
+ assert full_node_2.full_node.blockchain.get_peak() == target_peak
176
+
177
+
178
+ @pytest.mark.anyio
179
+ @pytest.mark.parametrize("tx_size", [3000000000000])
180
+ async def test_block_compression(setup_two_nodes_and_wallet, empty_blockchain, tx_size, self_hostname):
181
+ nodes, wallets, bt = setup_two_nodes_and_wallet
182
+ server_1 = nodes[0].full_node.server
183
+ server_2 = nodes[1].full_node.server
184
+ server_3 = wallets[0][1]
185
+ full_node_1 = nodes[0]
186
+ full_node_2 = nodes[1]
187
+ wallet_node_1 = wallets[0][0]
188
+ wallet = wallet_node_1.wallet_state_manager.main_wallet
189
+
190
+ # Avoid retesting the slow reorg portion, not necessary more than once
191
+ test_reorgs = True
192
+ _ = await connect_and_get_peer(server_1, server_2, self_hostname)
193
+ _ = await connect_and_get_peer(server_1, server_3, self_hostname)
194
+
195
+ ph = await wallet.get_new_puzzlehash()
196
+
197
+ for i in range(4):
198
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
199
+
200
+ await time_out_assert(30, wallet_height_at_least, True, wallet_node_1, 4)
201
+ await time_out_assert(30, node_height_at_least, True, full_node_1, 4)
202
+ await time_out_assert(30, node_height_at_least, True, full_node_2, 4)
203
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
204
+
205
+ # Send a transaction to mempool
206
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
207
+ await wallet.generate_signed_transaction(
208
+ tx_size,
209
+ ph,
210
+ action_scope,
211
+ )
212
+ [tr] = action_scope.side_effects.transactions
213
+ await time_out_assert(
214
+ 10,
215
+ full_node_2.full_node.mempool_manager.get_spendbundle,
216
+ tr.spend_bundle,
217
+ tr.name,
218
+ )
219
+
220
+ # Farm a block
221
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
222
+ await time_out_assert(30, node_height_at_least, True, full_node_1, 5)
223
+ await time_out_assert(30, node_height_at_least, True, full_node_2, 5)
224
+ await time_out_assert(30, wallet_height_at_least, True, wallet_node_1, 5)
225
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
226
+
227
+ async def check_transaction_confirmed(transaction) -> bool:
228
+ tx = await wallet_node_1.wallet_state_manager.get_transaction(transaction.name)
229
+ return tx.confirmed
230
+
231
+ await time_out_assert(30, check_transaction_confirmed, True, tr)
232
+
233
+ # Confirm generator is not compressed
234
+ program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
235
+ assert program is not None
236
+ assert len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list) == 0
237
+
238
+ # Send another tx
239
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
240
+ await wallet.generate_signed_transaction(
241
+ 20000,
242
+ ph,
243
+ action_scope,
244
+ )
245
+ [tr] = action_scope.side_effects.transactions
246
+ await time_out_assert(
247
+ 10,
248
+ full_node_2.full_node.mempool_manager.get_spendbundle,
249
+ tr.spend_bundle,
250
+ tr.name,
251
+ )
252
+
253
+ # Farm a block
254
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
255
+ await time_out_assert(10, node_height_at_least, True, full_node_1, 6)
256
+ await time_out_assert(10, node_height_at_least, True, full_node_2, 6)
257
+ await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 6)
258
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
259
+
260
+ await time_out_assert(10, check_transaction_confirmed, True, tr)
261
+
262
+ # Confirm generator is compressed
263
+ program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
264
+ assert program is not None
265
+ num_blocks = len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list)
266
+ # since the hard fork, we don't use this compression mechanism
267
+ # anymore, we use CLVM backrefs in the encoding instead
268
+ assert num_blocks == 0
269
+
270
+ # Farm two empty blocks
271
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
272
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
273
+ await time_out_assert(10, node_height_at_least, True, full_node_1, 8)
274
+ await time_out_assert(10, node_height_at_least, True, full_node_2, 8)
275
+ await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 8)
276
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
277
+
278
+ # Send another 2 tx
279
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
280
+ await wallet.generate_signed_transaction(
281
+ 30000,
282
+ ph,
283
+ action_scope,
284
+ )
285
+ [tr] = action_scope.side_effects.transactions
286
+ await time_out_assert(
287
+ 10,
288
+ full_node_2.full_node.mempool_manager.get_spendbundle,
289
+ tr.spend_bundle,
290
+ tr.name,
291
+ )
292
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
293
+ await wallet.generate_signed_transaction(
294
+ 40000,
295
+ ph,
296
+ action_scope,
297
+ )
298
+ [tr] = action_scope.side_effects.transactions
299
+ await time_out_assert(
300
+ 10,
301
+ full_node_2.full_node.mempool_manager.get_spendbundle,
302
+ tr.spend_bundle,
303
+ tr.name,
304
+ )
305
+
306
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
307
+ await wallet.generate_signed_transaction(
308
+ 50000,
309
+ ph,
310
+ action_scope,
311
+ )
312
+ [tr] = action_scope.side_effects.transactions
313
+ await time_out_assert(
314
+ 10,
315
+ full_node_2.full_node.mempool_manager.get_spendbundle,
316
+ tr.spend_bundle,
317
+ tr.name,
318
+ )
319
+
320
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
321
+ await wallet.generate_signed_transaction(
322
+ 3000000000000,
323
+ ph,
324
+ action_scope,
325
+ )
326
+ [tr] = action_scope.side_effects.transactions
327
+ await time_out_assert(
328
+ 10,
329
+ full_node_2.full_node.mempool_manager.get_spendbundle,
330
+ tr.spend_bundle,
331
+ tr.name,
332
+ )
333
+
334
+ # Farm a block
335
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
336
+ await time_out_assert(10, node_height_at_least, True, full_node_1, 9)
337
+ await time_out_assert(10, node_height_at_least, True, full_node_2, 9)
338
+ await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 9)
339
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
340
+
341
+ await time_out_assert(10, check_transaction_confirmed, True, tr)
342
+
343
+ # Confirm generator is compressed
344
+ program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
345
+ assert program is not None
346
+ num_blocks = len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list)
347
+ # since the hard fork, we don't use this compression mechanism
348
+ # anymore, we use CLVM backrefs in the encoding instead
349
+ assert num_blocks == 0
350
+
351
+ # Creates a standard_transaction and an anyone-can-spend tx
352
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
353
+ await wallet.generate_signed_transaction(
354
+ 30000,
355
+ Program.to(1).get_tree_hash(),
356
+ action_scope,
357
+ )
358
+ [tr] = action_scope.side_effects.transactions
359
+ extra_spend = WalletSpendBundle(
360
+ [
361
+ make_spend(
362
+ next(coin for coin in tr.additions if coin.puzzle_hash == Program.to(1).get_tree_hash()),
363
+ Program.to(1),
364
+ Program.to([[51, ph, 30000]]),
365
+ )
366
+ ],
367
+ G2Element(),
368
+ )
369
+ new_spend_bundle = WalletSpendBundle.aggregate([tr.spend_bundle, extra_spend])
370
+ new_tr = dataclasses.replace(
371
+ tr,
372
+ spend_bundle=new_spend_bundle,
373
+ additions=new_spend_bundle.additions(),
374
+ removals=new_spend_bundle.removals(),
375
+ )
376
+ [new_tr] = await wallet.wallet_state_manager.add_pending_transactions([new_tr])
377
+ await time_out_assert(
378
+ 10,
379
+ full_node_2.full_node.mempool_manager.get_spendbundle,
380
+ new_tr.spend_bundle,
381
+ new_tr.spend_bundle.name(),
382
+ )
383
+
384
+ # Farm a block
385
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
386
+ await time_out_assert(10, node_height_at_least, True, full_node_1, 10)
387
+ await time_out_assert(10, node_height_at_least, True, full_node_2, 10)
388
+ await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 10)
389
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
390
+
391
+ await time_out_assert(10, check_transaction_confirmed, True, new_tr)
392
+
393
+ # Confirm generator is not compressed, #CAT creation has a cat spend
394
+ all_blocks = await full_node_1.get_all_full_blocks()
395
+ program: Optional[SerializedProgram] = all_blocks[-1].transactions_generator
396
+ assert program is not None
397
+ assert len(all_blocks[-1].transactions_generator_ref_list) == 0
398
+
399
+ # Make a standard transaction and an anyone-can-spend transaction
400
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
401
+ await wallet.generate_signed_transaction(
402
+ 30000,
403
+ Program.to(1).get_tree_hash(),
404
+ action_scope,
405
+ )
406
+ [tr] = action_scope.side_effects.transactions
407
+ extra_spend = WalletSpendBundle(
408
+ [
409
+ make_spend(
410
+ next(coin for coin in tr.additions if coin.puzzle_hash == Program.to(1).get_tree_hash()),
411
+ Program.to(1),
412
+ Program.to([[51, ph, 30000]]),
413
+ )
414
+ ],
415
+ G2Element(),
416
+ )
417
+ new_spend_bundle = WalletSpendBundle.aggregate([tr.spend_bundle, extra_spend])
418
+ new_tr = dataclasses.replace(
419
+ tr,
420
+ spend_bundle=new_spend_bundle,
421
+ additions=new_spend_bundle.additions(),
422
+ removals=new_spend_bundle.removals(),
423
+ )
424
+ [new_tr] = await wallet.wallet_state_manager.add_pending_transactions([new_tr])
425
+ await time_out_assert(
426
+ 10,
427
+ full_node_2.full_node.mempool_manager.get_spendbundle,
428
+ new_tr.spend_bundle,
429
+ new_tr.spend_bundle.name(),
430
+ )
431
+
432
+ # Farm a block
433
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
434
+ await time_out_assert(10, node_height_at_least, True, full_node_1, 11)
435
+ await time_out_assert(10, node_height_at_least, True, full_node_2, 11)
436
+ await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 11)
437
+ await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
438
+
439
+ # Confirm generator is not compressed
440
+ program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
441
+ assert program is not None
442
+ assert len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list) == 0
443
+
444
+ height = full_node_1.full_node.blockchain.get_peak().height
445
+
446
+ blockchain = empty_blockchain
447
+ all_blocks: list[FullBlock] = await full_node_1.get_all_full_blocks()
448
+ assert height == len(all_blocks) - 1
449
+
450
+ if test_reorgs:
451
+ ssi = bt.constants.SUB_SLOT_ITERS_STARTING
452
+ diff = bt.constants.DIFFICULTY_STARTING
453
+ reog_blocks = bt.get_consecutive_blocks(14)
454
+ for r in range(0, len(reog_blocks), 3):
455
+ fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
456
+ for reorg_block in reog_blocks[:r]:
457
+ await _validate_and_add_block_no_error(blockchain, reorg_block, fork_info=fork_info)
458
+ for i in range(1, height):
459
+ vs = ValidationState(ssi, diff, None)
460
+ chain = AugmentedBlockchain(blockchain)
461
+ futures: list[Awaitable[PreValidationResult]] = []
462
+ for block in all_blocks[:i]:
463
+ futures.append(
464
+ await pre_validate_block(
465
+ blockchain.constants,
466
+ chain,
467
+ block,
468
+ blockchain.pool,
469
+ None,
470
+ vs,
471
+ )
472
+ )
473
+ results: list[PreValidationResult] = list(await asyncio.gather(*futures))
474
+ for result in results:
475
+ assert result.error is None
476
+
477
+ for r in range(0, len(all_blocks), 3):
478
+ fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
479
+ for block in all_blocks[:r]:
480
+ await _validate_and_add_block_no_error(blockchain, block, fork_info=fork_info)
481
+ for i in range(1, height):
482
+ vs = ValidationState(ssi, diff, None)
483
+ chain = AugmentedBlockchain(blockchain)
484
+ futures = []
485
+ for block in all_blocks[:i]:
486
+ futures.append(
487
+ await pre_validate_block(blockchain.constants, chain, block, blockchain.pool, None, vs)
488
+ )
489
+ results = list(await asyncio.gather(*futures))
490
+ for result in results:
491
+ assert result.error is None
492
+
493
+
494
+ @pytest.mark.anyio
495
+ async def test_spendbundle_serialization():
496
+ sb: SpendBundle = make_spend_bundle(1)
497
+ protocol_message = RespondTransaction(sb)
498
+ assert bytes(sb) == bytes(protocol_message)
499
+
500
+
501
+ @pytest.mark.anyio
502
+ async def test_inbound_connection_limit(setup_four_nodes, self_hostname):
503
+ nodes, _, _ = setup_four_nodes
504
+ server_1 = nodes[0].full_node.server
505
+ server_1.config["target_peer_count"] = 2
506
+ server_1.config["target_outbound_peer_count"] = 0
507
+ for i in range(1, 4):
508
+ full_node_i = nodes[i]
509
+ server_i = full_node_i.full_node.server
510
+ await server_i.start_client(PeerInfo(self_hostname, server_1.get_port()))
511
+ assert len(server_1.get_connections(NodeType.FULL_NODE)) == 2
512
+
513
+
514
+ @pytest.mark.anyio
515
+ async def test_request_peers(wallet_nodes, self_hostname):
516
+ full_node_1, full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, _ = wallet_nodes
517
+ full_node_2.full_node.full_node_peers.address_manager.make_private_subnets_valid()
518
+ await server_2.start_client(PeerInfo(self_hostname, server_1.get_port()))
519
+
520
+ async def have_msgs():
521
+ await full_node_2.full_node.full_node_peers.address_manager.add_to_new_table(
522
+ [TimestampedPeerInfo("127.0.0.1", uint16(1000), uint64(int(time.time())) - 1000)],
523
+ None,
524
+ )
525
+ msg_bytes = await full_node_2.full_node.full_node_peers.request_peers(PeerInfo("::1", server_2._port))
526
+ msg = fnp.RespondPeers.from_bytes(msg_bytes.data)
527
+ if msg is not None and not (len(msg.peer_list) == 1):
528
+ return False
529
+ peer = msg.peer_list[0]
530
+ return (peer.host in {self_hostname, "127.0.0.1"}) and peer.port == 1000
531
+
532
+ await time_out_assert_custom_interval(10, 1, have_msgs, True)
533
+ full_node_1.full_node.full_node_peers.address_manager = AddressManager()
534
+
535
+
536
+ @pytest.mark.anyio
537
+ async def test_basic_chain(wallet_nodes, self_hostname):
538
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
539
+
540
+ incoming_queue, _ = await add_dummy_connection(server_1, self_hostname, 12312)
541
+ expected_requests = 0
542
+ if await full_node_1.full_node.synced():
543
+ expected_requests = 1
544
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
545
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
546
+ blocks = bt.get_consecutive_blocks(1)
547
+ for block in blocks[:1]:
548
+ await full_node_1.full_node.add_block(block, peer)
549
+
550
+ await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 1))
551
+
552
+ assert full_node_1.full_node.blockchain.get_peak().height == 0
553
+
554
+ fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
555
+ for block in bt.get_consecutive_blocks(30):
556
+ await full_node_1.full_node.add_block(block, peer, fork_info=fork_info)
557
+
558
+ assert full_node_1.full_node.blockchain.get_peak().height == 29
559
+
560
+
561
+ @pytest.mark.anyio
562
+ async def test_respond_end_of_sub_slot(wallet_nodes, self_hostname):
563
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
564
+
565
+ incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
566
+ expected_requests = 0
567
+ if await full_node_1.full_node.synced():
568
+ expected_requests = 1
569
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
570
+
571
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
572
+
573
+ # Create empty slots
574
+ blocks = await full_node_1.get_all_full_blocks()
575
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=6)
576
+
577
+ # Add empty slots successful
578
+ for slot in blocks[-1].finished_sub_slots[:-2]:
579
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
580
+ num_sub_slots_added = len(blocks[-1].finished_sub_slots[:-2])
581
+ await time_out_assert(
582
+ 10,
583
+ time_out_messages(
584
+ incoming_queue,
585
+ "new_signage_point_or_end_of_sub_slot",
586
+ num_sub_slots_added,
587
+ ),
588
+ )
589
+ # Already have sub slot
590
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(blocks[-1].finished_sub_slots[-3]), peer)
591
+ await asyncio.sleep(2)
592
+ assert incoming_queue.qsize() == 0
593
+
594
+ # Add empty slots unsuccessful
595
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(blocks[-1].finished_sub_slots[-1]), peer)
596
+ await asyncio.sleep(2)
597
+ assert incoming_queue.qsize() == 0
598
+
599
+ # Add some blocks
600
+ blocks = bt.get_consecutive_blocks(4, block_list_input=blocks)
601
+ for block in blocks[-5:]:
602
+ await full_node_1.full_node.add_block(block, peer)
603
+ await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 5))
604
+ blocks = bt.get_consecutive_blocks(1, skip_slots=2, block_list_input=blocks)
605
+
606
+ # Add empty slots successful
607
+ for slot in blocks[-1].finished_sub_slots:
608
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
609
+ num_sub_slots_added = len(blocks[-1].finished_sub_slots)
610
+ await time_out_assert(
611
+ 10,
612
+ time_out_messages(
613
+ incoming_queue,
614
+ "new_signage_point_or_end_of_sub_slot",
615
+ num_sub_slots_added,
616
+ ),
617
+ )
618
+
619
+
620
+ @pytest.mark.anyio
621
+ async def test_respond_end_of_sub_slot_no_reorg(wallet_nodes, self_hostname):
622
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
623
+
624
+ incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
625
+ expected_requests = 0
626
+ if await full_node_1.full_node.synced():
627
+ expected_requests = 1
628
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
629
+
630
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
631
+
632
+ # First get two blocks in the same sub slot
633
+ blocks = await full_node_1.get_all_full_blocks()
634
+
635
+ for i in range(0, 9999999):
636
+ blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, skip_slots=1, seed=i.to_bytes(4, "big"))
637
+ if len(blocks[-1].finished_sub_slots) == 0:
638
+ break
639
+
640
+ # Then create a fork after the first block.
641
+ blocks_alt_1 = bt.get_consecutive_blocks(1, block_list_input=blocks[:-1], skip_slots=1)
642
+ for slot in blocks[-1].finished_sub_slots[:-2]:
643
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
644
+
645
+ # Add all blocks
646
+ for block in blocks:
647
+ await full_node_1.full_node.add_block(block, peer)
648
+
649
+ original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:]
650
+
651
+ # Add subslot for first alternative
652
+ for slot in blocks_alt_1[-1].finished_sub_slots:
653
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
654
+
655
+ assert full_node_1.full_node.full_node_store.finished_sub_slots == original_ss
656
+
657
+
658
+ @pytest.mark.anyio
659
+ async def test_respond_end_of_sub_slot_race(wallet_nodes, self_hostname):
660
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
661
+
662
+ incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
663
+ expected_requests = 0
664
+ if await full_node_1.full_node.synced():
665
+ expected_requests = 1
666
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
667
+
668
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
669
+
670
+ # First get two blocks in the same sub slot
671
+ blocks = await full_node_1.get_all_full_blocks()
672
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
673
+
674
+ await full_node_1.full_node.add_block(blocks[-1], peer)
675
+
676
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
677
+
678
+ original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:].copy()
679
+ # Add the block
680
+ await full_node_1.full_node.add_block(blocks[-1], peer)
681
+
682
+ # Replace with original SS in order to imitate race condition (block added but subslot not yet added)
683
+ full_node_1.full_node.full_node_store.finished_sub_slots = original_ss
684
+
685
+ for slot in blocks[-1].finished_sub_slots:
686
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
687
+
688
+
689
+ @pytest.mark.anyio
690
+ async def test_respond_unfinished(wallet_nodes, self_hostname):
691
+ full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
692
+
693
+ incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
694
+ expected_requests = 0
695
+ if await full_node_1.full_node.synced():
696
+ expected_requests = 1
697
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
698
+
699
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
700
+ blocks = await full_node_1.get_all_full_blocks()
701
+
702
+ # Create empty slots
703
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=6)
704
+ block = blocks[-1]
705
+ unf = make_unfinished_block(block, bt.constants)
706
+
707
+ # Can't add because no sub slots
708
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
709
+
710
+ # Add empty slots successful
711
+ for slot in blocks[-1].finished_sub_slots:
712
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
713
+
714
+ await full_node_1.full_node.add_unfinished_block(unf, None)
715
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
716
+
717
+ # Do the same thing but with non-genesis
718
+ await full_node_1.full_node.add_block(block)
719
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=3)
720
+
721
+ block = blocks[-1]
722
+ unf = make_unfinished_block(block, bt.constants)
723
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
724
+
725
+ for slot in blocks[-1].finished_sub_slots:
726
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
727
+
728
+ await full_node_1.full_node.add_unfinished_block(unf, None)
729
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
730
+
731
+ # Do the same thing one more time, with overflow
732
+ await full_node_1.full_node.add_block(block)
733
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=3, force_overflow=True)
734
+
735
+ block = blocks[-1]
736
+ unf = make_unfinished_block(block, bt.constants, force_overflow=True)
737
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
738
+
739
+ for slot in blocks[-1].finished_sub_slots:
740
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
741
+
742
+ await full_node_1.full_node.add_unfinished_block(unf, None)
743
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
744
+
745
+ # This next section tests making unfinished block with transactions, and then submitting the finished block
746
+ ph = wallet_a.get_new_puzzlehash()
747
+ ph_receiver = wallet_receiver.get_new_puzzlehash()
748
+ blocks = await full_node_1.get_all_full_blocks()
749
+ blocks = bt.get_consecutive_blocks(
750
+ 2,
751
+ block_list_input=blocks,
752
+ guarantee_transaction_block=True,
753
+ farmer_reward_puzzle_hash=ph,
754
+ pool_reward_puzzle_hash=ph,
755
+ )
756
+ await full_node_1.full_node.add_block(blocks[-2])
757
+ await full_node_1.full_node.add_block(blocks[-1])
758
+ coin_to_spend = blocks[-1].get_included_reward_coins()[0]
759
+
760
+ spend_bundle = wallet_a.generate_signed_transaction(coin_to_spend.amount, ph_receiver, coin_to_spend)
761
+
762
+ blocks = bt.get_consecutive_blocks(
763
+ 1,
764
+ block_list_input=blocks,
765
+ guarantee_transaction_block=True,
766
+ transaction_data=spend_bundle,
767
+ force_overflow=True,
768
+ seed=b"random seed",
769
+ )
770
+ block = blocks[-1]
771
+ unf = make_unfinished_block(block, bt.constants, force_overflow=True)
772
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
773
+ await full_node_1.full_node.add_unfinished_block(unf, None)
774
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
775
+ entry = full_node_1.full_node.full_node_store.get_unfinished_block_result(
776
+ unf.partial_hash, unf.foliage.foliage_transaction_block_hash
777
+ )
778
+ assert entry is not None
779
+ result = entry.result
780
+ assert result is not None
781
+ assert result.conds is not None
782
+ assert result.conds.cost > 0
783
+
784
+ assert not full_node_1.full_node.blockchain.contains_block(block.header_hash)
785
+ assert block.transactions_generator is not None
786
+ block_no_transactions = block.replace(transactions_generator=None)
787
+ assert block_no_transactions.transactions_generator is None
788
+
789
+ await full_node_1.full_node.add_block(block_no_transactions)
790
+ assert full_node_1.full_node.blockchain.contains_block(block.header_hash)
791
+
792
+
793
+ @pytest.mark.anyio
794
+ async def test_new_peak(wallet_nodes, self_hostname):
795
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
796
+
797
+ incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
798
+ dummy_peer = server_1.all_connections[dummy_node_id]
799
+ expected_requests = 0
800
+ if await full_node_1.full_node.synced():
801
+ expected_requests = 1
802
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
803
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
804
+
805
+ blocks = await full_node_1.get_all_full_blocks()
806
+ blocks = bt.get_consecutive_blocks(3, block_list_input=blocks) # Alternate chain
807
+
808
+ blocks_reorg = bt.get_consecutive_blocks(3, block_list_input=blocks[:-1], seed=b"214") # Alternate chain
809
+ for block in blocks[-3:]:
810
+ new_peak = fnp.NewPeak(
811
+ block.header_hash,
812
+ block.height,
813
+ block.weight,
814
+ uint32(0),
815
+ block.reward_chain_block.get_unfinished().get_hash(),
816
+ )
817
+ task_1 = create_referenced_task(full_node_1.new_peak(new_peak, dummy_peer))
818
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
819
+ task_1.cancel()
820
+
821
+ await full_node_1.full_node.add_block(block, peer)
822
+ # Ignores, already have
823
+ task_2 = create_referenced_task(full_node_1.new_peak(new_peak, dummy_peer))
824
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 0))
825
+ task_2.cancel()
826
+
827
+ async def suppress_value_error(coro: Coroutine) -> None:
828
+ with contextlib.suppress(ValueError):
829
+ await coro
830
+
831
+ # Ignores low weight
832
+ new_peak = fnp.NewPeak(
833
+ blocks_reorg[-2].header_hash,
834
+ blocks_reorg[-2].height,
835
+ blocks_reorg[-2].weight,
836
+ uint32(0),
837
+ blocks_reorg[-2].reward_chain_block.get_unfinished().get_hash(),
838
+ )
839
+ create_referenced_task(suppress_value_error(full_node_1.new_peak(new_peak, dummy_peer)))
840
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 0))
841
+
842
+ # Does not ignore equal weight
843
+ new_peak = fnp.NewPeak(
844
+ blocks_reorg[-1].header_hash,
845
+ blocks_reorg[-1].height,
846
+ blocks_reorg[-1].weight,
847
+ uint32(0),
848
+ blocks_reorg[-1].reward_chain_block.get_unfinished().get_hash(),
849
+ )
850
+ create_referenced_task(suppress_value_error(full_node_1.new_peak(new_peak, dummy_peer)))
851
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
852
+
853
+
854
+ @pytest.mark.anyio
855
+ async def test_new_transaction_and_mempool(wallet_nodes, self_hostname, seeded_random: random.Random):
856
+ full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
857
+ wallet_ph = wallet_a.get_new_puzzlehash()
858
+ blocks = bt.get_consecutive_blocks(
859
+ 3,
860
+ guarantee_transaction_block=True,
861
+ farmer_reward_puzzle_hash=wallet_ph,
862
+ pool_reward_puzzle_hash=wallet_ph,
863
+ )
864
+ for block in blocks:
865
+ await full_node_1.full_node.add_block(block)
866
+
867
+ start_height = (
868
+ full_node_1.full_node.blockchain.get_peak().height
869
+ if full_node_1.full_node.blockchain.get_peak() is not None
870
+ else -1
871
+ )
872
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
873
+ incoming_queue, node_id = await add_dummy_connection(server_1, self_hostname, 12312)
874
+ fake_peer = server_1.all_connections[node_id]
875
+ puzzle_hashes = []
876
+
877
+ # Makes a bunch of coins
878
+ conditions_dict: dict = {ConditionOpcode.CREATE_COIN: []}
879
+ # This should fit in one transaction
880
+ for _ in range(100):
881
+ receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
882
+ puzzle_hashes.append(receiver_puzzlehash)
883
+ output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [receiver_puzzlehash, int_to_bytes(10000000000)])
884
+
885
+ conditions_dict[ConditionOpcode.CREATE_COIN].append(output)
886
+
887
+ spend_bundle = wallet_a.generate_signed_transaction(
888
+ 100,
889
+ puzzle_hashes[0],
890
+ get_future_reward_coins(blocks[1])[0],
891
+ condition_dic=conditions_dict,
892
+ )
893
+ assert spend_bundle is not None
894
+ new_transaction = fnp.NewTransaction(spend_bundle.get_hash(), uint64(100), uint64(100))
895
+
896
+ await full_node_1.new_transaction(new_transaction, fake_peer)
897
+ await time_out_assert(10, new_transaction_requested, True, incoming_queue, new_transaction)
898
+
899
+ respond_transaction_2 = fnp.RespondTransaction(spend_bundle)
900
+ await full_node_1.respond_transaction(respond_transaction_2, peer)
901
+
902
+ blocks = bt.get_consecutive_blocks(
903
+ 1,
904
+ block_list_input=blocks,
905
+ guarantee_transaction_block=True,
906
+ transaction_data=spend_bundle,
907
+ )
908
+ await full_node_1.full_node.add_block(blocks[-1], None)
909
+
910
+ # Already seen
911
+ await full_node_1.new_transaction(new_transaction, fake_peer)
912
+ await time_out_assert(10, new_transaction_not_requested, True, incoming_queue, new_transaction)
913
+
914
+ await time_out_assert(10, node_height_at_least, True, full_node_1, start_height + 1)
915
+ await time_out_assert(10, node_height_at_least, True, full_node_2, start_height + 1)
916
+
917
+ included_tx = 0
918
+ not_included_tx = 0
919
+ seen_bigger_transaction_has_high_fee = False
920
+ successful_bundle: Optional[WalletSpendBundle] = None
921
+
922
+ # Fill mempool
923
+ receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
924
+ random.seed(b"123465")
925
+ group_size = 3 # We will generate transaction bundles of this size (* standard transaction of around 3-4M cost)
926
+ for i in range(1, len(puzzle_hashes), group_size):
927
+ phs_to_use = [puzzle_hashes[i + j] for j in range(group_size) if (i + j) < len(puzzle_hashes)]
928
+ coin_records = [
929
+ (await full_node_1.full_node.coin_store.get_coin_records_by_puzzle_hash(True, puzzle_hash))[0]
930
+ for puzzle_hash in phs_to_use
931
+ ]
932
+
933
+ last_iteration = (i == len(puzzle_hashes) - group_size) or len(phs_to_use) < group_size
934
+ if last_iteration:
935
+ force_high_fee = True
936
+ fee = 100000000 * group_size # 100 million * group_size (20 fee per cost)
937
+ else:
938
+ force_high_fee = False
939
+ fee = random.randint(1, 100000000 * group_size)
940
+ spend_bundles = [
941
+ wallet_receiver.generate_signed_transaction(uint64(500), receiver_puzzlehash, coin_record.coin, fee=0)
942
+ for coin_record in coin_records[1:]
943
+ ] + [
944
+ wallet_receiver.generate_signed_transaction(uint64(500), receiver_puzzlehash, coin_records[0].coin, fee=fee)
945
+ ]
946
+ spend_bundle = WalletSpendBundle.aggregate(spend_bundles)
947
+ assert estimate_fees(spend_bundle) == fee
948
+ respond_transaction = wallet_protocol.SendTransaction(spend_bundle)
949
+
950
+ await full_node_1.send_transaction(respond_transaction)
951
+
952
+ request = fnp.RequestTransaction(spend_bundle.get_hash())
953
+ req = await full_node_1.request_transaction(request)
954
+
955
+ fee_rate_for_med = full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(5000000)
956
+ fee_rate_for_large = full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(50000000)
957
+ if fee_rate_for_large > fee_rate_for_med:
958
+ seen_bigger_transaction_has_high_fee = True
959
+
960
+ if req is not None and req.data == bytes(fnp.RespondTransaction(spend_bundle)):
961
+ included_tx += 1
962
+ spend_bundles.append(spend_bundle)
963
+ assert not full_node_1.full_node.mempool_manager.mempool.at_full_capacity(0)
964
+ assert full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(0) == 0
965
+ if force_high_fee:
966
+ successful_bundle = spend_bundle
967
+ else:
968
+ assert full_node_1.full_node.mempool_manager.mempool.at_full_capacity(10500000 * group_size)
969
+ assert full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(10500000 * group_size) > 0
970
+ assert not force_high_fee
971
+ not_included_tx += 1
972
+ assert successful_bundle is not None
973
+ assert full_node_1.full_node.mempool_manager.mempool.at_full_capacity(10000000 * group_size)
974
+
975
+ # these numbers reflect the capacity of the mempool. In these
976
+ # tests MEMPOOL_BLOCK_BUFFER is 1. The other factors are COST_PER_BYTE
977
+ # and MAX_BLOCK_COST_CLVM
978
+ assert included_tx == 23
979
+ assert not_included_tx == 10
980
+ assert seen_bigger_transaction_has_high_fee
981
+
982
+ # Mempool is full
983
+ new_transaction = fnp.NewTransaction(bytes32.random(seeded_random), uint64(10000000), uint64(1))
984
+ await full_node_1.new_transaction(new_transaction, fake_peer)
985
+ assert full_node_1.full_node.mempool_manager.mempool.at_full_capacity(10000000 * group_size)
986
+ await time_out_assert(
987
+ 30, full_node_2.full_node.mempool_manager.mempool.at_full_capacity, True, 10000000 * group_size
988
+ )
989
+
990
+ await time_out_assert(10, new_transaction_not_requested, True, incoming_queue, new_transaction)
991
+
992
+ # Idempotence in resubmission
993
+ status, err = await full_node_1.full_node.add_transaction(
994
+ successful_bundle, successful_bundle.name(), peer, test=True
995
+ )
996
+ assert status == MempoolInclusionStatus.SUCCESS
997
+ assert err is None
998
+
999
+ # Resubmission through wallet is also fine
1000
+ response_msg = await full_node_1.send_transaction(SendTransaction(successful_bundle), test=True)
1001
+ assert TransactionAck.from_bytes(response_msg.data).status == MempoolInclusionStatus.SUCCESS.value
1002
+
1003
+ # Farm one block to clear mempool
1004
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(receiver_puzzlehash))
1005
+
1006
+ # No longer full
1007
+ new_transaction = fnp.NewTransaction(bytes32.random(seeded_random), uint64(1000000), uint64(1))
1008
+ await full_node_1.new_transaction(new_transaction, fake_peer)
1009
+
1010
+ # Cannot resubmit transaction, but not because of ALREADY_INCLUDING
1011
+ status, err = await full_node_1.full_node.add_transaction(
1012
+ successful_bundle, successful_bundle.name(), peer, test=True
1013
+ )
1014
+ assert status == MempoolInclusionStatus.FAILED
1015
+ assert err != Err.ALREADY_INCLUDING_TRANSACTION
1016
+
1017
+ await time_out_assert(10, new_transaction_requested, True, incoming_queue, new_transaction)
1018
+
1019
+ # Reorg the blockchain
1020
+ blocks = await full_node_1.get_all_full_blocks()
1021
+ blocks = bt.get_consecutive_blocks(
1022
+ 2,
1023
+ block_list_input=blocks[:-1],
1024
+ guarantee_transaction_block=True,
1025
+ )
1026
+ await add_blocks_in_batches(blocks[-2:], full_node_1.full_node)
1027
+ # Can now resubmit a transaction after the reorg
1028
+ status, err = await full_node_1.full_node.add_transaction(
1029
+ successful_bundle, successful_bundle.name(), peer, test=True
1030
+ )
1031
+ assert err is None
1032
+ assert status == MempoolInclusionStatus.SUCCESS
1033
+
1034
+
1035
+ @pytest.mark.anyio
1036
+ async def test_request_respond_transaction(wallet_nodes, self_hostname, seeded_random: random.Random):
1037
+ full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1038
+ wallet_ph = wallet_a.get_new_puzzlehash()
1039
+ blocks = await full_node_1.get_all_full_blocks()
1040
+
1041
+ blocks = bt.get_consecutive_blocks(
1042
+ 3,
1043
+ block_list_input=blocks,
1044
+ guarantee_transaction_block=True,
1045
+ farmer_reward_puzzle_hash=wallet_ph,
1046
+ pool_reward_puzzle_hash=wallet_ph,
1047
+ )
1048
+
1049
+ incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
1050
+
1051
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1052
+
1053
+ for block in blocks[-3:]:
1054
+ await full_node_1.full_node.add_block(block, peer)
1055
+ await full_node_2.full_node.add_block(block, peer)
1056
+
1057
+ # Farm another block to clear mempool
1058
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(wallet_ph))
1059
+
1060
+ tx_id = bytes32.random(seeded_random)
1061
+ request_transaction = fnp.RequestTransaction(tx_id)
1062
+ msg = await full_node_1.request_transaction(request_transaction)
1063
+ assert msg is None
1064
+
1065
+ receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
1066
+
1067
+ spend_bundle = wallet_a.generate_signed_transaction(
1068
+ 100, receiver_puzzlehash, blocks[-1].get_included_reward_coins()[0]
1069
+ )
1070
+ assert spend_bundle is not None
1071
+ respond_transaction = fnp.RespondTransaction(spend_bundle)
1072
+ res = await full_node_1.respond_transaction(respond_transaction, peer)
1073
+ assert res is None
1074
+
1075
+ # Check broadcast
1076
+ await time_out_assert(10, time_out_messages(incoming_queue, "new_transaction"))
1077
+
1078
+ request_transaction = fnp.RequestTransaction(spend_bundle.get_hash())
1079
+ msg = await full_node_1.request_transaction(request_transaction)
1080
+ assert msg is not None
1081
+ assert msg.data == bytes(fnp.RespondTransaction(spend_bundle))
1082
+
1083
+
1084
+ @pytest.mark.anyio
1085
+ async def test_respond_transaction_fail(wallet_nodes, self_hostname, seeded_random: random.Random):
1086
+ full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1087
+ blocks = await full_node_1.get_all_full_blocks()
1088
+ cb_ph = wallet_a.get_new_puzzlehash()
1089
+
1090
+ incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
1091
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1092
+
1093
+ tx_id = bytes32.random(seeded_random)
1094
+ request_transaction = fnp.RequestTransaction(tx_id)
1095
+ msg = await full_node_1.request_transaction(request_transaction)
1096
+ assert msg is None
1097
+
1098
+ receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
1099
+
1100
+ blocks_new = bt.get_consecutive_blocks(
1101
+ 3,
1102
+ block_list_input=blocks,
1103
+ guarantee_transaction_block=True,
1104
+ farmer_reward_puzzle_hash=cb_ph,
1105
+ pool_reward_puzzle_hash=cb_ph,
1106
+ )
1107
+ await asyncio.sleep(1)
1108
+ while incoming_queue.qsize() > 0:
1109
+ await incoming_queue.get()
1110
+
1111
+ await full_node_1.full_node.add_block(blocks_new[-3], peer)
1112
+ await full_node_1.full_node.add_block(blocks_new[-2], peer)
1113
+ await full_node_1.full_node.add_block(blocks_new[-1], peer)
1114
+
1115
+ await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 3))
1116
+ # Invalid transaction does not propagate
1117
+ spend_bundle = wallet_a.generate_signed_transaction(
1118
+ 100000000000000,
1119
+ receiver_puzzlehash,
1120
+ blocks_new[-1].get_included_reward_coins()[0],
1121
+ )
1122
+
1123
+ assert spend_bundle is not None
1124
+ respond_transaction = fnp.RespondTransaction(spend_bundle)
1125
+ msg = await full_node_1.respond_transaction(respond_transaction, peer)
1126
+ assert msg is None
1127
+
1128
+ await asyncio.sleep(1)
1129
+ assert incoming_queue.qsize() == 0
1130
+
1131
+
1132
+ @pytest.mark.anyio
1133
+ async def test_request_block(wallet_nodes):
1134
+ full_node_1, _full_node_2, _server_1, _server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1135
+ blocks = await full_node_1.get_all_full_blocks()
1136
+
1137
+ blocks = bt.get_consecutive_blocks(
1138
+ 3,
1139
+ block_list_input=blocks,
1140
+ guarantee_transaction_block=True,
1141
+ farmer_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
1142
+ pool_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
1143
+ )
1144
+ spend_bundle = wallet_a.generate_signed_transaction(
1145
+ 1123,
1146
+ wallet_receiver.get_new_puzzlehash(),
1147
+ blocks[-1].get_included_reward_coins()[0],
1148
+ )
1149
+ blocks = bt.get_consecutive_blocks(
1150
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle
1151
+ )
1152
+
1153
+ for block in blocks:
1154
+ await full_node_1.full_node.add_block(block)
1155
+
1156
+ # Don't have height
1157
+ res = await full_node_1.request_block(fnp.RequestBlock(uint32(1248921), False))
1158
+ assert res.type == ProtocolMessageTypes.reject_block.value
1159
+
1160
+ # Ask without transactions
1161
+ res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height, False))
1162
+ assert res.type != ProtocolMessageTypes.reject_block.value
1163
+ assert fnp.RespondBlock.from_bytes(res.data).block.transactions_generator is None
1164
+
1165
+ # Ask with transactions
1166
+ res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height, True))
1167
+ assert res.type != ProtocolMessageTypes.reject_block.value
1168
+ assert fnp.RespondBlock.from_bytes(res.data).block.transactions_generator is not None
1169
+
1170
+ # Ask for another one
1171
+ res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height - 1, True))
1172
+ assert res.type != ProtocolMessageTypes.reject_block.value
1173
+
1174
+
1175
+ @pytest.mark.anyio
1176
+ async def test_request_blocks(wallet_nodes):
1177
+ full_node_1, _full_node_2, _server_1, _server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1178
+ blocks = await full_node_1.get_all_full_blocks()
1179
+
1180
+ # create more blocks than constants.MAX_BLOCK_COUNT_PER_REQUEST (32)
1181
+ blocks = bt.get_consecutive_blocks(
1182
+ 33,
1183
+ block_list_input=blocks,
1184
+ guarantee_transaction_block=True,
1185
+ farmer_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
1186
+ pool_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
1187
+ )
1188
+
1189
+ spend_bundle = wallet_a.generate_signed_transaction(
1190
+ 1123,
1191
+ wallet_receiver.get_new_puzzlehash(),
1192
+ blocks[-1].get_included_reward_coins()[0],
1193
+ )
1194
+ blocks_t = bt.get_consecutive_blocks(
1195
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle
1196
+ )
1197
+
1198
+ for block in blocks_t:
1199
+ await full_node_1.full_node.add_block(block)
1200
+
1201
+ peak_height = blocks_t[-1].height
1202
+
1203
+ # Start >= End
1204
+ res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(4), uint32(4), False))
1205
+ assert res is not None
1206
+ fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
1207
+ assert len(fetched_blocks) == 1
1208
+ assert fetched_blocks[0].header_hash == blocks[4].header_hash
1209
+ res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(5), uint32(4), False))
1210
+ assert res.type == ProtocolMessageTypes.reject_blocks.value
1211
+ # Invalid range
1212
+ res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height + 5), False))
1213
+ assert res.type == ProtocolMessageTypes.reject_blocks.value
1214
+
1215
+ # Try fetching more blocks than constants.MAX_BLOCK_COUNT_PER_REQUESTS
1216
+ res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(0), uint32(33), False))
1217
+ assert res.type == ProtocolMessageTypes.reject_blocks.value
1218
+
1219
+ # Ask without transactions
1220
+ res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), False))
1221
+
1222
+ fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
1223
+ assert len(fetched_blocks) == 6
1224
+ for b in fetched_blocks:
1225
+ assert b.transactions_generator is None
1226
+
1227
+ # Ask with transactions
1228
+ res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), True))
1229
+ fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
1230
+ assert len(fetched_blocks) == 6
1231
+ assert fetched_blocks[-1].transactions_generator is not None
1232
+ assert std_hash(fetched_blocks[-1]) == std_hash(blocks_t[-1])
1233
+
1234
+
1235
+ @pytest.mark.anyio
1236
+ @pytest.mark.parametrize("peer_version", ["0.0.35", "0.0.36"])
1237
+ @pytest.mark.parametrize("requesting", [0, 1, 2])
1238
+ async def test_new_unfinished_block(wallet_nodes, peer_version: str, requesting: int, self_hostname: str):
1239
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
1240
+ blocks = await full_node_1.get_all_full_blocks()
1241
+
1242
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1243
+ assert peer in server_1.all_connections.values()
1244
+
1245
+ blocks = bt.get_consecutive_blocks(2, block_list_input=blocks)
1246
+ block: FullBlock = blocks[-1]
1247
+ unf = make_unfinished_block(block, bt.constants)
1248
+
1249
+ # Don't have
1250
+ if requesting == 1:
1251
+ full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(unf.partial_hash, None)
1252
+ res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
1253
+ assert res is None
1254
+ elif requesting == 2:
1255
+ full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(
1256
+ unf.partial_hash, unf.foliage.foliage_transaction_block_hash
1257
+ )
1258
+ res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
1259
+ assert res is None
1260
+ else:
1261
+ res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
1262
+ assert res is not None
1263
+ assert res is not None and res.data == bytes(fnp.RequestUnfinishedBlock(unf.partial_hash))
1264
+
1265
+ # when we receive a new unfinished block, we advertize it to our peers.
1266
+ # We send new_unfinished_blocks to old peers (0.0.35 and earlier) and we
1267
+ # send new_unfinishe_blocks2 to new peers (0.0.6 and later). Test both
1268
+ peer.protocol_version = Version(peer_version)
1269
+
1270
+ await full_node_1.full_node.add_block(blocks[-2])
1271
+ await full_node_1.full_node.add_unfinished_block(unf, None)
1272
+
1273
+ msg = peer.outgoing_queue.get_nowait()
1274
+ assert msg.type == ProtocolMessageTypes.new_peak.value
1275
+ msg = peer.outgoing_queue.get_nowait()
1276
+ if peer_version == "0.0.35":
1277
+ assert msg.type == ProtocolMessageTypes.new_unfinished_block.value
1278
+ assert msg.data == bytes(fnp.NewUnfinishedBlock(unf.partial_hash))
1279
+ elif peer_version == "0.0.36":
1280
+ assert msg.type == ProtocolMessageTypes.new_unfinished_block2.value
1281
+ assert msg.data == bytes(fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash))
1282
+ else: # pragma: no cover
1283
+ # the test parameters must have been updated, update the test too!
1284
+ assert False
1285
+
1286
+ # Have
1287
+ res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
1288
+ assert res is None
1289
+
1290
+
1291
+ @pytest.mark.anyio
1292
+ @pytest.mark.parametrize("requesting", [0, 1, 2])
1293
+ async def test_new_unfinished_block2(wallet_nodes, requesting: int, self_hostname: str):
1294
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
1295
+ blocks = await full_node_1.get_all_full_blocks()
1296
+
1297
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1298
+
1299
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1300
+ block: FullBlock = blocks[-1]
1301
+ unf = make_unfinished_block(block, bt.constants)
1302
+
1303
+ # Don't have
1304
+ if requesting == 1:
1305
+ full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(unf.partial_hash, None)
1306
+
1307
+ if requesting == 2:
1308
+ full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(
1309
+ unf.partial_hash, unf.foliage.foliage_transaction_block_hash
1310
+ )
1311
+ res = await full_node_1.new_unfinished_block2(
1312
+ fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1313
+ )
1314
+ assert res is None
1315
+ else:
1316
+ res = await full_node_1.new_unfinished_block2(
1317
+ fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1318
+ )
1319
+ assert res is not None and res.data == bytes(
1320
+ fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1321
+ )
1322
+
1323
+ await full_node_1.full_node.add_unfinished_block(unf, peer)
1324
+
1325
+ # Have
1326
+ res = await full_node_1.new_unfinished_block2(
1327
+ fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1328
+ )
1329
+ assert res is None
1330
+
1331
+
1332
+ @pytest.mark.anyio
1333
+ async def test_new_unfinished_block2_forward_limit(wallet_nodes, self_hostname: str):
1334
+ full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1335
+ blocks = bt.get_consecutive_blocks(3, guarantee_transaction_block=True)
1336
+ for block in blocks:
1337
+ await full_node_1.full_node.add_block(block)
1338
+ coin = blocks[-1].get_included_reward_coins()[0]
1339
+ puzzle_hash = wallet_receiver.get_new_puzzlehash()
1340
+
1341
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1342
+
1343
+ # notify the node of unfinished blocks for this reward block hash
1344
+ # we forward 3 different blocks with the same reward block hash, but no
1345
+ # more (it's configurable)
1346
+ # also, we don't forward unfinished blocks that are "worse" than the
1347
+ # best block we've already seen, so we may need to send more than 3
1348
+ # blocks to the node for it to forward 3
1349
+
1350
+ unf_blocks: list[UnfinishedBlock] = []
1351
+
1352
+ last_reward_hash: Optional[bytes32] = None
1353
+ for idx in range(0, 6):
1354
+ # we include a different transaction in each block. This makes the
1355
+ # foliage different in each of them, but the reward block (plot) the same
1356
+ tx = wallet_a.generate_signed_transaction(100 * (idx + 1), puzzle_hash, coin)
1357
+
1358
+ # note that we use the same chain to build the new block on top of every time
1359
+ block = bt.get_consecutive_blocks(
1360
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
1361
+ )[-1]
1362
+ unf = make_unfinished_block(block, bt.constants)
1363
+ unf_blocks.append(unf)
1364
+
1365
+ if last_reward_hash is None:
1366
+ last_reward_hash = unf.partial_hash
1367
+ else:
1368
+ assert last_reward_hash == unf.partial_hash
1369
+
1370
+ # sort the blocks from worst -> best
1371
+ def sort_key(b: UnfinishedBlock) -> bytes32:
1372
+ assert b.foliage.foliage_transaction_block_hash is not None
1373
+ return b.foliage.foliage_transaction_block_hash
1374
+
1375
+ unf_blocks.sort(reverse=True, key=sort_key)
1376
+
1377
+ for idx, unf in enumerate(unf_blocks):
1378
+ res = await full_node_1.new_unfinished_block2(
1379
+ fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1380
+ )
1381
+ # 3 is the default number of different unfinished blocks we forward
1382
+ if idx < 3:
1383
+ # Don't have
1384
+ assert res is not None and res.data == bytes(
1385
+ fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1386
+ )
1387
+ else:
1388
+ # too many UnfinishedBlocks with the same reward hash
1389
+ assert res is None
1390
+ await full_node_1.full_node.add_unfinished_block(unf, peer)
1391
+
1392
+
1393
+ @pytest.mark.anyio
1394
+ @pytest.mark.parametrize(
1395
+ "committment,expected",
1396
+ [
1397
+ (0, Err.INVALID_TRANSACTIONS_GENERATOR_HASH),
1398
+ (1, Err.INVALID_TRANSACTIONS_INFO_HASH),
1399
+ (2, Err.INVALID_FOLIAGE_BLOCK_HASH),
1400
+ (3, Err.INVALID_PLOT_SIGNATURE),
1401
+ (4, Err.INVALID_PLOT_SIGNATURE),
1402
+ (5, Err.INVALID_POSPACE),
1403
+ (6, Err.INVALID_POSPACE),
1404
+ (7, Err.TOO_MANY_GENERATOR_REFS),
1405
+ ],
1406
+ )
1407
+ async def test_unfinished_block_with_replaced_generator(wallet_nodes, self_hostname, committment, expected):
1408
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
1409
+ blocks = await full_node_1.get_all_full_blocks()
1410
+
1411
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1412
+
1413
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1414
+ block: FullBlock = blocks[0]
1415
+ overflow = is_overflow_block(bt.constants, block.reward_chain_block.signage_point_index)
1416
+
1417
+ replaced_generator = SerializedProgram.from_bytes(b"\x80")
1418
+
1419
+ if committment > 0:
1420
+ tr = block.transactions_info
1421
+ transactions_info = TransactionsInfo(
1422
+ std_hash(bytes(replaced_generator)),
1423
+ tr.generator_refs_root,
1424
+ tr.aggregated_signature,
1425
+ tr.fees,
1426
+ tr.cost,
1427
+ tr.reward_claims_incorporated,
1428
+ )
1429
+ else:
1430
+ transactions_info = block.transactions_info
1431
+
1432
+ if committment > 1:
1433
+ tb = block.foliage_transaction_block
1434
+ transaction_block = FoliageTransactionBlock(
1435
+ tb.prev_transaction_block_hash,
1436
+ tb.timestamp,
1437
+ tb.filter_hash,
1438
+ tb.additions_root,
1439
+ tb.removals_root,
1440
+ transactions_info.get_hash(),
1441
+ )
1442
+ else:
1443
+ transaction_block = block.foliage_transaction_block
1444
+
1445
+ if committment > 2:
1446
+ fl = block.foliage
1447
+ foliage = Foliage(
1448
+ fl.prev_block_hash,
1449
+ fl.reward_block_hash,
1450
+ fl.foliage_block_data,
1451
+ fl.foliage_block_data_signature,
1452
+ transaction_block.get_hash(),
1453
+ fl.foliage_transaction_block_signature,
1454
+ )
1455
+ else:
1456
+ foliage = block.foliage
1457
+
1458
+ if committment > 3:
1459
+ fl = block.foliage
1460
+
1461
+ secret_key: PrivateKey = AugSchemeMPL.key_gen(bytes([2] * 32))
1462
+ public_key = secret_key.get_g1()
1463
+ signature = AugSchemeMPL.sign(secret_key, transaction_block.get_hash())
1464
+
1465
+ foliage = Foliage(
1466
+ fl.prev_block_hash,
1467
+ fl.reward_block_hash,
1468
+ fl.foliage_block_data,
1469
+ fl.foliage_block_data_signature,
1470
+ transaction_block.get_hash(),
1471
+ signature,
1472
+ )
1473
+
1474
+ if committment > 4:
1475
+ pos = block.reward_chain_block.proof_of_space
1476
+
1477
+ if committment > 5:
1478
+ if pos.pool_public_key is None:
1479
+ plot_id = calculate_plot_id_pk(pos.pool_contract_puzzle_hash, public_key)
1480
+ else:
1481
+ plot_id = calculate_plot_id_pk(pos.pool_public_key, public_key)
1482
+ original_challenge_hash = block.reward_chain_block.pos_ss_cc_challenge_hash
1483
+
1484
+ if block.reward_chain_block.challenge_chain_sp_vdf is None:
1485
+ # Edge case of first sp (start of slot), where sp_iters == 0
1486
+ cc_sp_hash = original_challenge_hash
1487
+ else:
1488
+ cc_sp_hash = block.reward_chain_block.challenge_chain_sp_vdf.output.get_hash()
1489
+ challenge = calculate_pos_challenge(plot_id, original_challenge_hash, cc_sp_hash)
1490
+
1491
+ else:
1492
+ challenge = pos.challenge
1493
+
1494
+ proof_of_space = ProofOfSpace(
1495
+ challenge,
1496
+ pos.pool_public_key,
1497
+ pos.pool_contract_puzzle_hash,
1498
+ public_key,
1499
+ pos.size,
1500
+ pos.proof,
1501
+ )
1502
+
1503
+ rcb = block.reward_chain_block.get_unfinished()
1504
+ reward_chain_block = RewardChainBlockUnfinished(
1505
+ rcb.total_iters,
1506
+ rcb.signage_point_index,
1507
+ rcb.pos_ss_cc_challenge_hash,
1508
+ proof_of_space,
1509
+ rcb.challenge_chain_sp_vdf,
1510
+ rcb.challenge_chain_sp_signature,
1511
+ rcb.reward_chain_sp_vdf,
1512
+ rcb.reward_chain_sp_signature,
1513
+ )
1514
+ else:
1515
+ reward_chain_block = block.reward_chain_block.get_unfinished()
1516
+
1517
+ else:
1518
+ reward_chain_block = block.reward_chain_block.get_unfinished()
1519
+
1520
+ generator_refs: list[uint32] = []
1521
+ if committment > 6:
1522
+ generator_refs = [uint32(n) for n in range(600)]
1523
+
1524
+ unf = UnfinishedBlock(
1525
+ block.finished_sub_slots[:] if not overflow else block.finished_sub_slots[:-1],
1526
+ reward_chain_block,
1527
+ block.challenge_chain_sp_proof,
1528
+ block.reward_chain_sp_proof,
1529
+ foliage,
1530
+ transaction_block,
1531
+ transactions_info,
1532
+ replaced_generator,
1533
+ generator_refs,
1534
+ )
1535
+
1536
+ _, header_error = await full_node_1.full_node.blockchain.validate_unfinished_block_header(unf)
1537
+ assert header_error == expected
1538
+
1539
+ # tampered-with generator
1540
+ res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
1541
+ assert res is not None
1542
+ with pytest.raises(ConsensusError, match=f"{str(expected).split('.')[1]}"):
1543
+ await full_node_1.full_node.add_unfinished_block(unf, peer)
1544
+
1545
+
1546
+ @pytest.mark.anyio
1547
+ async def test_double_blocks_same_pospace(wallet_nodes, self_hostname):
1548
+ full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1549
+
1550
+ incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
1551
+ dummy_peer = server_1.all_connections[dummy_node_id]
1552
+ _ = await connect_and_get_peer(server_1, server_2, self_hostname)
1553
+
1554
+ ph = wallet_a.get_new_puzzlehash()
1555
+
1556
+ for i in range(2):
1557
+ await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
1558
+ blocks: list[FullBlock] = await full_node_1.get_all_full_blocks()
1559
+
1560
+ coin = blocks[-1].get_included_reward_coins()[0]
1561
+ tx = wallet_a.generate_signed_transaction(10000, wallet_receiver.get_new_puzzlehash(), coin)
1562
+
1563
+ blocks = bt.get_consecutive_blocks(
1564
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
1565
+ )
1566
+
1567
+ block: FullBlock = blocks[-1]
1568
+ unf = make_unfinished_block(block, bt.constants)
1569
+ await full_node_1.full_node.add_unfinished_block(unf, dummy_peer)
1570
+ assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash)
1571
+
1572
+ block_2 = recursive_replace(
1573
+ blocks[-1], "foliage_transaction_block.timestamp", unf.foliage_transaction_block.timestamp + 1
1574
+ )
1575
+ new_m = block_2.foliage.foliage_transaction_block_hash
1576
+ new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1577
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1578
+ block_2 = recursive_replace(block_2, "transactions_generator", None)
1579
+
1580
+ rb_task = create_referenced_task(full_node_2.full_node.add_block(block_2, dummy_peer))
1581
+
1582
+ await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
1583
+ rb_task.cancel()
1584
+
1585
+
1586
+ @pytest.mark.anyio
1587
+ async def test_request_unfinished_block(wallet_nodes, self_hostname):
1588
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
1589
+ blocks = await full_node_1.get_all_full_blocks()
1590
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1591
+ blocks = bt.get_consecutive_blocks(10, block_list_input=blocks, seed=b"12345")
1592
+ for block in blocks[:-1]:
1593
+ await full_node_1.full_node.add_block(block)
1594
+ block: FullBlock = blocks[-1]
1595
+ unf = make_unfinished_block(block, bt.constants)
1596
+
1597
+ # Don't have
1598
+ res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
1599
+ assert res is None
1600
+ await full_node_1.full_node.add_unfinished_block(unf, peer)
1601
+ # Have
1602
+ res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
1603
+ assert res is not None
1604
+
1605
+
1606
+ @pytest.mark.anyio
1607
+ async def test_request_unfinished_block2(wallet_nodes, self_hostname):
1608
+ full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
1609
+ blocks = await full_node_1.get_all_full_blocks()
1610
+ blocks = bt.get_consecutive_blocks(3, guarantee_transaction_block=True)
1611
+ for block in blocks:
1612
+ await full_node_1.full_node.add_block(block)
1613
+ coin = blocks[-1].get_included_reward_coins()[0]
1614
+ puzzle_hash = wallet_receiver.get_new_puzzlehash()
1615
+
1616
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1617
+
1618
+ # the "best" unfinished block according to the metric we use to pick one
1619
+ # deterministically
1620
+ best_unf: Optional[UnfinishedBlock] = None
1621
+
1622
+ for idx in range(0, 6):
1623
+ # we include a different transaction in each block. This makes the
1624
+ # foliage different in each of them, but the reward block (plot) the same
1625
+ tx = wallet_a.generate_signed_transaction(100 * (idx + 1), puzzle_hash, coin)
1626
+
1627
+ # note that we use the same chain to build the new block on top of every time
1628
+ block = bt.get_consecutive_blocks(
1629
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
1630
+ )[-1]
1631
+ unf = make_unfinished_block(block, bt.constants)
1632
+ assert unf.foliage.foliage_transaction_block_hash is not None
1633
+
1634
+ if best_unf is None:
1635
+ best_unf = unf
1636
+ elif (
1637
+ unf.foliage.foliage_transaction_block_hash is not None
1638
+ and unf.foliage.foliage_transaction_block_hash < best_unf.foliage.foliage_transaction_block_hash
1639
+ ):
1640
+ best_unf = unf
1641
+
1642
+ # Don't have
1643
+ res = await full_node_1.request_unfinished_block2(
1644
+ fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1645
+ )
1646
+ assert res is None
1647
+
1648
+ await full_node_1.full_node.add_unfinished_block(unf, peer)
1649
+ # Have
1650
+ res = await full_node_1.request_unfinished_block2(
1651
+ fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
1652
+ )
1653
+ assert res.data == bytes(fnp.RespondUnfinishedBlock(unf))
1654
+
1655
+ res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
1656
+ assert res.data == bytes(fnp.RespondUnfinishedBlock(best_unf))
1657
+
1658
+ res = await full_node_1.request_unfinished_block2(fnp.RequestUnfinishedBlock2(unf.partial_hash, None))
1659
+ assert res.data == bytes(fnp.RespondUnfinishedBlock(best_unf))
1660
+
1661
+
1662
+ @pytest.mark.anyio
1663
+ async def test_new_signage_point_or_end_of_sub_slot(wallet_nodes, self_hostname):
1664
+ full_node_1, full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
1665
+ blocks = await full_node_1.get_all_full_blocks()
1666
+
1667
+ blocks = bt.get_consecutive_blocks(3, block_list_input=blocks, skip_slots=2)
1668
+ await full_node_1.full_node.add_block(blocks[-3])
1669
+ await full_node_1.full_node.add_block(blocks[-2])
1670
+ await full_node_1.full_node.add_block(blocks[-1])
1671
+
1672
+ blockchain = full_node_1.full_node.blockchain
1673
+ peak = blockchain.get_peak()
1674
+
1675
+ sp = get_signage_point(
1676
+ bt.constants,
1677
+ blockchain,
1678
+ peak,
1679
+ peak.ip_sub_slot_total_iters(bt.constants),
1680
+ uint8(11),
1681
+ [],
1682
+ peak.sub_slot_iters,
1683
+ )
1684
+
1685
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1686
+ res = await full_node_1.new_signage_point_or_end_of_sub_slot(
1687
+ fnp.NewSignagePointOrEndOfSubSlot(None, sp.cc_vdf.challenge, uint8(11), sp.rc_vdf.challenge), peer
1688
+ )
1689
+ assert res.type == ProtocolMessageTypes.request_signage_point_or_end_of_sub_slot.value
1690
+ assert fnp.RequestSignagePointOrEndOfSubSlot.from_bytes(res.data).index_from_challenge == uint8(11)
1691
+
1692
+ for block in blocks:
1693
+ await full_node_2.full_node.add_block(block)
1694
+
1695
+ num_slots = 20
1696
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=num_slots)
1697
+ slots = blocks[-1].finished_sub_slots
1698
+
1699
+ assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
1700
+ assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
1701
+
1702
+ for slot in slots[:-1]:
1703
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
1704
+ assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots - 1
1705
+
1706
+ _incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
1707
+ dummy_peer = server_1.all_connections[dummy_node_id]
1708
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slots[-1]), dummy_peer)
1709
+
1710
+ assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots
1711
+
1712
+ def caught_up_slots():
1713
+ return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
1714
+
1715
+ await time_out_assert(20, caught_up_slots)
1716
+
1717
+
1718
+ @pytest.mark.anyio
1719
+ async def test_new_signage_point_caching(wallet_nodes, empty_blockchain, self_hostname):
1720
+ full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
1721
+ blocks = await full_node_1.get_all_full_blocks()
1722
+
1723
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1724
+ blocks = bt.get_consecutive_blocks(3, block_list_input=blocks, skip_slots=2)
1725
+ await full_node_1.full_node.add_block(blocks[-3])
1726
+ await full_node_1.full_node.add_block(blocks[-2])
1727
+ await full_node_1.full_node.add_block(blocks[-1])
1728
+
1729
+ blockchain = full_node_1.full_node.blockchain
1730
+
1731
+ # Submit the sub slot, but not the last block
1732
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1, force_overflow=True)
1733
+ for ss in blocks[-1].finished_sub_slots:
1734
+ challenge_chain = ss.challenge_chain.replace(
1735
+ new_difficulty=20,
1736
+ )
1737
+ slot2 = ss.replace(
1738
+ challenge_chain=challenge_chain,
1739
+ )
1740
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot2), peer)
1741
+
1742
+ second_blockchain = empty_blockchain
1743
+ for block in blocks:
1744
+ await _validate_and_add_block(second_blockchain, block)
1745
+
1746
+ # Creates a signage point based on the last block
1747
+ peak_2 = second_blockchain.get_peak()
1748
+ sp: SignagePoint = get_signage_point(
1749
+ bt.constants,
1750
+ blockchain,
1751
+ peak_2,
1752
+ peak_2.ip_sub_slot_total_iters(bt.constants),
1753
+ uint8(4),
1754
+ [],
1755
+ peak_2.sub_slot_iters,
1756
+ )
1757
+ # Submits the signage point, cannot add because don't have block
1758
+ await full_node_1.respond_signage_point(
1759
+ fnp.RespondSignagePoint(4, sp.cc_vdf, sp.cc_proof, sp.rc_vdf, sp.rc_proof), peer
1760
+ )
1761
+ # Should not add duplicates to cache though
1762
+ await full_node_1.respond_signage_point(
1763
+ fnp.RespondSignagePoint(4, sp.cc_vdf, sp.cc_proof, sp.rc_vdf, sp.rc_proof), peer
1764
+ )
1765
+ assert full_node_1.full_node.full_node_store.get_signage_point(sp.cc_vdf.output.get_hash()) is None
1766
+ assert len(full_node_1.full_node.full_node_store.future_sp_cache[sp.rc_vdf.challenge]) == 1
1767
+
1768
+ # Add block
1769
+ await full_node_1.full_node.add_block(blocks[-1], peer)
1770
+
1771
+ # Now signage point should be added
1772
+ sp = full_node_1.full_node.full_node_store.get_signage_point(sp.cc_vdf.output.get_hash())
1773
+ assert sp is not None
1774
+
1775
+
1776
+ @pytest.mark.anyio
1777
+ async def test_slot_catch_up_genesis(setup_two_nodes_fixture, self_hostname):
1778
+ nodes, _, bt = setup_two_nodes_fixture
1779
+ server_1 = nodes[0].full_node.server
1780
+ server_2 = nodes[1].full_node.server
1781
+ full_node_1 = nodes[0]
1782
+ full_node_2 = nodes[1]
1783
+
1784
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
1785
+ num_slots = 20
1786
+ blocks = bt.get_consecutive_blocks(1, skip_slots=num_slots)
1787
+ slots = blocks[-1].finished_sub_slots
1788
+
1789
+ assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
1790
+ assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
1791
+
1792
+ for slot in slots[:-1]:
1793
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
1794
+ assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots - 1
1795
+
1796
+ _incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
1797
+ dummy_peer = server_1.all_connections[dummy_node_id]
1798
+ await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slots[-1]), dummy_peer)
1799
+
1800
+ assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots
1801
+
1802
+ def caught_up_slots():
1803
+ return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
1804
+
1805
+ await time_out_assert(20, caught_up_slots)
1806
+
1807
+
1808
+ @pytest.mark.anyio
1809
+ async def test_compact_protocol(setup_two_nodes_fixture):
1810
+ nodes, _, bt = setup_two_nodes_fixture
1811
+ full_node_1 = nodes[0]
1812
+ full_node_2 = nodes[1]
1813
+ blocks = bt.get_consecutive_blocks(num_blocks=10, skip_slots=3)
1814
+ block = blocks[0]
1815
+ for b in blocks:
1816
+ await full_node_1.full_node.add_block(b)
1817
+ timelord_protocol_finished = []
1818
+ cc_eos_count = 0
1819
+ for sub_slot in block.finished_sub_slots:
1820
+ vdf_info, vdf_proof = get_vdf_info_and_proof(
1821
+ bt.constants,
1822
+ ClassgroupElement.get_default_element(),
1823
+ sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.challenge,
1824
+ sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.number_of_iterations,
1825
+ True,
1826
+ )
1827
+ cc_eos_count += 1
1828
+ timelord_protocol_finished.append(
1829
+ timelord_protocol.RespondCompactProofOfTime(
1830
+ vdf_info,
1831
+ vdf_proof,
1832
+ block.header_hash,
1833
+ block.height,
1834
+ CompressibleVDFField.CC_EOS_VDF,
1835
+ )
1836
+ )
1837
+ blocks_2 = bt.get_consecutive_blocks(num_blocks=10, block_list_input=blocks, skip_slots=3)
1838
+ block = blocks_2[-10]
1839
+ for b in blocks_2[-11:]:
1840
+ await full_node_1.full_node.add_block(b)
1841
+ icc_eos_count = 0
1842
+ for sub_slot in block.finished_sub_slots:
1843
+ if sub_slot.infused_challenge_chain is not None:
1844
+ icc_eos_count += 1
1845
+ vdf_info, vdf_proof = get_vdf_info_and_proof(
1846
+ bt.constants,
1847
+ ClassgroupElement.get_default_element(),
1848
+ sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.challenge,
1849
+ sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.number_of_iterations,
1850
+ True,
1851
+ )
1852
+ timelord_protocol_finished.append(
1853
+ timelord_protocol.RespondCompactProofOfTime(
1854
+ vdf_info,
1855
+ vdf_proof,
1856
+ block.header_hash,
1857
+ block.height,
1858
+ CompressibleVDFField.ICC_EOS_VDF,
1859
+ )
1860
+ )
1861
+ assert block.reward_chain_block.challenge_chain_sp_vdf is not None
1862
+ vdf_info, vdf_proof = get_vdf_info_and_proof(
1863
+ bt.constants,
1864
+ ClassgroupElement.get_default_element(),
1865
+ block.reward_chain_block.challenge_chain_sp_vdf.challenge,
1866
+ block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
1867
+ True,
1868
+ )
1869
+ timelord_protocol_finished.append(
1870
+ timelord_protocol.RespondCompactProofOfTime(
1871
+ vdf_info,
1872
+ vdf_proof,
1873
+ block.header_hash,
1874
+ block.height,
1875
+ CompressibleVDFField.CC_SP_VDF,
1876
+ )
1877
+ )
1878
+ vdf_info, vdf_proof = get_vdf_info_and_proof(
1879
+ bt.constants,
1880
+ ClassgroupElement.get_default_element(),
1881
+ block.reward_chain_block.challenge_chain_ip_vdf.challenge,
1882
+ block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
1883
+ True,
1884
+ )
1885
+ timelord_protocol_finished.append(
1886
+ timelord_protocol.RespondCompactProofOfTime(
1887
+ vdf_info,
1888
+ vdf_proof,
1889
+ block.header_hash,
1890
+ block.height,
1891
+ CompressibleVDFField.CC_IP_VDF,
1892
+ )
1893
+ )
1894
+
1895
+ # Note: the below numbers depend on the block cache, so might need to be updated
1896
+ assert cc_eos_count == 3 and icc_eos_count == 3
1897
+ for compact_proof in timelord_protocol_finished:
1898
+ await full_node_1.full_node.add_compact_proof_of_time(compact_proof)
1899
+ stored_blocks = await full_node_1.get_all_full_blocks()
1900
+ cc_eos_compact_count = 0
1901
+ icc_eos_compact_count = 0
1902
+ has_compact_cc_sp_vdf = False
1903
+ has_compact_cc_ip_vdf = False
1904
+ for block in stored_blocks:
1905
+ for sub_slot in block.finished_sub_slots:
1906
+ if sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity:
1907
+ cc_eos_compact_count += 1
1908
+ if (
1909
+ sub_slot.proofs.infused_challenge_chain_slot_proof is not None
1910
+ and sub_slot.proofs.infused_challenge_chain_slot_proof.normalized_to_identity
1911
+ ):
1912
+ icc_eos_compact_count += 1
1913
+ if block.challenge_chain_sp_proof is not None and block.challenge_chain_sp_proof.normalized_to_identity:
1914
+ has_compact_cc_sp_vdf = True
1915
+ if block.challenge_chain_ip_proof.normalized_to_identity:
1916
+ has_compact_cc_ip_vdf = True
1917
+ # Note: the below numbers depend on the block cache, so might need to be updated
1918
+ assert cc_eos_compact_count == 3
1919
+ assert icc_eos_compact_count == 3
1920
+ assert has_compact_cc_sp_vdf
1921
+ assert has_compact_cc_ip_vdf
1922
+ for height, block in enumerate(stored_blocks):
1923
+ await full_node_2.full_node.add_block(block)
1924
+ assert full_node_2.full_node.blockchain.get_peak().height == height
1925
+
1926
+
1927
+ @pytest.mark.anyio
1928
+ async def test_compact_protocol_invalid_messages(setup_two_nodes_fixture, self_hostname):
1929
+ nodes, _, bt = setup_two_nodes_fixture
1930
+ full_node_1 = nodes[0]
1931
+ full_node_2 = nodes[1]
1932
+ blocks = bt.get_consecutive_blocks(num_blocks=1, skip_slots=3)
1933
+ blocks_2 = bt.get_consecutive_blocks(num_blocks=3, block_list_input=blocks, skip_slots=3)
1934
+ for block in blocks_2[:2]:
1935
+ await full_node_1.full_node.add_block(block)
1936
+ assert full_node_1.full_node.blockchain.get_peak().height == 1
1937
+ # (wrong_vdf_info, wrong_vdf_proof) pair verifies, but it's not present in the blockchain at all.
1938
+ block = blocks_2[2]
1939
+ wrong_vdf_info, wrong_vdf_proof = get_vdf_info_and_proof(
1940
+ bt.constants,
1941
+ ClassgroupElement.get_default_element(),
1942
+ block.reward_chain_block.challenge_chain_ip_vdf.challenge,
1943
+ block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
1944
+ True,
1945
+ )
1946
+ timelord_protocol_invalid_messages = []
1947
+ full_node_protocol_invalid_messaages = []
1948
+ for block in blocks_2[:2]:
1949
+ for sub_slot in block.finished_sub_slots:
1950
+ vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
1951
+ bt.constants,
1952
+ ClassgroupElement.get_default_element(),
1953
+ sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.challenge,
1954
+ sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.number_of_iterations,
1955
+ True,
1956
+ )
1957
+ assert wrong_vdf_proof != correct_vdf_proof
1958
+ timelord_protocol_invalid_messages.append(
1959
+ timelord_protocol.RespondCompactProofOfTime(
1960
+ vdf_info,
1961
+ wrong_vdf_proof,
1962
+ block.header_hash,
1963
+ block.height,
1964
+ CompressibleVDFField.CC_EOS_VDF,
1965
+ )
1966
+ )
1967
+ full_node_protocol_invalid_messaages.append(
1968
+ fnp.RespondCompactVDF(
1969
+ block.height,
1970
+ block.header_hash,
1971
+ CompressibleVDFField.CC_EOS_VDF,
1972
+ vdf_info,
1973
+ wrong_vdf_proof,
1974
+ )
1975
+ )
1976
+ if sub_slot.infused_challenge_chain is not None:
1977
+ vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
1978
+ bt.constants,
1979
+ ClassgroupElement.get_default_element(),
1980
+ sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.challenge,
1981
+ sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.number_of_iterations,
1982
+ True,
1983
+ )
1984
+ assert wrong_vdf_proof != correct_vdf_proof
1985
+ timelord_protocol_invalid_messages.append(
1986
+ timelord_protocol.RespondCompactProofOfTime(
1987
+ vdf_info,
1988
+ wrong_vdf_proof,
1989
+ block.header_hash,
1990
+ block.height,
1991
+ CompressibleVDFField.ICC_EOS_VDF,
1992
+ )
1993
+ )
1994
+ full_node_protocol_invalid_messaages.append(
1995
+ fnp.RespondCompactVDF(
1996
+ block.height,
1997
+ block.header_hash,
1998
+ CompressibleVDFField.ICC_EOS_VDF,
1999
+ vdf_info,
2000
+ wrong_vdf_proof,
2001
+ )
2002
+ )
2003
+
2004
+ if block.reward_chain_block.challenge_chain_sp_vdf is not None:
2005
+ vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
2006
+ bt.constants,
2007
+ ClassgroupElement.get_default_element(),
2008
+ block.reward_chain_block.challenge_chain_sp_vdf.challenge,
2009
+ block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
2010
+ True,
2011
+ )
2012
+ sp_vdf_proof = wrong_vdf_proof
2013
+ if wrong_vdf_proof == correct_vdf_proof:
2014
+ # This can actually happen...
2015
+ sp_vdf_proof = VDFProof(uint8(0), b"1239819023890", True)
2016
+ timelord_protocol_invalid_messages.append(
2017
+ timelord_protocol.RespondCompactProofOfTime(
2018
+ vdf_info,
2019
+ sp_vdf_proof,
2020
+ block.header_hash,
2021
+ block.height,
2022
+ CompressibleVDFField.CC_SP_VDF,
2023
+ )
2024
+ )
2025
+ full_node_protocol_invalid_messaages.append(
2026
+ fnp.RespondCompactVDF(
2027
+ block.height,
2028
+ block.header_hash,
2029
+ CompressibleVDFField.CC_SP_VDF,
2030
+ vdf_info,
2031
+ sp_vdf_proof,
2032
+ )
2033
+ )
2034
+
2035
+ vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
2036
+ bt.constants,
2037
+ ClassgroupElement.get_default_element(),
2038
+ block.reward_chain_block.challenge_chain_ip_vdf.challenge,
2039
+ block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
2040
+ True,
2041
+ )
2042
+ ip_vdf_proof = wrong_vdf_proof
2043
+ if wrong_vdf_proof == correct_vdf_proof:
2044
+ # This can actually happen...
2045
+ ip_vdf_proof = VDFProof(uint8(0), b"1239819023890", True)
2046
+ timelord_protocol_invalid_messages.append(
2047
+ timelord_protocol.RespondCompactProofOfTime(
2048
+ vdf_info,
2049
+ ip_vdf_proof,
2050
+ block.header_hash,
2051
+ block.height,
2052
+ CompressibleVDFField.CC_IP_VDF,
2053
+ )
2054
+ )
2055
+ full_node_protocol_invalid_messaages.append(
2056
+ fnp.RespondCompactVDF(
2057
+ block.height,
2058
+ block.header_hash,
2059
+ CompressibleVDFField.CC_IP_VDF,
2060
+ vdf_info,
2061
+ ip_vdf_proof,
2062
+ )
2063
+ )
2064
+
2065
+ timelord_protocol_invalid_messages.append(
2066
+ timelord_protocol.RespondCompactProofOfTime(
2067
+ wrong_vdf_info,
2068
+ wrong_vdf_proof,
2069
+ block.header_hash,
2070
+ block.height,
2071
+ CompressibleVDFField.CC_EOS_VDF,
2072
+ )
2073
+ )
2074
+ timelord_protocol_invalid_messages.append(
2075
+ timelord_protocol.RespondCompactProofOfTime(
2076
+ wrong_vdf_info,
2077
+ wrong_vdf_proof,
2078
+ block.header_hash,
2079
+ block.height,
2080
+ CompressibleVDFField.ICC_EOS_VDF,
2081
+ )
2082
+ )
2083
+ timelord_protocol_invalid_messages.append(
2084
+ timelord_protocol.RespondCompactProofOfTime(
2085
+ wrong_vdf_info,
2086
+ wrong_vdf_proof,
2087
+ block.header_hash,
2088
+ block.height,
2089
+ CompressibleVDFField.CC_SP_VDF,
2090
+ )
2091
+ )
2092
+ timelord_protocol_invalid_messages.append(
2093
+ timelord_protocol.RespondCompactProofOfTime(
2094
+ wrong_vdf_info,
2095
+ wrong_vdf_proof,
2096
+ block.header_hash,
2097
+ block.height,
2098
+ CompressibleVDFField.CC_IP_VDF,
2099
+ )
2100
+ )
2101
+ full_node_protocol_invalid_messaages.append(
2102
+ fnp.RespondCompactVDF(
2103
+ block.height,
2104
+ block.header_hash,
2105
+ CompressibleVDFField.CC_EOS_VDF,
2106
+ wrong_vdf_info,
2107
+ wrong_vdf_proof,
2108
+ )
2109
+ )
2110
+ full_node_protocol_invalid_messaages.append(
2111
+ fnp.RespondCompactVDF(
2112
+ block.height,
2113
+ block.header_hash,
2114
+ CompressibleVDFField.ICC_EOS_VDF,
2115
+ wrong_vdf_info,
2116
+ wrong_vdf_proof,
2117
+ )
2118
+ )
2119
+ full_node_protocol_invalid_messaages.append(
2120
+ fnp.RespondCompactVDF(
2121
+ block.height,
2122
+ block.header_hash,
2123
+ CompressibleVDFField.CC_SP_VDF,
2124
+ wrong_vdf_info,
2125
+ wrong_vdf_proof,
2126
+ )
2127
+ )
2128
+ full_node_protocol_invalid_messaages.append(
2129
+ fnp.RespondCompactVDF(
2130
+ block.height,
2131
+ block.header_hash,
2132
+ CompressibleVDFField.CC_IP_VDF,
2133
+ wrong_vdf_info,
2134
+ wrong_vdf_proof,
2135
+ )
2136
+ )
2137
+ server_1 = full_node_1.full_node.server
2138
+ server_2 = full_node_2.full_node.server
2139
+ peer = await connect_and_get_peer(server_1, server_2, self_hostname)
2140
+ for invalid_compact_proof in timelord_protocol_invalid_messages:
2141
+ await full_node_1.full_node.add_compact_proof_of_time(invalid_compact_proof)
2142
+ for invalid_compact_proof in full_node_protocol_invalid_messaages:
2143
+ await full_node_1.full_node.add_compact_vdf(invalid_compact_proof, peer)
2144
+ stored_blocks = await full_node_1.get_all_full_blocks()
2145
+ for block in stored_blocks:
2146
+ for sub_slot in block.finished_sub_slots:
2147
+ assert not sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity
2148
+ if sub_slot.proofs.infused_challenge_chain_slot_proof is not None:
2149
+ assert not sub_slot.proofs.infused_challenge_chain_slot_proof.normalized_to_identity
2150
+ if block.challenge_chain_sp_proof is not None:
2151
+ assert not block.challenge_chain_sp_proof.normalized_to_identity
2152
+ assert not block.challenge_chain_ip_proof.normalized_to_identity
2153
+
2154
+
2155
+ @pytest.mark.anyio
2156
+ async def test_respond_compact_proof_message_limit(setup_two_nodes_fixture):
2157
+ nodes, _, bt = setup_two_nodes_fixture
2158
+ full_node_1 = nodes[0]
2159
+ full_node_2 = nodes[1]
2160
+ NUM_BLOCKS = 20
2161
+ # We don't compactify the last 5 blocks.
2162
+ EXPECTED_COMPACTIFIED = NUM_BLOCKS - 5
2163
+ blocks = bt.get_consecutive_blocks(num_blocks=NUM_BLOCKS)
2164
+ finished_compact_proofs = []
2165
+ for block in blocks:
2166
+ await full_node_1.full_node.add_block(block)
2167
+ await full_node_2.full_node.add_block(block)
2168
+ vdf_info, vdf_proof = get_vdf_info_and_proof(
2169
+ bt.constants,
2170
+ ClassgroupElement.get_default_element(),
2171
+ block.reward_chain_block.challenge_chain_ip_vdf.challenge,
2172
+ block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
2173
+ True,
2174
+ )
2175
+ finished_compact_proofs.append(
2176
+ timelord_protocol.RespondCompactProofOfTime(
2177
+ vdf_info,
2178
+ vdf_proof,
2179
+ block.header_hash,
2180
+ block.height,
2181
+ CompressibleVDFField.CC_IP_VDF,
2182
+ )
2183
+ )
2184
+
2185
+ async def coro(full_node, compact_proof):
2186
+ await full_node.respond_compact_proof_of_time(compact_proof)
2187
+
2188
+ full_node_1.full_node._compact_vdf_sem = LimitedSemaphore.create(active_limit=1, waiting_limit=2)
2189
+ tasks = asyncio.gather(
2190
+ *[coro(full_node_1, respond_compact_proof) for respond_compact_proof in finished_compact_proofs]
2191
+ )
2192
+ await tasks
2193
+ stored_blocks = await full_node_1.get_all_full_blocks()
2194
+ compactified = 0
2195
+ for block in stored_blocks:
2196
+ if block.challenge_chain_ip_proof.normalized_to_identity:
2197
+ compactified += 1
2198
+ assert compactified == 3
2199
+
2200
+ # The other full node receives the compact messages one at a time.
2201
+ for respond_compact_proof in finished_compact_proofs:
2202
+ await full_node_2.full_node.add_compact_proof_of_time(respond_compact_proof)
2203
+ stored_blocks = await full_node_2.get_all_full_blocks()
2204
+ compactified = 0
2205
+ for block in stored_blocks:
2206
+ if block.challenge_chain_ip_proof.normalized_to_identity:
2207
+ compactified += 1
2208
+ assert compactified == EXPECTED_COMPACTIFIED
2209
+
2210
+
2211
+ @pytest.mark.parametrize(
2212
+ argnames=["custom_capabilities", "expect_success"],
2213
+ argvalues=[
2214
+ # standard
2215
+ [default_capabilities[NodeType.FULL_NODE], True],
2216
+ # an additional enabled but unknown capability
2217
+ [[*default_capabilities[NodeType.FULL_NODE], (uint16(max(Capability) + 1), "1")], True],
2218
+ # no capability, not even Chia mainnet
2219
+ # TODO: shouldn't we fail without Capability.BASE?
2220
+ [[], True],
2221
+ # only an unknown capability
2222
+ # TODO: shouldn't we fail without Capability.BASE?
2223
+ [[(uint16(max(Capability) + 1), "1")], True],
2224
+ ],
2225
+ )
2226
+ @pytest.mark.anyio
2227
+ async def test_invalid_capability_can_connect(
2228
+ two_nodes: tuple[FullNodeAPI, FullNodeAPI, ChiaServer, ChiaServer, BlockTools],
2229
+ self_hostname: str,
2230
+ custom_capabilities: list[tuple[uint16, str]],
2231
+ expect_success: bool,
2232
+ ) -> None:
2233
+ # TODO: consider not testing this against both DB v1 and v2?
2234
+
2235
+ [
2236
+ _initiating_full_node_api,
2237
+ _listening_full_node_api,
2238
+ initiating_server,
2239
+ listening_server,
2240
+ _bt,
2241
+ ] = two_nodes
2242
+
2243
+ initiating_server._local_capabilities_for_handshake = custom_capabilities
2244
+
2245
+ connected = await initiating_server.start_client(PeerInfo(self_hostname, listening_server.get_port()), None)
2246
+ assert connected == expect_success, custom_capabilities
2247
+
2248
+
2249
+ @pytest.mark.anyio
2250
+ async def test_node_start_with_existing_blocks(db_version: int) -> None:
2251
+ with TempKeyring(populate=True) as keychain:
2252
+ block_tools = await create_block_tools_async(keychain=keychain)
2253
+
2254
+ blocks_per_cycle = 5
2255
+ expected_height = 0
2256
+
2257
+ for cycle in range(2):
2258
+ async with setup_full_node(
2259
+ consensus_constants=block_tools.constants,
2260
+ db_name="node_restart_test.db",
2261
+ self_hostname=block_tools.config["self_hostname"],
2262
+ local_bt=block_tools,
2263
+ simulator=True,
2264
+ db_version=db_version,
2265
+ reuse_db=True,
2266
+ ) as service:
2267
+ simulator_api = service._api
2268
+ assert isinstance(simulator_api, FullNodeSimulator)
2269
+ await simulator_api.farm_blocks_to_puzzlehash(count=blocks_per_cycle)
2270
+
2271
+ expected_height += blocks_per_cycle
2272
+ assert simulator_api.full_node._blockchain is not None
2273
+ block_record = simulator_api.full_node._blockchain.get_peak()
2274
+
2275
+ assert block_record is not None, f"block_record is None on cycle {cycle + 1}"
2276
+ assert block_record.height == expected_height, f"wrong height on cycle {cycle + 1}"
2277
+
2278
+
2279
+ @pytest.mark.anyio
2280
+ async def test_wallet_sync_task_failure(
2281
+ one_node: SimulatorsAndWalletsServices, caplog: pytest.LogCaptureFixture
2282
+ ) -> None:
2283
+ [full_node_service], _, _ = one_node
2284
+ full_node = full_node_service._node
2285
+ assert full_node.wallet_sync_task is not None
2286
+ caplog.set_level(logging.DEBUG)
2287
+ peak = Peak(bytes32(32 * b"0"), uint32(0), uint128(0))
2288
+ # WalletUpdate with invalid args to force an exception in FullNode.update_wallets / FullNode.wallet_sync_task
2289
+ bad_wallet_update = WalletUpdate(-10, peak, [], {}) # type: ignore[arg-type]
2290
+ await full_node.wallet_sync_queue.put(bad_wallet_update)
2291
+ await time_out_assert(30, full_node.wallet_sync_queue.empty)
2292
+ assert "update_wallets - fork_height: -10, peak_height: 0" in caplog.text
2293
+ assert "Wallet sync task failure" in caplog.text
2294
+ assert not full_node.wallet_sync_task.done()
2295
+ caplog.clear()
2296
+ # WalletUpdate with valid args to test continued processing after failure
2297
+ good_wallet_update = WalletUpdate(uint32(10), peak, [], {})
2298
+ await full_node.wallet_sync_queue.put(good_wallet_update)
2299
+ await time_out_assert(30, full_node.wallet_sync_queue.empty)
2300
+ assert "update_wallets - fork_height: 10, peak_height: 0" in caplog.text
2301
+ assert "Wallet sync task failure" not in caplog.text
2302
+ assert not full_node.wallet_sync_task.done()
2303
+
2304
+
2305
+ def print_coin_records(records: dict[bytes32, CoinRecord]) -> None: # pragma: no cover
2306
+ print("found unexpected coins in database")
2307
+ for rec in records.values():
2308
+ print(f"{rec}")
2309
+
2310
+
2311
+ async def validate_coin_set(coin_store: CoinStore, blocks: list[FullBlock]) -> None:
2312
+ prev_height = blocks[0].height - 1
2313
+ prev_hash = blocks[0].prev_header_hash
2314
+ for block in blocks:
2315
+ assert block.height == prev_height + 1
2316
+ assert block.prev_header_hash == prev_hash
2317
+ prev_height = int(block.height)
2318
+ prev_hash = block.header_hash
2319
+ rewards = block.get_included_reward_coins()
2320
+ records = {rec.coin.name(): rec for rec in await coin_store.get_coins_added_at_height(block.height)}
2321
+
2322
+ # validate reward coins
2323
+ for reward in rewards:
2324
+ rec = records.pop(reward.name())
2325
+ assert rec is not None
2326
+ assert rec.confirmed_block_index == block.height
2327
+ assert rec.coin == reward
2328
+ assert rec.coinbase
2329
+
2330
+ if block.transactions_generator is None:
2331
+ if len(records) > 0: # pragma: no cover
2332
+ print(f"height: {block.height} unexpected coins in the DB: {records} TX: No")
2333
+ print_coin_records(records)
2334
+ assert records == {}
2335
+ continue
2336
+
2337
+ if len(block.transactions_generator_ref_list) > 0: # pragma: no cover
2338
+ # TODO: Support block references
2339
+ assert False
2340
+
2341
+ flags = get_flags_for_height_and_constants(block.height, test_constants)
2342
+ additions, removals = additions_and_removals(bytes(block.transactions_generator), [], flags, test_constants)
2343
+
2344
+ for add, hint in additions:
2345
+ rec = records.pop(add.name())
2346
+ assert rec is not None
2347
+ assert rec.confirmed_block_index == block.height
2348
+ assert rec.coin == add
2349
+ assert not rec.coinbase
2350
+
2351
+ if len(records) > 0: # pragma: no cover
2352
+ print(f"height: {block.height} unexpected coins in the DB: {records} TX: Yes")
2353
+ print_coin_records(records)
2354
+ assert records == {}
2355
+
2356
+ records = {rec.coin.name(): rec for rec in await coin_store.get_coins_removed_at_height(block.height)}
2357
+ for rem in removals:
2358
+ rec = records.pop(rem.name())
2359
+ assert rec is not None
2360
+ assert rec.spent_block_index == block.height
2361
+ assert rec.coin == rem
2362
+
2363
+ if len(records) > 0: # pragma: no cover
2364
+ print(f"height: {block.height} unexpected removals: {records} TX: Yes")
2365
+ print_coin_records(records)
2366
+ assert records == {}
2367
+
2368
+
2369
+ @pytest.mark.anyio
2370
+ @pytest.mark.parametrize("light_blocks", [True, False])
2371
+ async def test_long_reorg(
2372
+ light_blocks: bool,
2373
+ one_node_one_block,
2374
+ default_10000_blocks: list[FullBlock],
2375
+ test_long_reorg_1500_blocks: list[FullBlock],
2376
+ test_long_reorg_1500_blocks_light: list[FullBlock],
2377
+ seeded_random: random.Random,
2378
+ ):
2379
+ node, _server, _bt = one_node_one_block
2380
+
2381
+ fork_point = 1499
2382
+ blocks = default_10000_blocks[:3000]
2383
+
2384
+ if light_blocks:
2385
+ # if the blocks have lighter weight, we need more height to compensate,
2386
+ # to force a reorg
2387
+ reorg_blocks = test_long_reorg_1500_blocks_light[:3050]
2388
+ else:
2389
+ reorg_blocks = test_long_reorg_1500_blocks[:2700]
2390
+
2391
+ await add_blocks_in_batches(blocks, node.full_node)
2392
+ peak = node.full_node.blockchain.get_peak()
2393
+ chain_1_height = peak.height
2394
+ chain_1_weight = peak.weight
2395
+ chain_1_peak = peak.header_hash
2396
+
2397
+ assert reorg_blocks[fork_point] == default_10000_blocks[fork_point]
2398
+ assert reorg_blocks[fork_point + 1] != default_10000_blocks[fork_point + 1]
2399
+
2400
+ await validate_coin_set(node.full_node._coin_store, blocks)
2401
+
2402
+ # one aspect of this test is to make sure we can reorg blocks that are
2403
+ # not in the cache. We need to explicitly prune the cache to get that
2404
+ # effect.
2405
+ node.full_node.blockchain.clean_block_records()
2406
+ await add_blocks_in_batches(reorg_blocks, node.full_node)
2407
+ # if these asserts fires, there was no reorg
2408
+ peak = node.full_node.blockchain.get_peak()
2409
+ assert peak.header_hash != chain_1_peak
2410
+ assert peak.weight > chain_1_weight
2411
+ chain_2_weight = peak.weight
2412
+ chain_2_peak = peak.header_hash
2413
+
2414
+ await validate_coin_set(node.full_node._coin_store, reorg_blocks)
2415
+
2416
+ # if the reorg chain has lighter blocks, once we've re-orged onto it, we
2417
+ # have a greater block height. If the reorg chain has heavier blocks, we
2418
+ # end up with a lower height than the original chain (but greater weight)
2419
+ if light_blocks:
2420
+ assert peak.height > chain_1_height
2421
+ else:
2422
+ assert peak.height < chain_1_height
2423
+ # now reorg back to the original chain
2424
+ # this exercises the case where we have some of the blocks in the DB already
2425
+ node.full_node.blockchain.clean_block_records()
2426
+ # when using add_block manualy we must warmup the cache
2427
+ await node.full_node.blockchain.warmup(fork_point - 100)
2428
+ if light_blocks:
2429
+ blocks = default_10000_blocks[fork_point - 100 : 3200]
2430
+ else:
2431
+ blocks = default_10000_blocks[fork_point - 100 : 5500]
2432
+ await add_blocks_in_batches(blocks, node.full_node)
2433
+ # if these asserts fires, there was no reorg back to the original chain
2434
+ peak = node.full_node.blockchain.get_peak()
2435
+ assert peak.header_hash != chain_2_peak
2436
+ assert peak.weight > chain_2_weight
2437
+
2438
+ await validate_coin_set(node.full_node._coin_store, blocks)
2439
+
2440
+
2441
+ @pytest.mark.anyio
2442
+ @pytest.mark.parametrize("light_blocks", [True, False])
2443
+ @pytest.mark.parametrize("chain_length", [0, 100])
2444
+ @pytest.mark.parametrize("fork_point", [500, 1500])
2445
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.HARD_FORK_2_0], reason="save time")
2446
+ async def test_long_reorg_nodes(
2447
+ light_blocks: bool,
2448
+ chain_length: int,
2449
+ fork_point: int,
2450
+ three_nodes,
2451
+ default_10000_blocks: list[FullBlock],
2452
+ test_long_reorg_blocks: list[FullBlock],
2453
+ test_long_reorg_blocks_light: list[FullBlock],
2454
+ test_long_reorg_1500_blocks: list[FullBlock],
2455
+ test_long_reorg_1500_blocks_light: list[FullBlock],
2456
+ self_hostname: str,
2457
+ seeded_random: random.Random,
2458
+ ):
2459
+ full_node_1, full_node_2, full_node_3 = three_nodes
2460
+
2461
+ if fork_point == 1500:
2462
+ blocks = default_10000_blocks[: 3600 - chain_length]
2463
+ else:
2464
+ blocks = default_10000_blocks[: 1600 - chain_length]
2465
+
2466
+ if light_blocks:
2467
+ if fork_point == 1500:
2468
+ reorg_blocks = test_long_reorg_1500_blocks_light[: 3600 - chain_length]
2469
+ reorg_height = 4000
2470
+ else:
2471
+ reorg_blocks = test_long_reorg_blocks_light[: 1600 - chain_length]
2472
+ reorg_height = 4000
2473
+ else:
2474
+ if fork_point == 1500:
2475
+ reorg_blocks = test_long_reorg_1500_blocks[: 3100 - chain_length]
2476
+ reorg_height = 10000
2477
+ else:
2478
+ reorg_blocks = test_long_reorg_blocks[: 1200 - chain_length]
2479
+ reorg_height = 4000
2480
+ pytest.skip("We rely on the light-blocks test for a 0 forkpoint")
2481
+
2482
+ await add_blocks_in_batches(blocks, full_node_1.full_node)
2483
+
2484
+ # full node 2 has the reorg-chain
2485
+ await add_blocks_in_batches(reorg_blocks[:-1], full_node_2.full_node)
2486
+ await connect_and_get_peer(full_node_1.full_node.server, full_node_2.full_node.server, self_hostname)
2487
+
2488
+ # TODO: There appears to be an issue where the node with the lighter chain
2489
+ # fails to initiate the reorg until there's a new block farmed onto the
2490
+ # heavier chain.
2491
+ await full_node_2.full_node.add_block(reorg_blocks[-1])
2492
+
2493
+ start = time.monotonic()
2494
+
2495
+ def check_nodes_in_sync():
2496
+ p1 = full_node_2.full_node.blockchain.get_peak()
2497
+ p2 = full_node_1.full_node.blockchain.get_peak()
2498
+ return p1 == p2
2499
+
2500
+ await time_out_assert(100, check_nodes_in_sync)
2501
+ peak = full_node_2.full_node.blockchain.get_peak()
2502
+ print(f"peak: {str(peak.header_hash)[:6]}")
2503
+
2504
+ reorg1_timing = time.monotonic() - start
2505
+
2506
+ p1 = full_node_1.full_node.blockchain.get_peak()
2507
+ p2 = full_node_2.full_node.blockchain.get_peak()
2508
+
2509
+ assert p1.header_hash == reorg_blocks[-1].header_hash
2510
+ assert p2.header_hash == reorg_blocks[-1].header_hash
2511
+
2512
+ await validate_coin_set(full_node_1.full_node._coin_store, reorg_blocks)
2513
+ await validate_coin_set(full_node_2.full_node._coin_store, reorg_blocks)
2514
+
2515
+ blocks = default_10000_blocks[:reorg_height]
2516
+
2517
+ # this is a pre-requisite for a reorg to happen
2518
+ assert blocks[-1].weight > p1.weight
2519
+ assert blocks[-1].weight > p2.weight
2520
+
2521
+ # full node 3 has the original chain, but even longer
2522
+ await add_blocks_in_batches(blocks, full_node_3.full_node)
2523
+ print("connecting node 3")
2524
+ await connect_and_get_peer(full_node_3.full_node.server, full_node_1.full_node.server, self_hostname)
2525
+ await connect_and_get_peer(full_node_3.full_node.server, full_node_2.full_node.server, self_hostname)
2526
+
2527
+ start = time.monotonic()
2528
+
2529
+ def check_nodes_in_sync2():
2530
+ p1 = full_node_1.full_node.blockchain.get_peak()
2531
+ p2 = full_node_2.full_node.blockchain.get_peak()
2532
+ p3 = full_node_3.full_node.blockchain.get_peak()
2533
+ return p1 == p3 and p1 == p2
2534
+
2535
+ await time_out_assert(900, check_nodes_in_sync2)
2536
+
2537
+ reorg2_timing = time.monotonic() - start
2538
+
2539
+ p1 = full_node_1.full_node.blockchain.get_peak()
2540
+ p2 = full_node_2.full_node.blockchain.get_peak()
2541
+ p3 = full_node_3.full_node.blockchain.get_peak()
2542
+
2543
+ assert p1.header_hash == blocks[-1].header_hash
2544
+ assert p2.header_hash == blocks[-1].header_hash
2545
+ assert p3.header_hash == blocks[-1].header_hash
2546
+
2547
+ print(f"reorg1 timing: {reorg1_timing:0.2f}s")
2548
+ print(f"reorg2 timing: {reorg2_timing:0.2f}s")
2549
+
2550
+ await validate_coin_set(full_node_1.full_node._coin_store, blocks)
2551
+ await validate_coin_set(full_node_2.full_node._coin_store, blocks)
2552
+ await validate_coin_set(full_node_3.full_node._coin_store, blocks)
2553
+
2554
+
2555
+ @pytest.mark.anyio
2556
+ async def test_shallow_reorg_nodes(
2557
+ three_nodes,
2558
+ self_hostname: str,
2559
+ bt: BlockTools,
2560
+ ):
2561
+ full_node_1, full_node_2, _ = three_nodes
2562
+
2563
+ # node 1 has chan A, then we replace the top block and ensure
2564
+ # node 2 follows along correctly
2565
+
2566
+ await connect_and_get_peer(full_node_1.full_node.server, full_node_2.full_node.server, self_hostname)
2567
+
2568
+ wallet_a = WalletTool(bt.constants)
2569
+ WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(2)]
2570
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
2571
+ receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
2572
+
2573
+ chain = bt.get_consecutive_blocks(
2574
+ 10,
2575
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
2576
+ pool_reward_puzzle_hash=receiver_puzzlehash,
2577
+ guarantee_transaction_block=True,
2578
+ )
2579
+ await add_blocks_in_batches(chain, full_node_1.full_node)
2580
+
2581
+ all_coins = []
2582
+ for spend_block in chain:
2583
+ for coin in spend_block.get_included_reward_coins():
2584
+ if coin.puzzle_hash == coinbase_puzzlehash:
2585
+ all_coins.append(coin)
2586
+
2587
+ def check_nodes_in_sync():
2588
+ p1 = full_node_2.full_node.blockchain.get_peak()
2589
+ p2 = full_node_1.full_node.blockchain.get_peak()
2590
+ return p1 == p2
2591
+
2592
+ await time_out_assert(10, check_nodes_in_sync)
2593
+ await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain)
2594
+ await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain)
2595
+
2596
+ # we spend a coin in the next block
2597
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
2598
+
2599
+ # make a non transaction block with fewer iterations than a, which should
2600
+ # replace it
2601
+ chain_b = bt.get_consecutive_blocks(
2602
+ 1,
2603
+ chain,
2604
+ guarantee_transaction_block=False,
2605
+ seed=b"{seed}",
2606
+ )
2607
+
2608
+ chain_a = bt.get_consecutive_blocks(
2609
+ 1,
2610
+ chain,
2611
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
2612
+ pool_reward_puzzle_hash=receiver_puzzlehash,
2613
+ transaction_data=spend_bundle,
2614
+ guarantee_transaction_block=True,
2615
+ min_signage_point=chain_b[-1].reward_chain_block.signage_point_index,
2616
+ )
2617
+
2618
+ print(f"chain A: {chain_a[-1].header_hash.hex()}")
2619
+ print(f"chain B: {chain_b[-1].header_hash.hex()}")
2620
+
2621
+ assert chain_b[-1].total_iters < chain_a[-1].total_iters
2622
+
2623
+ await add_blocks_in_batches(chain_a[-1:], full_node_1.full_node)
2624
+
2625
+ await time_out_assert(10, check_nodes_in_sync)
2626
+ await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain_a)
2627
+ await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain_a)
2628
+
2629
+ await add_blocks_in_batches(chain_b[-1:], full_node_1.full_node)
2630
+
2631
+ # make sure node 1 reorged onto chain B
2632
+ assert full_node_1.full_node.blockchain.get_peak().header_hash == chain_b[-1].header_hash
2633
+
2634
+ await time_out_assert(10, check_nodes_in_sync)
2635
+ await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain_b)
2636
+ await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain_b)
2637
+
2638
+ # now continue building the chain on top of B
2639
+ # since spend_bundle was supposed to have been reorged-out, we should be
2640
+ # able to include it in another block, howerver, since we replaced a TX
2641
+ # block with a non-TX block, it won't be available immediately at height 11
2642
+
2643
+ # add a TX block, this will make spend_bundle valid in the next block
2644
+ chain = bt.get_consecutive_blocks(
2645
+ 1,
2646
+ chain,
2647
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
2648
+ pool_reward_puzzle_hash=receiver_puzzlehash,
2649
+ guarantee_transaction_block=True,
2650
+ )
2651
+ for coin in chain[-1].get_included_reward_coins():
2652
+ if coin.puzzle_hash == coinbase_puzzlehash:
2653
+ all_coins.append(coin)
2654
+
2655
+ for i in range(3):
2656
+ chain = bt.get_consecutive_blocks(
2657
+ 1,
2658
+ chain,
2659
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
2660
+ pool_reward_puzzle_hash=receiver_puzzlehash,
2661
+ transaction_data=spend_bundle,
2662
+ guarantee_transaction_block=True,
2663
+ )
2664
+ for coin in chain[-1].get_included_reward_coins():
2665
+ if coin.puzzle_hash == coinbase_puzzlehash:
2666
+ all_coins.append(coin)
2667
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
2668
+
2669
+ await add_blocks_in_batches(chain[-4:], full_node_1.full_node)
2670
+ await time_out_assert(10, check_nodes_in_sync)
2671
+ await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain)
2672
+ await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain)
2673
+
2674
+
2675
+ @pytest.mark.anyio
2676
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.HARD_FORK_2_0], reason="save time")
2677
+ async def test_eviction_from_bls_cache(one_node_one_block: tuple[FullNodeSimulator, ChiaServer, BlockTools]) -> None:
2678
+ """
2679
+ This test covers the case where adding a block to the blockchain evicts
2680
+ all its pk msg pairs from the BLS cache.
2681
+ """
2682
+ full_node_1, _, bt = one_node_one_block
2683
+ blocks = bt.get_consecutive_blocks(
2684
+ 3, guarantee_transaction_block=True, farmer_reward_puzzle_hash=bt.pool_ph, pool_reward_puzzle_hash=bt.pool_ph
2685
+ )
2686
+ await add_blocks_in_batches(blocks, full_node_1.full_node)
2687
+ wt = bt.get_pool_wallet_tool()
2688
+ reward_coins = blocks[-1].get_included_reward_coins()
2689
+ # Setup a test block with two pk msg pairs
2690
+ tx1 = wt.generate_signed_transaction(uint64(42), wt.get_new_puzzlehash(), reward_coins[0])
2691
+ tx2 = wt.generate_signed_transaction(uint64(1337), wt.get_new_puzzlehash(), reward_coins[1])
2692
+ tx = SpendBundle.aggregate([tx1, tx2])
2693
+ await full_node_1.full_node.add_transaction(tx, tx.name(), None, test=True)
2694
+ assert len(full_node_1.full_node._bls_cache.items()) == 2
2695
+ blocks = bt.get_consecutive_blocks(
2696
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2697
+ )
2698
+ # Farming a block with this tx evicts those pk msg pairs from the BLS cache
2699
+ await full_node_1.full_node.add_block(blocks[-1], None, full_node_1.full_node._bls_cache)
2700
+ assert len(full_node_1.full_node._bls_cache.items()) == 0