chia-blockchain 2.4.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1028) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +197 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +147 -0
  9. chia/_tests/blockchain/test_blockchain.py +4100 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1050 -0
  11. chia/_tests/blockchain/test_build_chains.py +61 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +195 -0
  14. chia/_tests/build-init-files.py +93 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +73 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +147 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +57 -0
  26. chia/_tests/clvm/test_program.py +150 -0
  27. chia/_tests/clvm/test_puzzle_compression.py +144 -0
  28. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  29. chia/_tests/clvm/test_puzzles.py +247 -0
  30. chia/_tests/clvm/test_singletons.py +540 -0
  31. chia/_tests/clvm/test_spend_sim.py +181 -0
  32. chia/_tests/cmds/__init__.py +0 -0
  33. chia/_tests/cmds/cmd_test_utils.py +472 -0
  34. chia/_tests/cmds/config.py +3 -0
  35. chia/_tests/cmds/conftest.py +23 -0
  36. chia/_tests/cmds/test_click_types.py +195 -0
  37. chia/_tests/cmds/test_cmd_framework.py +400 -0
  38. chia/_tests/cmds/test_cmds_util.py +97 -0
  39. chia/_tests/cmds/test_daemon.py +92 -0
  40. chia/_tests/cmds/test_farm_cmd.py +67 -0
  41. chia/_tests/cmds/test_show.py +116 -0
  42. chia/_tests/cmds/test_sim.py +207 -0
  43. chia/_tests/cmds/test_timelock_args.py +75 -0
  44. chia/_tests/cmds/test_tx_config_args.py +153 -0
  45. chia/_tests/cmds/testing_classes.py +59 -0
  46. chia/_tests/cmds/wallet/__init__.py +0 -0
  47. chia/_tests/cmds/wallet/test_coins.py +195 -0
  48. chia/_tests/cmds/wallet/test_consts.py +47 -0
  49. chia/_tests/cmds/wallet/test_dao.py +565 -0
  50. chia/_tests/cmds/wallet/test_did.py +403 -0
  51. chia/_tests/cmds/wallet/test_nft.py +470 -0
  52. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  53. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  54. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  55. chia/_tests/cmds/wallet/test_vcs.py +376 -0
  56. chia/_tests/cmds/wallet/test_wallet.py +1126 -0
  57. chia/_tests/cmds/wallet/test_wallet_check.py +111 -0
  58. chia/_tests/conftest.py +1304 -0
  59. chia/_tests/connection_utils.py +124 -0
  60. chia/_tests/core/__init__.py +0 -0
  61. chia/_tests/core/cmds/__init__.py +0 -0
  62. chia/_tests/core/cmds/test_beta.py +382 -0
  63. chia/_tests/core/cmds/test_keys.py +1734 -0
  64. chia/_tests/core/cmds/test_wallet.py +126 -0
  65. chia/_tests/core/config.py +3 -0
  66. chia/_tests/core/consensus/__init__.py +0 -0
  67. chia/_tests/core/consensus/test_block_creation.py +56 -0
  68. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  69. chia/_tests/core/custom_types/__init__.py +0 -0
  70. chia/_tests/core/custom_types/test_coin.py +109 -0
  71. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  72. chia/_tests/core/custom_types/test_spend_bundle.py +71 -0
  73. chia/_tests/core/daemon/__init__.py +0 -0
  74. chia/_tests/core/daemon/config.py +4 -0
  75. chia/_tests/core/daemon/test_daemon.py +2128 -0
  76. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  77. chia/_tests/core/daemon/test_keychain_proxy.py +100 -0
  78. chia/_tests/core/data_layer/__init__.py +0 -0
  79. chia/_tests/core/data_layer/config.py +5 -0
  80. chia/_tests/core/data_layer/conftest.py +105 -0
  81. chia/_tests/core/data_layer/test_data_cli.py +57 -0
  82. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  83. chia/_tests/core/data_layer/test_data_layer_util.py +219 -0
  84. chia/_tests/core/data_layer/test_data_rpc.py +3865 -0
  85. chia/_tests/core/data_layer/test_data_store.py +2423 -0
  86. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  87. chia/_tests/core/data_layer/test_plugin.py +91 -0
  88. chia/_tests/core/data_layer/util.py +232 -0
  89. chia/_tests/core/farmer/__init__.py +0 -0
  90. chia/_tests/core/farmer/config.py +3 -0
  91. chia/_tests/core/farmer/test_farmer_api.py +101 -0
  92. chia/_tests/core/full_node/__init__.py +0 -0
  93. chia/_tests/core/full_node/config.py +4 -0
  94. chia/_tests/core/full_node/dos/__init__.py +0 -0
  95. chia/_tests/core/full_node/dos/config.py +3 -0
  96. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  97. chia/_tests/core/full_node/full_sync/config.py +4 -0
  98. chia/_tests/core/full_node/full_sync/test_full_sync.py +448 -0
  99. chia/_tests/core/full_node/ram_db.py +27 -0
  100. chia/_tests/core/full_node/stores/__init__.py +0 -0
  101. chia/_tests/core/full_node/stores/config.py +4 -0
  102. chia/_tests/core/full_node/stores/test_block_store.py +488 -0
  103. chia/_tests/core/full_node/stores/test_coin_store.py +888 -0
  104. chia/_tests/core/full_node/stores/test_full_node_store.py +1215 -0
  105. chia/_tests/core/full_node/stores/test_hint_store.py +230 -0
  106. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  107. chia/_tests/core/full_node/test_address_manager.py +588 -0
  108. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  109. chia/_tests/core/full_node/test_conditions.py +558 -0
  110. chia/_tests/core/full_node/test_full_node.py +2445 -0
  111. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  112. chia/_tests/core/full_node/test_hint_management.py +104 -0
  113. chia/_tests/core/full_node/test_node_load.py +34 -0
  114. chia/_tests/core/full_node/test_performance.py +182 -0
  115. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  116. chia/_tests/core/full_node/test_transactions.py +203 -0
  117. chia/_tests/core/full_node/test_tx_processing_queue.py +154 -0
  118. chia/_tests/core/large_block.py +2388 -0
  119. chia/_tests/core/make_block_generator.py +72 -0
  120. chia/_tests/core/mempool/__init__.py +0 -0
  121. chia/_tests/core/mempool/config.py +4 -0
  122. chia/_tests/core/mempool/test_mempool.py +3180 -0
  123. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  124. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  125. chia/_tests/core/mempool/test_mempool_item_queries.py +192 -0
  126. chia/_tests/core/mempool/test_mempool_manager.py +2054 -0
  127. chia/_tests/core/mempool/test_mempool_performance.py +65 -0
  128. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  129. chia/_tests/core/node_height.py +28 -0
  130. chia/_tests/core/server/__init__.py +0 -0
  131. chia/_tests/core/server/config.py +3 -0
  132. chia/_tests/core/server/flood.py +82 -0
  133. chia/_tests/core/server/serve.py +132 -0
  134. chia/_tests/core/server/test_capabilities.py +68 -0
  135. chia/_tests/core/server/test_dos.py +320 -0
  136. chia/_tests/core/server/test_event_loop.py +109 -0
  137. chia/_tests/core/server/test_loop.py +290 -0
  138. chia/_tests/core/server/test_node_discovery.py +74 -0
  139. chia/_tests/core/server/test_rate_limits.py +370 -0
  140. chia/_tests/core/server/test_server.py +225 -0
  141. chia/_tests/core/server/test_upnp.py +8 -0
  142. chia/_tests/core/services/__init__.py +0 -0
  143. chia/_tests/core/services/config.py +3 -0
  144. chia/_tests/core/services/test_services.py +166 -0
  145. chia/_tests/core/ssl/__init__.py +0 -0
  146. chia/_tests/core/ssl/config.py +3 -0
  147. chia/_tests/core/ssl/test_ssl.py +198 -0
  148. chia/_tests/core/test_coins.py +33 -0
  149. chia/_tests/core/test_cost_calculation.py +314 -0
  150. chia/_tests/core/test_crawler.py +175 -0
  151. chia/_tests/core/test_crawler_rpc.py +53 -0
  152. chia/_tests/core/test_daemon_rpc.py +24 -0
  153. chia/_tests/core/test_db_conversion.py +129 -0
  154. chia/_tests/core/test_db_validation.py +161 -0
  155. chia/_tests/core/test_farmer_harvester_rpc.py +504 -0
  156. chia/_tests/core/test_filter.py +37 -0
  157. chia/_tests/core/test_full_node_rpc.py +794 -0
  158. chia/_tests/core/test_merkle_set.py +343 -0
  159. chia/_tests/core/test_program.py +49 -0
  160. chia/_tests/core/test_rpc_util.py +87 -0
  161. chia/_tests/core/test_seeder.py +308 -0
  162. chia/_tests/core/test_setproctitle.py +13 -0
  163. chia/_tests/core/util/__init__.py +0 -0
  164. chia/_tests/core/util/config.py +4 -0
  165. chia/_tests/core/util/test_block_cache.py +44 -0
  166. chia/_tests/core/util/test_cached_bls.py +57 -0
  167. chia/_tests/core/util/test_config.py +337 -0
  168. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  169. chia/_tests/core/util/test_files.py +391 -0
  170. chia/_tests/core/util/test_jsonify.py +146 -0
  171. chia/_tests/core/util/test_keychain.py +514 -0
  172. chia/_tests/core/util/test_keyring_wrapper.py +490 -0
  173. chia/_tests/core/util/test_lockfile.py +380 -0
  174. chia/_tests/core/util/test_log_exceptions.py +187 -0
  175. chia/_tests/core/util/test_lru_cache.py +56 -0
  176. chia/_tests/core/util/test_significant_bits.py +40 -0
  177. chia/_tests/core/util/test_streamable.py +883 -0
  178. chia/_tests/db/__init__.py +0 -0
  179. chia/_tests/db/test_db_wrapper.py +565 -0
  180. chia/_tests/environments/__init__.py +0 -0
  181. chia/_tests/environments/common.py +35 -0
  182. chia/_tests/environments/full_node.py +47 -0
  183. chia/_tests/environments/wallet.py +368 -0
  184. chia/_tests/ether.py +19 -0
  185. chia/_tests/farmer_harvester/__init__.py +0 -0
  186. chia/_tests/farmer_harvester/config.py +3 -0
  187. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  188. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  189. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +130 -0
  190. chia/_tests/farmer_harvester/test_third_party_harvesters.py +501 -0
  191. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  192. chia/_tests/fee_estimation/__init__.py +0 -0
  193. chia/_tests/fee_estimation/config.py +3 -0
  194. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  195. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +145 -0
  197. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  198. chia/_tests/generator/__init__.py +0 -0
  199. chia/_tests/generator/puzzles/__init__.py +0 -0
  200. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  201. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  202. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  203. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  204. chia/_tests/generator/test_compression.py +218 -0
  205. chia/_tests/generator/test_generator_types.py +44 -0
  206. chia/_tests/generator/test_rom.py +182 -0
  207. chia/_tests/plot_sync/__init__.py +0 -0
  208. chia/_tests/plot_sync/config.py +3 -0
  209. chia/_tests/plot_sync/test_delta.py +102 -0
  210. chia/_tests/plot_sync/test_plot_sync.py +617 -0
  211. chia/_tests/plot_sync/test_receiver.py +451 -0
  212. chia/_tests/plot_sync/test_sender.py +116 -0
  213. chia/_tests/plot_sync/test_sync_simulated.py +450 -0
  214. chia/_tests/plot_sync/util.py +67 -0
  215. chia/_tests/plotting/__init__.py +0 -0
  216. chia/_tests/plotting/config.py +3 -0
  217. chia/_tests/plotting/test_plot_manager.py +738 -0
  218. chia/_tests/plotting/util.py +13 -0
  219. chia/_tests/pools/__init__.py +0 -0
  220. chia/_tests/pools/config.py +5 -0
  221. chia/_tests/pools/test_pool_cmdline.py +23 -0
  222. chia/_tests/pools/test_pool_config.py +44 -0
  223. chia/_tests/pools/test_pool_puzzles_lifecycle.py +398 -0
  224. chia/_tests/pools/test_pool_rpc.py +1010 -0
  225. chia/_tests/pools/test_pool_wallet.py +201 -0
  226. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  227. chia/_tests/process_junit.py +349 -0
  228. chia/_tests/rpc/__init__.py +0 -0
  229. chia/_tests/rpc/test_rpc_client.py +81 -0
  230. chia/_tests/simulation/__init__.py +0 -0
  231. chia/_tests/simulation/config.py +6 -0
  232. chia/_tests/simulation/test_simulation.py +501 -0
  233. chia/_tests/simulation/test_simulator.py +234 -0
  234. chia/_tests/simulation/test_start_simulator.py +106 -0
  235. chia/_tests/testconfig.py +13 -0
  236. chia/_tests/timelord/__init__.py +0 -0
  237. chia/_tests/timelord/config.py +3 -0
  238. chia/_tests/timelord/test_new_peak.py +437 -0
  239. chia/_tests/timelord/test_timelord.py +11 -0
  240. chia/_tests/tools/1315537.json +170 -0
  241. chia/_tests/tools/1315544.json +160 -0
  242. chia/_tests/tools/1315630.json +150 -0
  243. chia/_tests/tools/300000.json +105 -0
  244. chia/_tests/tools/442734.json +140 -0
  245. chia/_tests/tools/466212.json +130 -0
  246. chia/_tests/tools/__init__.py +0 -0
  247. chia/_tests/tools/config.py +5 -0
  248. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  249. chia/_tests/tools/test_full_sync.py +30 -0
  250. chia/_tests/tools/test_legacy_keyring.py +82 -0
  251. chia/_tests/tools/test_run_block.py +129 -0
  252. chia/_tests/util/__init__.py +0 -0
  253. chia/_tests/util/benchmark_cost.py +170 -0
  254. chia/_tests/util/benchmarks.py +154 -0
  255. chia/_tests/util/bip39_test_vectors.json +148 -0
  256. chia/_tests/util/blockchain.py +133 -0
  257. chia/_tests/util/blockchain_mock.py +132 -0
  258. chia/_tests/util/build_network_protocol_files.py +302 -0
  259. chia/_tests/util/clvm_generator.bin +0 -0
  260. chia/_tests/util/config.py +3 -0
  261. chia/_tests/util/constants.py +20 -0
  262. chia/_tests/util/db_connection.py +36 -0
  263. chia/_tests/util/full_sync.py +245 -0
  264. chia/_tests/util/gen_ssl_certs.py +115 -0
  265. chia/_tests/util/generator_tools_testing.py +47 -0
  266. chia/_tests/util/key_tool.py +37 -0
  267. chia/_tests/util/misc.py +722 -0
  268. chia/_tests/util/network_protocol_data.py +1074 -0
  269. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  270. chia/_tests/util/protocol_messages_json.py +2700 -0
  271. chia/_tests/util/rpc.py +23 -0
  272. chia/_tests/util/run_block.py +163 -0
  273. chia/_tests/util/setup_nodes.py +479 -0
  274. chia/_tests/util/split_managers.py +99 -0
  275. chia/_tests/util/temp_file.py +14 -0
  276. chia/_tests/util/test_action_scope.py +143 -0
  277. chia/_tests/util/test_async_pool.py +366 -0
  278. chia/_tests/util/test_build_job_matrix.py +43 -0
  279. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  280. chia/_tests/util/test_chia_version.py +50 -0
  281. chia/_tests/util/test_collection.py +11 -0
  282. chia/_tests/util/test_condition_tools.py +231 -0
  283. chia/_tests/util/test_config.py +426 -0
  284. chia/_tests/util/test_dump_keyring.py +60 -0
  285. chia/_tests/util/test_errors.py +10 -0
  286. chia/_tests/util/test_full_block_utils.py +271 -0
  287. chia/_tests/util/test_installed.py +20 -0
  288. chia/_tests/util/test_limited_semaphore.py +52 -0
  289. chia/_tests/util/test_logging_filter.py +43 -0
  290. chia/_tests/util/test_misc.py +444 -0
  291. chia/_tests/util/test_network.py +74 -0
  292. chia/_tests/util/test_network_protocol_files.py +579 -0
  293. chia/_tests/util/test_network_protocol_json.py +266 -0
  294. chia/_tests/util/test_network_protocol_test.py +257 -0
  295. chia/_tests/util/test_paginator.py +72 -0
  296. chia/_tests/util/test_pprint.py +17 -0
  297. chia/_tests/util/test_priority_mutex.py +487 -0
  298. chia/_tests/util/test_recursive_replace.py +116 -0
  299. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  300. chia/_tests/util/test_service_groups.py +15 -0
  301. chia/_tests/util/test_ssl_check.py +31 -0
  302. chia/_tests/util/test_testnet_overrides.py +19 -0
  303. chia/_tests/util/test_tests_misc.py +38 -0
  304. chia/_tests/util/test_timing.py +37 -0
  305. chia/_tests/util/test_trusted_peer.py +51 -0
  306. chia/_tests/util/time_out_assert.py +154 -0
  307. chia/_tests/wallet/__init__.py +0 -0
  308. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  309. chia/_tests/wallet/cat_wallet/config.py +4 -0
  310. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  311. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  312. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1738 -0
  313. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  314. chia/_tests/wallet/cat_wallet/test_trades.py +2578 -0
  315. chia/_tests/wallet/clawback/__init__.py +0 -0
  316. chia/_tests/wallet/clawback/config.py +3 -0
  317. chia/_tests/wallet/clawback/test_clawback_decorator.py +80 -0
  318. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  319. chia/_tests/wallet/clawback/test_clawback_metadata.py +51 -0
  320. chia/_tests/wallet/config.py +4 -0
  321. chia/_tests/wallet/conftest.py +217 -0
  322. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  323. chia/_tests/wallet/dao_wallet/config.py +3 -0
  324. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1322 -0
  325. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  326. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  327. chia/_tests/wallet/db_wallet/config.py +3 -0
  328. chia/_tests/wallet/db_wallet/test_db_graftroot.py +143 -0
  329. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  330. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  331. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  332. chia/_tests/wallet/did_wallet/config.py +4 -0
  333. chia/_tests/wallet/did_wallet/test_did.py +1481 -0
  334. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  335. chia/_tests/wallet/nft_wallet/config.py +4 -0
  336. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1492 -0
  337. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1014 -0
  338. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +376 -0
  339. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  340. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  341. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2558 -0
  342. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  343. chia/_tests/wallet/rpc/__init__.py +0 -0
  344. chia/_tests/wallet/rpc/config.py +4 -0
  345. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +287 -0
  346. chia/_tests/wallet/rpc/test_wallet_rpc.py +3106 -0
  347. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  348. chia/_tests/wallet/simple_sync/config.py +3 -0
  349. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +719 -0
  350. chia/_tests/wallet/sync/__init__.py +0 -0
  351. chia/_tests/wallet/sync/config.py +4 -0
  352. chia/_tests/wallet/sync/test_wallet_sync.py +1529 -0
  353. chia/_tests/wallet/test_address_type.py +189 -0
  354. chia/_tests/wallet/test_bech32m.py +45 -0
  355. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  356. chia/_tests/wallet/test_coin_selection.py +589 -0
  357. chia/_tests/wallet/test_conditions.py +388 -0
  358. chia/_tests/wallet/test_debug_spend_bundle.py +76 -0
  359. chia/_tests/wallet/test_new_wallet_protocol.py +1176 -0
  360. chia/_tests/wallet/test_nft_store.py +193 -0
  361. chia/_tests/wallet/test_notifications.py +196 -0
  362. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  363. chia/_tests/wallet/test_puzzle_store.py +133 -0
  364. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  365. chia/_tests/wallet/test_signer_protocol.py +948 -0
  366. chia/_tests/wallet/test_singleton.py +122 -0
  367. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  368. chia/_tests/wallet/test_singleton_store.py +152 -0
  369. chia/_tests/wallet/test_taproot.py +19 -0
  370. chia/_tests/wallet/test_transaction_store.py +941 -0
  371. chia/_tests/wallet/test_util.py +181 -0
  372. chia/_tests/wallet/test_wallet.py +2139 -0
  373. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  374. chia/_tests/wallet/test_wallet_blockchain.py +113 -0
  375. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  376. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  377. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  378. chia/_tests/wallet/test_wallet_node.py +783 -0
  379. chia/_tests/wallet/test_wallet_retry.py +95 -0
  380. chia/_tests/wallet/test_wallet_state_manager.py +252 -0
  381. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  382. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  383. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  384. chia/_tests/wallet/test_wallet_utils.py +155 -0
  385. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  386. chia/_tests/wallet/vc_wallet/config.py +3 -0
  387. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  388. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  389. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +801 -0
  390. chia/_tests/wallet/wallet_block_tools.py +327 -0
  391. chia/_tests/weight_proof/__init__.py +0 -0
  392. chia/_tests/weight_proof/config.py +3 -0
  393. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  394. chia/clvm/__init__.py +0 -0
  395. chia/clvm/spend_sim.py +488 -0
  396. chia/cmds/__init__.py +0 -0
  397. chia/cmds/beta.py +183 -0
  398. chia/cmds/beta_funcs.py +133 -0
  399. chia/cmds/check_wallet_db.py +418 -0
  400. chia/cmds/chia.py +143 -0
  401. chia/cmds/cmd_classes.py +315 -0
  402. chia/cmds/cmds_util.py +498 -0
  403. chia/cmds/coin_funcs.py +260 -0
  404. chia/cmds/coins.py +220 -0
  405. chia/cmds/completion.py +49 -0
  406. chia/cmds/configure.py +331 -0
  407. chia/cmds/dao.py +1008 -0
  408. chia/cmds/dao_funcs.py +576 -0
  409. chia/cmds/data.py +707 -0
  410. chia/cmds/data_funcs.py +380 -0
  411. chia/cmds/db.py +86 -0
  412. chia/cmds/db_backup_func.py +77 -0
  413. chia/cmds/db_upgrade_func.py +452 -0
  414. chia/cmds/db_validate_func.py +184 -0
  415. chia/cmds/dev.py +16 -0
  416. chia/cmds/farm.py +87 -0
  417. chia/cmds/farm_funcs.py +207 -0
  418. chia/cmds/init.py +70 -0
  419. chia/cmds/init_funcs.py +367 -0
  420. chia/cmds/installers.py +129 -0
  421. chia/cmds/keys.py +510 -0
  422. chia/cmds/keys_funcs.py +864 -0
  423. chia/cmds/netspace.py +47 -0
  424. chia/cmds/netspace_funcs.py +53 -0
  425. chia/cmds/options.py +32 -0
  426. chia/cmds/param_types.py +228 -0
  427. chia/cmds/passphrase.py +130 -0
  428. chia/cmds/passphrase_funcs.py +346 -0
  429. chia/cmds/peer.py +50 -0
  430. chia/cmds/peer_funcs.py +129 -0
  431. chia/cmds/plotnft.py +206 -0
  432. chia/cmds/plotnft_funcs.py +374 -0
  433. chia/cmds/plots.py +222 -0
  434. chia/cmds/plotters.py +17 -0
  435. chia/cmds/rpc.py +188 -0
  436. chia/cmds/show.py +71 -0
  437. chia/cmds/show_funcs.py +214 -0
  438. chia/cmds/signer.py +304 -0
  439. chia/cmds/sim.py +217 -0
  440. chia/cmds/sim_funcs.py +509 -0
  441. chia/cmds/start.py +24 -0
  442. chia/cmds/start_funcs.py +112 -0
  443. chia/cmds/stop.py +61 -0
  444. chia/cmds/units.py +11 -0
  445. chia/cmds/wallet.py +1745 -0
  446. chia/cmds/wallet_funcs.py +1800 -0
  447. chia/consensus/__init__.py +0 -0
  448. chia/consensus/block_body_validation.py +515 -0
  449. chia/consensus/block_creation.py +525 -0
  450. chia/consensus/block_header_validation.py +1064 -0
  451. chia/consensus/block_record.py +32 -0
  452. chia/consensus/block_rewards.py +53 -0
  453. chia/consensus/block_root_validation.py +46 -0
  454. chia/consensus/blockchain.py +1100 -0
  455. chia/consensus/blockchain_interface.py +56 -0
  456. chia/consensus/coinbase.py +30 -0
  457. chia/consensus/condition_costs.py +9 -0
  458. chia/consensus/constants.py +49 -0
  459. chia/consensus/cost_calculator.py +15 -0
  460. chia/consensus/default_constants.py +90 -0
  461. chia/consensus/deficit.py +55 -0
  462. chia/consensus/difficulty_adjustment.py +412 -0
  463. chia/consensus/find_fork_point.py +111 -0
  464. chia/consensus/full_block_to_block_record.py +167 -0
  465. chia/consensus/get_block_challenge.py +106 -0
  466. chia/consensus/get_block_generator.py +26 -0
  467. chia/consensus/make_sub_epoch_summary.py +210 -0
  468. chia/consensus/multiprocess_validation.py +365 -0
  469. chia/consensus/pos_quality.py +19 -0
  470. chia/consensus/pot_iterations.py +67 -0
  471. chia/consensus/puzzles/__init__.py +0 -0
  472. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  473. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  474. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  475. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  476. chia/consensus/vdf_info_computation.py +156 -0
  477. chia/daemon/__init__.py +0 -0
  478. chia/daemon/client.py +233 -0
  479. chia/daemon/keychain_proxy.py +501 -0
  480. chia/daemon/keychain_server.py +365 -0
  481. chia/daemon/server.py +1616 -0
  482. chia/daemon/windows_signal.py +56 -0
  483. chia/data_layer/__init__.py +0 -0
  484. chia/data_layer/data_layer.py +1303 -0
  485. chia/data_layer/data_layer_api.py +25 -0
  486. chia/data_layer/data_layer_errors.py +50 -0
  487. chia/data_layer/data_layer_server.py +170 -0
  488. chia/data_layer/data_layer_util.py +985 -0
  489. chia/data_layer/data_layer_wallet.py +1315 -0
  490. chia/data_layer/data_store.py +2267 -0
  491. chia/data_layer/dl_wallet_store.py +407 -0
  492. chia/data_layer/download_data.py +389 -0
  493. chia/data_layer/puzzles/__init__.py +0 -0
  494. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  495. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  496. chia/data_layer/s3_plugin_config.yml +33 -0
  497. chia/data_layer/s3_plugin_service.py +468 -0
  498. chia/data_layer/util/__init__.py +0 -0
  499. chia/data_layer/util/benchmark.py +108 -0
  500. chia/data_layer/util/plugin.py +41 -0
  501. chia/farmer/__init__.py +0 -0
  502. chia/farmer/farmer.py +920 -0
  503. chia/farmer/farmer_api.py +814 -0
  504. chia/full_node/__init__.py +0 -0
  505. chia/full_node/bitcoin_fee_estimator.py +85 -0
  506. chia/full_node/block_height_map.py +271 -0
  507. chia/full_node/block_store.py +570 -0
  508. chia/full_node/bundle_tools.py +19 -0
  509. chia/full_node/coin_store.py +646 -0
  510. chia/full_node/fee_estimate.py +54 -0
  511. chia/full_node/fee_estimate_store.py +24 -0
  512. chia/full_node/fee_estimation.py +93 -0
  513. chia/full_node/fee_estimator.py +90 -0
  514. chia/full_node/fee_estimator_constants.py +38 -0
  515. chia/full_node/fee_estimator_interface.py +42 -0
  516. chia/full_node/fee_history.py +26 -0
  517. chia/full_node/fee_tracker.py +564 -0
  518. chia/full_node/full_node.py +3052 -0
  519. chia/full_node/full_node_api.py +1974 -0
  520. chia/full_node/full_node_store.py +1033 -0
  521. chia/full_node/hint_management.py +56 -0
  522. chia/full_node/hint_store.py +94 -0
  523. chia/full_node/mempool.py +583 -0
  524. chia/full_node/mempool_check_conditions.py +177 -0
  525. chia/full_node/mempool_manager.py +858 -0
  526. chia/full_node/pending_tx_cache.py +112 -0
  527. chia/full_node/puzzles/__init__.py +0 -0
  528. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  529. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  530. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  531. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  532. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  533. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  534. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  535. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  536. chia/full_node/signage_point.py +16 -0
  537. chia/full_node/subscriptions.py +248 -0
  538. chia/full_node/sync_store.py +145 -0
  539. chia/full_node/tx_processing_queue.py +78 -0
  540. chia/full_node/weight_proof.py +1719 -0
  541. chia/harvester/__init__.py +0 -0
  542. chia/harvester/harvester.py +271 -0
  543. chia/harvester/harvester_api.py +374 -0
  544. chia/introducer/__init__.py +0 -0
  545. chia/introducer/introducer.py +120 -0
  546. chia/introducer/introducer_api.py +64 -0
  547. chia/legacy/__init__.py +0 -0
  548. chia/legacy/keyring.py +154 -0
  549. chia/plot_sync/__init__.py +0 -0
  550. chia/plot_sync/delta.py +61 -0
  551. chia/plot_sync/exceptions.py +56 -0
  552. chia/plot_sync/receiver.py +385 -0
  553. chia/plot_sync/sender.py +337 -0
  554. chia/plot_sync/util.py +43 -0
  555. chia/plotters/__init__.py +0 -0
  556. chia/plotters/bladebit.py +388 -0
  557. chia/plotters/chiapos.py +63 -0
  558. chia/plotters/madmax.py +224 -0
  559. chia/plotters/plotters.py +577 -0
  560. chia/plotters/plotters_util.py +131 -0
  561. chia/plotting/__init__.py +0 -0
  562. chia/plotting/cache.py +212 -0
  563. chia/plotting/check_plots.py +283 -0
  564. chia/plotting/create_plots.py +278 -0
  565. chia/plotting/manager.py +436 -0
  566. chia/plotting/util.py +324 -0
  567. chia/pools/__init__.py +0 -0
  568. chia/pools/pool_config.py +110 -0
  569. chia/pools/pool_puzzles.py +459 -0
  570. chia/pools/pool_wallet.py +926 -0
  571. chia/pools/pool_wallet_info.py +118 -0
  572. chia/pools/puzzles/__init__.py +0 -0
  573. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  574. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  575. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  576. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  577. chia/protocols/__init__.py +0 -0
  578. chia/protocols/farmer_protocol.py +102 -0
  579. chia/protocols/full_node_protocol.py +219 -0
  580. chia/protocols/harvester_protocol.py +216 -0
  581. chia/protocols/introducer_protocol.py +26 -0
  582. chia/protocols/pool_protocol.py +177 -0
  583. chia/protocols/protocol_message_types.py +139 -0
  584. chia/protocols/protocol_state_machine.py +87 -0
  585. chia/protocols/protocol_timing.py +7 -0
  586. chia/protocols/shared_protocol.py +86 -0
  587. chia/protocols/timelord_protocol.py +93 -0
  588. chia/protocols/wallet_protocol.py +401 -0
  589. chia/py.typed +0 -0
  590. chia/rpc/__init__.py +0 -0
  591. chia/rpc/crawler_rpc_api.py +75 -0
  592. chia/rpc/data_layer_rpc_api.py +639 -0
  593. chia/rpc/data_layer_rpc_client.py +188 -0
  594. chia/rpc/data_layer_rpc_util.py +62 -0
  595. chia/rpc/farmer_rpc_api.py +360 -0
  596. chia/rpc/farmer_rpc_client.py +86 -0
  597. chia/rpc/full_node_rpc_api.py +954 -0
  598. chia/rpc/full_node_rpc_client.py +292 -0
  599. chia/rpc/harvester_rpc_api.py +136 -0
  600. chia/rpc/harvester_rpc_client.py +54 -0
  601. chia/rpc/rpc_client.py +144 -0
  602. chia/rpc/rpc_server.py +447 -0
  603. chia/rpc/timelord_rpc_api.py +27 -0
  604. chia/rpc/util.py +293 -0
  605. chia/rpc/wallet_request_types.py +688 -0
  606. chia/rpc/wallet_rpc_api.py +4779 -0
  607. chia/rpc/wallet_rpc_client.py +1844 -0
  608. chia/seeder/__init__.py +0 -0
  609. chia/seeder/crawl_store.py +427 -0
  610. chia/seeder/crawler.py +423 -0
  611. chia/seeder/crawler_api.py +129 -0
  612. chia/seeder/dns_server.py +544 -0
  613. chia/seeder/peer_record.py +146 -0
  614. chia/seeder/start_crawler.py +88 -0
  615. chia/server/__init__.py +0 -0
  616. chia/server/address_manager.py +658 -0
  617. chia/server/address_manager_store.py +237 -0
  618. chia/server/api_protocol.py +11 -0
  619. chia/server/capabilities.py +24 -0
  620. chia/server/chia_policy.py +345 -0
  621. chia/server/introducer_peers.py +76 -0
  622. chia/server/node_discovery.py +718 -0
  623. chia/server/outbound_message.py +33 -0
  624. chia/server/rate_limit_numbers.py +204 -0
  625. chia/server/rate_limits.py +113 -0
  626. chia/server/server.py +720 -0
  627. chia/server/signal_handlers.py +117 -0
  628. chia/server/ssl_context.py +32 -0
  629. chia/server/start_data_layer.py +137 -0
  630. chia/server/start_farmer.py +86 -0
  631. chia/server/start_full_node.py +106 -0
  632. chia/server/start_harvester.py +80 -0
  633. chia/server/start_introducer.py +69 -0
  634. chia/server/start_service.py +328 -0
  635. chia/server/start_timelord.py +82 -0
  636. chia/server/start_wallet.py +109 -0
  637. chia/server/upnp.py +117 -0
  638. chia/server/ws_connection.py +752 -0
  639. chia/simulator/__init__.py +0 -0
  640. chia/simulator/block_tools.py +2053 -0
  641. chia/simulator/full_node_simulator.py +802 -0
  642. chia/simulator/keyring.py +128 -0
  643. chia/simulator/setup_services.py +505 -0
  644. chia/simulator/simulator_constants.py +13 -0
  645. chia/simulator/simulator_full_node_rpc_api.py +101 -0
  646. chia/simulator/simulator_full_node_rpc_client.py +62 -0
  647. chia/simulator/simulator_protocol.py +29 -0
  648. chia/simulator/simulator_test_tools.py +163 -0
  649. chia/simulator/socket.py +27 -0
  650. chia/simulator/ssl_certs.py +114 -0
  651. chia/simulator/ssl_certs_1.py +699 -0
  652. chia/simulator/ssl_certs_10.py +699 -0
  653. chia/simulator/ssl_certs_2.py +699 -0
  654. chia/simulator/ssl_certs_3.py +699 -0
  655. chia/simulator/ssl_certs_4.py +699 -0
  656. chia/simulator/ssl_certs_5.py +699 -0
  657. chia/simulator/ssl_certs_6.py +699 -0
  658. chia/simulator/ssl_certs_7.py +699 -0
  659. chia/simulator/ssl_certs_8.py +699 -0
  660. chia/simulator/ssl_certs_9.py +699 -0
  661. chia/simulator/start_simulator.py +135 -0
  662. chia/simulator/wallet_tools.py +245 -0
  663. chia/ssl/__init__.py +0 -0
  664. chia/ssl/chia_ca.crt +19 -0
  665. chia/ssl/chia_ca.key +28 -0
  666. chia/ssl/create_ssl.py +249 -0
  667. chia/ssl/dst_root_ca.pem +20 -0
  668. chia/timelord/__init__.py +0 -0
  669. chia/timelord/iters_from_block.py +50 -0
  670. chia/timelord/timelord.py +1202 -0
  671. chia/timelord/timelord_api.py +132 -0
  672. chia/timelord/timelord_launcher.py +188 -0
  673. chia/timelord/timelord_state.py +244 -0
  674. chia/timelord/types.py +22 -0
  675. chia/types/__init__.py +0 -0
  676. chia/types/aliases.py +35 -0
  677. chia/types/block_protocol.py +20 -0
  678. chia/types/blockchain_format/__init__.py +0 -0
  679. chia/types/blockchain_format/classgroup.py +5 -0
  680. chia/types/blockchain_format/coin.py +28 -0
  681. chia/types/blockchain_format/foliage.py +8 -0
  682. chia/types/blockchain_format/pool_target.py +5 -0
  683. chia/types/blockchain_format/program.py +270 -0
  684. chia/types/blockchain_format/proof_of_space.py +135 -0
  685. chia/types/blockchain_format/reward_chain_block.py +6 -0
  686. chia/types/blockchain_format/serialized_program.py +5 -0
  687. chia/types/blockchain_format/sized_bytes.py +11 -0
  688. chia/types/blockchain_format/slots.py +9 -0
  689. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  690. chia/types/blockchain_format/tree_hash.py +72 -0
  691. chia/types/blockchain_format/vdf.py +86 -0
  692. chia/types/clvm_cost.py +13 -0
  693. chia/types/coin_record.py +43 -0
  694. chia/types/coin_spend.py +115 -0
  695. chia/types/condition_opcodes.py +73 -0
  696. chia/types/condition_with_args.py +17 -0
  697. chia/types/eligible_coin_spends.py +364 -0
  698. chia/types/end_of_slot_bundle.py +5 -0
  699. chia/types/fee_rate.py +38 -0
  700. chia/types/full_block.py +5 -0
  701. chia/types/generator_types.py +14 -0
  702. chia/types/header_block.py +5 -0
  703. chia/types/internal_mempool_item.py +19 -0
  704. chia/types/mempool_inclusion_status.py +9 -0
  705. chia/types/mempool_item.py +85 -0
  706. chia/types/mempool_submission_status.py +30 -0
  707. chia/types/mojos.py +7 -0
  708. chia/types/peer_info.py +64 -0
  709. chia/types/signing_mode.py +29 -0
  710. chia/types/spend_bundle.py +31 -0
  711. chia/types/spend_bundle_conditions.py +7 -0
  712. chia/types/transaction_queue_entry.py +55 -0
  713. chia/types/unfinished_block.py +5 -0
  714. chia/types/unfinished_header_block.py +37 -0
  715. chia/types/weight_proof.py +50 -0
  716. chia/util/__init__.py +0 -0
  717. chia/util/action_scope.py +168 -0
  718. chia/util/api_decorators.py +89 -0
  719. chia/util/async_pool.py +224 -0
  720. chia/util/augmented_chain.py +130 -0
  721. chia/util/batches.py +39 -0
  722. chia/util/bech32m.py +123 -0
  723. chia/util/beta_metrics.py +118 -0
  724. chia/util/block_cache.py +56 -0
  725. chia/util/byte_types.py +10 -0
  726. chia/util/check_fork_next_block.py +32 -0
  727. chia/util/chia_logging.py +124 -0
  728. chia/util/chia_version.py +33 -0
  729. chia/util/collection.py +17 -0
  730. chia/util/condition_tools.py +201 -0
  731. chia/util/config.py +366 -0
  732. chia/util/cpu.py +20 -0
  733. chia/util/db_synchronous.py +21 -0
  734. chia/util/db_version.py +30 -0
  735. chia/util/db_wrapper.py +427 -0
  736. chia/util/default_root.py +10 -0
  737. chia/util/dump_keyring.py +93 -0
  738. chia/util/english.txt +2048 -0
  739. chia/util/errors.py +351 -0
  740. chia/util/file_keyring.py +480 -0
  741. chia/util/files.py +95 -0
  742. chia/util/full_block_utils.py +321 -0
  743. chia/util/generator_tools.py +62 -0
  744. chia/util/hash.py +29 -0
  745. chia/util/initial-config.yaml +675 -0
  746. chia/util/inline_executor.py +24 -0
  747. chia/util/ints.py +19 -0
  748. chia/util/json_util.py +41 -0
  749. chia/util/keychain.py +673 -0
  750. chia/util/keyring_wrapper.py +266 -0
  751. chia/util/limited_semaphore.py +39 -0
  752. chia/util/lock.py +47 -0
  753. chia/util/log_exceptions.py +29 -0
  754. chia/util/logging.py +34 -0
  755. chia/util/lru_cache.py +29 -0
  756. chia/util/math.py +20 -0
  757. chia/util/network.py +240 -0
  758. chia/util/paginator.py +46 -0
  759. chia/util/path.py +29 -0
  760. chia/util/permissions.py +19 -0
  761. chia/util/pprint.py +40 -0
  762. chia/util/prev_transaction_block.py +23 -0
  763. chia/util/priority_mutex.py +92 -0
  764. chia/util/profiler.py +194 -0
  765. chia/util/recursive_replace.py +22 -0
  766. chia/util/safe_cancel_task.py +14 -0
  767. chia/util/service_groups.py +47 -0
  768. chia/util/setproctitle.py +20 -0
  769. chia/util/significant_bits.py +30 -0
  770. chia/util/ssl_check.py +213 -0
  771. chia/util/streamable.py +654 -0
  772. chia/util/task_timing.py +378 -0
  773. chia/util/timing.py +64 -0
  774. chia/util/vdf_prover.py +31 -0
  775. chia/util/ws_message.py +66 -0
  776. chia/wallet/__init__.py +0 -0
  777. chia/wallet/cat_wallet/__init__.py +0 -0
  778. chia/wallet/cat_wallet/cat_constants.py +75 -0
  779. chia/wallet/cat_wallet/cat_info.py +47 -0
  780. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  781. chia/wallet/cat_wallet/cat_utils.py +163 -0
  782. chia/wallet/cat_wallet/cat_wallet.py +869 -0
  783. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  784. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  785. chia/wallet/cat_wallet/lineage_store.py +74 -0
  786. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  787. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  788. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  789. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  790. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  791. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  792. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  793. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  794. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  795. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  796. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  797. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  798. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  799. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  800. chia/wallet/coin_selection.py +188 -0
  801. chia/wallet/conditions.py +1326 -0
  802. chia/wallet/dao_wallet/__init__.py +0 -0
  803. chia/wallet/dao_wallet/dao_info.py +61 -0
  804. chia/wallet/dao_wallet/dao_utils.py +810 -0
  805. chia/wallet/dao_wallet/dao_wallet.py +2121 -0
  806. chia/wallet/db_wallet/__init__.py +0 -0
  807. chia/wallet/db_wallet/db_wallet_puzzles.py +107 -0
  808. chia/wallet/derivation_record.py +30 -0
  809. chia/wallet/derive_keys.py +146 -0
  810. chia/wallet/did_wallet/__init__.py +0 -0
  811. chia/wallet/did_wallet/did_info.py +39 -0
  812. chia/wallet/did_wallet/did_wallet.py +1485 -0
  813. chia/wallet/did_wallet/did_wallet_puzzles.py +220 -0
  814. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  815. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  816. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  817. chia/wallet/driver_protocol.py +26 -0
  818. chia/wallet/key_val_store.py +55 -0
  819. chia/wallet/lineage_proof.py +58 -0
  820. chia/wallet/nft_wallet/__init__.py +0 -0
  821. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  822. chia/wallet/nft_wallet/nft_info.py +120 -0
  823. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  824. chia/wallet/nft_wallet/nft_wallet.py +1686 -0
  825. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  826. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  827. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  828. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  829. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  830. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  831. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  832. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  833. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  834. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  835. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  836. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  837. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  838. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  839. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  840. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  841. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  842. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  843. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  844. chia/wallet/notification_manager.py +117 -0
  845. chia/wallet/notification_store.py +178 -0
  846. chia/wallet/outer_puzzles.py +84 -0
  847. chia/wallet/payment.py +34 -0
  848. chia/wallet/puzzle_drivers.py +118 -0
  849. chia/wallet/puzzles/__init__.py +0 -0
  850. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  851. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  852. chia/wallet/puzzles/clawback/__init__.py +0 -0
  853. chia/wallet/puzzles/clawback/drivers.py +188 -0
  854. chia/wallet/puzzles/clawback/metadata.py +38 -0
  855. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  856. chia/wallet/puzzles/condition_codes.clib +77 -0
  857. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  858. chia/wallet/puzzles/curry.clib +135 -0
  859. chia/wallet/puzzles/curry_by_index.clib +16 -0
  860. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  861. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  862. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  863. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  864. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  865. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  866. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  867. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  868. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  869. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  870. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  871. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  872. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  873. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  874. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  876. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  877. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  878. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  879. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  880. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  881. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  882. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  883. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  884. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  885. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  886. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  887. chia/wallet/puzzles/json.clib +25 -0
  888. chia/wallet/puzzles/load_clvm.py +162 -0
  889. chia/wallet/puzzles/merkle_utils.clib +18 -0
  890. chia/wallet/puzzles/notification.clsp +7 -0
  891. chia/wallet/puzzles/notification.clsp.hex +1 -0
  892. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  893. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  894. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  895. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  896. chia/wallet/puzzles/p2_conditions.py +27 -0
  897. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  898. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  899. chia/wallet/puzzles/p2_delegated_conditions.py +22 -0
  900. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  901. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  902. chia/wallet/puzzles/p2_delegated_puzzle.py +35 -0
  903. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  904. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +161 -0
  906. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  907. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  908. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +22 -0
  909. chia/wallet/puzzles/p2_parent.clsp +19 -0
  910. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  911. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  912. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  913. chia/wallet/puzzles/p2_puzzle_hash.py +28 -0
  914. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  915. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  916. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  917. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  919. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  920. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  921. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  922. chia/wallet/puzzles/puzzle_utils.py +34 -0
  923. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  924. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  925. chia/wallet/puzzles/sha256tree.clib +11 -0
  926. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  927. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  928. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  929. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  930. chia/wallet/puzzles/singleton_top_layer.py +295 -0
  931. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  932. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  933. chia/wallet/puzzles/singleton_top_layer_v1_1.py +344 -0
  934. chia/wallet/puzzles/singleton_truths.clib +21 -0
  935. chia/wallet/puzzles/tails.py +344 -0
  936. chia/wallet/puzzles/utility_macros.clib +48 -0
  937. chia/wallet/signer_protocol.py +126 -0
  938. chia/wallet/singleton.py +106 -0
  939. chia/wallet/singleton_record.py +30 -0
  940. chia/wallet/trade_manager.py +1088 -0
  941. chia/wallet/trade_record.py +67 -0
  942. chia/wallet/trading/__init__.py +0 -0
  943. chia/wallet/trading/offer.py +703 -0
  944. chia/wallet/trading/trade_status.py +13 -0
  945. chia/wallet/trading/trade_store.py +526 -0
  946. chia/wallet/transaction_record.py +143 -0
  947. chia/wallet/transaction_sorting.py +14 -0
  948. chia/wallet/uncurried_puzzle.py +17 -0
  949. chia/wallet/util/__init__.py +0 -0
  950. chia/wallet/util/address_type.py +55 -0
  951. chia/wallet/util/blind_signer_tl.py +168 -0
  952. chia/wallet/util/clvm_streamable.py +203 -0
  953. chia/wallet/util/compute_hints.py +66 -0
  954. chia/wallet/util/compute_memos.py +45 -0
  955. chia/wallet/util/curry_and_treehash.py +90 -0
  956. chia/wallet/util/debug_spend_bundle.py +234 -0
  957. chia/wallet/util/merkle_tree.py +100 -0
  958. chia/wallet/util/merkle_utils.py +102 -0
  959. chia/wallet/util/new_peak_queue.py +82 -0
  960. chia/wallet/util/notifications.py +12 -0
  961. chia/wallet/util/peer_request_cache.py +174 -0
  962. chia/wallet/util/puzzle_compression.py +96 -0
  963. chia/wallet/util/puzzle_decorator.py +100 -0
  964. chia/wallet/util/puzzle_decorator_type.py +7 -0
  965. chia/wallet/util/query_filter.py +60 -0
  966. chia/wallet/util/transaction_type.py +23 -0
  967. chia/wallet/util/tx_config.py +158 -0
  968. chia/wallet/util/wallet_sync_utils.py +348 -0
  969. chia/wallet/util/wallet_types.py +65 -0
  970. chia/wallet/vc_wallet/__init__.py +0 -0
  971. chia/wallet/vc_wallet/cr_cat_drivers.py +663 -0
  972. chia/wallet/vc_wallet/cr_cat_wallet.py +875 -0
  973. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  974. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  975. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  976. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  977. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  978. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  979. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  980. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  981. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  982. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  983. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  984. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  985. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  986. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  987. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  988. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  989. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  990. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  992. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  994. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  996. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  997. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  998. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_store.py +263 -0
  1002. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1003. chia/wallet/wallet.py +698 -0
  1004. chia/wallet/wallet_action_scope.py +95 -0
  1005. chia/wallet/wallet_blockchain.py +244 -0
  1006. chia/wallet/wallet_coin_record.py +72 -0
  1007. chia/wallet/wallet_coin_store.py +351 -0
  1008. chia/wallet/wallet_info.py +36 -0
  1009. chia/wallet/wallet_interested_store.py +188 -0
  1010. chia/wallet/wallet_nft_store.py +279 -0
  1011. chia/wallet/wallet_node.py +1769 -0
  1012. chia/wallet/wallet_node_api.py +201 -0
  1013. chia/wallet/wallet_pool_store.py +120 -0
  1014. chia/wallet/wallet_protocol.py +90 -0
  1015. chia/wallet/wallet_puzzle_store.py +365 -0
  1016. chia/wallet/wallet_retry_store.py +70 -0
  1017. chia/wallet/wallet_singleton_store.py +258 -0
  1018. chia/wallet/wallet_spend_bundle.py +41 -0
  1019. chia/wallet/wallet_state_manager.py +2820 -0
  1020. chia/wallet/wallet_transaction_store.py +470 -0
  1021. chia/wallet/wallet_user_store.py +110 -0
  1022. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1023. chia_blockchain-2.4.4.dist-info/LICENSE +201 -0
  1024. chia_blockchain-2.4.4.dist-info/METADATA +161 -0
  1025. chia_blockchain-2.4.4.dist-info/RECORD +1028 -0
  1026. chia_blockchain-2.4.4.dist-info/WHEEL +4 -0
  1027. chia_blockchain-2.4.4.dist-info/entry_points.txt +17 -0
  1028. mozilla-ca/cacert.pem +3666 -0
