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