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