@@ -0,0 +1,4100 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import random
5
+ import time
6
+ from contextlib import asynccontextmanager
7
+ from dataclasses import replace
8
+ from typing import AsyncIterator, Dict, List, Optional
9
+
10
+ import pytest
11
+ from chia_rs import AugSchemeMPL, G2Element, MerkleSet
12
+ from clvm.casts import int_to_bytes
13
+
14
+ from chia._tests.blockchain.blockchain_test_utils import (
15
+ _validate_and_add_block,
16
+ _validate_and_add_block_multi_error,
17
+ _validate_and_add_block_multi_result,
18
+ _validate_and_add_block_no_error,
19
+ check_block_store_invariant,
20
+ )
21
+ from chia._tests.conftest import ConsensusMode
22
+ from chia._tests.util.blockchain import create_blockchain
23
+ from chia.consensus.block_body_validation import ForkInfo
24
+ from chia.consensus.block_header_validation import validate_finished_header_block
25
+ from chia.consensus.block_record import BlockRecord
26
+ from chia.consensus.block_rewards import calculate_base_farmer_reward
27
+ from chia.consensus.blockchain import AddBlockResult, Blockchain
28
+ from chia.consensus.coinbase import create_farmer_coin
29
+ from chia.consensus.constants import ConsensusConstants
30
+ from chia.consensus.full_block_to_block_record import block_to_block_record
31
+ from chia.consensus.get_block_generator import get_block_generator
32
+ from chia.consensus.multiprocess_validation import PreValidationResult, pre_validate_blocks_multiprocessing
33
+ from chia.consensus.pot_iterations import is_overflow_block
34
+ from chia.full_node.mempool_check_conditions import get_name_puzzle_conditions
35
+ from chia.simulator.block_tools import BlockTools, create_block_tools_async
36
+ from chia.simulator.keyring import TempKeyring
37
+ from chia.simulator.wallet_tools import WalletTool
38
+ from chia.types.blockchain_format.classgroup import ClassgroupElement
39
+ from chia.types.blockchain_format.coin import Coin
40
+ from chia.types.blockchain_format.foliage import TransactionsInfo
41
+ from chia.types.blockchain_format.serialized_program import SerializedProgram
42
+ from chia.types.blockchain_format.sized_bytes import bytes32
43
+ from chia.types.blockchain_format.slots import InfusedChallengeChainSubSlot
44
+ from chia.types.blockchain_format.vdf import VDFInfo, VDFProof, validate_vdf
45
+ from chia.types.condition_opcodes import ConditionOpcode
46
+ from chia.types.condition_with_args import ConditionWithArgs
47
+ from chia.types.end_of_slot_bundle import EndOfSubSlotBundle
48
+ from chia.types.full_block import FullBlock
49
+ from chia.types.generator_types import BlockGenerator
50
+ from chia.types.spend_bundle import SpendBundle
51
+ from chia.types.unfinished_block import UnfinishedBlock
52
+ from chia.util.cpu import available_logical_cores
53
+ from chia.util.errors import Err
54
+ from chia.util.generator_tools import get_block_header
55
+ from chia.util.hash import std_hash
56
+ from chia.util.ints import uint8, uint32, uint64
57
+ from chia.util.keychain import Keychain
58
+ from chia.util.recursive_replace import recursive_replace
59
+ from chia.util.vdf_prover import get_vdf_info_and_proof
60
+ from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
61
+ DEFAULT_HIDDEN_PUZZLE_HASH,
62
+ calculate_synthetic_secret_key,
63
+ )
64
+
65
+ log = logging.getLogger(__name__)
66
+ bad_element = ClassgroupElement.create(b"\x00")
67
+
68
+
69
+ @asynccontextmanager
70
+ async def make_empty_blockchain(constants: ConsensusConstants) -> AsyncIterator[Blockchain]:
71
+ """
72
+ Provides a list of 10 valid blocks, as well as a blockchain with 9 blocks added to it.
73
+ """
74
+
75
+ async with create_blockchain(constants, 2) as (bc, db_wrapper):
76
+ yield bc
77
+
78
+
79
+ class TestGenesisBlock:
80
+ @pytest.mark.anyio
81
+ async def test_block_tools_proofs_400(
82
+ self, default_400_blocks: List[FullBlock], blockchain_constants: ConsensusConstants
83
+ ) -> None:
84
+ vdf, proof = get_vdf_info_and_proof(
85
+ blockchain_constants,
86
+ ClassgroupElement.get_default_element(),
87
+ blockchain_constants.GENESIS_CHALLENGE,
88
+ uint64(231),
89
+ )
90
+ if validate_vdf(proof, blockchain_constants, ClassgroupElement.get_default_element(), vdf) is False:
91
+ raise Exception("invalid proof")
92
+
93
+ @pytest.mark.anyio
94
+ async def test_block_tools_proofs_1000(
95
+ self, default_1000_blocks: List[FullBlock], blockchain_constants: ConsensusConstants
96
+ ) -> None:
97
+ vdf, proof = get_vdf_info_and_proof(
98
+ blockchain_constants,
99
+ ClassgroupElement.get_default_element(),
100
+ blockchain_constants.GENESIS_CHALLENGE,
101
+ uint64(231),
102
+ )
103
+ if validate_vdf(proof, blockchain_constants, ClassgroupElement.get_default_element(), vdf) is False:
104
+ raise Exception("invalid proof")
105
+
106
+ @pytest.mark.anyio
107
+ async def test_block_tools_proofs(self, blockchain_constants: ConsensusConstants) -> None:
108
+ vdf, proof = get_vdf_info_and_proof(
109
+ blockchain_constants,
110
+ ClassgroupElement.get_default_element(),
111
+ blockchain_constants.GENESIS_CHALLENGE,
112
+ uint64(231),
113
+ )
114
+ if validate_vdf(proof, blockchain_constants, ClassgroupElement.get_default_element(), vdf) is False:
115
+ raise Exception("invalid proof")
116
+
117
+ @pytest.mark.anyio
118
+ async def test_non_overflow_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
119
+ assert empty_blockchain.get_peak() is None
120
+ genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
121
+ await _validate_and_add_block(empty_blockchain, genesis)
122
+ peak = empty_blockchain.get_peak()
123
+ assert peak is not None
124
+ assert peak.height == 0
125
+
126
+ @pytest.mark.anyio
127
+ async def test_overflow_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
128
+ genesis = bt.get_consecutive_blocks(1, force_overflow=True)[0]
129
+ await _validate_and_add_block(empty_blockchain, genesis)
130
+
131
+ @pytest.mark.anyio
132
+ async def test_genesis_empty_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
133
+ genesis = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=30)[0]
134
+ await _validate_and_add_block(empty_blockchain, genesis)
135
+
136
+ @pytest.mark.anyio
137
+ async def test_overflow_genesis_empty_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
138
+ genesis = bt.get_consecutive_blocks(1, force_overflow=True, skip_slots=3)[0]
139
+ await _validate_and_add_block(empty_blockchain, genesis)
140
+
141
+ @pytest.mark.anyio
142
+ async def test_genesis_validate_1(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
143
+ genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
144
+ bad_prev = bytes([1] * 32)
145
+ genesis = recursive_replace(genesis, "foliage.prev_block_hash", bad_prev)
146
+ await _validate_and_add_block(empty_blockchain, genesis, expected_error=Err.INVALID_PREV_BLOCK_HASH)
147
+
148
+
149
+ class TestBlockHeaderValidation:
150
+ @pytest.mark.limit_consensus_modes(reason="save time")
151
+ @pytest.mark.anyio
152
+ async def test_long_chain(self, empty_blockchain: Blockchain, default_1000_blocks: List[FullBlock]) -> None:
153
+ blocks = default_1000_blocks
154
+ for block in blocks:
155
+ if (
156
+ len(block.finished_sub_slots) > 0
157
+ and block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is not None
158
+ ):
159
+ # Sub/Epoch. Try using a bad ssi and difficulty to test 2m and 2n
160
+ new_finished_ss = recursive_replace(
161
+ block.finished_sub_slots[0],
162
+ "challenge_chain.new_sub_slot_iters",
163
+ uint64(10_000_000),
164
+ )
165
+ block_bad = recursive_replace(
166
+ block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:]
167
+ )
168
+ header_block_bad = get_block_header(block_bad, [], [])
169
+ # TODO: Inspect these block values as they are currently None
170
+ expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
171
+ expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
172
+ _, error = validate_finished_header_block(
173
+ empty_blockchain.constants,
174
+ empty_blockchain,
175
+ header_block_bad,
176
+ False,
177
+ expected_difficulty,
178
+ expected_sub_slot_iters,
179
+ )
180
+ assert error is not None
181
+ assert error.code == Err.INVALID_NEW_SUB_SLOT_ITERS
182
+
183
+ # Also fails calling the outer methods, but potentially with a different error
184
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
185
+
186
+ new_finished_ss_2 = recursive_replace(
187
+ block.finished_sub_slots[0],
188
+ "challenge_chain.new_difficulty",
189
+ uint64(10_000_000),
190
+ )
191
+ block_bad_2 = recursive_replace(
192
+ block, "finished_sub_slots", [new_finished_ss_2] + block.finished_sub_slots[1:]
193
+ )
194
+
195
+ header_block_bad_2 = get_block_header(block_bad_2, [], [])
196
+ # TODO: Inspect these block values as they are currently None
197
+ expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
198
+ expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
199
+ _, error = validate_finished_header_block(
200
+ empty_blockchain.constants,
201
+ empty_blockchain,
202
+ header_block_bad_2,
203
+ False,
204
+ expected_difficulty,
205
+ expected_sub_slot_iters,
206
+ )
207
+ assert error is not None
208
+ assert error.code == Err.INVALID_NEW_DIFFICULTY
209
+
210
+ # Also fails calling the outer methods, but potentially with a different error
211
+ await _validate_and_add_block(
212
+ empty_blockchain, block_bad_2, expected_result=AddBlockResult.INVALID_BLOCK
213
+ )
214
+
215
+ # 3c
216
+ new_finished_ss_3: EndOfSubSlotBundle = recursive_replace(
217
+ block.finished_sub_slots[0],
218
+ "challenge_chain.subepoch_summary_hash",
219
+ bytes([0] * 32),
220
+ )
221
+ new_finished_ss_3 = recursive_replace(
222
+ new_finished_ss_3,
223
+ "reward_chain.challenge_chain_sub_slot_hash",
224
+ new_finished_ss_3.challenge_chain.get_hash(),
225
+ )
226
+ log.warning(f"Number of slots: {len(block.finished_sub_slots)}")
227
+ block_bad_3 = recursive_replace(block, "finished_sub_slots", [new_finished_ss_3])
228
+
229
+ header_block_bad_3 = get_block_header(block_bad_3, [], [])
230
+ # TODO: Inspect these block values as they are currently None
231
+ expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
232
+ expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
233
+ _, error = validate_finished_header_block(
234
+ empty_blockchain.constants,
235
+ empty_blockchain,
236
+ header_block_bad_3,
237
+ False,
238
+ expected_difficulty,
239
+ expected_sub_slot_iters,
240
+ )
241
+ assert error is not None
242
+ assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY
243
+
244
+ # Also fails calling the outer methods, but potentially with a different error
245
+ await _validate_and_add_block(
246
+ empty_blockchain, block_bad_3, expected_result=AddBlockResult.INVALID_BLOCK
247
+ )
248
+
249
+ # 3d
250
+ new_finished_ss_4 = recursive_replace(
251
+ block.finished_sub_slots[0],
252
+ "challenge_chain.subepoch_summary_hash",
253
+ std_hash(b"123"),
254
+ )
255
+ new_finished_ss_4 = recursive_replace(
256
+ new_finished_ss_4,
257
+ "reward_chain.challenge_chain_sub_slot_hash",
258
+ new_finished_ss_4.challenge_chain.get_hash(),
259
+ )
260
+ block_bad_4 = recursive_replace(block, "finished_sub_slots", [new_finished_ss_4])
261
+
262
+ header_block_bad_4 = get_block_header(block_bad_4, [], [])
263
+ # TODO: Inspect these block values as they are currently None
264
+ expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
265
+ expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
266
+ _, error = validate_finished_header_block(
267
+ empty_blockchain.constants,
268
+ empty_blockchain,
269
+ header_block_bad_4,
270
+ False,
271
+ expected_difficulty,
272
+ expected_sub_slot_iters,
273
+ )
274
+ assert error is not None
275
+ assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY
276
+
277
+ # Also fails calling the outer methods, but potentially with a different error
278
+ await _validate_and_add_block(
279
+ empty_blockchain, block_bad_4, expected_result=AddBlockResult.INVALID_BLOCK
280
+ )
281
+ await _validate_and_add_block(empty_blockchain, block)
282
+ log.info(
283
+ f"Added block {block.height} total iters {block.total_iters} "
284
+ f"new slot? {len(block.finished_sub_slots)}"
285
+ )
286
+ peak = empty_blockchain.get_peak()
287
+ assert peak is not None
288
+ assert peak.height == len(blocks) - 1
289
+
290
+ @pytest.mark.anyio
291
+ async def test_unfinished_blocks(
292
+ self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
293
+ ) -> None:
294
+ blockchain = empty_blockchain
295
+ blocks = bt.get_consecutive_blocks(3)
296
+ for block in blocks[:-1]:
297
+ await _validate_and_add_block(empty_blockchain, block)
298
+ block = blocks[-1]
299
+ unf = UnfinishedBlock(
300
+ block.finished_sub_slots,
301
+ block.reward_chain_block.get_unfinished(),
302
+ block.challenge_chain_sp_proof,
303
+ block.reward_chain_sp_proof,
304
+ block.foliage,
305
+ block.foliage_transaction_block,
306
+ block.transactions_info,
307
+ block.transactions_generator,
308
+ [],
309
+ )
310
+ npc_result = None
311
+ # if this assert fires, remove it along with the pragma for the block
312
+ # below
313
+ assert unf.transactions_generator is None
314
+ if unf.transactions_generator is not None: # pragma: no cover
315
+ block_generator = await get_block_generator(blockchain.lookup_block_generators, unf)
316
+ assert block_generator is not None
317
+ block_bytes = bytes(unf)
318
+ npc_result = await blockchain.run_generator(block_bytes, block_generator, height=softfork_height)
319
+
320
+ validate_res = await blockchain.validate_unfinished_block(unf, npc_result, False)
321
+ err = validate_res.error
322
+ assert err is None
323
+
324
+ await _validate_and_add_block(empty_blockchain, block)
325
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
326
+ block = blocks[-1]
327
+ unf = UnfinishedBlock(
328
+ block.finished_sub_slots,
329
+ block.reward_chain_block.get_unfinished(),
330
+ block.challenge_chain_sp_proof,
331
+ block.reward_chain_sp_proof,
332
+ block.foliage,
333
+ block.foliage_transaction_block,
334
+ block.transactions_info,
335
+ block.transactions_generator,
336
+ [],
337
+ )
338
+ npc_result = None
339
+ # if this assert fires, remove it along with the pragma for the block
340
+ # below
341
+ assert unf.transactions_generator is None
342
+ if unf.transactions_generator is not None: # pragma: no cover
343
+ block_generator = await get_block_generator(blockchain.lookup_block_generators, unf)
344
+ assert block_generator is not None
345
+ block_bytes = bytes(unf)
346
+ npc_result = await blockchain.run_generator(block_bytes, block_generator, height=softfork_height)
347
+ validate_res = await blockchain.validate_unfinished_block(unf, npc_result, False)
348
+ assert validate_res.error is None
349
+
350
+ @pytest.mark.anyio
351
+ async def test_empty_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
352
+ for block in bt.get_consecutive_blocks(2, skip_slots=3):
353
+ await _validate_and_add_block(empty_blockchain, block)
354
+
355
+ @pytest.mark.anyio
356
+ async def test_empty_slots_non_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
357
+ blockchain = empty_blockchain
358
+ blocks = bt.get_consecutive_blocks(10)
359
+ for block in blocks:
360
+ await _validate_and_add_block(empty_blockchain, block)
361
+
362
+ blocks = bt.get_consecutive_blocks(10, skip_slots=2, block_list_input=blocks)
363
+ for block in blocks[10:]:
364
+ await _validate_and_add_block(empty_blockchain, block)
365
+ peak = blockchain.get_peak()
366
+ assert peak is not None
367
+ assert peak.height == 19
368
+
369
+ @pytest.mark.anyio
370
+ async def test_one_sb_per_slot(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
371
+ blockchain = empty_blockchain
372
+ num_blocks = 20
373
+ blocks: List[FullBlock] = []
374
+ for _ in range(num_blocks):
375
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
376
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
377
+ peak = blockchain.get_peak()
378
+ assert peak is not None
379
+ assert peak.height == num_blocks - 1
380
+
381
+ @pytest.mark.anyio
382
+ async def test_all_overflow(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
383
+ blockchain = empty_blockchain
384
+ num_rounds = 5
385
+ blocks: List[FullBlock] = []
386
+ num_blocks = 0
387
+ for i in range(1, num_rounds):
388
+ num_blocks += i
389
+ blocks = bt.get_consecutive_blocks(i, block_list_input=blocks, skip_slots=1, force_overflow=True)
390
+ for block in blocks[-i:]:
391
+ await _validate_and_add_block(empty_blockchain, block)
392
+ peak = blockchain.get_peak()
393
+ assert peak is not None
394
+ assert peak.height == num_blocks - 1
395
+
396
+ @pytest.mark.anyio
397
+ async def test_unf_block_overflow(
398
+ self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
399
+ ) -> None:
400
+ blockchain = empty_blockchain
401
+
402
+ blocks: List[FullBlock] = []
403
+ while True:
404
+ # This creates an overflow block, then a normal block, and then an overflow in the next sub-slot
405
+ # blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
406
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
407
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
408
+
409
+ await _validate_and_add_block(blockchain, blocks[-2])
410
+
411
+ sb_1 = blockchain.block_record(blocks[-2].header_hash)
412
+
413
+ sb_2_next_ss = blocks[-1].total_iters - blocks[-2].total_iters < sb_1.sub_slot_iters
414
+ # We might not get a normal block for sb_2, and we might not get them in the right slots
415
+ # So this while loop keeps trying
416
+ if sb_1.overflow and sb_2_next_ss:
417
+ block = blocks[-1]
418
+ unf = UnfinishedBlock(
419
+ [],
420
+ block.reward_chain_block.get_unfinished(),
421
+ block.challenge_chain_sp_proof,
422
+ block.reward_chain_sp_proof,
423
+ block.foliage,
424
+ block.foliage_transaction_block,
425
+ block.transactions_info,
426
+ block.transactions_generator,
427
+ [],
428
+ )
429
+ npc_result = None
430
+ # if this assert fires, remove it along with the pragma for the block
431
+ # below
432
+ assert block.transactions_generator is None
433
+ if block.transactions_generator is not None: # pragma: no cover
434
+ block_generator = await get_block_generator(blockchain.lookup_block_generators, unf)
435
+ assert block_generator is not None
436
+ block_bytes = bytes(unf)
437
+ npc_result = await blockchain.run_generator(block_bytes, block_generator, height=softfork_height)
438
+ validate_res = await blockchain.validate_unfinished_block(
439
+ unf, npc_result, skip_overflow_ss_validation=True
440
+ )
441
+ assert validate_res.error is None
442
+ return None
443
+
444
+ await _validate_and_add_block(blockchain, blocks[-1])
445
+
446
+ @pytest.mark.anyio
447
+ async def test_one_sb_per_two_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
448
+ blockchain = empty_blockchain
449
+ num_blocks = 20
450
+ blocks: List[FullBlock] = []
451
+ for _ in range(num_blocks): # Same thing, but 2 sub-slots per block
452
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2)
453
+ await _validate_and_add_block(blockchain, blocks[-1])
454
+ peak = blockchain.get_peak()
455
+ assert peak is not None
456
+ assert peak.height == num_blocks - 1
457
+
458
+ @pytest.mark.anyio
459
+ async def test_one_sb_per_five_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
460
+ blockchain = empty_blockchain
461
+ num_blocks = 10
462
+ blocks: List[FullBlock] = []
463
+ for _ in range(num_blocks): # Same thing, but 5 sub-slots per block
464
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=5)
465
+ await _validate_and_add_block(blockchain, blocks[-1])
466
+ peak = blockchain.get_peak()
467
+ assert peak is not None
468
+ assert peak.height == num_blocks - 1
469
+
470
+ @pytest.mark.anyio
471
+ async def test_basic_chain_overflow(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
472
+ blocks = bt.get_consecutive_blocks(5, force_overflow=True)
473
+ for block in blocks:
474
+ await _validate_and_add_block(empty_blockchain, block)
475
+ peak = empty_blockchain.get_peak()
476
+ assert peak is not None
477
+ assert peak.height == len(blocks) - 1
478
+
479
+ @pytest.mark.anyio
480
+ async def test_one_sb_per_two_slots_force_overflow(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
481
+ blockchain = empty_blockchain
482
+ num_blocks = 10
483
+ blocks: List[FullBlock] = []
484
+ for _ in range(num_blocks):
485
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2, force_overflow=True)
486
+ await _validate_and_add_block(blockchain, blocks[-1])
487
+ peak = blockchain.get_peak()
488
+ assert peak is not None
489
+ assert peak.height == num_blocks - 1
490
+
491
+ @pytest.mark.anyio
492
+ async def test_invalid_prev(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
493
+ # 1
494
+ blocks = bt.get_consecutive_blocks(2, force_overflow=False)
495
+ await _validate_and_add_block(empty_blockchain, blocks[0])
496
+ block_1_bad = recursive_replace(blocks[-1], "foliage.prev_block_hash", bytes([0] * 32))
497
+
498
+ await _validate_and_add_block(empty_blockchain, block_1_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
499
+
500
+ @pytest.mark.anyio
501
+ async def test_invalid_pospace(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
502
+ # 2
503
+ blocks = bt.get_consecutive_blocks(2, force_overflow=False)
504
+ await _validate_and_add_block(empty_blockchain, blocks[0])
505
+ block_1_bad = recursive_replace(blocks[-1], "reward_chain_block.proof_of_space.proof", bytes([0] * 32))
506
+
507
+ await _validate_and_add_block(empty_blockchain, block_1_bad, expected_error=Err.INVALID_POSPACE)
508
+
509
+ @pytest.mark.anyio
510
+ async def test_invalid_sub_slot_challenge_hash_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
511
+ # 2a
512
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
513
+ new_finished_ss = recursive_replace(
514
+ blocks[0].finished_sub_slots[0],
515
+ "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
516
+ bytes([2] * 32),
517
+ )
518
+ block_0_bad = recursive_replace(
519
+ blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
520
+ )
521
+
522
+ header_block_bad = get_block_header(block_0_bad, [], [])
523
+ _, error = validate_finished_header_block(
524
+ empty_blockchain.constants,
525
+ empty_blockchain,
526
+ header_block_bad,
527
+ False,
528
+ empty_blockchain.constants.DIFFICULTY_STARTING,
529
+ empty_blockchain.constants.SUB_SLOT_ITERS_STARTING,
530
+ )
531
+
532
+ assert error is not None
533
+ assert error.code == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
534
+ await _validate_and_add_block(empty_blockchain, block_0_bad, expected_result=AddBlockResult.INVALID_BLOCK)
535
+
536
+ @pytest.mark.anyio
537
+ async def test_invalid_sub_slot_challenge_hash_non_genesis(
538
+ self, empty_blockchain: Blockchain, bt: BlockTools
539
+ ) -> None:
540
+ # 2b
541
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
542
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1, block_list_input=blocks)
543
+ new_finished_ss = recursive_replace(
544
+ blocks[1].finished_sub_slots[0],
545
+ "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
546
+ bytes([2] * 32),
547
+ )
548
+ block_1_bad = recursive_replace(
549
+ blocks[1], "finished_sub_slots", [new_finished_ss] + blocks[1].finished_sub_slots[1:]
550
+ )
551
+
552
+ await _validate_and_add_block(empty_blockchain, blocks[0])
553
+ header_block_bad = get_block_header(block_1_bad, [], [])
554
+ # TODO: Inspect these block values as they are currently None
555
+ expected_difficulty = blocks[1].finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
556
+ expected_sub_slot_iters = blocks[1].finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
557
+ _, error = validate_finished_header_block(
558
+ empty_blockchain.constants,
559
+ empty_blockchain,
560
+ header_block_bad,
561
+ False,
562
+ expected_difficulty,
563
+ expected_sub_slot_iters,
564
+ )
565
+ assert error is not None
566
+ assert error.code == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
567
+ await _validate_and_add_block(empty_blockchain, block_1_bad, expected_result=AddBlockResult.INVALID_BLOCK)
568
+
569
+ @pytest.mark.anyio
570
+ async def test_invalid_sub_slot_challenge_hash_empty_ss(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
571
+ # 2c
572
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
573
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=2, block_list_input=blocks)
574
+ new_finished_ss = recursive_replace(
575
+ blocks[1].finished_sub_slots[-1],
576
+ "challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
577
+ bytes([2] * 32),
578
+ )
579
+ block_1_bad = recursive_replace(
580
+ blocks[1], "finished_sub_slots", blocks[1].finished_sub_slots[:-1] + [new_finished_ss]
581
+ )
582
+ await _validate_and_add_block(empty_blockchain, blocks[0])
583
+
584
+ header_block_bad = get_block_header(block_1_bad, [], [])
585
+ # TODO: Inspect these block values as they are currently None
586
+ expected_difficulty = blocks[1].finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
587
+ expected_sub_slot_iters = blocks[1].finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
588
+ _, error = validate_finished_header_block(
589
+ empty_blockchain.constants,
590
+ empty_blockchain,
591
+ header_block_bad,
592
+ False,
593
+ expected_difficulty,
594
+ expected_sub_slot_iters,
595
+ )
596
+ assert error is not None
597
+ assert error.code == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
598
+ await _validate_and_add_block(empty_blockchain, block_1_bad, expected_result=AddBlockResult.INVALID_BLOCK)
599
+
600
+ @pytest.mark.anyio
601
+ async def test_genesis_no_icc(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
602
+ # 2d
603
+ blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
604
+ new_finished_ss = recursive_replace(
605
+ blocks[0].finished_sub_slots[0],
606
+ "infused_challenge_chain",
607
+ InfusedChallengeChainSubSlot(
608
+ VDFInfo(
609
+ bytes32([0] * 32),
610
+ uint64(1200),
611
+ ClassgroupElement.get_default_element(),
612
+ )
613
+ ),
614
+ )
615
+ block_0_bad = recursive_replace(
616
+ blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
617
+ )
618
+ await _validate_and_add_block(empty_blockchain, block_0_bad, expected_error=Err.SHOULD_NOT_HAVE_ICC)
619
+
620
+ async def do_test_invalid_icc_sub_slot_vdf(
621
+ self, keychain: Keychain, db_version: int, constants: ConsensusConstants
622
+ ) -> None:
623
+ bt_high_iters = await create_block_tools_async(
624
+ constants=constants.replace(
625
+ SUB_SLOT_ITERS_STARTING=uint64(2**12),
626
+ DIFFICULTY_STARTING=uint64(2**14),
627
+ ),
628
+ keychain=keychain,
629
+ )
630
+ async with create_blockchain(bt_high_iters.constants, db_version) as (bc1, db_wrapper):
631
+ blocks = bt_high_iters.get_consecutive_blocks(10)
632
+ for block in blocks:
633
+ if (
634
+ len(block.finished_sub_slots) > 0
635
+ and block.finished_sub_slots[-1].infused_challenge_chain is not None
636
+ ):
637
+ # Bad iters
638
+ new_finished_ss = recursive_replace(
639
+ block.finished_sub_slots[-1],
640
+ "infused_challenge_chain",
641
+ InfusedChallengeChainSubSlot(
642
+ block.finished_sub_slots[
643
+ -1
644
+ ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.replace(
645
+ number_of_iterations=uint64(10000000),
646
+ )
647
+ ),
648
+ )
649
+ block_bad = recursive_replace(
650
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
651
+ )
652
+ await _validate_and_add_block(bc1, block_bad, expected_error=Err.INVALID_ICC_EOS_VDF)
653
+
654
+ # Bad output
655
+ new_finished_ss_2 = recursive_replace(
656
+ block.finished_sub_slots[-1],
657
+ "infused_challenge_chain",
658
+ InfusedChallengeChainSubSlot(
659
+ block.finished_sub_slots[
660
+ -1
661
+ ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.replace(
662
+ output=ClassgroupElement.get_default_element(),
663
+ )
664
+ ),
665
+ )
666
+ log.warning(f"Proof: {block.finished_sub_slots[-1].proofs}")
667
+ block_bad_2 = recursive_replace(
668
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
669
+ )
670
+ await _validate_and_add_block(bc1, block_bad_2, expected_error=Err.INVALID_ICC_EOS_VDF)
671
+
672
+ # Bad challenge hash
673
+ new_finished_ss_3 = recursive_replace(
674
+ block.finished_sub_slots[-1],
675
+ "infused_challenge_chain",
676
+ InfusedChallengeChainSubSlot(
677
+ block.finished_sub_slots[
678
+ -1
679
+ ].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.replace(
680
+ challenge=bytes32([0] * 32)
681
+ )
682
+ ),
683
+ )
684
+ block_bad_3 = recursive_replace(
685
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
686
+ )
687
+ await _validate_and_add_block(bc1, block_bad_3, expected_error=Err.INVALID_ICC_EOS_VDF)
688
+
689
+ # Bad proof
690
+ new_finished_ss_5 = recursive_replace(
691
+ block.finished_sub_slots[-1],
692
+ "proofs.infused_challenge_chain_slot_proof",
693
+ VDFProof(uint8(0), b"1239819023890", False),
694
+ )
695
+ block_bad_5 = recursive_replace(
696
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
697
+ )
698
+ await _validate_and_add_block(bc1, block_bad_5, expected_error=Err.INVALID_ICC_EOS_VDF)
699
+
700
+ await _validate_and_add_block(bc1, block)
701
+
702
+ @pytest.mark.anyio
703
+ async def test_invalid_icc_sub_slot_vdf(self, db_version: int, blockchain_constants: ConsensusConstants) -> None:
704
+ with TempKeyring() as keychain:
705
+ await self.do_test_invalid_icc_sub_slot_vdf(keychain, db_version, blockchain_constants)
706
+
707
+ @pytest.mark.anyio
708
+ async def test_invalid_icc_into_cc(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
709
+ blockchain = empty_blockchain
710
+ blocks = bt.get_consecutive_blocks(1)
711
+ await _validate_and_add_block(blockchain, blocks[0])
712
+ case_1, case_2 = False, False
713
+ while not case_1 or not case_2:
714
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
715
+ block = blocks[-1]
716
+ if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
717
+ if block.finished_sub_slots[-1].reward_chain.deficit == bt.constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK:
718
+ # 2g
719
+ case_1 = True
720
+ new_finished_ss = recursive_replace(
721
+ block.finished_sub_slots[-1],
722
+ "challenge_chain",
723
+ block.finished_sub_slots[-1].challenge_chain.replace(
724
+ infused_challenge_chain_sub_slot_hash=bytes32([1] * 32)
725
+ ),
726
+ )
727
+ else:
728
+ # 2h
729
+ case_2 = True
730
+ new_finished_ss = recursive_replace(
731
+ block.finished_sub_slots[-1],
732
+ "challenge_chain",
733
+ block.finished_sub_slots[-1].challenge_chain.replace(
734
+ infused_challenge_chain_sub_slot_hash=block.finished_sub_slots[
735
+ -1
736
+ ].infused_challenge_chain.get_hash(),
737
+ ),
738
+ )
739
+ block_bad = recursive_replace(
740
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
741
+ )
742
+
743
+ header_block_bad = get_block_header(block_bad, [], [])
744
+ # TODO: Inspect these block values as they are currently None
745
+ expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
746
+ expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
747
+ _, error = validate_finished_header_block(
748
+ empty_blockchain.constants,
749
+ empty_blockchain,
750
+ header_block_bad,
751
+ False,
752
+ expected_difficulty,
753
+ expected_sub_slot_iters,
754
+ )
755
+ assert error is not None
756
+ assert error.code == Err.INVALID_ICC_HASH_CC
757
+ await _validate_and_add_block(blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
758
+
759
+ # 2i
760
+ new_finished_ss_bad_rc = recursive_replace(
761
+ block.finished_sub_slots[-1],
762
+ "reward_chain",
763
+ block.finished_sub_slots[-1].reward_chain.replace(infused_challenge_chain_sub_slot_hash=None),
764
+ )
765
+ block_bad = recursive_replace(
766
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
767
+ )
768
+ await _validate_and_add_block(blockchain, block_bad, expected_error=Err.INVALID_ICC_HASH_RC)
769
+ elif len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is None:
770
+ # 2j
771
+ # TODO: This code path is currently not exercised
772
+ new_finished_ss_bad_cc = recursive_replace(
773
+ block.finished_sub_slots[-1],
774
+ "challenge_chain",
775
+ block.finished_sub_slots[-1].challenge_chain.replace(
776
+ infused_challenge_chain_sub_slot_hash=bytes32([1] * 32)
777
+ ),
778
+ )
779
+ block_bad = recursive_replace(
780
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_cc]
781
+ )
782
+ await _validate_and_add_block(blockchain, block_bad, expected_error=Err.INVALID_ICC_HASH_CC)
783
+
784
+ # 2k
785
+ # TODO: This code path is currently not exercised
786
+ new_finished_ss_bad_rc = recursive_replace(
787
+ block.finished_sub_slots[-1],
788
+ "reward_chain",
789
+ block.finished_sub_slots[-1].reward_chain.replace(
790
+ infused_challenge_chain_sub_slot_hash=bytes32([1] * 32)
791
+ ),
792
+ )
793
+ block_bad = recursive_replace(
794
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
795
+ )
796
+ await _validate_and_add_block(blockchain, block_bad, expected_error=Err.INVALID_ICC_HASH_RC)
797
+
798
+ # Finally, add the block properly
799
+ await _validate_and_add_block(blockchain, block)
800
+
801
+ @pytest.mark.anyio
802
+ async def test_empty_slot_no_ses(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
803
+ # 2l
804
+ blockchain = empty_blockchain
805
+ blocks = bt.get_consecutive_blocks(1)
806
+ await _validate_and_add_block(blockchain, blocks[0])
807
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=4)
808
+
809
+ new_finished_ss = recursive_replace(
810
+ blocks[-1].finished_sub_slots[-1],
811
+ "challenge_chain",
812
+ blocks[-1].finished_sub_slots[-1].challenge_chain.replace(subepoch_summary_hash=std_hash(b"0")),
813
+ )
814
+ block_bad = recursive_replace(
815
+ blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
816
+ )
817
+
818
+ header_block_bad = get_block_header(block_bad, [], [])
819
+ _, error = validate_finished_header_block(
820
+ empty_blockchain.constants,
821
+ empty_blockchain,
822
+ header_block_bad,
823
+ False,
824
+ empty_blockchain.constants.DIFFICULTY_STARTING,
825
+ empty_blockchain.constants.SUB_SLOT_ITERS_STARTING,
826
+ )
827
+ assert error is not None
828
+ assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
829
+ await _validate_and_add_block(blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
830
+
831
+ @pytest.mark.anyio
832
+ async def test_empty_sub_slots_epoch(
833
+ self, empty_blockchain: Blockchain, default_400_blocks: List[FullBlock], bt: BlockTools
834
+ ) -> None:
835
+ # 2m
836
+ # Tests adding an empty sub slot after the sub-epoch / epoch.
837
+ # Also tests overflow block in epoch
838
+ blocks_base = default_400_blocks[: bt.constants.EPOCH_BLOCKS]
839
+ assert len(blocks_base) == bt.constants.EPOCH_BLOCKS
840
+ blocks_1 = bt.get_consecutive_blocks(1, block_list_input=blocks_base, force_overflow=True)
841
+ blocks_2 = bt.get_consecutive_blocks(1, skip_slots=5, block_list_input=blocks_base, force_overflow=True)
842
+ for block in blocks_base:
843
+ await _validate_and_add_block(empty_blockchain, block, skip_prevalidation=True)
844
+ await _validate_and_add_block(
845
+ empty_blockchain, blocks_1[-1], expected_result=AddBlockResult.NEW_PEAK, skip_prevalidation=True
846
+ )
847
+ assert blocks_1[-1].header_hash != blocks_2[-1].header_hash
848
+ await _validate_and_add_block(
849
+ empty_blockchain, blocks_2[-1], expected_result=AddBlockResult.ADDED_AS_ORPHAN, skip_prevalidation=True
850
+ )
851
+
852
+ @pytest.mark.anyio
853
+ async def test_wrong_cc_hash_rc(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
854
+ # 2o
855
+ blockchain = empty_blockchain
856
+ blocks = bt.get_consecutive_blocks(1, skip_slots=1)
857
+ blocks = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks)
858
+ await _validate_and_add_block(empty_blockchain, blocks[0])
859
+
860
+ new_finished_ss = recursive_replace(
861
+ blocks[-1].finished_sub_slots[-1],
862
+ "reward_chain",
863
+ blocks[-1].finished_sub_slots[-1].reward_chain.replace(challenge_chain_sub_slot_hash=bytes32([3] * 32)),
864
+ )
865
+ block_1_bad = recursive_replace(
866
+ blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
867
+ )
868
+
869
+ await _validate_and_add_block(blockchain, block_1_bad, expected_error=Err.INVALID_CHALLENGE_SLOT_HASH_RC)
870
+
871
+ @pytest.mark.anyio
872
+ async def test_invalid_cc_sub_slot_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
873
+ # 2q
874
+ blocks: List[FullBlock] = []
875
+ found_overflow_slot: bool = False
876
+
877
+ while not found_overflow_slot:
878
+ blocks = bt.get_consecutive_blocks(1, blocks)
879
+ block = blocks[-1]
880
+ if (
881
+ len(block.finished_sub_slots)
882
+ and is_overflow_block(bt.constants, block.reward_chain_block.signage_point_index)
883
+ and block.finished_sub_slots[-1].challenge_chain.challenge_chain_end_of_slot_vdf.output
884
+ != ClassgroupElement.get_default_element()
885
+ ):
886
+ found_overflow_slot = True
887
+ # Bad iters
888
+ new_finished_ss = recursive_replace(
889
+ block.finished_sub_slots[-1],
890
+ "challenge_chain",
891
+ recursive_replace(
892
+ block.finished_sub_slots[-1].challenge_chain,
893
+ "challenge_chain_end_of_slot_vdf.number_of_iterations",
894
+ uint64(10000000),
895
+ ),
896
+ )
897
+ new_finished_ss = recursive_replace(
898
+ new_finished_ss,
899
+ "reward_chain.challenge_chain_sub_slot_hash",
900
+ new_finished_ss.challenge_chain.get_hash(),
901
+ )
902
+ log.warning(f"Num slots: {len(block.finished_sub_slots)}")
903
+ block_bad = recursive_replace(
904
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
905
+ )
906
+ log.warning(f"Signage point index: {block_bad.reward_chain_block.signage_point_index}")
907
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_EOS_VDF)
908
+
909
+ # Bad output
910
+ new_finished_ss_2 = recursive_replace(
911
+ block.finished_sub_slots[-1],
912
+ "challenge_chain",
913
+ recursive_replace(
914
+ block.finished_sub_slots[-1].challenge_chain,
915
+ "challenge_chain_end_of_slot_vdf.output",
916
+ ClassgroupElement.get_default_element(),
917
+ ),
918
+ )
919
+
920
+ new_finished_ss_2 = recursive_replace(
921
+ new_finished_ss_2,
922
+ "reward_chain.challenge_chain_sub_slot_hash",
923
+ new_finished_ss_2.challenge_chain.get_hash(),
924
+ )
925
+ block_bad_2 = recursive_replace(
926
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
927
+ )
928
+ await _validate_and_add_block(empty_blockchain, block_bad_2, expected_error=Err.INVALID_CC_EOS_VDF)
929
+
930
+ # Bad challenge hash
931
+ new_finished_ss_3 = recursive_replace(
932
+ block.finished_sub_slots[-1],
933
+ "challenge_chain",
934
+ recursive_replace(
935
+ block.finished_sub_slots[-1].challenge_chain,
936
+ "challenge_chain_end_of_slot_vdf.challenge",
937
+ bytes([1] * 32),
938
+ ),
939
+ )
940
+
941
+ new_finished_ss_3 = recursive_replace(
942
+ new_finished_ss_3,
943
+ "reward_chain.challenge_chain_sub_slot_hash",
944
+ new_finished_ss_3.challenge_chain.get_hash(),
945
+ )
946
+ block_bad_3 = recursive_replace(
947
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
948
+ )
949
+
950
+ await _validate_and_add_block_multi_error(
951
+ empty_blockchain,
952
+ block_bad_3,
953
+ [Err.INVALID_CC_EOS_VDF, Err.INVALID_PREV_CHALLENGE_SLOT_HASH, Err.INVALID_POSPACE],
954
+ )
955
+
956
+ # Bad proof
957
+ new_finished_ss_5 = recursive_replace(
958
+ block.finished_sub_slots[-1],
959
+ "proofs.challenge_chain_slot_proof",
960
+ VDFProof(uint8(0), b"1239819023890", False),
961
+ )
962
+ block_bad_5 = recursive_replace(
963
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
964
+ )
965
+ await _validate_and_add_block(empty_blockchain, block_bad_5, expected_error=Err.INVALID_CC_EOS_VDF)
966
+
967
+ await _validate_and_add_block(empty_blockchain, block)
968
+
969
+ @pytest.mark.anyio
970
+ async def test_invalid_rc_sub_slot_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
971
+ # 2p
972
+ blocks: List[FullBlock] = []
973
+ found_block: bool = False
974
+
975
+ while not found_block:
976
+ blocks = bt.get_consecutive_blocks(1, blocks)
977
+ block = blocks[-1]
978
+ if (
979
+ len(block.finished_sub_slots)
980
+ and block.finished_sub_slots[-1].reward_chain.end_of_slot_vdf.output
981
+ != ClassgroupElement.get_default_element()
982
+ ):
983
+ found_block = True
984
+ # Bad iters
985
+ new_finished_ss = recursive_replace(
986
+ block.finished_sub_slots[-1],
987
+ "reward_chain",
988
+ recursive_replace(
989
+ block.finished_sub_slots[-1].reward_chain,
990
+ "end_of_slot_vdf.number_of_iterations",
991
+ uint64(10000000),
992
+ ),
993
+ )
994
+ block_bad = recursive_replace(
995
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
996
+ )
997
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_EOS_VDF)
998
+
999
+ # Bad output
1000
+ new_finished_ss_2 = recursive_replace(
1001
+ block.finished_sub_slots[-1],
1002
+ "reward_chain",
1003
+ recursive_replace(
1004
+ block.finished_sub_slots[-1].reward_chain,
1005
+ "end_of_slot_vdf.output",
1006
+ ClassgroupElement.get_default_element(),
1007
+ ),
1008
+ )
1009
+ block_bad_2 = recursive_replace(
1010
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
1011
+ )
1012
+ await _validate_and_add_block(empty_blockchain, block_bad_2, expected_error=Err.INVALID_RC_EOS_VDF)
1013
+
1014
+ # Bad challenge hash
1015
+ new_finished_ss_3 = recursive_replace(
1016
+ block.finished_sub_slots[-1],
1017
+ "reward_chain",
1018
+ recursive_replace(
1019
+ block.finished_sub_slots[-1].reward_chain,
1020
+ "end_of_slot_vdf.challenge",
1021
+ bytes32([1] * 32),
1022
+ ),
1023
+ )
1024
+ block_bad_3 = recursive_replace(
1025
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
1026
+ )
1027
+ await _validate_and_add_block(empty_blockchain, block_bad_3, expected_error=Err.INVALID_RC_EOS_VDF)
1028
+
1029
+ # Bad proof
1030
+ new_finished_ss_5 = recursive_replace(
1031
+ block.finished_sub_slots[-1],
1032
+ "proofs.reward_chain_slot_proof",
1033
+ VDFProof(uint8(0), b"1239819023890", False),
1034
+ )
1035
+ block_bad_5 = recursive_replace(
1036
+ block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
1037
+ )
1038
+ await _validate_and_add_block(empty_blockchain, block_bad_5, expected_error=Err.INVALID_RC_EOS_VDF)
1039
+
1040
+ await _validate_and_add_block(empty_blockchain, block)
1041
+
1042
+ @pytest.mark.anyio
1043
+ async def test_genesis_bad_deficit(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1044
+ # 2r
1045
+ block = bt.get_consecutive_blocks(1, skip_slots=2)[0]
1046
+ new_finished_ss = recursive_replace(
1047
+ block.finished_sub_slots[-1],
1048
+ "reward_chain",
1049
+ recursive_replace(
1050
+ block.finished_sub_slots[-1].reward_chain,
1051
+ "deficit",
1052
+ bt.constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK - 1,
1053
+ ),
1054
+ )
1055
+ block_bad = recursive_replace(block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss])
1056
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_DEFICIT)
1057
+
1058
+ @pytest.mark.anyio
1059
+ async def test_reset_deficit(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1060
+ # 2s, 2t
1061
+ blockchain = empty_blockchain
1062
+ blocks = bt.get_consecutive_blocks(2)
1063
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1064
+ await _validate_and_add_block(empty_blockchain, blocks[1])
1065
+ case_1, case_2 = False, False
1066
+ while not case_1 or not case_2:
1067
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
1068
+ if len(blocks[-1].finished_sub_slots) > 0:
1069
+ new_finished_ss = recursive_replace(
1070
+ blocks[-1].finished_sub_slots[-1],
1071
+ "reward_chain",
1072
+ recursive_replace(
1073
+ blocks[-1].finished_sub_slots[-1].reward_chain,
1074
+ "deficit",
1075
+ uint8(0),
1076
+ ),
1077
+ )
1078
+ if blockchain.block_record(blocks[-2].header_hash).deficit == 0:
1079
+ case_1 = True
1080
+ else:
1081
+ case_2 = True
1082
+
1083
+ block_bad = recursive_replace(
1084
+ blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
1085
+ )
1086
+ await _validate_and_add_block_multi_error(
1087
+ empty_blockchain, block_bad, [Err.INVALID_DEFICIT, Err.INVALID_ICC_HASH_CC]
1088
+ )
1089
+
1090
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1091
+
1092
+ @pytest.mark.anyio
1093
+ async def test_genesis_has_ses(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1094
+ # 3a
1095
+ block = bt.get_consecutive_blocks(1, skip_slots=1)[0]
1096
+ new_finished_ss = recursive_replace(
1097
+ block.finished_sub_slots[0],
1098
+ "challenge_chain",
1099
+ recursive_replace(
1100
+ block.finished_sub_slots[0].challenge_chain,
1101
+ "subepoch_summary_hash",
1102
+ bytes32([0] * 32),
1103
+ ),
1104
+ )
1105
+
1106
+ new_finished_ss = recursive_replace(
1107
+ new_finished_ss,
1108
+ "reward_chain",
1109
+ new_finished_ss.reward_chain.replace(
1110
+ challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash()
1111
+ ),
1112
+ )
1113
+ block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:])
1114
+ with pytest.raises(AssertionError):
1115
+ # Fails pre validation
1116
+ await _validate_and_add_block(
1117
+ empty_blockchain, block_bad, expected_error=Err.INVALID_SUB_EPOCH_SUMMARY_HASH
1118
+ )
1119
+
1120
+ @pytest.mark.anyio
1121
+ async def test_no_ses_if_no_se(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1122
+ # 3b
1123
+ blocks = bt.get_consecutive_blocks(1)
1124
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1125
+
1126
+ while True:
1127
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1128
+ if len(blocks[-1].finished_sub_slots) > 0 and is_overflow_block(
1129
+ bt.constants, blocks[-1].reward_chain_block.signage_point_index
1130
+ ):
1131
+ new_finished_ss: EndOfSubSlotBundle = recursive_replace(
1132
+ blocks[-1].finished_sub_slots[0],
1133
+ "challenge_chain",
1134
+ recursive_replace(
1135
+ blocks[-1].finished_sub_slots[0].challenge_chain,
1136
+ "subepoch_summary_hash",
1137
+ bytes32([0] * 32),
1138
+ ),
1139
+ )
1140
+
1141
+ new_finished_ss = recursive_replace(
1142
+ new_finished_ss,
1143
+ "reward_chain",
1144
+ new_finished_ss.reward_chain.replace(
1145
+ challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash(),
1146
+ ),
1147
+ )
1148
+ block_bad = recursive_replace(
1149
+ blocks[-1], "finished_sub_slots", [new_finished_ss] + blocks[-1].finished_sub_slots[1:]
1150
+ )
1151
+ await _validate_and_add_block_multi_error(
1152
+ empty_blockchain,
1153
+ block_bad,
1154
+ expected_errors=[
1155
+ Err.INVALID_SUB_EPOCH_SUMMARY_HASH,
1156
+ Err.INVALID_SUB_EPOCH_SUMMARY,
1157
+ ],
1158
+ )
1159
+ return None
1160
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1161
+
1162
+ @pytest.mark.anyio
1163
+ async def test_too_many_blocks(self, empty_blockchain: Blockchain) -> None:
1164
+ # 4: TODO
1165
+ pass
1166
+
1167
+ @pytest.mark.anyio
1168
+ async def test_bad_pos(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1169
+ # 5
1170
+ blocks = bt.get_consecutive_blocks(2)
1171
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1172
+
1173
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.proof_of_space.challenge", std_hash(b""))
1174
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
1175
+
1176
+ block_bad = recursive_replace(
1177
+ blocks[-1], "reward_chain_block.proof_of_space.pool_contract_puzzle_hash", std_hash(b"")
1178
+ )
1179
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
1180
+
1181
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.proof_of_space.size", 62)
1182
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
1183
+
1184
+ block_bad = recursive_replace(
1185
+ blocks[-1],
1186
+ "reward_chain_block.proof_of_space.plot_public_key",
1187
+ AugSchemeMPL.key_gen(std_hash(b"1231n")).get_g1(),
1188
+ )
1189
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
1190
+ block_bad = recursive_replace(
1191
+ blocks[-1],
1192
+ "reward_chain_block.proof_of_space.size",
1193
+ 32,
1194
+ )
1195
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
1196
+ block_bad = recursive_replace(
1197
+ blocks[-1],
1198
+ "reward_chain_block.proof_of_space.proof",
1199
+ bytes([1] * int(blocks[-1].reward_chain_block.proof_of_space.size * 64 / 8)),
1200
+ )
1201
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
1202
+
1203
+ # TODO: test not passing the plot filter
1204
+
1205
+ @pytest.mark.anyio
1206
+ async def test_bad_signage_point_index(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1207
+ # 6
1208
+ blocks = bt.get_consecutive_blocks(2)
1209
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1210
+
1211
+ with pytest.raises(ValueError):
1212
+ block_bad = recursive_replace(
1213
+ blocks[-1], "reward_chain_block.signage_point_index", bt.constants.NUM_SPS_SUB_SLOT
1214
+ )
1215
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_SP_INDEX)
1216
+ with pytest.raises(ValueError):
1217
+ block_bad = recursive_replace(
1218
+ blocks[-1], "reward_chain_block.signage_point_index", bt.constants.NUM_SPS_SUB_SLOT + 1
1219
+ )
1220
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_SP_INDEX)
1221
+
1222
+ @pytest.mark.anyio
1223
+ async def test_sp_0_no_sp(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1224
+ # 7
1225
+ blocks: List[FullBlock] = []
1226
+ case_1, case_2 = False, False
1227
+ while not case_1 or not case_2:
1228
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1229
+ if blocks[-1].reward_chain_block.signage_point_index == 0:
1230
+ case_1 = True
1231
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.signage_point_index", uint8(1))
1232
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_SP_INDEX)
1233
+
1234
+ elif not is_overflow_block(bt.constants, blocks[-1].reward_chain_block.signage_point_index):
1235
+ case_2 = True
1236
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.signage_point_index", uint8(0))
1237
+ await _validate_and_add_block_multi_error(
1238
+ empty_blockchain, block_bad, [Err.INVALID_SP_INDEX, Err.INVALID_POSPACE]
1239
+ )
1240
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1241
+
1242
+ @pytest.mark.anyio
1243
+ async def test_epoch_overflows(self, empty_blockchain: Blockchain) -> None:
1244
+ # 9. TODO. This is hard to test because it requires modifying the block tools to make these special blocks
1245
+ pass
1246
+
1247
+ @pytest.mark.anyio
1248
+ async def test_bad_total_iters(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1249
+ # 10
1250
+ blocks = bt.get_consecutive_blocks(2)
1251
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1252
+
1253
+ block_bad = recursive_replace(
1254
+ blocks[-1], "reward_chain_block.total_iters", blocks[-1].reward_chain_block.total_iters + 1
1255
+ )
1256
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_TOTAL_ITERS)
1257
+
1258
+ @pytest.mark.anyio
1259
+ async def test_bad_rc_sp_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1260
+ # 11
1261
+ blocks = bt.get_consecutive_blocks(1)
1262
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1263
+
1264
+ while True:
1265
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1266
+ if blocks[-1].reward_chain_block.signage_point_index != 0:
1267
+ block_bad = recursive_replace(
1268
+ blocks[-1], "reward_chain_block.reward_chain_sp_vdf.challenge", std_hash(b"1")
1269
+ )
1270
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
1271
+ block_bad = recursive_replace(
1272
+ blocks[-1],
1273
+ "reward_chain_block.reward_chain_sp_vdf.output",
1274
+ bad_element,
1275
+ )
1276
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
1277
+ block_bad = recursive_replace(
1278
+ blocks[-1],
1279
+ "reward_chain_block.reward_chain_sp_vdf.number_of_iterations",
1280
+ uint64(1111111111111),
1281
+ )
1282
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
1283
+ block_bad = recursive_replace(
1284
+ blocks[-1],
1285
+ "reward_chain_sp_proof",
1286
+ VDFProof(uint8(0), std_hash(b""), False),
1287
+ )
1288
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
1289
+ return None
1290
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1291
+
1292
+ @pytest.mark.anyio
1293
+ async def test_bad_rc_sp_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1294
+ # 12
1295
+ blocks = bt.get_consecutive_blocks(2)
1296
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1297
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.reward_chain_sp_signature", G2Element.generator())
1298
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SIGNATURE)
1299
+
1300
+ @pytest.mark.anyio
1301
+ async def test_bad_cc_sp_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1302
+ # 13. Note: does not validate fully due to proof of space being validated first
1303
+
1304
+ blocks = bt.get_consecutive_blocks(1)
1305
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1306
+
1307
+ while True:
1308
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1309
+ if blocks[-1].reward_chain_block.signage_point_index != 0:
1310
+ block_bad = recursive_replace(
1311
+ blocks[-1], "reward_chain_block.challenge_chain_sp_vdf.challenge", std_hash(b"1")
1312
+ )
1313
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
1314
+ block_bad = recursive_replace(
1315
+ blocks[-1],
1316
+ "reward_chain_block.challenge_chain_sp_vdf.output",
1317
+ bad_element,
1318
+ )
1319
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
1320
+ block_bad = recursive_replace(
1321
+ blocks[-1],
1322
+ "reward_chain_block.challenge_chain_sp_vdf.number_of_iterations",
1323
+ uint64(1111111111111),
1324
+ )
1325
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
1326
+ block_bad = recursive_replace(
1327
+ blocks[-1],
1328
+ "challenge_chain_sp_proof",
1329
+ VDFProof(uint8(0), std_hash(b""), False),
1330
+ )
1331
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_SP_VDF)
1332
+ return None
1333
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1334
+
1335
+ @pytest.mark.anyio
1336
+ async def test_bad_cc_sp_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1337
+ # 14
1338
+ blocks = bt.get_consecutive_blocks(2)
1339
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1340
+ block_bad = recursive_replace(
1341
+ blocks[-1], "reward_chain_block.challenge_chain_sp_signature", G2Element.generator()
1342
+ )
1343
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_SIGNATURE)
1344
+
1345
+ @pytest.mark.anyio
1346
+ async def test_is_transaction_block(self, empty_blockchain: Blockchain) -> None:
1347
+ # 15: TODO
1348
+ pass
1349
+
1350
+ @pytest.mark.anyio
1351
+ async def test_bad_foliage_sb_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1352
+ # 16
1353
+ blocks = bt.get_consecutive_blocks(2)
1354
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1355
+ block_bad = recursive_replace(blocks[-1], "foliage.foliage_block_data_signature", G2Element.generator())
1356
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PLOT_SIGNATURE)
1357
+
1358
+ @pytest.mark.anyio
1359
+ async def test_bad_foliage_transaction_block_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1360
+ # 17
1361
+ blocks = bt.get_consecutive_blocks(1)
1362
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1363
+
1364
+ while True:
1365
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1366
+ if blocks[-1].foliage_transaction_block is not None:
1367
+ block_bad = recursive_replace(
1368
+ blocks[-1], "foliage.foliage_transaction_block_signature", G2Element.generator()
1369
+ )
1370
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PLOT_SIGNATURE)
1371
+ return None
1372
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1373
+
1374
+ @pytest.mark.anyio
1375
+ async def test_unfinished_reward_chain_sb_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1376
+ # 18
1377
+ blocks = bt.get_consecutive_blocks(2)
1378
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1379
+ block_bad: FullBlock = recursive_replace(
1380
+ blocks[-1], "foliage.foliage_block_data.unfinished_reward_block_hash", std_hash(b"2")
1381
+ )
1382
+ new_m = block_bad.foliage.foliage_block_data.get_hash()
1383
+ assert new_m is not None
1384
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1385
+ block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
1386
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_URSB_HASH)
1387
+
1388
+ @pytest.mark.anyio
1389
+ async def test_pool_target_height(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1390
+ # 19
1391
+ blocks = bt.get_consecutive_blocks(3)
1392
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1393
+ await _validate_and_add_block(empty_blockchain, blocks[1])
1394
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage.foliage_block_data.pool_target.max_height", 1)
1395
+ new_m = block_bad.foliage.foliage_block_data.get_hash()
1396
+ assert new_m is not None
1397
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1398
+ block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
1399
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.OLD_POOL_TARGET)
1400
+
1401
+ @pytest.mark.anyio
1402
+ async def test_pool_target_pre_farm(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1403
+ # 20a
1404
+ blocks = bt.get_consecutive_blocks(1)
1405
+ block_bad: FullBlock = recursive_replace(
1406
+ blocks[-1], "foliage.foliage_block_data.pool_target.puzzle_hash", std_hash(b"12")
1407
+ )
1408
+ new_m = block_bad.foliage.foliage_block_data.get_hash()
1409
+ assert new_m is not None
1410
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1411
+ block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
1412
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREFARM)
1413
+
1414
+ @pytest.mark.anyio
1415
+ async def test_pool_target_signature(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1416
+ # 20b
1417
+ blocks_initial = bt.get_consecutive_blocks(2)
1418
+ await _validate_and_add_block(empty_blockchain, blocks_initial[0])
1419
+ await _validate_and_add_block(empty_blockchain, blocks_initial[1])
1420
+
1421
+ attempts = 0
1422
+ while True:
1423
+ # Go until we get a block that has a pool pk, as opposed to a pool contract
1424
+ blocks = bt.get_consecutive_blocks(
1425
+ 1, blocks_initial, seed=std_hash(attempts.to_bytes(4, byteorder="big", signed=False))
1426
+ )
1427
+ if blocks[-1].foliage.foliage_block_data.pool_signature is not None:
1428
+ block_bad: FullBlock = recursive_replace(
1429
+ blocks[-1], "foliage.foliage_block_data.pool_signature", G2Element.generator()
1430
+ )
1431
+ new_m = block_bad.foliage.foliage_block_data.get_hash()
1432
+ assert new_m is not None
1433
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1434
+ block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
1435
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POOL_SIGNATURE)
1436
+ return None
1437
+ attempts += 1
1438
+
1439
+ @pytest.mark.anyio
1440
+ async def test_pool_target_contract(
1441
+ self, empty_blockchain: Blockchain, bt: BlockTools, seeded_random: random.Random
1442
+ ) -> None:
1443
+ # 20c invalid pool target with contract
1444
+ blocks_initial = bt.get_consecutive_blocks(2)
1445
+ await _validate_and_add_block(empty_blockchain, blocks_initial[0])
1446
+ await _validate_and_add_block(empty_blockchain, blocks_initial[1])
1447
+
1448
+ attempts = 0
1449
+ while True:
1450
+ # Go until we get a block that has a pool contract opposed to a pool pk
1451
+ blocks = bt.get_consecutive_blocks(
1452
+ 1, blocks_initial, seed=std_hash(attempts.to_bytes(4, byteorder="big", signed=False))
1453
+ )
1454
+ if blocks[-1].foliage.foliage_block_data.pool_signature is None:
1455
+ block_bad: FullBlock = recursive_replace(
1456
+ blocks[-1], "foliage.foliage_block_data.pool_target.puzzle_hash", bytes32.random(seeded_random)
1457
+ )
1458
+ new_m = block_bad.foliage.foliage_block_data.get_hash()
1459
+ assert new_m is not None
1460
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1461
+ block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
1462
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POOL_TARGET)
1463
+ return None
1464
+ attempts += 1
1465
+
1466
+ @pytest.mark.anyio
1467
+ async def test_foliage_data_presence(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1468
+ # 22
1469
+ blocks = bt.get_consecutive_blocks(1)
1470
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1471
+ case_1, case_2 = False, False
1472
+ while not case_1 or not case_2:
1473
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1474
+ if blocks[-1].foliage_transaction_block is not None:
1475
+ case_1 = True
1476
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage.foliage_transaction_block_hash", None)
1477
+ else:
1478
+ case_2 = True
1479
+ block_bad = recursive_replace(blocks[-1], "foliage.foliage_transaction_block_hash", std_hash(b""))
1480
+ await _validate_and_add_block_multi_error(
1481
+ empty_blockchain,
1482
+ block_bad,
1483
+ [
1484
+ Err.INVALID_FOLIAGE_BLOCK_PRESENCE,
1485
+ Err.INVALID_IS_TRANSACTION_BLOCK,
1486
+ Err.INVALID_PREV_BLOCK_HASH,
1487
+ Err.INVALID_PREV_BLOCK_HASH,
1488
+ ],
1489
+ )
1490
+
1491
+ @pytest.mark.anyio
1492
+ async def test_foliage_transaction_block_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1493
+ # 23
1494
+ blocks = bt.get_consecutive_blocks(1)
1495
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1496
+ case_1, case_2 = False, False
1497
+ while not case_1 or not case_2:
1498
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1499
+ if blocks[-1].foliage_transaction_block is not None:
1500
+ block_bad: FullBlock = recursive_replace(
1501
+ blocks[-1], "foliage.foliage_transaction_block_hash", std_hash(b"2")
1502
+ )
1503
+
1504
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1505
+ assert new_m is not None
1506
+ new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1507
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1508
+ await _validate_and_add_block(
1509
+ empty_blockchain, block_bad, expected_error=Err.INVALID_FOLIAGE_BLOCK_HASH
1510
+ )
1511
+ return None
1512
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1513
+
1514
+ @pytest.mark.anyio
1515
+ async def test_genesis_bad_prev_block(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1516
+ # 24a
1517
+ blocks = bt.get_consecutive_blocks(1)
1518
+ block_bad: FullBlock = recursive_replace(
1519
+ blocks[-1], "foliage_transaction_block.prev_transaction_block_hash", std_hash(b"2")
1520
+ )
1521
+ assert block_bad.foliage_transaction_block is not None
1522
+ block_bad = recursive_replace(
1523
+ block_bad, "foliage.foliage_transaction_block_hash", block_bad.foliage_transaction_block.get_hash()
1524
+ )
1525
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1526
+ assert new_m is not None
1527
+ new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1528
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1529
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
1530
+
1531
+ @pytest.mark.anyio
1532
+ async def test_bad_prev_block_non_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1533
+ # 24b
1534
+ blocks = bt.get_consecutive_blocks(1)
1535
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1536
+ while True:
1537
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1538
+ if blocks[-1].foliage_transaction_block is not None:
1539
+ block_bad: FullBlock = recursive_replace(
1540
+ blocks[-1], "foliage_transaction_block.prev_transaction_block_hash", std_hash(b"2")
1541
+ )
1542
+ assert block_bad.foliage_transaction_block is not None
1543
+ block_bad = recursive_replace(
1544
+ block_bad, "foliage.foliage_transaction_block_hash", block_bad.foliage_transaction_block.get_hash()
1545
+ )
1546
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1547
+ assert new_m is not None
1548
+ new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1549
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1550
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
1551
+ return None
1552
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1553
+
1554
+ @pytest.mark.anyio
1555
+ async def test_bad_filter_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1556
+ # 25
1557
+ blocks = bt.get_consecutive_blocks(1)
1558
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1559
+ while True:
1560
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1561
+ if blocks[-1].foliage_transaction_block is not None:
1562
+ block_bad: FullBlock = recursive_replace(
1563
+ blocks[-1], "foliage_transaction_block.filter_hash", std_hash(b"2")
1564
+ )
1565
+ assert block_bad.foliage_transaction_block is not None
1566
+ block_bad = recursive_replace(
1567
+ block_bad, "foliage.foliage_transaction_block_hash", block_bad.foliage_transaction_block.get_hash()
1568
+ )
1569
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1570
+ assert new_m is not None
1571
+ new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
1572
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1573
+ await _validate_and_add_block(
1574
+ empty_blockchain, block_bad, expected_error=Err.INVALID_TRANSACTIONS_FILTER_HASH
1575
+ )
1576
+ return None
1577
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1578
+
1579
+ @pytest.mark.anyio
1580
+ async def test_bad_timestamp(self, bt: BlockTools) -> None:
1581
+ # 26
1582
+ # the test constants set MAX_FUTURE_TIME to 10 days, restore it to
1583
+ # default for this test
1584
+ constants = bt.constants.replace(MAX_FUTURE_TIME2=uint32(2 * 60))
1585
+ time_delta = 2 * 60 + 1
1586
+
1587
+ blocks = bt.get_consecutive_blocks(1)
1588
+
1589
+ async with make_empty_blockchain(constants) as b:
1590
+ await _validate_and_add_block(b, blocks[0])
1591
+ while True:
1592
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1593
+ if blocks[-1].foliage_transaction_block is not None:
1594
+ assert blocks[0].foliage_transaction_block is not None
1595
+ block_bad: FullBlock = recursive_replace(
1596
+ blocks[-1],
1597
+ "foliage_transaction_block.timestamp",
1598
+ blocks[0].foliage_transaction_block.timestamp - 10,
1599
+ )
1600
+ assert block_bad.foliage_transaction_block is not None
1601
+ block_bad = recursive_replace(
1602
+ block_bad,
1603
+ "foliage.foliage_transaction_block_hash",
1604
+ block_bad.foliage_transaction_block.get_hash(),
1605
+ )
1606
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1607
+ assert new_m is not None
1608
+ new_fbh_sig = bt.get_plot_signature(
1609
+ new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key
1610
+ )
1611
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1612
+ await _validate_and_add_block(b, block_bad, expected_error=Err.TIMESTAMP_TOO_FAR_IN_PAST)
1613
+
1614
+ assert blocks[0].foliage_transaction_block is not None
1615
+ block_bad = recursive_replace(
1616
+ blocks[-1],
1617
+ "foliage_transaction_block.timestamp",
1618
+ blocks[0].foliage_transaction_block.timestamp,
1619
+ )
1620
+ assert block_bad.foliage_transaction_block is not None
1621
+ block_bad = recursive_replace(
1622
+ block_bad,
1623
+ "foliage.foliage_transaction_block_hash",
1624
+ block_bad.foliage_transaction_block.get_hash(),
1625
+ )
1626
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1627
+ assert new_m is not None
1628
+ new_fbh_sig = bt.get_plot_signature(
1629
+ new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key
1630
+ )
1631
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1632
+ await _validate_and_add_block(b, block_bad, expected_error=Err.TIMESTAMP_TOO_FAR_IN_PAST)
1633
+
1634
+ # since tests can run slow sometimes, and since we're using
1635
+ # the system clock, add some extra slack
1636
+ slack = 30
1637
+ block_bad = recursive_replace(
1638
+ blocks[-1],
1639
+ "foliage_transaction_block.timestamp",
1640
+ blocks[0].foliage_transaction_block.timestamp + time_delta + slack,
1641
+ )
1642
+ assert block_bad.foliage_transaction_block is not None
1643
+ block_bad = recursive_replace(
1644
+ block_bad,
1645
+ "foliage.foliage_transaction_block_hash",
1646
+ block_bad.foliage_transaction_block.get_hash(),
1647
+ )
1648
+ new_m = block_bad.foliage.foliage_transaction_block_hash
1649
+ assert new_m is not None
1650
+ new_fbh_sig = bt.get_plot_signature(
1651
+ new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key
1652
+ )
1653
+ block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
1654
+ await _validate_and_add_block(b, block_bad, expected_error=Err.TIMESTAMP_TOO_FAR_IN_FUTURE)
1655
+ return None
1656
+ await _validate_and_add_block(b, blocks[-1])
1657
+
1658
+ @pytest.mark.anyio
1659
+ async def test_height(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1660
+ # 27
1661
+ blocks = bt.get_consecutive_blocks(2)
1662
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1663
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.height", 2)
1664
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_HEIGHT)
1665
+
1666
+ @pytest.mark.anyio
1667
+ async def test_height_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1668
+ # 27
1669
+ blocks = bt.get_consecutive_blocks(1)
1670
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.height", 1)
1671
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
1672
+
1673
+ @pytest.mark.anyio
1674
+ async def test_weight(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1675
+ # 28
1676
+ blocks = bt.get_consecutive_blocks(2)
1677
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1678
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.weight", 22131)
1679
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_WEIGHT)
1680
+
1681
+ @pytest.mark.anyio
1682
+ async def test_weight_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1683
+ # 28
1684
+ blocks = bt.get_consecutive_blocks(1)
1685
+ block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.weight", 0)
1686
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_WEIGHT)
1687
+
1688
+ @pytest.mark.anyio
1689
+ async def test_bad_cc_ip_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1690
+ # 29
1691
+ blocks = bt.get_consecutive_blocks(1)
1692
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1693
+
1694
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1695
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.challenge_chain_ip_vdf.challenge", std_hash(b"1"))
1696
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
1697
+ block_bad = recursive_replace(
1698
+ blocks[-1],
1699
+ "reward_chain_block.challenge_chain_ip_vdf.output",
1700
+ bad_element,
1701
+ )
1702
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
1703
+ block_bad = recursive_replace(
1704
+ blocks[-1],
1705
+ "reward_chain_block.challenge_chain_ip_vdf.number_of_iterations",
1706
+ uint64(1111111111111),
1707
+ )
1708
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
1709
+ block_bad = recursive_replace(
1710
+ blocks[-1],
1711
+ "challenge_chain_ip_proof",
1712
+ VDFProof(uint8(0), std_hash(b""), False),
1713
+ )
1714
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
1715
+
1716
+ @pytest.mark.anyio
1717
+ async def test_bad_rc_ip_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1718
+ # 30
1719
+ blocks = bt.get_consecutive_blocks(1)
1720
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1721
+
1722
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1723
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.reward_chain_ip_vdf.challenge", std_hash(b"1"))
1724
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
1725
+ block_bad = recursive_replace(
1726
+ blocks[-1],
1727
+ "reward_chain_block.reward_chain_ip_vdf.output",
1728
+ bad_element,
1729
+ )
1730
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
1731
+ block_bad = recursive_replace(
1732
+ blocks[-1],
1733
+ "reward_chain_block.reward_chain_ip_vdf.number_of_iterations",
1734
+ uint64(1111111111111),
1735
+ )
1736
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
1737
+ block_bad = recursive_replace(
1738
+ blocks[-1],
1739
+ "reward_chain_ip_proof",
1740
+ VDFProof(uint8(0), std_hash(b""), False),
1741
+ )
1742
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
1743
+
1744
+ @pytest.mark.anyio
1745
+ async def test_bad_icc_ip_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1746
+ # 31
1747
+ blocks = bt.get_consecutive_blocks(1)
1748
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1749
+
1750
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1751
+ block_bad = recursive_replace(
1752
+ blocks[-1], "reward_chain_block.infused_challenge_chain_ip_vdf.challenge", std_hash(b"1")
1753
+ )
1754
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
1755
+ block_bad = recursive_replace(
1756
+ blocks[-1],
1757
+ "reward_chain_block.infused_challenge_chain_ip_vdf.output",
1758
+ bad_element,
1759
+ )
1760
+
1761
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
1762
+ block_bad = recursive_replace(
1763
+ blocks[-1],
1764
+ "reward_chain_block.infused_challenge_chain_ip_vdf.number_of_iterations",
1765
+ uint64(1111111111111),
1766
+ )
1767
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
1768
+ block_bad = recursive_replace(
1769
+ blocks[-1],
1770
+ "infused_challenge_chain_ip_proof",
1771
+ VDFProof(uint8(0), std_hash(b""), False),
1772
+ )
1773
+
1774
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
1775
+
1776
+ @pytest.mark.anyio
1777
+ async def test_reward_block_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1778
+ # 32
1779
+ blocks = bt.get_consecutive_blocks(2)
1780
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1781
+ block_bad: FullBlock = recursive_replace(blocks[-1], "foliage.reward_block_hash", std_hash(b""))
1782
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_REWARD_BLOCK_HASH)
1783
+
1784
+ @pytest.mark.anyio
1785
+ async def test_reward_block_hash_2(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1786
+ # 33
1787
+ blocks = bt.get_consecutive_blocks(1)
1788
+ block_bad: FullBlock = recursive_replace(blocks[0], "reward_chain_block.is_transaction_block", False)
1789
+ block_bad = recursive_replace(block_bad, "foliage.reward_block_hash", block_bad.reward_chain_block.get_hash())
1790
+ await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_FOLIAGE_BLOCK_PRESENCE)
1791
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1792
+
1793
+ # Test one which should not be a tx block
1794
+ while True:
1795
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
1796
+ if not blocks[-1].is_transaction_block():
1797
+ block_bad = recursive_replace(blocks[-1], "reward_chain_block.is_transaction_block", True)
1798
+ block_bad = recursive_replace(
1799
+ block_bad, "foliage.reward_block_hash", block_bad.reward_chain_block.get_hash()
1800
+ )
1801
+ await _validate_and_add_block(
1802
+ empty_blockchain, block_bad, expected_error=Err.INVALID_FOLIAGE_BLOCK_PRESENCE
1803
+ )
1804
+ return None
1805
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
1806
+
1807
+
1808
+ co = ConditionOpcode
1809
+ rbr = AddBlockResult
1810
+
1811
+
1812
+ class TestPreValidation:
1813
+ @pytest.mark.anyio
1814
+ async def test_pre_validation_fails_bad_blocks(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
1815
+ blocks = bt.get_consecutive_blocks(2)
1816
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1817
+ ssi = empty_blockchain.constants.SUB_SLOT_ITERS_STARTING
1818
+ difficulty = empty_blockchain.constants.DIFFICULTY_STARTING
1819
+ block_bad = recursive_replace(
1820
+ blocks[-1], "reward_chain_block.total_iters", blocks[-1].reward_chain_block.total_iters + 1
1821
+ )
1822
+ res = await pre_validate_blocks_multiprocessing(
1823
+ empty_blockchain.constants,
1824
+ empty_blockchain,
1825
+ [blocks[0], block_bad],
1826
+ empty_blockchain.pool,
1827
+ {},
1828
+ sub_slot_iters=ssi,
1829
+ difficulty=difficulty,
1830
+ prev_ses_block=None,
1831
+ validate_signatures=True,
1832
+ )
1833
+ assert res[0].error is None
1834
+ assert res[1].error is not None
1835
+
1836
+ @pytest.mark.anyio
1837
+ async def test_pre_validation(
1838
+ self, empty_blockchain: Blockchain, default_1000_blocks: List[FullBlock], bt: BlockTools
1839
+ ) -> None:
1840
+ blocks = default_1000_blocks[:100]
1841
+ start = time.time()
1842
+ n_at_a_time = min(available_logical_cores(), 32)
1843
+ times_pv = []
1844
+ times_rb = []
1845
+ ssi = empty_blockchain.constants.SUB_SLOT_ITERS_STARTING
1846
+ difficulty = empty_blockchain.constants.DIFFICULTY_STARTING
1847
+ for i in range(0, len(blocks), n_at_a_time):
1848
+ end_i = min(i + n_at_a_time, len(blocks))
1849
+ blocks_to_validate = blocks[i:end_i]
1850
+ start_pv = time.time()
1851
+ res = await pre_validate_blocks_multiprocessing(
1852
+ empty_blockchain.constants,
1853
+ empty_blockchain,
1854
+ blocks_to_validate,
1855
+ empty_blockchain.pool,
1856
+ {},
1857
+ sub_slot_iters=ssi,
1858
+ difficulty=difficulty,
1859
+ prev_ses_block=None,
1860
+ validate_signatures=True,
1861
+ )
1862
+ end_pv = time.time()
1863
+ times_pv.append(end_pv - start_pv)
1864
+ assert res is not None
1865
+ for n in range(end_i - i):
1866
+ assert res[n] is not None
1867
+ assert res[n].error is None
1868
+ block = blocks_to_validate[n]
1869
+ start_rb = time.time()
1870
+ result, err, _ = await empty_blockchain.add_block(block, res[n], None, ssi)
1871
+ end_rb = time.time()
1872
+ times_rb.append(end_rb - start_rb)
1873
+ assert err is None
1874
+ assert result == AddBlockResult.NEW_PEAK
1875
+ log.info(
1876
+ f"Added block {block.height} total iters {block.total_iters} "
1877
+ f"new slot? {len(block.finished_sub_slots)}, time {end_rb - start_rb}"
1878
+ )
1879
+ end = time.time()
1880
+ log.info(f"Total time: {end - start} seconds")
1881
+ log.info(f"Average pv: {sum(times_pv)/(len(blocks)/n_at_a_time)}")
1882
+ log.info(f"Average rb: {sum(times_rb)/(len(blocks))}")
1883
+
1884
+
1885
+ class TestBodyValidation:
1886
+ # TODO: add test for
1887
+ # ASSERT_COIN_ANNOUNCEMENT,
1888
+ # CREATE_COIN_ANNOUNCEMENT,
1889
+ # CREATE_PUZZLE_ANNOUNCEMENT,
1890
+ # ASSERT_PUZZLE_ANNOUNCEMENT,
1891
+
1892
+ @pytest.mark.anyio
1893
+ @pytest.mark.parametrize(
1894
+ "opcode",
1895
+ [
1896
+ ConditionOpcode.ASSERT_MY_AMOUNT,
1897
+ ConditionOpcode.ASSERT_MY_PUZZLEHASH,
1898
+ ConditionOpcode.ASSERT_MY_COIN_ID,
1899
+ ConditionOpcode.ASSERT_MY_PARENT_ID,
1900
+ ],
1901
+ )
1902
+ @pytest.mark.parametrize("with_garbage", [True, False])
1903
+ async def test_conditions(
1904
+ self, empty_blockchain: Blockchain, opcode: ConditionOpcode, with_garbage: bool, bt: BlockTools
1905
+ ) -> None:
1906
+ b = empty_blockchain
1907
+ blocks = bt.get_consecutive_blocks(
1908
+ 3,
1909
+ guarantee_transaction_block=True,
1910
+ farmer_reward_puzzle_hash=bt.pool_ph,
1911
+ pool_reward_puzzle_hash=bt.pool_ph,
1912
+ genesis_timestamp=uint64(10_000),
1913
+ time_per_block=10,
1914
+ )
1915
+ await _validate_and_add_block(empty_blockchain, blocks[0])
1916
+ await _validate_and_add_block(empty_blockchain, blocks[1])
1917
+ await _validate_and_add_block(empty_blockchain, blocks[2])
1918
+
1919
+ wt: WalletTool = bt.get_pool_wallet_tool()
1920
+
1921
+ tx1 = wt.generate_signed_transaction(
1922
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
1923
+ )
1924
+ coin1: Coin = tx1.additions()[0]
1925
+
1926
+ if opcode == ConditionOpcode.ASSERT_MY_AMOUNT:
1927
+ args = [int_to_bytes(coin1.amount)]
1928
+ elif opcode == ConditionOpcode.ASSERT_MY_PUZZLEHASH:
1929
+ args = [coin1.puzzle_hash]
1930
+ elif opcode == ConditionOpcode.ASSERT_MY_COIN_ID:
1931
+ args = [coin1.name()]
1932
+ elif opcode == ConditionOpcode.ASSERT_MY_PARENT_ID:
1933
+ args = [coin1.parent_coin_info]
1934
+ # elif opcode == ConditionOpcode.RESERVE_FEE:
1935
+ # args = [int_to_bytes(5)]
1936
+ # TODO: since we use the production wallet code, we can't (easily)
1937
+ # create a transaction with fee without also including a valid
1938
+ # RESERVE_FEE condition
1939
+ else:
1940
+ assert False
1941
+
1942
+ conditions: Dict[ConditionOpcode, List[ConditionWithArgs]] = {
1943
+ opcode: [ConditionWithArgs(opcode, args + ([b"garbage"] if with_garbage else []))]
1944
+ }
1945
+
1946
+ tx2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin1, condition_dic=conditions)
1947
+ assert coin1 in tx2.removals()
1948
+
1949
+ bundles = SpendBundle.aggregate([tx1, tx2])
1950
+ blocks = bt.get_consecutive_blocks(
1951
+ 1,
1952
+ block_list_input=blocks,
1953
+ guarantee_transaction_block=True,
1954
+ transaction_data=bundles,
1955
+ time_per_block=10,
1956
+ )
1957
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
1958
+ diff = b.constants.DIFFICULTY_STARTING
1959
+ pre_validation_results: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
1960
+ b.constants,
1961
+ b,
1962
+ [blocks[-1]],
1963
+ b.pool,
1964
+ {},
1965
+ sub_slot_iters=ssi,
1966
+ difficulty=diff,
1967
+ prev_ses_block=None,
1968
+ validate_signatures=False,
1969
+ )
1970
+ # Ignore errors from pre-validation, we are testing block_body_validation
1971
+ repl_preval_results = replace(pre_validation_results[0], error=None, required_iters=uint64(1))
1972
+ code, err, state_change = await b.add_block(blocks[-1], repl_preval_results, None, sub_slot_iters=ssi)
1973
+ assert code == AddBlockResult.NEW_PEAK
1974
+ assert err is None
1975
+ assert state_change is not None
1976
+ assert state_change.fork_height == 2
1977
+
1978
+ @pytest.mark.anyio
1979
+ @pytest.mark.parametrize(
1980
+ "opcode,lock_value,expected",
1981
+ [
1982
+ # the 3 blocks, starting at timestamp 10000 (and height 0).
1983
+ # each block is 10 seconds apart.
1984
+ # the 4th block (height 3, time 10030) spends a coin with the condition specified
1985
+ # by the test case. The coin was born in height 2 at time 10020
1986
+ # MY BIRHT HEIGHT
1987
+ (co.ASSERT_MY_BIRTH_HEIGHT, -1, rbr.INVALID_BLOCK),
1988
+ (co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, rbr.INVALID_BLOCK),
1989
+ (co.ASSERT_MY_BIRTH_HEIGHT, 2, rbr.NEW_PEAK), # <- coin birth height
1990
+ (co.ASSERT_MY_BIRTH_HEIGHT, 3, rbr.INVALID_BLOCK),
1991
+ # MY BIRHT SECONDS
1992
+ (co.ASSERT_MY_BIRTH_SECONDS, -1, rbr.INVALID_BLOCK),
1993
+ (co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, rbr.INVALID_BLOCK),
1994
+ (co.ASSERT_MY_BIRTH_SECONDS, 10019, rbr.INVALID_BLOCK),
1995
+ (co.ASSERT_MY_BIRTH_SECONDS, 10020, rbr.NEW_PEAK), # <- coin birth time
1996
+ (co.ASSERT_MY_BIRTH_SECONDS, 10021, rbr.INVALID_BLOCK),
1997
+ # SECONDS RELATIVE
1998
+ (co.ASSERT_SECONDS_RELATIVE, -2, rbr.NEW_PEAK),
1999
+ (co.ASSERT_SECONDS_RELATIVE, -1, rbr.NEW_PEAK),
2000
+ (co.ASSERT_SECONDS_RELATIVE, 0, rbr.NEW_PEAK), # <- birth time
2001
+ (co.ASSERT_SECONDS_RELATIVE, 1, rbr.INVALID_BLOCK),
2002
+ (co.ASSERT_SECONDS_RELATIVE, 9, rbr.INVALID_BLOCK),
2003
+ (co.ASSERT_SECONDS_RELATIVE, 10, rbr.INVALID_BLOCK), # <- current block time
2004
+ (co.ASSERT_SECONDS_RELATIVE, 11, rbr.INVALID_BLOCK),
2005
+ # BEFORE SECONDS RELATIVE
2006
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, -2, rbr.INVALID_BLOCK),
2007
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, -1, rbr.INVALID_BLOCK),
2008
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 0, rbr.INVALID_BLOCK), # <- birth time
2009
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 1, rbr.NEW_PEAK),
2010
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 9, rbr.NEW_PEAK),
2011
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 10, rbr.NEW_PEAK), # <- current block time
2012
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 11, rbr.NEW_PEAK),
2013
+ # HEIGHT RELATIVE
2014
+ (co.ASSERT_HEIGHT_RELATIVE, -2, rbr.NEW_PEAK),
2015
+ (co.ASSERT_HEIGHT_RELATIVE, -1, rbr.NEW_PEAK),
2016
+ (co.ASSERT_HEIGHT_RELATIVE, 0, rbr.NEW_PEAK),
2017
+ (co.ASSERT_HEIGHT_RELATIVE, 1, rbr.INVALID_BLOCK),
2018
+ # BEFORE HEIGHT RELATIVE
2019
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, -2, rbr.INVALID_BLOCK),
2020
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, -1, rbr.INVALID_BLOCK),
2021
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, 0, rbr.INVALID_BLOCK),
2022
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, 1, rbr.NEW_PEAK),
2023
+ # HEIGHT ABSOLUTE
2024
+ (co.ASSERT_HEIGHT_ABSOLUTE, 1, rbr.NEW_PEAK),
2025
+ (co.ASSERT_HEIGHT_ABSOLUTE, 2, rbr.NEW_PEAK),
2026
+ (co.ASSERT_HEIGHT_ABSOLUTE, 3, rbr.INVALID_BLOCK),
2027
+ (co.ASSERT_HEIGHT_ABSOLUTE, 4, rbr.INVALID_BLOCK),
2028
+ # BEFORE HEIGHT ABSOLUTE
2029
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 1, rbr.INVALID_BLOCK),
2030
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 2, rbr.INVALID_BLOCK),
2031
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 3, rbr.NEW_PEAK),
2032
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 4, rbr.NEW_PEAK),
2033
+ # SECONDS ABSOLUTE
2034
+ # genesis timestamp is 10000 and each block is 10 seconds
2035
+ (co.ASSERT_SECONDS_ABSOLUTE, 10019, rbr.NEW_PEAK),
2036
+ (co.ASSERT_SECONDS_ABSOLUTE, 10020, rbr.NEW_PEAK), # <- previous tx-block
2037
+ (co.ASSERT_SECONDS_ABSOLUTE, 10021, rbr.INVALID_BLOCK),
2038
+ (co.ASSERT_SECONDS_ABSOLUTE, 10029, rbr.INVALID_BLOCK),
2039
+ (co.ASSERT_SECONDS_ABSOLUTE, 10030, rbr.INVALID_BLOCK), # <- current block
2040
+ (co.ASSERT_SECONDS_ABSOLUTE, 10031, rbr.INVALID_BLOCK),
2041
+ (co.ASSERT_SECONDS_ABSOLUTE, 10032, rbr.INVALID_BLOCK),
2042
+ # BEFORE SECONDS ABSOLUTE
2043
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10019, rbr.INVALID_BLOCK),
2044
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10020, rbr.INVALID_BLOCK), # <- previous tx-block
2045
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10021, rbr.NEW_PEAK),
2046
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10029, rbr.NEW_PEAK),
2047
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10030, rbr.NEW_PEAK), # <- current block
2048
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10031, rbr.NEW_PEAK),
2049
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10032, rbr.NEW_PEAK),
2050
+ ],
2051
+ )
2052
+ async def test_timelock_conditions(
2053
+ self, opcode: ConditionOpcode, lock_value: int, expected: AddBlockResult, bt: BlockTools
2054
+ ) -> None:
2055
+ async with make_empty_blockchain(bt.constants) as b:
2056
+ blocks = bt.get_consecutive_blocks(
2057
+ 3,
2058
+ guarantee_transaction_block=True,
2059
+ farmer_reward_puzzle_hash=bt.pool_ph,
2060
+ pool_reward_puzzle_hash=bt.pool_ph,
2061
+ genesis_timestamp=uint64(10_000),
2062
+ time_per_block=10,
2063
+ )
2064
+ for bl in blocks:
2065
+ await _validate_and_add_block(b, bl)
2066
+
2067
+ wt: WalletTool = bt.get_pool_wallet_tool()
2068
+
2069
+ conditions = {opcode: [ConditionWithArgs(opcode, [int_to_bytes(lock_value)])]}
2070
+
2071
+ coin = blocks[-1].get_included_reward_coins()[0]
2072
+ tx = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin, condition_dic=conditions)
2073
+
2074
+ blocks = bt.get_consecutive_blocks(
2075
+ 1,
2076
+ block_list_input=blocks,
2077
+ guarantee_transaction_block=True,
2078
+ transaction_data=tx,
2079
+ time_per_block=10,
2080
+ )
2081
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
2082
+ diff = b.constants.DIFFICULTY_STARTING
2083
+ pre_validation_results: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
2084
+ b.constants,
2085
+ b,
2086
+ [blocks[-1]],
2087
+ b.pool,
2088
+ {},
2089
+ sub_slot_iters=ssi,
2090
+ difficulty=diff,
2091
+ prev_ses_block=None,
2092
+ validate_signatures=True,
2093
+ )
2094
+ assert pre_validation_results is not None
2095
+ assert (await b.add_block(blocks[-1], pre_validation_results[0], None, sub_slot_iters=ssi))[0] == expected
2096
+
2097
+ if expected == AddBlockResult.NEW_PEAK:
2098
+ # ensure coin was in fact spent
2099
+ c = await b.coin_store.get_coin_record(coin.name())
2100
+ assert c is not None and c.spent
2101
+
2102
+ @pytest.mark.anyio
2103
+ @pytest.mark.parametrize(
2104
+ "opcode",
2105
+ [
2106
+ ConditionOpcode.AGG_SIG_ME,
2107
+ ConditionOpcode.AGG_SIG_UNSAFE,
2108
+ ConditionOpcode.AGG_SIG_PARENT,
2109
+ ConditionOpcode.AGG_SIG_PUZZLE,
2110
+ ConditionOpcode.AGG_SIG_AMOUNT,
2111
+ ConditionOpcode.AGG_SIG_PUZZLE_AMOUNT,
2112
+ ConditionOpcode.AGG_SIG_PARENT_AMOUNT,
2113
+ ConditionOpcode.AGG_SIG_PARENT_PUZZLE,
2114
+ ],
2115
+ )
2116
+ @pytest.mark.parametrize("with_garbage", [True, False])
2117
+ async def test_aggsig_garbage(
2118
+ self,
2119
+ empty_blockchain: Blockchain,
2120
+ opcode: ConditionOpcode,
2121
+ with_garbage: bool,
2122
+ bt: BlockTools,
2123
+ consensus_mode: ConsensusMode,
2124
+ ) -> None:
2125
+ b = empty_blockchain
2126
+ blocks = bt.get_consecutive_blocks(
2127
+ 3,
2128
+ guarantee_transaction_block=True,
2129
+ farmer_reward_puzzle_hash=bt.pool_ph,
2130
+ pool_reward_puzzle_hash=bt.pool_ph,
2131
+ genesis_timestamp=uint64(10_000),
2132
+ time_per_block=10,
2133
+ )
2134
+ await _validate_and_add_block(empty_blockchain, blocks[0])
2135
+ await _validate_and_add_block(empty_blockchain, blocks[1])
2136
+ await _validate_and_add_block(empty_blockchain, blocks[2])
2137
+
2138
+ wt: WalletTool = bt.get_pool_wallet_tool()
2139
+
2140
+ tx1 = wt.generate_signed_transaction(
2141
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2142
+ )
2143
+ coin1: Coin = tx1.additions()[0]
2144
+ secret_key = wt.get_private_key_for_puzzle_hash(coin1.puzzle_hash)
2145
+ synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH)
2146
+ public_key = synthetic_secret_key.get_g1()
2147
+
2148
+ args = [bytes(public_key), b"msg"] + ([b"garbage"] if with_garbage else [])
2149
+ conditions = {opcode: [ConditionWithArgs(opcode, args)]}
2150
+
2151
+ tx2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin1, condition_dic=conditions)
2152
+ assert coin1 in tx2.removals()
2153
+
2154
+ bundles = SpendBundle.aggregate([tx1, tx2])
2155
+ blocks = bt.get_consecutive_blocks(
2156
+ 1,
2157
+ block_list_input=blocks,
2158
+ guarantee_transaction_block=True,
2159
+ transaction_data=bundles,
2160
+ time_per_block=10,
2161
+ )
2162
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
2163
+ diff = b.constants.DIFFICULTY_STARTING
2164
+ pre_validation_results: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
2165
+ b.constants,
2166
+ b,
2167
+ [blocks[-1]],
2168
+ b.pool,
2169
+ {},
2170
+ sub_slot_iters=ssi,
2171
+ difficulty=diff,
2172
+ prev_ses_block=None,
2173
+ validate_signatures=False,
2174
+ )
2175
+ # Ignore errors from pre-validation, we are testing block_body_validation
2176
+ repl_preval_results = replace(pre_validation_results[0], error=None, required_iters=uint64(1))
2177
+ res, error, state_change = await b.add_block(blocks[-1], repl_preval_results, None, sub_slot_iters=ssi)
2178
+ assert res == AddBlockResult.NEW_PEAK
2179
+ assert error is None
2180
+ assert state_change is not None and state_change.fork_height == uint32(2)
2181
+
2182
+ @pytest.mark.anyio
2183
+ @pytest.mark.parametrize("with_garbage", [True, False])
2184
+ @pytest.mark.parametrize(
2185
+ "opcode,lock_value,expected",
2186
+ [
2187
+ # we don't allow any birth assertions, not
2188
+ # relative time locks on ephemeral coins. This test is only for
2189
+ # ephemeral coins, so these cases should always fail
2190
+ # MY BIRHT HEIGHT
2191
+ (co.ASSERT_MY_BIRTH_HEIGHT, -1, rbr.INVALID_BLOCK),
2192
+ (co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, rbr.INVALID_BLOCK),
2193
+ (co.ASSERT_MY_BIRTH_HEIGHT, 2, rbr.INVALID_BLOCK),
2194
+ (co.ASSERT_MY_BIRTH_HEIGHT, 3, rbr.INVALID_BLOCK),
2195
+ # MY BIRHT SECONDS
2196
+ (co.ASSERT_MY_BIRTH_SECONDS, -1, rbr.INVALID_BLOCK),
2197
+ (co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, rbr.INVALID_BLOCK),
2198
+ (co.ASSERT_MY_BIRTH_SECONDS, 10029, rbr.INVALID_BLOCK),
2199
+ (co.ASSERT_MY_BIRTH_SECONDS, 10030, rbr.INVALID_BLOCK),
2200
+ (co.ASSERT_MY_BIRTH_SECONDS, 10031, rbr.INVALID_BLOCK),
2201
+ # SECONDS RELATIVE
2202
+ # genesis timestamp is 10000 and each block is 10 seconds
2203
+ (co.ASSERT_SECONDS_RELATIVE, -2, rbr.INVALID_BLOCK),
2204
+ (co.ASSERT_SECONDS_RELATIVE, -1, rbr.INVALID_BLOCK),
2205
+ (co.ASSERT_SECONDS_RELATIVE, 0, rbr.INVALID_BLOCK),
2206
+ (co.ASSERT_SECONDS_RELATIVE, 1, rbr.INVALID_BLOCK),
2207
+ # BEFORE SECONDS RELATIVE
2208
+ # relative conditions are not allowed on ephemeral spends
2209
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, -2, rbr.INVALID_BLOCK),
2210
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, -1, rbr.INVALID_BLOCK),
2211
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 0, rbr.INVALID_BLOCK),
2212
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 10, rbr.INVALID_BLOCK),
2213
+ (co.ASSERT_BEFORE_SECONDS_RELATIVE, 0x10000000000000000, rbr.INVALID_BLOCK),
2214
+ # HEIGHT RELATIVE
2215
+ (co.ASSERT_HEIGHT_RELATIVE, -2, rbr.INVALID_BLOCK),
2216
+ (co.ASSERT_HEIGHT_RELATIVE, -1, rbr.INVALID_BLOCK),
2217
+ (co.ASSERT_HEIGHT_RELATIVE, 0, rbr.INVALID_BLOCK),
2218
+ (co.ASSERT_HEIGHT_RELATIVE, 1, rbr.INVALID_BLOCK),
2219
+ # BEFORE HEIGHT RELATIVE
2220
+ # relative conditions are not allowed on ephemeral spends
2221
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, -2, rbr.INVALID_BLOCK),
2222
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, -1, rbr.INVALID_BLOCK),
2223
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, 0, rbr.INVALID_BLOCK),
2224
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, 1, rbr.INVALID_BLOCK),
2225
+ (co.ASSERT_BEFORE_HEIGHT_RELATIVE, 0x100000000, rbr.INVALID_BLOCK),
2226
+ # HEIGHT ABSOLUTE
2227
+ (co.ASSERT_HEIGHT_ABSOLUTE, 2, rbr.NEW_PEAK),
2228
+ (co.ASSERT_HEIGHT_ABSOLUTE, 3, rbr.INVALID_BLOCK),
2229
+ (co.ASSERT_HEIGHT_ABSOLUTE, 4, rbr.INVALID_BLOCK),
2230
+ # BEFORE HEIGHT ABSOLUTE
2231
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 2, rbr.INVALID_BLOCK),
2232
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 3, rbr.NEW_PEAK),
2233
+ (co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 4, rbr.NEW_PEAK),
2234
+ # SECONDS ABSOLUTE
2235
+ # genesis timestamp is 10000 and each block is 10 seconds
2236
+ (co.ASSERT_SECONDS_ABSOLUTE, 10020, rbr.NEW_PEAK), # <- previous tx-block
2237
+ (co.ASSERT_SECONDS_ABSOLUTE, 10021, rbr.INVALID_BLOCK),
2238
+ (co.ASSERT_SECONDS_ABSOLUTE, 10029, rbr.INVALID_BLOCK),
2239
+ (co.ASSERT_SECONDS_ABSOLUTE, 10030, rbr.INVALID_BLOCK), # <- current tx-block
2240
+ (co.ASSERT_SECONDS_ABSOLUTE, 10031, rbr.INVALID_BLOCK),
2241
+ (co.ASSERT_SECONDS_ABSOLUTE, 10032, rbr.INVALID_BLOCK),
2242
+ # BEFORE SECONDS ABSOLUTE
2243
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10020, rbr.INVALID_BLOCK),
2244
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10021, rbr.NEW_PEAK),
2245
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10030, rbr.NEW_PEAK),
2246
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10031, rbr.NEW_PEAK),
2247
+ (co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10032, rbr.NEW_PEAK),
2248
+ ],
2249
+ )
2250
+ async def test_ephemeral_timelock(
2251
+ self, opcode: ConditionOpcode, lock_value: int, expected: AddBlockResult, with_garbage: bool, bt: BlockTools
2252
+ ) -> None:
2253
+ async with make_empty_blockchain(bt.constants) as b:
2254
+ blocks = bt.get_consecutive_blocks(
2255
+ 3,
2256
+ guarantee_transaction_block=True,
2257
+ farmer_reward_puzzle_hash=bt.pool_ph,
2258
+ pool_reward_puzzle_hash=bt.pool_ph,
2259
+ genesis_timestamp=uint64(10_000),
2260
+ time_per_block=10,
2261
+ )
2262
+ await _validate_and_add_block(b, blocks[0])
2263
+ await _validate_and_add_block(b, blocks[1])
2264
+ await _validate_and_add_block(b, blocks[2])
2265
+
2266
+ wt: WalletTool = bt.get_pool_wallet_tool()
2267
+
2268
+ conditions = {
2269
+ opcode: [ConditionWithArgs(opcode, [int_to_bytes(lock_value)] + ([b"garbage"] if with_garbage else []))]
2270
+ }
2271
+
2272
+ tx1 = wt.generate_signed_transaction(
2273
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2274
+ )
2275
+ coin1: Coin = tx1.additions()[0]
2276
+ tx2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin1, condition_dic=conditions)
2277
+ assert coin1 in tx2.removals()
2278
+ coin2: Coin = tx2.additions()[0]
2279
+
2280
+ bundles = SpendBundle.aggregate([tx1, tx2])
2281
+ blocks = bt.get_consecutive_blocks(
2282
+ 1,
2283
+ block_list_input=blocks,
2284
+ guarantee_transaction_block=True,
2285
+ transaction_data=bundles,
2286
+ time_per_block=10,
2287
+ )
2288
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
2289
+ diff = b.constants.DIFFICULTY_STARTING
2290
+ pre_validation_results: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
2291
+ b.constants,
2292
+ b,
2293
+ [blocks[-1]],
2294
+ b.pool,
2295
+ {},
2296
+ sub_slot_iters=ssi,
2297
+ difficulty=diff,
2298
+ prev_ses_block=None,
2299
+ validate_signatures=True,
2300
+ )
2301
+ assert pre_validation_results is not None
2302
+ assert (await b.add_block(blocks[-1], pre_validation_results[0], None, sub_slot_iters=ssi))[0] == expected
2303
+
2304
+ if expected == AddBlockResult.NEW_PEAK:
2305
+ # ensure coin1 was in fact spent
2306
+ c = await b.coin_store.get_coin_record(coin1.name())
2307
+ assert c is not None and c.spent
2308
+ # ensure coin2 was NOT spent
2309
+ c = await b.coin_store.get_coin_record(coin2.name())
2310
+ assert c is not None and not c.spent
2311
+
2312
+ @pytest.mark.anyio
2313
+ async def test_not_tx_block_but_has_data(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2314
+ # 1
2315
+ blocks = bt.get_consecutive_blocks(1)
2316
+ while blocks[-1].foliage_transaction_block is not None:
2317
+ await _validate_and_add_block(empty_blockchain, blocks[-1])
2318
+ blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
2319
+ original_block: FullBlock = blocks[-1]
2320
+
2321
+ block = recursive_replace(original_block, "transactions_generator", SerializedProgram.to(None))
2322
+ await _validate_and_add_block(
2323
+ empty_blockchain, block, expected_error=Err.NOT_BLOCK_BUT_HAS_DATA, skip_prevalidation=True
2324
+ )
2325
+ h = std_hash(b"")
2326
+ i = uint64(1)
2327
+ block = recursive_replace(
2328
+ original_block,
2329
+ "transactions_info",
2330
+ TransactionsInfo(h, h, G2Element(), uint64(1), uint64(1), []),
2331
+ )
2332
+ await _validate_and_add_block(
2333
+ empty_blockchain, block, expected_error=Err.NOT_BLOCK_BUT_HAS_DATA, skip_prevalidation=True
2334
+ )
2335
+
2336
+ block = recursive_replace(original_block, "transactions_generator_ref_list", [i])
2337
+ await _validate_and_add_block(
2338
+ empty_blockchain, block, expected_error=Err.NOT_BLOCK_BUT_HAS_DATA, skip_prevalidation=True
2339
+ )
2340
+
2341
+ @pytest.mark.anyio
2342
+ async def test_tx_block_missing_data(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2343
+ # 2
2344
+ b = empty_blockchain
2345
+ blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
2346
+ await _validate_and_add_block(b, blocks[0])
2347
+ block = recursive_replace(
2348
+ blocks[-1],
2349
+ "foliage_transaction_block",
2350
+ None,
2351
+ )
2352
+ await _validate_and_add_block_multi_error(
2353
+ b, block, [Err.IS_TRANSACTION_BLOCK_BUT_NO_DATA, Err.INVALID_FOLIAGE_BLOCK_PRESENCE]
2354
+ )
2355
+
2356
+ block = recursive_replace(
2357
+ blocks[-1],
2358
+ "transactions_info",
2359
+ None,
2360
+ )
2361
+ with pytest.raises(AssertionError):
2362
+ await _validate_and_add_block_multi_error(
2363
+ b, block, [Err.IS_TRANSACTION_BLOCK_BUT_NO_DATA, Err.INVALID_FOLIAGE_BLOCK_PRESENCE]
2364
+ )
2365
+
2366
+ @pytest.mark.anyio
2367
+ async def test_invalid_transactions_info_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2368
+ # 3
2369
+ b = empty_blockchain
2370
+ blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
2371
+ await _validate_and_add_block(b, blocks[0])
2372
+ h = std_hash(b"")
2373
+ block = recursive_replace(
2374
+ blocks[-1],
2375
+ "foliage_transaction_block.transactions_info_hash",
2376
+ h,
2377
+ )
2378
+ block = recursive_replace(
2379
+ block, "foliage.foliage_transaction_block_hash", std_hash(block.foliage_transaction_block)
2380
+ )
2381
+ new_m = block.foliage.foliage_transaction_block_hash
2382
+ assert new_m is not None
2383
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
2384
+ block = recursive_replace(block, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2385
+
2386
+ await _validate_and_add_block(b, block, expected_error=Err.INVALID_TRANSACTIONS_INFO_HASH)
2387
+
2388
+ @pytest.mark.anyio
2389
+ async def test_invalid_transactions_block_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2390
+ # 4
2391
+ b = empty_blockchain
2392
+ blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
2393
+ await _validate_and_add_block(b, blocks[0])
2394
+ h = std_hash(b"")
2395
+ block = recursive_replace(blocks[-1], "foliage.foliage_transaction_block_hash", h)
2396
+ new_m = block.foliage.foliage_transaction_block_hash
2397
+ assert new_m is not None
2398
+ new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
2399
+ block = recursive_replace(block, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2400
+
2401
+ await _validate_and_add_block(b, block, expected_error=Err.INVALID_FOLIAGE_BLOCK_HASH)
2402
+
2403
+ @pytest.mark.anyio
2404
+ async def test_invalid_reward_claims(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2405
+ # 5
2406
+ b = empty_blockchain
2407
+ blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
2408
+ await _validate_and_add_block(b, blocks[0])
2409
+ block: FullBlock = blocks[-1]
2410
+
2411
+ # Too few
2412
+ assert block.transactions_info is not None
2413
+ too_few_reward_claims = block.transactions_info.reward_claims_incorporated[:-1]
2414
+ block_2: FullBlock = recursive_replace(
2415
+ block, "transactions_info.reward_claims_incorporated", too_few_reward_claims
2416
+ )
2417
+ assert block_2.transactions_info is not None
2418
+ block_2 = recursive_replace(
2419
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2420
+ )
2421
+
2422
+ assert block_2.foliage_transaction_block is not None
2423
+ block_2 = recursive_replace(
2424
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2425
+ )
2426
+ new_m = block_2.foliage.foliage_transaction_block_hash
2427
+ assert new_m is not None
2428
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2429
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2430
+
2431
+ await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_REWARD_COINS, skip_prevalidation=True)
2432
+
2433
+ # Too many
2434
+ h = std_hash(b"")
2435
+ too_many_reward_claims = block.transactions_info.reward_claims_incorporated + [
2436
+ Coin(h, h, too_few_reward_claims[0].amount)
2437
+ ]
2438
+ block_2 = recursive_replace(block, "transactions_info.reward_claims_incorporated", too_many_reward_claims)
2439
+ assert block_2.transactions_info is not None
2440
+ block_2 = recursive_replace(
2441
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2442
+ )
2443
+ assert block_2.foliage_transaction_block is not None
2444
+ block_2 = recursive_replace(
2445
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2446
+ )
2447
+ new_m = block_2.foliage.foliage_transaction_block_hash
2448
+ assert new_m is not None
2449
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2450
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2451
+
2452
+ await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_REWARD_COINS, skip_prevalidation=True)
2453
+
2454
+ # Duplicates
2455
+ duplicate_reward_claims = block.transactions_info.reward_claims_incorporated + [
2456
+ block.transactions_info.reward_claims_incorporated[-1]
2457
+ ]
2458
+ block_2 = recursive_replace(block, "transactions_info.reward_claims_incorporated", duplicate_reward_claims)
2459
+ assert block_2.transactions_info is not None
2460
+ block_2 = recursive_replace(
2461
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2462
+ )
2463
+ assert block_2.foliage_transaction_block is not None
2464
+ block_2 = recursive_replace(
2465
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2466
+ )
2467
+ new_m = block_2.foliage.foliage_transaction_block_hash
2468
+ assert new_m is not None
2469
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2470
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2471
+
2472
+ await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_REWARD_COINS, skip_prevalidation=True)
2473
+
2474
+ @pytest.mark.anyio
2475
+ async def test_invalid_transactions_generator_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2476
+ # 7
2477
+ b = empty_blockchain
2478
+ blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
2479
+ await _validate_and_add_block(b, blocks[0])
2480
+
2481
+ # No tx should have all zeroes
2482
+ block: FullBlock = blocks[-1]
2483
+ block_2 = recursive_replace(block, "transactions_info.generator_root", bytes([1] * 32))
2484
+ block_2 = recursive_replace(
2485
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2486
+ )
2487
+ block_2 = recursive_replace(
2488
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2489
+ )
2490
+ new_m = block_2.foliage.foliage_transaction_block_hash
2491
+ assert new_m is not None
2492
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2493
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2494
+
2495
+ await _validate_and_add_block(
2496
+ b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_HASH, skip_prevalidation=True
2497
+ )
2498
+
2499
+ await _validate_and_add_block(b, blocks[1])
2500
+ blocks = bt.get_consecutive_blocks(
2501
+ 2,
2502
+ block_list_input=blocks,
2503
+ guarantee_transaction_block=True,
2504
+ farmer_reward_puzzle_hash=bt.pool_ph,
2505
+ pool_reward_puzzle_hash=bt.pool_ph,
2506
+ )
2507
+ await _validate_and_add_block(b, blocks[2])
2508
+ await _validate_and_add_block(b, blocks[3])
2509
+
2510
+ wt: WalletTool = bt.get_pool_wallet_tool()
2511
+ tx = wt.generate_signed_transaction(
2512
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2513
+ )
2514
+ blocks = bt.get_consecutive_blocks(
2515
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2516
+ )
2517
+
2518
+ # Non empty generator hash must be correct
2519
+ block = blocks[-1]
2520
+ block_2 = recursive_replace(block, "transactions_info.generator_root", bytes([0] * 32))
2521
+ block_2 = recursive_replace(
2522
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2523
+ )
2524
+ block_2 = recursive_replace(
2525
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2526
+ )
2527
+ new_m = block_2.foliage.foliage_transaction_block_hash
2528
+ assert new_m is not None
2529
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2530
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2531
+ await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_HASH)
2532
+
2533
+ @pytest.mark.anyio
2534
+ async def test_invalid_transactions_ref_list(
2535
+ self, empty_blockchain: Blockchain, bt: BlockTools, consensus_mode: ConsensusMode
2536
+ ) -> None:
2537
+ # No generator should have [1]s for the root
2538
+ b = empty_blockchain
2539
+ blocks = bt.get_consecutive_blocks(
2540
+ 3,
2541
+ guarantee_transaction_block=True,
2542
+ farmer_reward_puzzle_hash=bt.pool_ph,
2543
+ pool_reward_puzzle_hash=bt.pool_ph,
2544
+ )
2545
+ await _validate_and_add_block(b, blocks[0])
2546
+ await _validate_and_add_block(b, blocks[1])
2547
+
2548
+ block: FullBlock = blocks[-1]
2549
+ block_2 = recursive_replace(block, "transactions_info.generator_refs_root", bytes([0] * 32))
2550
+ block_2 = recursive_replace(
2551
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2552
+ )
2553
+ block_2 = recursive_replace(
2554
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2555
+ )
2556
+ new_m = block_2.foliage.foliage_transaction_block_hash
2557
+ assert new_m is not None
2558
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2559
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2560
+
2561
+ await _validate_and_add_block(
2562
+ b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_REFS_ROOT, skip_prevalidation=True
2563
+ )
2564
+
2565
+ # No generator should have no refs list
2566
+ block_2 = recursive_replace(block, "transactions_generator_ref_list", [uint32(0)])
2567
+
2568
+ await _validate_and_add_block(
2569
+ b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_REFS_ROOT, skip_prevalidation=True
2570
+ )
2571
+
2572
+ # Hash should be correct when there is a ref list
2573
+ await _validate_and_add_block(b, blocks[-1])
2574
+ wt: WalletTool = bt.get_pool_wallet_tool()
2575
+ tx = wt.generate_signed_transaction(
2576
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2577
+ )
2578
+ blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, guarantee_transaction_block=False)
2579
+ for block in blocks[-5:]:
2580
+ await _validate_and_add_block(b, block)
2581
+
2582
+ blocks = bt.get_consecutive_blocks(
2583
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2584
+ )
2585
+ await _validate_and_add_block(b, blocks[-1])
2586
+ assert blocks[-1].transactions_generator is not None
2587
+
2588
+ blocks = bt.get_consecutive_blocks(
2589
+ 1,
2590
+ block_list_input=blocks,
2591
+ guarantee_transaction_block=True,
2592
+ transaction_data=tx,
2593
+ block_refs=[blocks[-1].height],
2594
+ )
2595
+ block = blocks[-1]
2596
+ # once the hard fork activated, we no longer use this form of block
2597
+ # compression anymore
2598
+ assert len(block.transactions_generator_ref_list) == 0
2599
+
2600
+ @pytest.mark.anyio
2601
+ async def test_cost_exceeds_max(
2602
+ self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
2603
+ ) -> None:
2604
+ # 7
2605
+ b = empty_blockchain
2606
+ blocks = bt.get_consecutive_blocks(
2607
+ 3,
2608
+ guarantee_transaction_block=True,
2609
+ farmer_reward_puzzle_hash=bt.pool_ph,
2610
+ pool_reward_puzzle_hash=bt.pool_ph,
2611
+ )
2612
+ await _validate_and_add_block(b, blocks[0])
2613
+ await _validate_and_add_block(b, blocks[1])
2614
+ await _validate_and_add_block(b, blocks[2])
2615
+
2616
+ wt: WalletTool = bt.get_pool_wallet_tool()
2617
+
2618
+ condition_dict: Dict[ConditionOpcode, List[ConditionWithArgs]] = {ConditionOpcode.CREATE_COIN: []}
2619
+ for i in range(7_000):
2620
+ output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt.pool_ph, int_to_bytes(i)])
2621
+ condition_dict[ConditionOpcode.CREATE_COIN].append(output)
2622
+
2623
+ tx = wt.generate_signed_transaction(
2624
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0], condition_dic=condition_dict
2625
+ )
2626
+
2627
+ blocks = bt.get_consecutive_blocks(
2628
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2629
+ )
2630
+
2631
+ assert blocks[-1].transactions_generator is not None
2632
+ block_generator = BlockGenerator(blocks[-1].transactions_generator, [])
2633
+ npc_result = get_name_puzzle_conditions(
2634
+ block_generator,
2635
+ b.constants.MAX_BLOCK_COST_CLVM * 1000,
2636
+ mempool_mode=False,
2637
+ height=softfork_height,
2638
+ constants=bt.constants,
2639
+ )
2640
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
2641
+ diff = b.constants.DIFFICULTY_STARTING
2642
+ err = (
2643
+ await b.add_block(
2644
+ blocks[-1],
2645
+ PreValidationResult(None, uint64(1), npc_result.conds, True, uint32(0)),
2646
+ None,
2647
+ sub_slot_iters=ssi,
2648
+ )
2649
+ )[1]
2650
+ assert err in [Err.BLOCK_COST_EXCEEDS_MAX]
2651
+ results: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
2652
+ b.constants,
2653
+ b,
2654
+ [blocks[-1]],
2655
+ b.pool,
2656
+ {},
2657
+ sub_slot_iters=ssi,
2658
+ difficulty=diff,
2659
+ prev_ses_block=None,
2660
+ validate_signatures=False,
2661
+ )
2662
+ assert results is not None
2663
+ assert Err(results[0].error) == Err.BLOCK_COST_EXCEEDS_MAX
2664
+
2665
+ @pytest.mark.anyio
2666
+ async def test_clvm_must_not_fail(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2667
+ # 8
2668
+ pass
2669
+
2670
+ @pytest.mark.anyio
2671
+ async def test_invalid_cost_in_block(
2672
+ self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
2673
+ ) -> None:
2674
+ # 9
2675
+ b = empty_blockchain
2676
+ blocks = bt.get_consecutive_blocks(
2677
+ 3,
2678
+ guarantee_transaction_block=True,
2679
+ farmer_reward_puzzle_hash=bt.pool_ph,
2680
+ pool_reward_puzzle_hash=bt.pool_ph,
2681
+ )
2682
+ await _validate_and_add_block(b, blocks[0])
2683
+ await _validate_and_add_block(b, blocks[1])
2684
+ await _validate_and_add_block(b, blocks[2])
2685
+
2686
+ wt: WalletTool = bt.get_pool_wallet_tool()
2687
+
2688
+ tx = wt.generate_signed_transaction(
2689
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2690
+ )
2691
+
2692
+ blocks = bt.get_consecutive_blocks(
2693
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2694
+ )
2695
+ block: FullBlock = blocks[-1]
2696
+
2697
+ # zero
2698
+ block_2: FullBlock = recursive_replace(block, "transactions_info.cost", uint64(0))
2699
+ assert block_2.transactions_info is not None
2700
+ block_2 = recursive_replace(
2701
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2702
+ )
2703
+ assert block_2.foliage_transaction_block is not None
2704
+ block_2 = recursive_replace(
2705
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2706
+ )
2707
+ new_m = block_2.foliage.foliage_transaction_block_hash
2708
+ assert new_m is not None
2709
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2710
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2711
+ assert block_2.transactions_generator is not None
2712
+ block_generator = BlockGenerator(block_2.transactions_generator, [])
2713
+ assert block.transactions_info is not None
2714
+ npc_result = get_name_puzzle_conditions(
2715
+ block_generator,
2716
+ min(b.constants.MAX_BLOCK_COST_CLVM * 1000, block.transactions_info.cost),
2717
+ mempool_mode=False,
2718
+ height=softfork_height,
2719
+ constants=bt.constants,
2720
+ )
2721
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
2722
+ _, err, _ = await b.add_block(
2723
+ block_2, PreValidationResult(None, uint64(1), npc_result.conds, False, uint32(0)), None, sub_slot_iters=ssi
2724
+ )
2725
+ assert err == Err.INVALID_BLOCK_COST
2726
+
2727
+ # too low
2728
+ block_2 = recursive_replace(block, "transactions_info.cost", uint64(1))
2729
+ assert block_2.transactions_info is not None
2730
+ block_2 = recursive_replace(
2731
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2732
+ )
2733
+ assert block_2.foliage_transaction_block is not None
2734
+ block_2 = recursive_replace(
2735
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2736
+ )
2737
+ new_m = block_2.foliage.foliage_transaction_block_hash
2738
+ assert new_m is not None
2739
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2740
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2741
+ assert block_2.transactions_generator is not None
2742
+ block_generator = BlockGenerator(block_2.transactions_generator, [])
2743
+ assert block.transactions_info is not None
2744
+ npc_result = get_name_puzzle_conditions(
2745
+ block_generator,
2746
+ min(b.constants.MAX_BLOCK_COST_CLVM * 1000, block.transactions_info.cost),
2747
+ mempool_mode=False,
2748
+ height=softfork_height,
2749
+ constants=bt.constants,
2750
+ )
2751
+ _, err, _ = await b.add_block(
2752
+ block_2, PreValidationResult(None, uint64(1), npc_result.conds, False, uint32(0)), None, sub_slot_iters=ssi
2753
+ )
2754
+ assert err == Err.INVALID_BLOCK_COST
2755
+
2756
+ # too high
2757
+ block_2 = recursive_replace(block, "transactions_info.cost", uint64(1000000))
2758
+ assert block_2.transactions_info is not None
2759
+ block_2 = recursive_replace(
2760
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
2761
+ )
2762
+ assert block_2.foliage_transaction_block is not None
2763
+ block_2 = recursive_replace(
2764
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2765
+ )
2766
+ new_m = block_2.foliage.foliage_transaction_block_hash
2767
+ assert new_m is not None
2768
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2769
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2770
+
2771
+ assert block_2.transactions_generator is not None
2772
+ block_generator = BlockGenerator(block_2.transactions_generator, [])
2773
+ max_cost = (
2774
+ min(b.constants.MAX_BLOCK_COST_CLVM * 1000, block.transactions_info.cost)
2775
+ if block.transactions_info is not None
2776
+ else b.constants.MAX_BLOCK_COST_CLVM * 1000
2777
+ )
2778
+ npc_result = get_name_puzzle_conditions(
2779
+ block_generator, max_cost, mempool_mode=False, height=softfork_height, constants=bt.constants
2780
+ )
2781
+
2782
+ result, err, _ = await b.add_block(
2783
+ block_2, PreValidationResult(None, uint64(1), npc_result.conds, False, uint32(0)), None, sub_slot_iters=ssi
2784
+ )
2785
+ assert err == Err.INVALID_BLOCK_COST
2786
+
2787
+ # when the CLVM program exceeds cost during execution, it will fail with
2788
+ # a general runtime error. The previous test tests this.
2789
+
2790
+ @pytest.mark.anyio
2791
+ async def test_max_coin_amount(self, db_version: int, bt: BlockTools) -> None:
2792
+ # 10
2793
+ # TODO: fix, this is not reaching validation. Because we can't create a block with such amounts due to uint64
2794
+ # limit in Coin
2795
+ pass
2796
+ #
2797
+ # with TempKeyring() as keychain:
2798
+ # new_test_constants = bt.constants.replace(
2799
+ # GENESIS_PRE_FARM_POOL_PUZZLE_HASH=bt.pool_ph,
2800
+ # GENESIS_PRE_FARM_FARMER_PUZZLE_HASH=bt.pool_ph,
2801
+ # )
2802
+ # b, db_wrapper = await create_blockchain(new_test_constants, db_version)
2803
+ # bt_2 = await create_block_tools_async(constants=new_test_constants, keychain=keychain)
2804
+ # bt_2.constants = bt_2.constants.replace(
2805
+ # GENESIS_PRE_FARM_POOL_PUZZLE_HASH=bt.pool_ph,
2806
+ # GENESIS_PRE_FARM_FARMER_PUZZLE_HASH=bt.pool_ph,
2807
+ # )
2808
+ # blocks = bt_2.get_consecutive_blocks(
2809
+ # 3,
2810
+ # guarantee_transaction_block=True,
2811
+ # farmer_reward_puzzle_hash=bt.pool_ph,
2812
+ # pool_reward_puzzle_hash=bt.pool_ph,
2813
+ # )
2814
+ # assert (await b.add_block(blocks[0]))[0] == AddBlockResult.NEW_PEAK
2815
+ # assert (await b.add_block(blocks[1]))[0] == AddBlockResult.NEW_PEAK
2816
+ # assert (await b.add_block(blocks[2]))[0] == AddBlockResult.NEW_PEAK
2817
+
2818
+ # wt: WalletTool = bt_2.get_pool_wallet_tool()
2819
+
2820
+ # condition_dict: Dict[ConditionOpcode, List[ConditionWithArgs]] = {ConditionOpcode.CREATE_COIN: []}
2821
+ # output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt_2.pool_ph, int_to_bytes(2 ** 64)])
2822
+ # condition_dict[ConditionOpcode.CREATE_COIN].append(output)
2823
+
2824
+ # tx = wt.generate_signed_transaction_multiple_coins(
2825
+ # uint64(10),
2826
+ # wt.get_new_puzzlehash(),
2827
+ # blocks[1].get_included_reward_coins(),
2828
+ # condition_dic=condition_dict,
2829
+ # )
2830
+ # with pytest.raises(Exception):
2831
+ # blocks = bt_2.get_consecutive_blocks(
2832
+ # 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2833
+ # )
2834
+ # await db_wrapper.close()
2835
+ # b.shut_down()
2836
+
2837
+ @pytest.mark.anyio
2838
+ async def test_invalid_merkle_roots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2839
+ # 11
2840
+ blocks = bt.get_consecutive_blocks(
2841
+ 3,
2842
+ guarantee_transaction_block=True,
2843
+ farmer_reward_puzzle_hash=bt.pool_ph,
2844
+ pool_reward_puzzle_hash=bt.pool_ph,
2845
+ )
2846
+ await _validate_and_add_block(empty_blockchain, blocks[0])
2847
+ await _validate_and_add_block(empty_blockchain, blocks[1])
2848
+ await _validate_and_add_block(empty_blockchain, blocks[2])
2849
+
2850
+ wt: WalletTool = bt.get_pool_wallet_tool()
2851
+
2852
+ tx = wt.generate_signed_transaction(
2853
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2854
+ )
2855
+
2856
+ blocks = bt.get_consecutive_blocks(
2857
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2858
+ )
2859
+ block: FullBlock = blocks[-1]
2860
+
2861
+ merkle_set = MerkleSet([])
2862
+ # additions
2863
+ block_2 = recursive_replace(block, "foliage_transaction_block.additions_root", merkle_set.get_root())
2864
+ block_2 = recursive_replace(
2865
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2866
+ )
2867
+ new_m = block_2.foliage.foliage_transaction_block_hash
2868
+ assert new_m is not None
2869
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2870
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2871
+
2872
+ await _validate_and_add_block(empty_blockchain, block_2, expected_error=Err.BAD_ADDITION_ROOT)
2873
+
2874
+ # removals
2875
+ merkle_set = MerkleSet([std_hash(b"1")])
2876
+ block_2 = recursive_replace(block, "foliage_transaction_block.removals_root", merkle_set.get_root())
2877
+ block_2 = recursive_replace(
2878
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2879
+ )
2880
+ new_m = block_2.foliage.foliage_transaction_block_hash
2881
+ assert new_m is not None
2882
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2883
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2884
+
2885
+ await _validate_and_add_block(empty_blockchain, block_2, expected_error=Err.BAD_REMOVAL_ROOT)
2886
+
2887
+ @pytest.mark.anyio
2888
+ async def test_invalid_filter(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2889
+ # 12
2890
+ b = empty_blockchain
2891
+ blocks = bt.get_consecutive_blocks(
2892
+ 3,
2893
+ guarantee_transaction_block=True,
2894
+ farmer_reward_puzzle_hash=bt.pool_ph,
2895
+ pool_reward_puzzle_hash=bt.pool_ph,
2896
+ )
2897
+ await _validate_and_add_block(b, blocks[0])
2898
+ await _validate_and_add_block(b, blocks[1])
2899
+ await _validate_and_add_block(b, blocks[2])
2900
+
2901
+ wt: WalletTool = bt.get_pool_wallet_tool()
2902
+
2903
+ tx = wt.generate_signed_transaction(
2904
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2905
+ )
2906
+
2907
+ blocks = bt.get_consecutive_blocks(
2908
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2909
+ )
2910
+ block: FullBlock = blocks[-1]
2911
+ block_2 = recursive_replace(block, "foliage_transaction_block.filter_hash", std_hash(b"3"))
2912
+ block_2 = recursive_replace(
2913
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
2914
+ )
2915
+ new_m = block_2.foliage.foliage_transaction_block_hash
2916
+ assert new_m is not None
2917
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
2918
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
2919
+
2920
+ await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_TRANSACTIONS_FILTER_HASH)
2921
+
2922
+ @pytest.mark.anyio
2923
+ async def test_duplicate_outputs(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2924
+ # 13
2925
+ b = empty_blockchain
2926
+ blocks = bt.get_consecutive_blocks(
2927
+ 3,
2928
+ guarantee_transaction_block=True,
2929
+ farmer_reward_puzzle_hash=bt.pool_ph,
2930
+ pool_reward_puzzle_hash=bt.pool_ph,
2931
+ )
2932
+ await _validate_and_add_block(b, blocks[0])
2933
+ await _validate_and_add_block(b, blocks[1])
2934
+ await _validate_and_add_block(b, blocks[2])
2935
+
2936
+ wt: WalletTool = bt.get_pool_wallet_tool()
2937
+
2938
+ condition_dict: Dict[ConditionOpcode, List[ConditionWithArgs]] = {ConditionOpcode.CREATE_COIN: []}
2939
+ for _ in range(2):
2940
+ output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt.pool_ph, int_to_bytes(1)])
2941
+ condition_dict[ConditionOpcode.CREATE_COIN].append(output)
2942
+
2943
+ tx = wt.generate_signed_transaction(
2944
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0], condition_dic=condition_dict
2945
+ )
2946
+
2947
+ blocks = bt.get_consecutive_blocks(
2948
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
2949
+ )
2950
+ await _validate_and_add_block(b, blocks[-1], expected_error=Err.DUPLICATE_OUTPUT)
2951
+
2952
+ @pytest.mark.anyio
2953
+ async def test_duplicate_removals(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2954
+ # 14
2955
+ b = empty_blockchain
2956
+ blocks = bt.get_consecutive_blocks(
2957
+ 3,
2958
+ guarantee_transaction_block=True,
2959
+ farmer_reward_puzzle_hash=bt.pool_ph,
2960
+ pool_reward_puzzle_hash=bt.pool_ph,
2961
+ )
2962
+ await _validate_and_add_block(b, blocks[0])
2963
+ await _validate_and_add_block(b, blocks[1])
2964
+ await _validate_and_add_block(b, blocks[2])
2965
+
2966
+ wt: WalletTool = bt.get_pool_wallet_tool()
2967
+
2968
+ tx = wt.generate_signed_transaction(
2969
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2970
+ )
2971
+ tx_2 = wt.generate_signed_transaction(
2972
+ uint64(11), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2973
+ )
2974
+ agg = SpendBundle.aggregate([tx, tx_2])
2975
+
2976
+ blocks = bt.get_consecutive_blocks(
2977
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=agg
2978
+ )
2979
+ await _validate_and_add_block(b, blocks[-1], expected_error=Err.DOUBLE_SPEND)
2980
+
2981
+ @pytest.mark.anyio
2982
+ async def test_double_spent_in_coin_store(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
2983
+ # 15
2984
+ b = empty_blockchain
2985
+ blocks = bt.get_consecutive_blocks(
2986
+ 3,
2987
+ guarantee_transaction_block=True,
2988
+ farmer_reward_puzzle_hash=bt.pool_ph,
2989
+ pool_reward_puzzle_hash=bt.pool_ph,
2990
+ )
2991
+ await _validate_and_add_block(b, blocks[0])
2992
+ await _validate_and_add_block(b, blocks[1])
2993
+ await _validate_and_add_block(b, blocks[2])
2994
+
2995
+ wt: WalletTool = bt.get_pool_wallet_tool()
2996
+
2997
+ tx = wt.generate_signed_transaction(
2998
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
2999
+ )
3000
+
3001
+ blocks = bt.get_consecutive_blocks(
3002
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
3003
+ )
3004
+ await _validate_and_add_block(b, blocks[-1])
3005
+
3006
+ tx_2 = wt.generate_signed_transaction(
3007
+ uint64(10), wt.get_new_puzzlehash(), blocks[-2].get_included_reward_coins()[0]
3008
+ )
3009
+ blocks = bt.get_consecutive_blocks(
3010
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx_2
3011
+ )
3012
+
3013
+ await _validate_and_add_block(b, blocks[-1], expected_error=Err.DOUBLE_SPEND)
3014
+
3015
+ @pytest.mark.anyio
3016
+ async def test_double_spent_in_reorg(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3017
+ # 15
3018
+ b = empty_blockchain
3019
+ blocks = bt.get_consecutive_blocks(
3020
+ 3,
3021
+ guarantee_transaction_block=True,
3022
+ farmer_reward_puzzle_hash=bt.pool_ph,
3023
+ pool_reward_puzzle_hash=bt.pool_ph,
3024
+ )
3025
+ await _validate_and_add_block(b, blocks[0])
3026
+ await _validate_and_add_block(b, blocks[1])
3027
+ await _validate_and_add_block(b, blocks[2])
3028
+
3029
+ wt: WalletTool = bt.get_pool_wallet_tool()
3030
+
3031
+ tx = wt.generate_signed_transaction(
3032
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
3033
+ )
3034
+ blocks = bt.get_consecutive_blocks(
3035
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
3036
+ )
3037
+ await _validate_and_add_block(b, blocks[-1])
3038
+
3039
+ new_coin: Coin = tx.additions()[0]
3040
+ tx_2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), new_coin)
3041
+ # This is fine because coin exists
3042
+ blocks = bt.get_consecutive_blocks(
3043
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx_2
3044
+ )
3045
+ await _validate_and_add_block(b, blocks[-1])
3046
+ blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, guarantee_transaction_block=True)
3047
+ for block in blocks[-5:]:
3048
+ await _validate_and_add_block(b, block)
3049
+
3050
+ blocks_reorg = bt.get_consecutive_blocks(2, block_list_input=blocks[:-7], guarantee_transaction_block=True)
3051
+ await _validate_and_add_block(b, blocks_reorg[-2], expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3052
+ await _validate_and_add_block(b, blocks_reorg[-1], expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3053
+
3054
+ # Coin does not exist in reorg
3055
+ blocks_reorg = bt.get_consecutive_blocks(
3056
+ 1, block_list_input=blocks_reorg, guarantee_transaction_block=True, transaction_data=tx_2
3057
+ )
3058
+
3059
+ await _validate_and_add_block(b, blocks_reorg[-1], expected_error=Err.UNKNOWN_UNSPENT)
3060
+
3061
+ # Finally add the block to the fork (spending both in same bundle, this is ephemeral)
3062
+ agg = SpendBundle.aggregate([tx, tx_2])
3063
+ blocks_reorg = bt.get_consecutive_blocks(
3064
+ 1, block_list_input=blocks_reorg[:-1], guarantee_transaction_block=True, transaction_data=agg
3065
+ )
3066
+ await _validate_and_add_block(b, blocks_reorg[-1], expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3067
+
3068
+ blocks_reorg = bt.get_consecutive_blocks(
3069
+ 1, block_list_input=blocks_reorg, guarantee_transaction_block=True, transaction_data=tx_2
3070
+ )
3071
+ await _validate_and_add_block(b, blocks_reorg[-1], expected_error=Err.DOUBLE_SPEND_IN_FORK)
3072
+
3073
+ rewards_ph = wt.get_new_puzzlehash()
3074
+ blocks_reorg = bt.get_consecutive_blocks(
3075
+ 10,
3076
+ block_list_input=blocks_reorg[:-1],
3077
+ guarantee_transaction_block=True,
3078
+ farmer_reward_puzzle_hash=rewards_ph,
3079
+ )
3080
+ for block in blocks_reorg[-10:]:
3081
+ await _validate_and_add_block_multi_result(
3082
+ b, block, expected_result=[AddBlockResult.ADDED_AS_ORPHAN, AddBlockResult.NEW_PEAK]
3083
+ )
3084
+
3085
+ # ephemeral coin is spent
3086
+ first_coin = await b.coin_store.get_coin_record(new_coin.name())
3087
+ assert first_coin is not None and first_coin.spent
3088
+ second_coin = await b.coin_store.get_coin_record(tx_2.additions()[0].name())
3089
+ assert second_coin is not None and not second_coin.spent
3090
+
3091
+ farmer_coin = create_farmer_coin(
3092
+ blocks_reorg[-1].height,
3093
+ rewards_ph,
3094
+ calculate_base_farmer_reward(blocks_reorg[-1].height),
3095
+ bt.constants.GENESIS_CHALLENGE,
3096
+ )
3097
+ tx_3 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), farmer_coin)
3098
+
3099
+ blocks_reorg = bt.get_consecutive_blocks(
3100
+ 1, block_list_input=blocks_reorg, guarantee_transaction_block=True, transaction_data=tx_3
3101
+ )
3102
+ await _validate_and_add_block(b, blocks_reorg[-1])
3103
+
3104
+ farmer_coin_record = await b.coin_store.get_coin_record(farmer_coin.name())
3105
+ assert farmer_coin_record is not None and farmer_coin_record.spent
3106
+
3107
+ @pytest.mark.anyio
3108
+ async def test_minting_coin(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3109
+ # 16 Minting coin check
3110
+ b = empty_blockchain
3111
+ blocks = bt.get_consecutive_blocks(
3112
+ 3,
3113
+ guarantee_transaction_block=True,
3114
+ farmer_reward_puzzle_hash=bt.pool_ph,
3115
+ pool_reward_puzzle_hash=bt.pool_ph,
3116
+ )
3117
+ await _validate_and_add_block(b, blocks[0])
3118
+ await _validate_and_add_block(b, blocks[1])
3119
+ await _validate_and_add_block(b, blocks[2])
3120
+
3121
+ wt: WalletTool = bt.get_pool_wallet_tool()
3122
+
3123
+ spend = blocks[-1].get_included_reward_coins()[0]
3124
+ print("spend=", spend)
3125
+ # this create coin will spend all of the coin, so the 10 mojos below
3126
+ # will be "minted".
3127
+ output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt.pool_ph, int_to_bytes(spend.amount)])
3128
+ condition_dict = {ConditionOpcode.CREATE_COIN: [output]}
3129
+
3130
+ tx = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), spend, condition_dic=condition_dict)
3131
+
3132
+ blocks = bt.get_consecutive_blocks(
3133
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
3134
+ )
3135
+ await _validate_and_add_block(b, blocks[-1], expected_error=Err.MINTING_COIN)
3136
+ # 17 is tested in mempool tests
3137
+
3138
+ @pytest.mark.anyio
3139
+ async def test_max_coin_amount_fee(self) -> None:
3140
+ # 18 TODO: we can't create a block with such amounts due to uint64
3141
+ pass
3142
+
3143
+ @pytest.mark.anyio
3144
+ async def test_invalid_fees_in_block(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3145
+ # 19
3146
+ b = empty_blockchain
3147
+ blocks = bt.get_consecutive_blocks(
3148
+ 3,
3149
+ guarantee_transaction_block=True,
3150
+ farmer_reward_puzzle_hash=bt.pool_ph,
3151
+ pool_reward_puzzle_hash=bt.pool_ph,
3152
+ )
3153
+ await _validate_and_add_block(b, blocks[0])
3154
+ await _validate_and_add_block(b, blocks[1])
3155
+ await _validate_and_add_block(b, blocks[2])
3156
+
3157
+ wt: WalletTool = bt.get_pool_wallet_tool()
3158
+
3159
+ tx = wt.generate_signed_transaction(
3160
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
3161
+ )
3162
+
3163
+ blocks = bt.get_consecutive_blocks(
3164
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
3165
+ )
3166
+ block: FullBlock = blocks[-1]
3167
+
3168
+ # wrong feees
3169
+ block_2: FullBlock = recursive_replace(block, "transactions_info.fees", uint64(1239))
3170
+ assert block_2.transactions_info is not None
3171
+ block_2 = recursive_replace(
3172
+ block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
3173
+ )
3174
+ assert block_2.foliage_transaction_block is not None
3175
+ block_2 = recursive_replace(
3176
+ block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
3177
+ )
3178
+ new_m = block_2.foliage.foliage_transaction_block_hash
3179
+ assert new_m is not None
3180
+ new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
3181
+ block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
3182
+
3183
+ await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_BLOCK_FEE_AMOUNT)
3184
+
3185
+ @pytest.mark.anyio
3186
+ async def test_invalid_agg_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3187
+ # 22
3188
+ b = empty_blockchain
3189
+ blocks = bt.get_consecutive_blocks(
3190
+ 3,
3191
+ guarantee_transaction_block=True,
3192
+ farmer_reward_puzzle_hash=bt.pool_ph,
3193
+ pool_reward_puzzle_hash=bt.pool_ph,
3194
+ )
3195
+ await _validate_and_add_block(b, blocks[0])
3196
+ await _validate_and_add_block(b, blocks[1])
3197
+ await _validate_and_add_block(b, blocks[2])
3198
+
3199
+ wt: WalletTool = bt.get_pool_wallet_tool()
3200
+
3201
+ tx = wt.generate_signed_transaction(
3202
+ uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
3203
+ )
3204
+ blocks = bt.get_consecutive_blocks(
3205
+ 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
3206
+ )
3207
+
3208
+ last_block = recursive_replace(blocks[-1], "transactions_info.aggregated_signature", G2Element.generator())
3209
+ assert last_block.transactions_info is not None
3210
+ last_block = recursive_replace(
3211
+ last_block, "foliage_transaction_block.transactions_info_hash", last_block.transactions_info.get_hash()
3212
+ )
3213
+ assert last_block.foliage_transaction_block is not None
3214
+ last_block = recursive_replace(
3215
+ last_block, "foliage.foliage_transaction_block_hash", last_block.foliage_transaction_block.get_hash()
3216
+ )
3217
+ new_m = last_block.foliage.foliage_transaction_block_hash
3218
+ assert new_m is not None
3219
+ new_fsb_sig = bt.get_plot_signature(new_m, last_block.reward_chain_block.proof_of_space.plot_public_key)
3220
+ last_block = recursive_replace(last_block, "foliage.foliage_transaction_block_signature", new_fsb_sig)
3221
+
3222
+ # Bad signature fails during add_block
3223
+ await _validate_and_add_block(b, last_block, expected_error=Err.BAD_AGGREGATE_SIGNATURE)
3224
+ # Also test the same case but when using BLSCache
3225
+ await _validate_and_add_block(b, last_block, expected_error=Err.BAD_AGGREGATE_SIGNATURE, use_bls_cache=True)
3226
+
3227
+ # Bad signature also fails in prevalidation
3228
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
3229
+ diff = b.constants.DIFFICULTY_STARTING
3230
+ preval_results = await pre_validate_blocks_multiprocessing(
3231
+ b.constants,
3232
+ b,
3233
+ [last_block],
3234
+ b.pool,
3235
+ {},
3236
+ sub_slot_iters=ssi,
3237
+ difficulty=diff,
3238
+ prev_ses_block=None,
3239
+ validate_signatures=True,
3240
+ )
3241
+ assert preval_results is not None
3242
+ assert preval_results[0].error == Err.BAD_AGGREGATE_SIGNATURE.value
3243
+
3244
+
3245
+ def maybe_header_hash(block: Optional[BlockRecord]) -> Optional[bytes32]:
3246
+ if block is None:
3247
+ return None
3248
+ return block.header_hash
3249
+
3250
+
3251
+ class TestReorgs:
3252
+ @pytest.mark.anyio
3253
+ async def test_basic_reorg(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3254
+ b = empty_blockchain
3255
+ blocks = bt.get_consecutive_blocks(15)
3256
+
3257
+ for block in blocks:
3258
+ await _validate_and_add_block(b, block)
3259
+ peak = b.get_peak()
3260
+ assert peak is not None
3261
+ assert peak.height == 14
3262
+
3263
+ blocks_reorg_chain = bt.get_consecutive_blocks(7, blocks[:10], seed=b"2")
3264
+ for reorg_block in blocks_reorg_chain:
3265
+ if reorg_block.height < 10:
3266
+ await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK)
3267
+ elif reorg_block.height < 15:
3268
+ await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3269
+ elif reorg_block.height >= 15:
3270
+ await _validate_and_add_block(b, reorg_block)
3271
+ peak = b.get_peak()
3272
+ assert peak is not None
3273
+ assert peak.height == 16
3274
+
3275
+ @pytest.mark.anyio
3276
+ async def test_get_tx_peak_reorg(
3277
+ self, empty_blockchain: Blockchain, bt: BlockTools, consensus_mode: ConsensusMode
3278
+ ) -> None:
3279
+ b = empty_blockchain
3280
+
3281
+ if consensus_mode < ConsensusMode.HARD_FORK_2_0:
3282
+ reorg_point = 13
3283
+ else:
3284
+ reorg_point = 12
3285
+ blocks = bt.get_consecutive_blocks(reorg_point)
3286
+
3287
+ last_tx_block: Optional[bytes32] = None
3288
+ for block in blocks:
3289
+ assert maybe_header_hash(b.get_tx_peak()) == last_tx_block
3290
+ await _validate_and_add_block(b, block)
3291
+ if block.is_transaction_block():
3292
+ last_tx_block = block.header_hash
3293
+ peak = b.get_peak()
3294
+ assert peak is not None
3295
+ assert peak.height == reorg_point - 1
3296
+ assert maybe_header_hash(b.get_tx_peak()) == last_tx_block
3297
+
3298
+ reorg_last_tx_block: Optional[bytes32] = None
3299
+
3300
+ blocks_reorg_chain = bt.get_consecutive_blocks(7, blocks[:10], seed=b"2")
3301
+ assert blocks_reorg_chain[reorg_point].is_transaction_block() is False
3302
+ for reorg_block in blocks_reorg_chain:
3303
+ if reorg_block.height < 10:
3304
+ await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK)
3305
+ elif reorg_block.height < reorg_point:
3306
+ await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3307
+ elif reorg_block.height >= reorg_point:
3308
+ await _validate_and_add_block(b, reorg_block)
3309
+
3310
+ if reorg_block.is_transaction_block():
3311
+ reorg_last_tx_block = reorg_block.header_hash
3312
+ if reorg_block.height >= reorg_point:
3313
+ last_tx_block = reorg_last_tx_block
3314
+
3315
+ assert maybe_header_hash(b.get_tx_peak()) == last_tx_block
3316
+
3317
+ peak = b.get_peak()
3318
+ assert peak is not None
3319
+ assert peak.height == 16
3320
+
3321
+ @pytest.mark.anyio
3322
+ @pytest.mark.parametrize("light_blocks", [True, False])
3323
+ async def test_long_reorg(
3324
+ self,
3325
+ light_blocks: bool,
3326
+ empty_blockchain: Blockchain,
3327
+ default_10000_blocks: List[FullBlock],
3328
+ test_long_reorg_blocks: List[FullBlock],
3329
+ test_long_reorg_blocks_light: List[FullBlock],
3330
+ ) -> None:
3331
+ if light_blocks:
3332
+ reorg_blocks = test_long_reorg_blocks_light[:1650]
3333
+ else:
3334
+ reorg_blocks = test_long_reorg_blocks[:1200]
3335
+
3336
+ # Reorg longer than a difficulty adjustment
3337
+ # Also tests higher weight chain but lower height
3338
+ b = empty_blockchain
3339
+ num_blocks_chain_1 = 1600
3340
+ num_blocks_chain_2_start = 500
3341
+
3342
+ assert num_blocks_chain_1 < 10000
3343
+ blocks = default_10000_blocks[:num_blocks_chain_1]
3344
+
3345
+ print(f"pre-validating {len(blocks)} blocks")
3346
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
3347
+ diff = b.constants.DIFFICULTY_STARTING
3348
+ pre_validation_results: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
3349
+ b.constants,
3350
+ b,
3351
+ blocks,
3352
+ b.pool,
3353
+ {},
3354
+ sub_slot_iters=ssi,
3355
+ difficulty=diff,
3356
+ prev_ses_block=None,
3357
+ validate_signatures=False,
3358
+ )
3359
+ for i, block in enumerate(blocks):
3360
+ if block.height != 0 and len(block.finished_sub_slots) > 0:
3361
+ if block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters is not None:
3362
+ ssi = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters
3363
+ assert pre_validation_results[i].error is None
3364
+ if (block.height % 100) == 0:
3365
+ print(f"main chain: {block.height:4} weight: {block.weight}")
3366
+ (result, err, _) = await b.add_block(block, pre_validation_results[i], None, sub_slot_iters=ssi)
3367
+ await check_block_store_invariant(b)
3368
+ assert err is None
3369
+ assert result == AddBlockResult.NEW_PEAK
3370
+
3371
+ peak = b.get_peak()
3372
+ assert peak is not None
3373
+ chain_1_height = peak.height
3374
+ chain_1_weight = peak.weight
3375
+ assert chain_1_height == (num_blocks_chain_1 - 1)
3376
+
3377
+ # The reorg blocks will have less time between them (timestamp) and therefore will make difficulty go up
3378
+ # This means that the weight will grow faster, and we can get a heavier chain with lower height
3379
+
3380
+ # If these assert fail, you probably need to change the fixture in reorg_blocks to create the
3381
+ # right amount of blocks at the right time
3382
+ assert reorg_blocks[num_blocks_chain_2_start - 1] == default_10000_blocks[num_blocks_chain_2_start - 1]
3383
+ assert reorg_blocks[num_blocks_chain_2_start] != default_10000_blocks[num_blocks_chain_2_start]
3384
+
3385
+ # one aspect of this test is to make sure we can reorg blocks that are
3386
+ # not in the cache. We need to explicitly prune the cache to get that
3387
+ # effect.
3388
+ b.clean_block_records()
3389
+
3390
+ first_peak = b.get_peak()
3391
+ fork_info: Optional[ForkInfo] = None
3392
+ for reorg_block in reorg_blocks:
3393
+ if (reorg_block.height % 100) == 0:
3394
+ peak = b.get_peak()
3395
+ assert peak is not None
3396
+ print(
3397
+ f"reorg chain: {reorg_block.height:4} "
3398
+ f"weight: {reorg_block.weight:7} "
3399
+ f"peak: {str(peak.header_hash)[:6]}"
3400
+ )
3401
+
3402
+ if reorg_block.height < num_blocks_chain_2_start:
3403
+ await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK)
3404
+ elif reorg_block.weight <= chain_1_weight:
3405
+ if fork_info is None:
3406
+ fork_info = ForkInfo(reorg_block.height - 1, reorg_block.height - 1, reorg_block.prev_header_hash)
3407
+ await _validate_and_add_block(
3408
+ b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
3409
+ )
3410
+ elif reorg_block.weight > chain_1_weight:
3411
+ await _validate_and_add_block(
3412
+ b, reorg_block, expected_result=AddBlockResult.NEW_PEAK, fork_info=fork_info
3413
+ )
3414
+
3415
+ # if these asserts fires, there was no reorg
3416
+ peak = b.get_peak()
3417
+ assert peak is not None
3418
+ assert first_peak != peak
3419
+ assert peak is not None
3420
+ assert peak.weight > chain_1_weight
3421
+ second_peak = peak
3422
+
3423
+ if light_blocks:
3424
+ assert peak.height > chain_1_height
3425
+ else:
3426
+ assert peak.height < chain_1_height
3427
+
3428
+ chain_2_weight = peak.weight
3429
+
3430
+ # now reorg back to the original chain
3431
+ # this exercises the case where we have some of the blocks in the DB already
3432
+ b.clean_block_records()
3433
+
3434
+ if light_blocks:
3435
+ blocks = default_10000_blocks[num_blocks_chain_2_start - 100 : 1800]
3436
+ else:
3437
+ blocks = default_10000_blocks[num_blocks_chain_2_start - 100 : 2600]
3438
+
3439
+ # the block validation requires previous block records to be in the
3440
+ # cache
3441
+ br = await b.get_block_record_from_db(blocks[0].prev_header_hash)
3442
+ for i in range(200):
3443
+ assert br is not None
3444
+ b.add_block_record(br)
3445
+ br = await b.get_block_record_from_db(br.prev_hash)
3446
+ assert br is not None
3447
+ b.add_block_record(br)
3448
+
3449
+ # start the fork point a few blocks back, to test that the blockchain
3450
+ # can catch up
3451
+ fork_block = default_10000_blocks[num_blocks_chain_2_start - 200]
3452
+ fork_info = ForkInfo(fork_block.height, fork_block.height, fork_block.header_hash)
3453
+ await b.warmup(fork_block.height)
3454
+ for block in blocks:
3455
+ if (block.height % 128) == 0:
3456
+ peak = b.get_peak()
3457
+ assert peak is not None
3458
+ print(
3459
+ f"original chain: {block.height:4} "
3460
+ f"weight: {block.weight:7} "
3461
+ f"peak: {str(peak.header_hash)[:6]}"
3462
+ )
3463
+ if block.height <= chain_1_height:
3464
+ expect = AddBlockResult.ALREADY_HAVE_BLOCK
3465
+ elif block.weight < chain_2_weight:
3466
+ expect = AddBlockResult.ADDED_AS_ORPHAN
3467
+ else:
3468
+ expect = AddBlockResult.NEW_PEAK
3469
+ await _validate_and_add_block(b, block, fork_info=fork_info, expected_result=expect)
3470
+
3471
+ # if these asserts fires, there was no reorg back to the original chain
3472
+ peak = b.get_peak()
3473
+ assert peak is not None
3474
+ assert peak.header_hash != second_peak.header_hash
3475
+ assert peak.weight > chain_2_weight
3476
+
3477
+ @pytest.mark.anyio
3478
+ async def test_long_compact_blockchain(
3479
+ self, empty_blockchain: Blockchain, default_2000_blocks_compact: List[FullBlock]
3480
+ ) -> None:
3481
+ b = empty_blockchain
3482
+ for block in default_2000_blocks_compact:
3483
+ await _validate_and_add_block(b, block, skip_prevalidation=True)
3484
+ peak = b.get_peak()
3485
+ assert peak is not None
3486
+ assert peak.height == len(default_2000_blocks_compact) - 1
3487
+
3488
+ @pytest.mark.anyio
3489
+ async def test_reorg_from_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3490
+ b = empty_blockchain
3491
+
3492
+ blocks = bt.get_consecutive_blocks(15)
3493
+
3494
+ for block in blocks:
3495
+ await _validate_and_add_block(b, block)
3496
+ peak = b.get_peak()
3497
+ assert peak is not None
3498
+ assert peak.height == 14
3499
+
3500
+ # Reorg to alternate chain that is 1 height longer
3501
+ blocks_reorg_chain = bt.get_consecutive_blocks(16, [], seed=b"2")
3502
+ for reorg_block in blocks_reorg_chain:
3503
+ if reorg_block.height < 15:
3504
+ await _validate_and_add_block_multi_result(
3505
+ b,
3506
+ reorg_block,
3507
+ expected_result=[AddBlockResult.ADDED_AS_ORPHAN, AddBlockResult.ALREADY_HAVE_BLOCK],
3508
+ )
3509
+ elif reorg_block.height >= 15:
3510
+ await _validate_and_add_block(b, reorg_block)
3511
+
3512
+ # Back to original chain
3513
+ blocks_reorg_chain_2 = bt.get_consecutive_blocks(3, blocks, seed=b"3")
3514
+
3515
+ await _validate_and_add_block(b, blocks_reorg_chain_2[-3], expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3516
+ await _validate_and_add_block(b, blocks_reorg_chain_2[-2])
3517
+ await _validate_and_add_block(b, blocks_reorg_chain_2[-1])
3518
+
3519
+ peak = b.get_peak()
3520
+ assert peak is not None
3521
+ assert peak.height == 17
3522
+
3523
+ @pytest.mark.anyio
3524
+ async def test_reorg_transaction(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3525
+ b = empty_blockchain
3526
+ wallet_a = WalletTool(b.constants)
3527
+ WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
3528
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
3529
+ receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
3530
+
3531
+ blocks = bt.get_consecutive_blocks(10, farmer_reward_puzzle_hash=coinbase_puzzlehash)
3532
+ blocks = bt.get_consecutive_blocks(
3533
+ 2, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True
3534
+ )
3535
+
3536
+ spend_block = blocks[10]
3537
+ spend_coin = None
3538
+ for coin in spend_block.get_included_reward_coins():
3539
+ if coin.puzzle_hash == coinbase_puzzlehash:
3540
+ spend_coin = coin
3541
+ assert spend_coin is not None
3542
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, spend_coin)
3543
+
3544
+ blocks = bt.get_consecutive_blocks(
3545
+ 2,
3546
+ blocks,
3547
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3548
+ transaction_data=spend_bundle,
3549
+ guarantee_transaction_block=True,
3550
+ )
3551
+
3552
+ blocks_fork = bt.get_consecutive_blocks(
3553
+ 1, blocks[:12], farmer_reward_puzzle_hash=coinbase_puzzlehash, seed=b"123", guarantee_transaction_block=True
3554
+ )
3555
+ blocks_fork = bt.get_consecutive_blocks(
3556
+ 2,
3557
+ blocks_fork,
3558
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3559
+ transaction_data=spend_bundle,
3560
+ guarantee_transaction_block=True,
3561
+ seed=b"1245",
3562
+ )
3563
+ for block in blocks:
3564
+ await _validate_and_add_block(b, block)
3565
+
3566
+ for block in blocks_fork:
3567
+ await _validate_and_add_block_no_error(b, block)
3568
+
3569
+ @pytest.mark.anyio
3570
+ async def test_get_header_blocks_in_range_tx_filter(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
3571
+ b = empty_blockchain
3572
+ blocks = bt.get_consecutive_blocks(
3573
+ 3,
3574
+ guarantee_transaction_block=True,
3575
+ pool_reward_puzzle_hash=bt.pool_ph,
3576
+ farmer_reward_puzzle_hash=bt.pool_ph,
3577
+ )
3578
+ await _validate_and_add_block(b, blocks[0])
3579
+ await _validate_and_add_block(b, blocks[1])
3580
+ await _validate_and_add_block(b, blocks[2])
3581
+ wt: WalletTool = bt.get_pool_wallet_tool()
3582
+ tx = wt.generate_signed_transaction(
3583
+ uint64(10), wt.get_new_puzzlehash(), blocks[2].get_included_reward_coins()[0]
3584
+ )
3585
+ blocks = bt.get_consecutive_blocks(
3586
+ 1,
3587
+ block_list_input=blocks,
3588
+ guarantee_transaction_block=True,
3589
+ transaction_data=tx,
3590
+ )
3591
+ await _validate_and_add_block(b, blocks[-1])
3592
+
3593
+ blocks_with_filter = await b.get_header_blocks_in_range(0, 10, tx_filter=True)
3594
+ blocks_without_filter = await b.get_header_blocks_in_range(0, 10, tx_filter=False)
3595
+ header_hash = blocks[-1].header_hash
3596
+ assert (
3597
+ blocks_with_filter[header_hash].transactions_filter
3598
+ != blocks_without_filter[header_hash].transactions_filter
3599
+ )
3600
+ assert blocks_with_filter[header_hash].header_hash == blocks_without_filter[header_hash].header_hash
3601
+
3602
+ @pytest.mark.anyio
3603
+ async def test_get_blocks_at(self, empty_blockchain: Blockchain, default_1000_blocks: List[FullBlock]) -> None:
3604
+ b = empty_blockchain
3605
+ heights = []
3606
+ for block in default_1000_blocks[:200]:
3607
+ heights.append(block.height)
3608
+ await _validate_and_add_block(b, block)
3609
+
3610
+ blocks = await b.get_block_records_at(heights, batch_size=2)
3611
+ assert blocks
3612
+ assert len(blocks) == 200
3613
+ assert blocks[-1].height == 199
3614
+
3615
+
3616
+ @pytest.mark.anyio
3617
+ async def test_reorg_new_ref(empty_blockchain: Blockchain, bt: BlockTools) -> None:
3618
+ b = empty_blockchain
3619
+ wallet_a = WalletTool(b.constants)
3620
+ WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
3621
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
3622
+ receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
3623
+
3624
+ blocks = bt.get_consecutive_blocks(
3625
+ 5,
3626
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3627
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3628
+ guarantee_transaction_block=True,
3629
+ )
3630
+
3631
+ all_coins = []
3632
+ for spend_block in blocks[:5]:
3633
+ for coin in spend_block.get_included_reward_coins():
3634
+ if coin.puzzle_hash == coinbase_puzzlehash:
3635
+ all_coins.append(coin)
3636
+ spend_bundle_0 = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3637
+ blocks = bt.get_consecutive_blocks(
3638
+ 15,
3639
+ block_list_input=blocks,
3640
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3641
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3642
+ transaction_data=spend_bundle_0,
3643
+ guarantee_transaction_block=True,
3644
+ )
3645
+
3646
+ for block in blocks:
3647
+ await _validate_and_add_block(b, block)
3648
+ peak = b.get_peak()
3649
+ assert peak is not None
3650
+ assert peak.height == 19
3651
+
3652
+ print("first chain done")
3653
+
3654
+ # Make sure a ref back into the reorg chain itself works as expected
3655
+
3656
+ blocks_reorg_chain = bt.get_consecutive_blocks(
3657
+ 1,
3658
+ blocks[:10],
3659
+ seed=b"2",
3660
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3661
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3662
+ )
3663
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3664
+
3665
+ blocks_reorg_chain = bt.get_consecutive_blocks(
3666
+ 2,
3667
+ blocks_reorg_chain,
3668
+ seed=b"2",
3669
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3670
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3671
+ transaction_data=spend_bundle,
3672
+ guarantee_transaction_block=True,
3673
+ )
3674
+
3675
+ spend_bundle2 = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3676
+ blocks_reorg_chain = bt.get_consecutive_blocks(
3677
+ 4, blocks_reorg_chain, seed=b"2", block_refs=[uint32(5), uint32(11)], transaction_data=spend_bundle2
3678
+ )
3679
+ blocks_reorg_chain = bt.get_consecutive_blocks(4, blocks_reorg_chain, seed=b"2")
3680
+
3681
+ for i, block in enumerate(blocks_reorg_chain):
3682
+ fork_info: Optional[ForkInfo] = None
3683
+ if i < 10:
3684
+ expected = AddBlockResult.ALREADY_HAVE_BLOCK
3685
+ elif i < 19:
3686
+ expected = AddBlockResult.ADDED_AS_ORPHAN
3687
+ elif i == 19:
3688
+ # same height as peak decide by iterations
3689
+ peak = b.get_peak()
3690
+ assert peak is not None
3691
+ # same height as peak should be ADDED_AS_ORPHAN if block.total_iters >= peak.total_iters
3692
+ assert block.total_iters < peak.total_iters
3693
+ expected = AddBlockResult.NEW_PEAK
3694
+ else:
3695
+ expected = AddBlockResult.NEW_PEAK
3696
+ if fork_info is None:
3697
+ fork_info = ForkInfo(blocks[1].height, blocks[1].height, blocks[1].header_hash)
3698
+ await _validate_and_add_block(b, block, expected_result=expected, fork_info=fork_info)
3699
+ peak = b.get_peak()
3700
+ assert peak is not None
3701
+ assert peak.height == 20
3702
+
3703
+
3704
+ # this test doesn't reorg, but _reconsider_peak() is passed a stale
3705
+ # "fork_height" to make it look like it's in a reorg, but all the same blocks
3706
+ # are just added back.
3707
+ @pytest.mark.anyio
3708
+ async def test_reorg_stale_fork_height(empty_blockchain: Blockchain, bt: BlockTools) -> None:
3709
+ b = empty_blockchain
3710
+ wallet_a = WalletTool(b.constants)
3711
+ WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
3712
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
3713
+ receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
3714
+
3715
+ blocks = bt.get_consecutive_blocks(
3716
+ 5,
3717
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3718
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3719
+ guarantee_transaction_block=True,
3720
+ )
3721
+
3722
+ all_coins = []
3723
+ for spend_block in blocks:
3724
+ for coin in spend_block.get_included_reward_coins():
3725
+ if coin.puzzle_hash == coinbase_puzzlehash:
3726
+ all_coins.append(coin)
3727
+
3728
+ # Make sure a ref back into the reorg chain itself works as expected
3729
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3730
+
3731
+ # make sure we have a transaction block, with at least one transaction in it
3732
+ blocks = bt.get_consecutive_blocks(
3733
+ 5,
3734
+ blocks,
3735
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3736
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3737
+ transaction_data=spend_bundle,
3738
+ guarantee_transaction_block=True,
3739
+ )
3740
+
3741
+ # this block (height 10) refers back to the generator in block 5
3742
+ spend_bundle2 = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3743
+ blocks = bt.get_consecutive_blocks(4, blocks, block_refs=[uint32(5)], transaction_data=spend_bundle2)
3744
+
3745
+ for block in blocks[:5]:
3746
+ await _validate_and_add_block(b, block, expected_result=AddBlockResult.NEW_PEAK)
3747
+
3748
+ # fake the fork_info to make every new block look like a reorg
3749
+ fork_info = ForkInfo(blocks[1].height, blocks[1].height, blocks[1].header_hash)
3750
+ for block in blocks[5:]:
3751
+ await _validate_and_add_block(b, block, expected_result=AddBlockResult.NEW_PEAK, fork_info=fork_info)
3752
+ peak = b.get_peak()
3753
+ assert peak is not None
3754
+ assert peak.height == 13
3755
+
3756
+
3757
+ @pytest.mark.anyio
3758
+ async def test_chain_failed_rollback(empty_blockchain: Blockchain, bt: BlockTools) -> None:
3759
+ b = empty_blockchain
3760
+ wallet_a = WalletTool(b.constants)
3761
+ WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
3762
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
3763
+ receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
3764
+
3765
+ blocks = bt.get_consecutive_blocks(
3766
+ 20,
3767
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3768
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3769
+ )
3770
+
3771
+ for block in blocks:
3772
+ await _validate_and_add_block(b, block)
3773
+ peak = b.get_peak()
3774
+ assert peak is not None
3775
+ assert peak.height == 19
3776
+
3777
+ print("first chain done")
3778
+
3779
+ # Make sure a ref back into the reorg chain itself works as expected
3780
+
3781
+ all_coins = []
3782
+ for spend_block in blocks[:10]:
3783
+ for coin in spend_block.get_included_reward_coins():
3784
+ if coin.puzzle_hash == coinbase_puzzlehash:
3785
+ all_coins.append(coin)
3786
+
3787
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3788
+
3789
+ blocks_reorg_chain = bt.get_consecutive_blocks(
3790
+ 11,
3791
+ blocks[:10],
3792
+ seed=b"2",
3793
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3794
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3795
+ transaction_data=spend_bundle,
3796
+ guarantee_transaction_block=True,
3797
+ )
3798
+
3799
+ for block in blocks_reorg_chain[10:-1]:
3800
+ await _validate_and_add_block(b, block, expected_result=AddBlockResult.ADDED_AS_ORPHAN)
3801
+
3802
+ # Incorrectly set the height as spent in DB to trigger an error
3803
+ print(f"{await b.coin_store.get_coin_record(spend_bundle.coin_spends[0].coin.name())}")
3804
+ print(spend_bundle.coin_spends[0].coin.name())
3805
+ # await b.coin_store._set_spent([spend_bundle.coin_spends[0].coin.name()], 8)
3806
+ await b.coin_store.rollback_to_block(2)
3807
+ print(f"{await b.coin_store.get_coin_record(spend_bundle.coin_spends[0].coin.name())}")
3808
+
3809
+ with pytest.raises(ValueError, match="Invalid operation to set spent"):
3810
+ await _validate_and_add_block(b, blocks_reorg_chain[-1])
3811
+
3812
+ peak = b.get_peak()
3813
+ assert peak is not None
3814
+ assert peak.height == 19
3815
+
3816
+
3817
+ @pytest.mark.anyio
3818
+ async def test_reorg_flip_flop(empty_blockchain: Blockchain, bt: BlockTools) -> None:
3819
+ b = empty_blockchain
3820
+ wallet_a = WalletTool(b.constants)
3821
+ WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
3822
+ coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
3823
+ receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
3824
+
3825
+ chain_a = bt.get_consecutive_blocks(
3826
+ 10,
3827
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3828
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3829
+ guarantee_transaction_block=True,
3830
+ )
3831
+
3832
+ all_coins = []
3833
+ for spend_block in chain_a:
3834
+ for coin in spend_block.get_included_reward_coins():
3835
+ if coin.puzzle_hash == coinbase_puzzlehash:
3836
+ all_coins.append(coin)
3837
+
3838
+ # this is a transaction block at height 10
3839
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3840
+ chain_a = bt.get_consecutive_blocks(
3841
+ 5,
3842
+ chain_a,
3843
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3844
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3845
+ transaction_data=spend_bundle,
3846
+ guarantee_transaction_block=True,
3847
+ )
3848
+
3849
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3850
+ chain_a = bt.get_consecutive_blocks(
3851
+ 5,
3852
+ chain_a,
3853
+ block_refs=[uint32(10)],
3854
+ transaction_data=spend_bundle,
3855
+ guarantee_transaction_block=True,
3856
+ )
3857
+
3858
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3859
+ chain_a = bt.get_consecutive_blocks(
3860
+ 20,
3861
+ chain_a,
3862
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3863
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3864
+ transaction_data=spend_bundle,
3865
+ guarantee_transaction_block=True,
3866
+ )
3867
+
3868
+ # chain A is 40 blocks deep
3869
+ # chain B share the first 20 blocks with chain A
3870
+
3871
+ # add 5 blocks on top of the first 20, to form chain B
3872
+ chain_b = bt.get_consecutive_blocks(
3873
+ 5,
3874
+ chain_a[:20],
3875
+ seed=b"2",
3876
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3877
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3878
+ )
3879
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3880
+
3881
+ # this is a transaction block at height 15 (in Chain B)
3882
+ chain_b = bt.get_consecutive_blocks(
3883
+ 5,
3884
+ chain_b,
3885
+ seed=b"2",
3886
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3887
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3888
+ transaction_data=spend_bundle,
3889
+ guarantee_transaction_block=True,
3890
+ )
3891
+
3892
+ spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
3893
+ chain_b = bt.get_consecutive_blocks(10, chain_b, seed=b"2", block_refs=[uint32(15)], transaction_data=spend_bundle)
3894
+
3895
+ assert len(chain_a) == len(chain_b)
3896
+
3897
+ counter = 0
3898
+ ssi = b.constants.SUB_SLOT_ITERS_STARTING
3899
+ diff = b.constants.DIFFICULTY_STARTING
3900
+ for b1, b2 in zip(chain_a, chain_b):
3901
+ # alternate the order we add blocks from the two chains, to ensure one
3902
+ # chain overtakes the other one in weight every other time
3903
+ if counter % 2 == 0:
3904
+ block1, block2 = b2, b1
3905
+ else:
3906
+ block1, block2 = b1, b2
3907
+ counter += 1
3908
+
3909
+ preval: List[PreValidationResult] = await pre_validate_blocks_multiprocessing(
3910
+ b.constants,
3911
+ b,
3912
+ [block1],
3913
+ b.pool,
3914
+ {},
3915
+ sub_slot_iters=ssi,
3916
+ difficulty=diff,
3917
+ prev_ses_block=None,
3918
+ validate_signatures=False,
3919
+ )
3920
+ _, err, _ = await b.add_block(block1, preval[0], None, sub_slot_iters=ssi)
3921
+ assert err is None
3922
+ preval = await pre_validate_blocks_multiprocessing(
3923
+ b.constants,
3924
+ b,
3925
+ [block2],
3926
+ b.pool,
3927
+ {},
3928
+ sub_slot_iters=ssi,
3929
+ difficulty=diff,
3930
+ prev_ses_block=None,
3931
+ validate_signatures=False,
3932
+ )
3933
+ _, err, _ = await b.add_block(block2, preval[0], None, sub_slot_iters=ssi)
3934
+ assert err is None
3935
+
3936
+ peak = b.get_peak()
3937
+ assert peak is not None
3938
+ assert peak.height == 39
3939
+
3940
+ chain_b = bt.get_consecutive_blocks(
3941
+ 10,
3942
+ chain_b,
3943
+ seed=b"2",
3944
+ farmer_reward_puzzle_hash=coinbase_puzzlehash,
3945
+ pool_reward_puzzle_hash=receiver_puzzlehash,
3946
+ )
3947
+
3948
+ for block in chain_b[40:]:
3949
+ await _validate_and_add_block(b, block)
3950
+
3951
+
3952
+ async def test_get_tx_peak(default_400_blocks: List[FullBlock], empty_blockchain: Blockchain) -> None:
3953
+ bc = empty_blockchain
3954
+ test_blocks = default_400_blocks[:100]
3955
+ ssi = bc.constants.SUB_SLOT_ITERS_STARTING
3956
+ diff = bc.constants.DIFFICULTY_STARTING
3957
+ res = await pre_validate_blocks_multiprocessing(
3958
+ bc.constants,
3959
+ bc,
3960
+ test_blocks,
3961
+ bc.pool,
3962
+ {},
3963
+ sub_slot_iters=ssi,
3964
+ difficulty=diff,
3965
+ prev_ses_block=None,
3966
+ validate_signatures=False,
3967
+ )
3968
+
3969
+ last_tx_block_record = None
3970
+ for b, prevalidation_res in zip(test_blocks, res):
3971
+ assert bc.get_tx_peak() == last_tx_block_record
3972
+ _, err, _ = await bc.add_block(b, prevalidation_res, None, sub_slot_iters=ssi)
3973
+ assert err is None
3974
+
3975
+ if b.is_transaction_block():
3976
+ assert prevalidation_res.required_iters is not None
3977
+ block_record = block_to_block_record(
3978
+ bc.constants,
3979
+ bc,
3980
+ prevalidation_res.required_iters,
3981
+ b,
3982
+ empty_blockchain.constants.SUB_SLOT_ITERS_STARTING,
3983
+ )
3984
+ last_tx_block_record = block_record
3985
+
3986
+ assert bc.get_tx_peak() == last_tx_block_record
3987
+
3988
+
3989
+ def to_bytes(gen: Optional[SerializedProgram]) -> bytes:
3990
+ assert gen is not None
3991
+ return bytes(gen)
3992
+
3993
+
3994
+ @pytest.mark.anyio
3995
+ @pytest.mark.limit_consensus_modes(reason="block heights for generators differ between test chains in different modes")
3996
+ @pytest.mark.parametrize("clear_cache", [True, False])
3997
+ async def test_lookup_block_generators(
3998
+ default_10000_blocks: List[FullBlock],
3999
+ test_long_reorg_blocks_light: List[FullBlock],
4000
+ bt: BlockTools,
4001
+ empty_blockchain: Blockchain,
4002
+ clear_cache: bool,
4003
+ ) -> None:
4004
+ b = empty_blockchain
4005
+ blocks_1 = default_10000_blocks
4006
+ blocks_2 = test_long_reorg_blocks_light
4007
+
4008
+ # this test blockchain is expected to have block generators at these
4009
+ # heights:
4010
+ # 2, 3, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
4011
+ # 24, 25, 26, 28
4012
+
4013
+ # default_10000_blocks and test_long_reorg_blocks_light diverge at height
4014
+ # 500. Add blocks from both past the fork to be able to test both
4015
+
4016
+ # fork 1 is expected to have generators at these heights:
4017
+ # 503, 507, 511, 517, 524, 529, 532, 533, 534, 539, 542, 543, 546, 547
4018
+
4019
+ # fork 2 is expected to have generators at these heights:
4020
+ # 507, 516, 527, 535, 539, 543, 547
4021
+
4022
+ # start with adding some blocks to test lookups from the mainchain
4023
+ for block in blocks_2[:550]:
4024
+ await _validate_and_add_block(b, block, expected_result=AddBlockResult.NEW_PEAK)
4025
+
4026
+ for block in blocks_1[500:550]:
4027
+ await _validate_and_add_block(b, block, expected_result=AddBlockResult.ADDED_AS_ORPHAN)
4028
+
4029
+ # now we have a blockchain with two forks, the peak is at blocks_2[550] and
4030
+ # the leight weight peak is at blocks_1[550]
4031
+ # make sure we can lookup block generators from each fork
4032
+
4033
+ peak_1 = blocks_1[550]
4034
+ peak_2 = blocks_2[550]
4035
+
4036
+ # single generators, from the shared part of the chain
4037
+ for peak in [peak_1, peak_2]:
4038
+ if clear_cache:
4039
+ b.clean_block_records()
4040
+ generators = await b.lookup_block_generators(peak.prev_header_hash, {uint32(2)})
4041
+ assert generators == {
4042
+ uint32(2): to_bytes(blocks_1[2].transactions_generator),
4043
+ }
4044
+
4045
+ # multiple generators from the shared part of the chain
4046
+ for peak in [peak_1, peak_2]:
4047
+ if clear_cache:
4048
+ b.clean_block_records()
4049
+ generators = await b.lookup_block_generators(peak.prev_header_hash, {uint32(2), uint32(10), uint32(26)})
4050
+ assert generators == {
4051
+ uint32(2): to_bytes(blocks_1[2].transactions_generator),
4052
+ uint32(10): to_bytes(blocks_1[10].transactions_generator),
4053
+ uint32(26): to_bytes(blocks_1[26].transactions_generator),
4054
+ }
4055
+
4056
+ # lookups from the past the fork
4057
+ if clear_cache:
4058
+ b.clean_block_records()
4059
+ generators = await b.lookup_block_generators(peak_1.prev_header_hash, {uint32(503)})
4060
+ assert generators == {uint32(503): to_bytes(blocks_1[503].transactions_generator)}
4061
+
4062
+ if clear_cache:
4063
+ b.clean_block_records()
4064
+ generators = await b.lookup_block_generators(peak_2.prev_header_hash, {uint32(516)})
4065
+ assert generators == {uint32(516): to_bytes(blocks_2[516].transactions_generator)}
4066
+
4067
+ # make sure we don't cross the forks
4068
+ if clear_cache:
4069
+ b.clean_block_records()
4070
+ with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
4071
+ await b.lookup_block_generators(peak_1.prev_header_hash, {uint32(516)})
4072
+
4073
+ if clear_cache:
4074
+ b.clean_block_records()
4075
+ with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
4076
+ await b.lookup_block_generators(peak_2.prev_header_hash, {uint32(503)})
4077
+
4078
+ # make sure we fail when looking up a non-transaction block from the main
4079
+ # chain, regardless of which chain we start at
4080
+ if clear_cache:
4081
+ b.clean_block_records()
4082
+ with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
4083
+ await b.lookup_block_generators(peak_1.prev_header_hash, {uint32(8)})
4084
+
4085
+ if clear_cache:
4086
+ b.clean_block_records()
4087
+ with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
4088
+ await b.lookup_block_generators(peak_2.prev_header_hash, {uint32(8)})
4089
+
4090
+ # if we try to look up generators starting from a disconnected block, we
4091
+ # fail
4092
+ if clear_cache:
4093
+ b.clean_block_records()
4094
+ with pytest.raises(AssertionError):
4095
+ await b.lookup_block_generators(blocks_2[600].prev_header_hash, {uint32(3)})
4096
+
4097
+ if clear_cache:
4098
+ b.clean_block_records()
4099
+ with pytest.raises(AssertionError):
4100
+ await b.lookup_block_generators(blocks_1[600].prev_header_hash, {uint32(3)})